#include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "git.h" #include "macros.h" #include "misc.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; free(repo); } } 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(); } pull_request *get_pull_request(int id, const char *root) { } int create_info(pull_request *pr, const char *pr_dir) { int len = strlen(pr_dir) + strlen("/info"); char *info = calloc(len+1, sizeof(char)); char *info_buf; FILE *fp; /* Append /info to the PR directory. */ sprintf(info, "%s/info", pr_dir); /* TODO: Write the rest of the code. */ /* Is there already an info file? */ if (access(info, F_OK) == 0) { long size = 0; char *buf = read_file(info, &size); log(LOG_NOTICE, "Info file already exists."); /* Did we read the file? */ if (buf != NULL) { /* Are the contents of the info file the same? */ if (strcmp(info_buf, buf) == 0) { log(LOG_NOTICE, "New info file is the same as the existing one."); free(info); free(info_buf); free(buf); return 2; } free(buf); } else { log(LOG_ERR, "Couldn't open existing info file."); return 0; } } /* Open the info file. */ fp = fopen(pr_dir, "w"); /* Did we fail to open the file? */ if (fp == NULL) { log(LOG_ERR, "Failed to open info file."); return 0; } return 1; } int create_pull_request_dir(pull_request *pr, int id, const char *root) { int ret = id; struct stat st; file **commits; char *pr_dir; /* Is this a NULL PR? */ if (pr == NULL) { log(LOG_ERR, "Pull Request is NULL."); return -1; } /* Is the ID negative, and the PR title blank, or NULL? */ if (id < 0 && (pr->title == NULL || pr->title[0] == '\0')) { log(LOG_ERR, "Negative ID, and either blank, or NULL Pull Request title."); return -1; } /* Did we fail to create the info file? */ if (!create_info(pr, pr_dir)) { log(LOG_ERR, "Failed to create info file."); return -1; } /* Get the path of the PR's directory. */ pr_dir = (pr->title != NULL && pr->title[0] != '\0') ? dir_path_name(root, sanitize_str(pr->title)) : dir_path_num(root, id); /* Is there no existing directory? */ if (stat(pr_dir, &st) < -1) { /* Create a directory with a name of the stringified ID. */ mkdir(pr_dir, 0755); } /* Get the patch files. */ commits = (pr->pr_type) ? get_branch_commits(pr->branch) : pr->patches; /* Make patch files for each commit of PR. */ for (int i = 0; commits[i] != NULL; i++) { FILE *fp; /* Does this patch file exists? */ if (access(commits[i]->name, F_OK) == 0) { long size = 0; char *buf = read_file(commits[i]->name, &size); log(LOG_NOTICE, "Patch file %s already exists.", commits[i]->name); /* Did we read the file? */ if (buf != NULL) { /* Are the contents of the patch file the same? */ if (strcmp(commits[i]->buf, buf) == 0) { /* Skip creating this patch file. */ log(LOG_NOTICE, "Patch file %s is the same as the new one.", commits[i]->name); free(buf); continue; } free(buf); } else { log(LOG_WARNING, "Couldn't open patch file %s.", commits[i]->name); continue; } } /* Create the format patch file for this commit. */ fp = fopen(commits[i]->name, "w"); fwrite(commits[i]->buf, sizeof(char), strlen(commits[i]->buf), fp); fclose(fp); } free(pr_dir); if (pr->pr_type) { free_files(commits); } return ret; } 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) + 2, 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; }