summaryrefslogtreecommitdiff
path: root/git.c
blob: 5e86642a37fd7350bc6345ae9f4c558398492be4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include "config.h"
#include "git.h"
#include "macros.h"


git_repo *add_repo(git_repository *repo, git_repo **first, git_repo **last) {
	git_repo *new_repo = calloc(1, sizeof(git_repo));
	(*last != NULL) ? ((*last)->next = new_repo) : (*first = new_repo);

	new_repo->repo = repo;

	*last = new_repo;

	return new_repo;
}

int find_ignore_file(const char *path) {
	DIR *root = opendir(path);
	struct dirent entry, *result;

	while (readdir_r(root, &entry, &result) == 0 && result != NULL) {
		/* Is this entry a regular file, and is it the ignore file? */
		if (entry.d_type == DT_REG && strcasecmp(entry.d_name, "pullreqd-ignore") == 0) {
			return 1;
		}
	}

	return 0;
}

void cleanup_linked_list(git_repo *root) {
	if (root != NULL) {
		git_repo *repo = root;
		cleanup_linked_list(root->next);
		repo->repo = NULL;
		repo->next = NULL;
	}
}

void cleanup_git_repos(git_repository **repos) {
	for (int i = 0; repos[i] != NULL; i++) {
		git_repository_free(repos[i]);
		repos[i] = NULL;
	}
	free(repos);
}

void cleanup_git(git_repository **repos) {
	cleanup_git_repos(repos);
	git_libgit2_shutdown();
}

git_repository **init_git(config *cfg) {
	git_repository **repos = NULL;
	git_repository *repo = NULL;
	git_repo *first = NULL, *last = NULL, *current = NULL;
	DIR *root = opendir(cfg->git_root);
	struct dirent entry, *result;
	int repo_count = 0;

	log(LOG_INFO, "Initializing libgit2.");
	int ret = git_libgit2_init();

	log(LOG_INFO, "Searching \"%s\" for repositories.", cfg->git_root);
	/* Find all git repos in the git root. */
	while (readdir_r(root, &entry, &result) == 0 && result != NULL) {
		log(LOG_DEBUG, "entry.d_name %s, result->d_name: %s", entry.d_name, result->d_name);
		/* Is this entry a directory? */
		if (entry.d_type == DT_DIR) {
			/* Is the entry neither ".", nor ".."? */
			if (strcmp(entry.d_name, ".") && strcmp(entry.d_name, "..")) {
				char *repo_dir = calloc(strlen(cfg->git_root) + strlen(entry.d_name) + 1, sizeof(char));

				/* Append the directory name to the git root. */
				/* Could also do this:
				 * memcpy(repo_dir, cfg->git_root, strlen(cfg->git_repo));
				 * strcat(repo_dir, entry.d_name);
				 */
				sprintf(repo_dir, "%s%s", cfg->git_root, entry.d_name);
				/* Was no ignore file found? */
				if (!find_ignore_file(repo_dir)) {
					/* Did we fail to open the git repo? */
					if (git_repository_open(&repo, repo_dir)) {
						log(LOG_ERR, "Failed to open git repository %s, ignoring.", entry.d_name);
					} else {
						log(LOG_INFO, "Successfully opened git repository %s", entry.d_name);
						current = add_repo(repo, &first, &last);
						repo_count++;
					}
				}
				free(repo_dir);
			}
		}
	}

	/* Did we find any repos? */
	if (repo_count) {
		log(LOG_INFO, "Found, and opened %i repositories.", repo_count);
		/* Allocate repo_count + 1 git repos, since we need a NULL entry to denote the end. */
		repos = calloc(repo_count+1, sizeof(git_repository *));
		/* Add the repos to the array. */
		int i = 0;
		for (git_repo *r = first; r != NULL; /*repos[i] = r->repo,*/ r = r->next, i++) {
			repos[i] = r->repo;
		}
		cleanup_linked_list(first);
		first = NULL;
		last = NULL;
		current = NULL;

	} else {
		log(LOG_ERR, "Couldn't find, and/or open any repositories.");
	}

	return repos;
}