commit cd95becd3d0ee4fb578daf570177c3550cb19e08 from: Stefan Sperling date: Fri Nov 29 02:46:04 2019 UTC parse remotes from gitconfig commit - bd5895f3726fd0edc272b4c44727f60b5a5132c9 commit + cd95becd3d0ee4fb578daf570177c3550cb19e08 blob - e2e96e4065e6d735452b5a23c4eb1ad179abfa67 blob + d0df1255deadae95cebcf18a88340a0d87666d46 --- include/got_error.h +++ include/got_error.h @@ -127,6 +127,7 @@ #define GOT_ERR_REBASE_REQUIRED 111 #define GOT_ERR_REGEX 112 #define GOT_ERR_REF_NAME_MINUS 113 +#define GOT_ERR_GITCONFIG_SYNTAX 114 static const struct got_error { int code; @@ -260,6 +261,7 @@ static const struct got_error { { GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" }, { GOT_ERR_REGEX, "regular expression error" }, { GOT_ERR_REF_NAME_MINUS, "reference name may not start with '-'" }, + { GOT_ERR_GITCONFIG_SYNTAX, "gitconfig syntax error" }, }; /* blob - 7ed477b1d49d732af4362f4100cb33659065f814 blob + 6ef2a57e12d131c901a5bce6196837a91a3618ba --- include/got_repository.h +++ include/got_repository.h @@ -44,6 +44,16 @@ const char *got_repo_get_global_gitconfig_author_name( /* Obtain global commit author email parsed ~/.gitconfig, else NULL. */ const char *got_repo_get_global_gitconfig_author_email(struct got_repository *); +/* Information about one remote repository. */ +struct got_remote_repo { + char *name; + char *url; +}; + +/* Obtain the list of remote repositories parsed from gitconfig. */ +void got_repo_get_gitconfig_remotes(int *, struct got_remote_repo **, + struct got_repository *); + /* * Obtain paths to various directories within a repository. * The caller must dispose of a path with free(3). blob - 1ddfb97d543989190d1cf894c45ed4ed1424f1aa blob + 5188ecbf5c2419c20c0064c42212be9f91f390f0 --- lib/gitconfig.c +++ lib/gitconfig.c @@ -493,7 +493,52 @@ got_gitconfig_get_str(struct got_gitconfig *conf, char tag)); return 0; } + +const struct got_error * +got_gitconfig_get_section_list(struct got_gitconfig_list **sections, + struct got_gitconfig *conf) +{ + const struct got_error *err = NULL; + struct got_gitconfig_list *list = NULL; + struct got_gitconfig_list_node *node = 0; + struct got_gitconfig_binding *cb; + int i; + + *sections = NULL; + list = malloc(sizeof *list); + if (!list) + return got_error_from_errno("malloc"); + TAILQ_INIT(&list->fields); + list->cnt = 0; + for (i = 0; i < nitems(conf->bindings); i++) { + for (cb = LIST_FIRST(&conf->bindings[i]); cb; + cb = LIST_NEXT(cb, link)) { + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) { + err = got_error_from_errno("calloc"); + goto cleanup; + } + node->field = strdup(cb->section); + if (!node->field) { + err = got_error_from_errno("strdup"); + goto cleanup; + } + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + } + + *sections = list; + return NULL; + +cleanup: + free(node); + if (list) + got_gitconfig_free_list(list); + return err; +} + /* * Build a list of string values out of the comma separated value denoted by * TAG in SECTION. blob - 4d61ab3964722d849b94e3048f1cb6a15d2edc3f blob + 615d2690ac39f3fceb3704b2624a85e8de2ba65c --- lib/got_lib_gitconfig.h +++ lib/got_lib_gitconfig.h @@ -39,6 +39,8 @@ struct got_gitconfig_list { struct got_gitconfig; void got_gitconfig_free_list(struct got_gitconfig_list *); +const struct got_error *got_gitconfig_get_section_list( + struct got_gitconfig_list **, struct got_gitconfig *); struct got_gitconfig_list *got_gitconfig_get_list(struct got_gitconfig *, char *, char *); struct got_gitconfig_list *got_gitconfig_get_tag_list(struct got_gitconfig *, char *); blob - a37a450e6e18733afec74aa1dc9cb427c9d27acb blob + b27325da498aa72413f8377303ba76d4012c7813 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -111,8 +111,11 @@ enum got_imsg_type { GOT_IMSG_GITCONFIG_REPOSITORY_FORMAT_VERSION_REQUEST, GOT_IMSG_GITCONFIG_AUTHOR_NAME_REQUEST, GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, + GOT_IMSG_GITCONFIG_REMOTES_REQUEST, GOT_IMSG_GITCONFIG_INT_VAL, GOT_IMSG_GITCONFIG_STR_VAL, + GOT_IMSG_GITCONFIG_REMOTES, + GOT_IMSG_GITCONFIG_REMOTE, }; /* Structure for GOT_IMSG_ERROR. */ @@ -229,6 +232,24 @@ struct got_imsg_packed_object { int idx; } __attribute__((__packed__)); +/* + * Structure for GOT_IMSG_GITCONFIG_REMOTE data. + */ +struct got_imsg_remote { + size_t name_len; + size_t url_len; + + /* Followed by name_len + url_len data bytes. */ +}; + +/* + * Structure for GOT_IMSG_GITCONFIG_REMOTES data. + */ +struct got_imsg_remotes { + int nremotes; /* This many GOT_IMSG_GITCONFIG_REMOTE messages follow. */ +}; + +struct got_remote_repo; struct got_pack; struct got_packidx; struct got_pathlist_head; @@ -285,11 +306,17 @@ const struct got_error *got_privsep_send_gitconfig_aut struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_author_email_req( struct imsgbuf *); +const struct got_error *got_privsep_send_gitconfig_remotes_req( + struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_str(struct imsgbuf *, const char *); const struct got_error *got_privsep_recv_gitconfig_str(char **, struct imsgbuf *); const struct got_error *got_privsep_send_gitconfig_int(struct imsgbuf *, int); const struct got_error *got_privsep_recv_gitconfig_int(int *, struct imsgbuf *); +const struct got_error *got_privsep_send_gitconfig_remotes(struct imsgbuf *, + struct got_remote_repo *, int); +const struct got_error *got_privsep_recv_gitconfig_remotes( + struct got_remote_repo **, int *, struct imsgbuf *); void got_privsep_exec_child(int[2], const char *, const char *); blob - c304faf993ada599d3d88ab1f3172d00c4ba1225 blob + 93f1734b814bde4b84f85106f95c3646947c45d8 --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -47,6 +47,8 @@ struct got_repository { char *gitconfig_author_email; char *global_gitconfig_author_name; char *global_gitconfig_author_email; + int ngitconfig_remotes; + struct got_remote_repo *gitconfig_remotes; }; const struct got_error*got_repo_cache_object(struct got_repository *, blob - 58bdc0196125fd795f5e78ba1b0c888f248e9fa2 blob + f31cafb2ee6c5d18919265def86f6ddd6193c86d --- lib/privsep.c +++ lib/privsep.c @@ -34,6 +34,7 @@ #include "got_object.h" #include "got_error.h" #include "got_path.h" +#include "got_repository.h" #include "got_lib_sha1.h" #include "got_lib_delta.h" @@ -1274,6 +1275,17 @@ got_privsep_send_gitconfig_author_email_req(struct ims GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST, 0, 0, -1, NULL, 0) == -1) return got_error_from_errno("imsg_compose " "GITCONFIG_AUTHOR_EMAIL_REQUEST"); + + return flush_imsg(ibuf); +} + +const struct got_error * +got_privsep_send_gitconfig_remotes_req(struct imsgbuf *ibuf) +{ + if (imsg_compose(ibuf, + GOT_IMSG_GITCONFIG_REMOTES_REQUEST, 0, 0, -1, NULL, 0) == -1) + return got_error_from_errno("imsg_compose " + "GITCONFIG_REMOTE_REQUEST"); return flush_imsg(ibuf); } @@ -1359,6 +1371,108 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu break; } memcpy(val, imsg.data, sizeof(*val)); + break; + default: + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + + imsg_free(&imsg); + return err; +} + +const struct got_error * +got_privsep_send_gitconfig_remotes(struct imsgbuf *ibuf, + struct got_remote_repo *remotes, int nremotes) +{ + const struct got_error *err = NULL; + struct got_imsg_remotes iremotes; + int i; + + iremotes.nremotes = nremotes; + if (imsg_compose(ibuf, GOT_IMSG_GITCONFIG_REMOTES, 0, 0, -1, + &iremotes, sizeof(iremotes)) == -1) + return got_error_from_errno("imsg_compose GITCONFIG_REMOTES"); + + err = flush_imsg(ibuf); + imsg_clear(ibuf); + if (err) + return err; + + for (i = 0; i < nremotes; i++) { + struct got_imsg_remote iremote; + size_t len = sizeof(iremote); + struct ibuf *wbuf; + + iremote.name_len = strlen(remotes[i].name); + len += iremote.name_len; + iremote.url_len = strlen(remotes[i].url); + len += iremote.url_len; + + wbuf = imsg_create(ibuf, GOT_IMSG_GITCONFIG_REMOTE, 0, 0, len); + if (wbuf == NULL) + return got_error_from_errno( + "imsg_create GITCONFIG_REMOTE"); + + if (imsg_add(wbuf, &iremote, sizeof(iremote)) == -1) { + err = got_error_from_errno( + "imsg_add GIITCONFIG_REMOTE"); + ibuf_free(wbuf); + return err; + } + + if (imsg_add(wbuf, remotes[i].name, iremote.name_len) == -1) { + err = got_error_from_errno( + "imsg_add GIITCONFIG_REMOTE"); + ibuf_free(wbuf); + return err; + } + if (imsg_add(wbuf, remotes[i].url, iremote.url_len) == -1) { + err = got_error_from_errno( + "imsg_add GIITCONFIG_REMOTE"); + ibuf_free(wbuf); + return err; + } + + wbuf->fd = -1; + imsg_close(ibuf, wbuf); + err = flush_imsg(ibuf); + if (err) + return err; + } + + return NULL; +} + +const struct got_error * +got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes, + int *nremotes, struct imsgbuf *ibuf) +{ + const struct got_error *err = NULL; + struct imsg imsg; + size_t datalen; + struct got_imsg_remotes iremotes; + struct got_imsg_remote iremote; + + *remotes = NULL; + *nremotes = 0; + + err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremotes)); + if (err) + return err; + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case GOT_IMSG_GITCONFIG_REMOTES: + if (datalen != sizeof(iremotes)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + memcpy(&iremotes, imsg.data, sizeof(iremotes)); + if (iremotes.nremotes == 0) { + imsg_free(&imsg); + return NULL; + } break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); @@ -1366,6 +1480,68 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu } imsg_free(&imsg); + + *remotes = recallocarray(NULL, 0, iremotes.nremotes, sizeof(iremote)); + if (*remotes == NULL) + return got_error_from_errno("recallocarray"); + + while (*nremotes < iremotes.nremotes) { + struct got_remote_repo *remote; + + err = got_privsep_recv_imsg(&imsg, ibuf, sizeof(iremote)); + if (err) + break; + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + + switch (imsg.hdr.type) { + case GOT_IMSG_GITCONFIG_REMOTE: + remote = &(*remotes)[*nremotes]; + if (datalen < sizeof(iremote)) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + memcpy(&iremote, imsg.data, sizeof(iremote)); + if (iremote.name_len == 0 || iremote.url_len == 0 || + (sizeof(iremote) + iremote.name_len + + iremote.url_len) > datalen) { + err = got_error(GOT_ERR_PRIVSEP_LEN); + break; + } + remote->name = strndup(imsg.data + sizeof(iremote), + iremote.name_len); + if (remote->name == NULL) { + err = got_error_from_errno("strndup"); + break; + } + remote->url = strndup(imsg.data + sizeof(iremote) + + iremote.name_len, iremote.url_len); + if (remote->url == NULL) { + err = got_error_from_errno("strndup"); + free(remote->name); + break; + } + (*nremotes)++; + break; + default: + err = got_error(GOT_ERR_PRIVSEP_MSG); + break; + } + + imsg_free(&imsg); + if (err) + break; + } + + if (err) { + int i; + for (i = 0; i < *nremotes; i++) { + free((*remotes)[i].name); + free((*remotes)[i].url); + } + free(*remotes); + *remotes = NULL; + *nremotes = 0; + } return err; } blob - a5b0f8fded6c31a6c08dace849ceda974c1ef3c8 blob + e7022555ae9106a6b519d797cb9e28bbdfe897b4 --- lib/repository.c +++ lib/repository.c @@ -168,6 +168,14 @@ get_path_gitconfig(char **p, struct got_repository *re if (*p == NULL) return got_error_from_errno("asprintf"); return NULL; +} + +void +got_repo_get_gitconfig_remotes(int *nremotes, struct got_remote_repo **remotes, + struct got_repository *repo) +{ + *nremotes = repo->ngitconfig_remotes; + *remotes = repo->gitconfig_remotes; } static int @@ -365,6 +373,7 @@ done: static const struct got_error * parse_gitconfig_file(int *gitconfig_repository_format_version, char **gitconfig_author_name, char **gitconfig_author_email, + struct got_remote_repo **remotes, int *nremotes, const char *gitconfig_path) { const struct got_error *err = NULL, *child_err = NULL; @@ -441,6 +450,17 @@ parse_gitconfig_file(int *gitconfig_repository_format_ err = got_privsep_recv_gitconfig_str(gitconfig_author_email, ibuf); if (err) goto done; + + if (remotes && nremotes) { + err = got_privsep_send_gitconfig_remotes_req(ibuf); + if (err) + goto done; + + err = got_privsep_recv_gitconfig_remotes(remotes, + nremotes, ibuf); + if (err) + goto done; + } imsg_clear(ibuf); err = got_privsep_send_stop(imsg_fds[0]); @@ -470,7 +490,7 @@ read_gitconfig(struct got_repository *repo, const char err = parse_gitconfig_file(&dummy_repo_version, &repo->global_gitconfig_author_name, &repo->global_gitconfig_author_email, - global_gitconfig_path); + NULL, NULL, global_gitconfig_path); if (err) return err; } @@ -482,6 +502,7 @@ read_gitconfig(struct got_repository *repo, const char err = parse_gitconfig_file(&repo->gitconfig_repository_format_version, &repo->gitconfig_author_name, &repo->gitconfig_author_email, + &repo->gitconfig_remotes, &repo->ngitconfig_remotes, repo_gitconfig_path); if (err) goto done; @@ -620,6 +641,11 @@ got_repo_close(struct got_repository *repo) free(repo->gitconfig_author_name); free(repo->gitconfig_author_email); + for (i = 0; i < repo->ngitconfig_remotes; i++) { + free(repo->gitconfig_remotes[i].name); + free(repo->gitconfig_remotes[i].url); + } + free(repo->gitconfig_remotes); free(repo); return err; blob - c14f37dd21a67e7027328b8a776e99a036726c7c blob + 7c6439deb2b6bd6dd54a308e07d765495636ca39 --- libexec/got-read-gitconfig/got-read-gitconfig.c +++ libexec/got-read-gitconfig/got-read-gitconfig.c @@ -32,6 +32,7 @@ #include "got_error.h" #include "got_object.h" +#include "got_repository.h" #include "got_lib_delta.h" #include "got_lib_object.h" @@ -72,6 +73,75 @@ gitconfig_str_request(struct imsgbuf *ibuf, struct got return got_privsep_send_gitconfig_str(ibuf, value); } +static const struct got_error * +gitconfig_remotes_request(struct imsgbuf *ibuf, struct got_gitconfig *gitconfig) +{ + const struct got_error *err = NULL; + struct got_gitconfig_list *sections; + struct got_gitconfig_list_node *node; + struct got_remote_repo *remotes = NULL; + int nremotes = 0, i; + + if (gitconfig == NULL) + return got_error(GOT_ERR_PRIVSEP_MSG); + + err = got_gitconfig_get_section_list(§ions, gitconfig); + if (err) + return err; + + TAILQ_FOREACH(node, §ions->fields, link) { + if (strncasecmp("remote \"", node->field, 8) != 0) + continue; + nremotes++; + } + + if (nremotes == 0) { + err = got_privsep_send_gitconfig_remotes(ibuf, NULL, 0); + goto done; + } + + remotes = recallocarray(NULL, 0, nremotes, sizeof(*remotes)); + if (remotes == NULL) { + err = got_error_from_errno("recallocarray"); + goto done; + } + + i = 0; + TAILQ_FOREACH(node, §ions->fields, link) { + char *name, *end; + + if (strncasecmp("remote \"", node->field, 8) != 0) + continue; + + name = strdup(node->field + 8); + if (name == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + end = strrchr(name, '"'); + if (end) + *end = '\0'; + remotes[i].name = name; + + remotes[i].url = got_gitconfig_get_str(gitconfig, + node->field, "url"); + if (remotes[i].url == NULL) { + err = got_error(GOT_ERR_GITCONFIG_SYNTAX); + goto done; + } + + i++; + } + + err = got_privsep_send_gitconfig_remotes(ibuf, remotes, nremotes); +done: + for (i = 0; i < nremotes; i++) + free(remotes[i].name); + free(remotes); + got_gitconfig_free_list(sections); + return err; +} + int main(int argc, char *argv[]) { @@ -147,6 +217,9 @@ main(int argc, char *argv[]) err = gitconfig_str_request(&ibuf, gitconfig, "user", "email"); break; + case GOT_IMSG_GITCONFIG_REMOTES_REQUEST: + err = gitconfig_remotes_request(&ibuf, gitconfig); + break; default: err = got_error(GOT_ERR_PRIVSEP_MSG); break;