Download raw body.
parse remotes from gitconfig
This patch parses remote repository configuration from gitconfig.
For now this only gets the user-specified remote name and the
corresponding repository URL. I hope we won't ever need refspecs.
This could soon become useful ;)
diff refs/heads/master refs/heads/gitconfig-remotes
blob - 4e252ffbac5584645f2d0ce7bd4ba2688825f65d
blob + 270c02605b7ca7f47d34f3b4268483afafcec01f
--- include/got_error.h
+++ include/got_error.h
@@ -126,6 +126,7 @@
#define GOT_ERR_GIT_REPO_FORMAT 110
#define GOT_ERR_REBASE_REQUIRED 111
#define GOT_ERR_REGEX 112
+#define GOT_ERR_GITCONFIG_SYNTAX 113
static const struct got_error {
int code;
@@ -258,6 +259,7 @@ static const struct got_error {
{ GOT_ERR_GIT_REPO_FORMAT,"unknown git repository format version" },
{ GOT_ERR_REBASE_REQUIRED,"specified branch must be rebased first" },
{ GOT_ERR_REGEX, "regular expression error" },
+ { GOT_ERR_GITCONFIG_SYNTAX, "gitconfig syntax error" },
};
/*
blob - 7ed477b1d49d732af4362f4100cb33659065f814
blob + 0a1c3f25d0677cbebea9562b70a802af37922ef9
--- 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_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
@@ -494,6 +494,51 @@ got_gitconfig_get_str(struct got_gitconfig *conf, char
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 + caf2d341d728e1ec64eda8a41ce83e7526ac33fb
--- 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 nremotes;
+ struct got_remote_repo *remotes;
};
const struct got_error*got_repo_cache_object(struct got_repository *,
blob - c2e79e1f376e55f2a9fc904479ab7c82e7cef1b9
blob + 9bf89c79a1b03b9ca2568c5b44f463e6ef4b0ea2
--- 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"
@@ -1281,6 +1282,17 @@ got_privsep_send_gitconfig_author_email_req(struct ims
}
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);
+}
+
+const struct got_error *
got_privsep_send_gitconfig_str(struct imsgbuf *ibuf, const char *value)
{
size_t len = value ? strlen(value) + 1 : 0;
@@ -1368,6 +1380,170 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu
}
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);
+ break;
+ }
+
+ 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 - 9dffdcd83aa6b08ebbb5d3c8526500f507c72877
blob + bbb0fe207f98082b7572f6903331cfd865f6af21
--- lib/repository.c
+++ lib/repository.c
@@ -170,6 +170,14 @@ get_path_gitconfig(char **p, struct got_repository *re
return NULL;
}
+void
+got_repo_get_remotes(int *nremotes, struct got_remote_repo **remotes,
+ struct got_repository *repo)
+{
+ *nremotes = repo->nremotes;
+ *remotes = repo->remotes;
+}
+
static int
is_git_repo(struct got_repository *repo)
{
@@ -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;
@@ -442,6 +451,17 @@ parse_gitconfig_file(int *gitconfig_repository_format_
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]);
child_err = got_privsep_wait_for_child(pid);
@@ -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,7 +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_path);
+ &repo->remotes, &repo->nremotes, repo_gitconfig_path);
if (err)
goto done;
done:
@@ -620,6 +640,11 @@ got_repo_close(struct got_repository *repo)
free(repo->gitconfig_author_name);
free(repo->gitconfig_author_email);
+ for (i = 0; i < repo->nremotes; i++) {
+ free(repo->remotes[i].name);
+ free(repo->remotes[i].url);
+ }
+ free(repo->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[])
{
@@ -146,6 +216,9 @@ main(int argc, char *argv[])
case GOT_IMSG_GITCONFIG_AUTHOR_EMAIL_REQUEST:
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);
parse remotes from gitconfig