{"thread":{"id":"7980","subject":"[PATCH] Move remote parsing into a library file out of builtin-push.","startedAt":"2007-05-05T05:09:42Z","lastAt":"2007-05-05T05:09:42Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"41118","messageId":"Pine.LNX.4.64.0705050108280.28708@iabervon.org","threadId":"7980","inReplyTo":null,"subject":"[PATCH] Move remote parsing into a library file out of builtin-push.","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-05-05T05:09:42Z","receivedAt":"2007-05-05T05:09:42Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"The new parser is different from the one in builtin-push in two ways:\nthe default is to use the current branch's remote, if there is one,\nbefore \"origin\"; and config is used in preference to remotes.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n Makefile       |    5 +-\n builtin-push.c |  201 ++++++++------------------------------------------------\n remote.c       |  201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n remote.h       |   18 +++++\n 4 files changed, 250 insertions(+), 175 deletions(-)\n create mode 100644 remote.c\n create mode 100644 remote.h\n\ndiff --git a/Makefile b/Makefile\nindex e0a1308..dd64b7d 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -288,7 +288,8 @@ LIB_H = \\\n \tdiff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \\\n \trun-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \\\n \ttree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \\\n-\tutf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h\n+\tutf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \\\n+\tmailmap.h remote.h\n \n DIFF_OBJS = \\\n \tdiff.o diff-lib.o diffcore-break.o diffcore-order.o \\\n@@ -310,7 +311,7 @@ LIB_OBJS = \\\n \twrite_or_die.o trace.o list-objects.o grep.o match-trees.o \\\n \talloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \\\n \tcolor.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \\\n-\tconvert.o attr.o decorate.o progress.o mailmap.o\n+\tconvert.o attr.o decorate.o progress.o mailmap.o remote.o\n \n BUILTIN_OBJS = \\\n \tbuiltin-add.o \\\ndiff --git a/builtin-push.c b/builtin-push.c\nindex cb78401..49a83bb 100644\n--- a/builtin-push.c\n+++ b/builtin-push.c\n@@ -5,17 +5,13 @@\n #include \"refs.h\"\n #include \"run-command.h\"\n #include \"builtin.h\"\n-\n-#define MAX_URI (16)\n+#include \"remote.h\"\n \n static const char push_usage[] = \"git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]\";\n \n static int all, tags, force, thin = 1, verbose;\n static const char *receivepack;\n \n-#define BUF_SIZE (2084)\n-static char buffer[BUF_SIZE];\n-\n static const char **refspec;\n static int refspec_nr;\n \n@@ -137,176 +133,30 @@ static void set_refspecs(const char **refs, int nr)\n \texpand_refspecs();\n }\n \n-static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])\n-{\n-\tint n = 0;\n-\tFILE *f = fopen(git_path(\"remotes/%s\", repo), \"r\");\n-\tint has_explicit_refspec = refspec_nr || all || tags;\n-\n-\tif (!f)\n-\t\treturn -1;\n-\twhile (fgets(buffer, BUF_SIZE, f)) {\n-\t\tint is_refspec;\n-\t\tchar *s, *p;\n-\n-\t\tif (!prefixcmp(buffer, \"URL:\")) {\n-\t\t\tis_refspec = 0;\n-\t\t\ts = buffer + 4;\n-\t\t} else if (!prefixcmp(buffer, \"Push:\")) {\n-\t\t\tis_refspec = 1;\n-\t\t\ts = buffer + 5;\n-\t\t} else\n-\t\t\tcontinue;\n-\n-\t\t/* Remove whitespace at the head.. */\n-\t\twhile (isspace(*s))\n-\t\t\ts++;\n-\t\tif (!*s)\n-\t\t\tcontinue;\n-\n-\t\t/* ..and at the end */\n-\t\tp = s + strlen(s);\n-\t\twhile (isspace(p[-1]))\n-\t\t\t*--p = 0;\n-\n-\t\tif (!is_refspec) {\n-\t\t\tif (n < MAX_URI)\n-\t\t\t\turi[n++] = xstrdup(s);\n-\t\t\telse\n-\t\t\t\terror(\"more than %d URL's specified, ignoring the rest\", MAX_URI);\n-\t\t}\n-\t\telse if (is_refspec && !has_explicit_refspec) {\n-\t\t\tif (!wildcard_ref(s))\n-\t\t\t\tadd_refspec(xstrdup(s));\n-\t\t}\n-\t}\n-\tfclose(f);\n-\tif (!n)\n-\t\tdie(\"remote '%s' has no URL\", repo);\n-\treturn n;\n-}\n-\n-static const char **config_uri;\n-static const char *config_repo;\n-static int config_repo_len;\n-static int config_current_uri;\n-static int config_get_refspecs;\n-static int config_get_receivepack;\n-\n-static int get_remote_config(const char* key, const char* value)\n-{\n-\tif (!prefixcmp(key, \"remote.\") &&\n-\t    !strncmp(key + 7, config_repo, config_repo_len)) {\n-\t\tif (!strcmp(key + 7 + config_repo_len, \".url\")) {\n-\t\t\tif (config_current_uri < MAX_URI)\n-\t\t\t\tconfig_uri[config_current_uri++] = xstrdup(value);\n-\t\t\telse\n-\t\t\t\terror(\"more than %d URL's specified, ignoring the rest\", MAX_URI);\n-\t\t}\n-\t\telse if (config_get_refspecs &&\n-\t\t\t !strcmp(key + 7 + config_repo_len, \".push\")) {\n-\t\t\tif (!wildcard_ref(value))\n-\t\t\t\tadd_refspec(xstrdup(value));\n-\t\t}\n-\t\telse if (config_get_receivepack &&\n-\t\t\t !strcmp(key + 7 + config_repo_len, \".receivepack\")) {\n-\t\t\tif (!receivepack) {\n-\t\t\t\tchar *rp = xmalloc(strlen(value) + 16);\n-\t\t\t\tsprintf(rp, \"--receive-pack=%s\", value);\n-\t\t\t\treceivepack = rp;\n-\t\t\t} else\n-\t\t\t\terror(\"more than one receivepack given, using the first\");\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n-static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])\n-{\n-\tconfig_repo_len = strlen(repo);\n-\tconfig_repo = repo;\n-\tconfig_current_uri = 0;\n-\tconfig_uri = uri;\n-\tconfig_get_refspecs = !(refspec_nr || all || tags);\n-\tconfig_get_receivepack = (receivepack == NULL);\n-\n-\tgit_config(get_remote_config);\n-\treturn config_current_uri;\n-}\n-\n-static int get_branches_uri(const char *repo, const char *uri[MAX_URI])\n-{\n-\tconst char *slash = strchr(repo, '/');\n-\tint n = slash ? slash - repo : 1000;\n-\tFILE *f = fopen(git_path(\"branches/%.*s\", n, repo), \"r\");\n-\tchar *s, *p;\n-\tint len;\n-\n-\tif (!f)\n-\t\treturn 0;\n-\ts = fgets(buffer, BUF_SIZE, f);\n-\tfclose(f);\n-\tif (!s)\n-\t\treturn 0;\n-\twhile (isspace(*s))\n-\t\ts++;\n-\tif (!*s)\n-\t\treturn 0;\n-\tp = s + strlen(s);\n-\twhile (isspace(p[-1]))\n-\t\t*--p = 0;\n-\tlen = p - s;\n-\tif (slash)\n-\t\tlen += strlen(slash);\n-\tp = xmalloc(len + 1);\n-\tstrcpy(p, s);\n-\tif (slash)\n-\t\tstrcat(p, slash);\n-\turi[0] = p;\n-\treturn 1;\n-}\n-\n-/*\n- * Read remotes and branches file, fill the push target URI\n- * list.  If there is no command line refspecs, read Push: lines\n- * to set up the *refspec list as well.\n- * return the number of push target URIs\n- */\n-static int read_config(const char *repo, const char *uri[MAX_URI])\n-{\n-\tint n;\n-\n-\tif (*repo != '/') {\n-\t\tn = get_remotes_uri(repo, uri);\n-\t\tif (n > 0)\n-\t\t\treturn n;\n-\n-\t\tn = get_config_remotes_uri(repo, uri);\n-\t\tif (n > 0)\n-\t\t\treturn n;\n-\n-\t\tn = get_branches_uri(repo, uri);\n-\t\tif (n > 0)\n-\t\t\treturn n;\n-\t}\n-\n-\turi[0] = repo;\n-\treturn 1;\n-}\n-\n static int do_push(const char *repo)\n {\n-\tconst char *uri[MAX_URI];\n-\tint i, n, errs;\n+\tint i, errs;\n \tint common_argc;\n \tconst char **argv;\n \tint argc;\n+\tstruct remote *remote;\n+\n+\tremote = remote_get(repo);\n \n-\tn = read_config(repo, uri);\n-\tif (n <= 0)\n+\tif (!remote)\n \t\tdie(\"bad repository '%s'\", repo);\n \n-\targv = xmalloc((refspec_nr + 10) * sizeof(char *));\n+\tif (remote->receivepack) {\n+\t\tchar *rp = xmalloc(strlen(remote->receivepack) + 16);\n+\t\tsprintf(rp, \"--receive-pack=%s\", remote->receivepack);\n+\t\treceivepack = rp;\n+\t}\n+\tif (!refspec && !all && !tags && remote->push_refspec_nr) {\n+\t\trefspec_nr = remote->push_refspec_nr;\n+\t\trefspec = remote->push_refspec;\n+\t}\n+\n+\targv = xmalloc((refspec_nr + 11) * sizeof(char *));\n \targv[0] = \"dummy-send-pack\";\n \targc = 1;\n \tif (all)\n@@ -318,18 +168,23 @@ static int do_push(const char *repo)\n \tcommon_argc = argc;\n \n \terrs = 0;\n-\tfor (i = 0; i < n; i++) {\n+\tfor (i = 0; i < remote->uri_nr; i++) {\n \t\tint err;\n \t\tint dest_argc = common_argc;\n \t\tint dest_refspec_nr = refspec_nr;\n \t\tconst char **dest_refspec = refspec;\n-\t\tconst char *dest = uri[i];\n+\t\tconst char *dest = remote->uri[i];\n \t\tconst char *sender = \"send-pack\";\n \t\tif (!prefixcmp(dest, \"http://\") ||\n \t\t    !prefixcmp(dest, \"https://\"))\n \t\t\tsender = \"http-push\";\n-\t\telse if (thin)\n-\t\t\targv[dest_argc++] = \"--thin\";\n+\t\telse {\n+\t\t\tchar *rem = xmalloc(strlen(remote->name) + 10);\n+\t\t\tsprintf(rem, \"--remote=%s\", remote->name);\n+\t\t\targv[dest_argc++] = rem;\n+\t\t\tif (thin)\n+\t\t\t\targv[dest_argc++] = \"--thin\";\n+\t\t}\n \t\targv[0] = sender;\n \t\targv[dest_argc++] = dest;\n \t\twhile (dest_refspec_nr--)\n@@ -341,7 +196,7 @@ static int do_push(const char *repo)\n \t\tif (!err)\n \t\t\tcontinue;\n \n-\t\terror(\"failed to push to '%s'\", uri[i]);\n+\t\terror(\"failed to push to '%s'\", remote->uri[i]);\n \t\tswitch (err) {\n \t\tcase -ERR_RUN_COMMAND_FORK:\n \t\t\terror(\"unable to fork for %s\", sender);\n@@ -362,7 +217,7 @@ static int do_push(const char *repo)\n int cmd_push(int argc, const char **argv, const char *prefix)\n {\n \tint i;\n-\tconst char *repo = \"origin\";\t/* default repository */\n+\tconst char *repo = NULL;\t/* default repository */\n \n \tfor (i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\ndiff --git a/remote.c b/remote.c\nnew file mode 100644\nindex 0000000..32a0acf\n--- /dev/null\n+++ b/remote.c\n@@ -0,0 +1,201 @@\n+#include \"cache.h\"\n+#include \"remote.h\"\n+#include \"refs.h\"\n+\n+static struct remote **remotes;\n+static int allocated_remotes;\n+\n+#define BUF_SIZE (2084)\n+static char buffer[BUF_SIZE];\n+\n+static void add_push_refspec(struct remote *remote, const char *ref)\n+{\n+\tint nr = remote->push_refspec_nr + 1;\n+\tremote->push_refspec =\n+\t\txrealloc(remote->push_refspec, nr * sizeof(char *));\n+\tremote->push_refspec[nr-1] = ref;\n+\tremote->push_refspec_nr = nr;\n+}\n+\n+static void add_uri(struct remote *remote, const char *uri)\n+{\n+\tint nr = remote->uri_nr + 1;\n+\tremote->uri =\n+\t\txrealloc(remote->uri, nr * sizeof(char *));\n+\tremote->uri[nr-1] = uri;\n+\tremote->uri_nr = nr;\n+}\n+\n+static struct remote *make_remote(const char *name, int len)\n+{\n+\tint i, empty = -1;\n+\n+\tfor (i = 0; i < allocated_remotes; i++) {\n+\t\tif (!remotes[i]) {\n+\t\t\tif (empty < 0)\n+\t\t\t\tempty = i;\n+\t\t} else {\n+\t\t\tif (len ? (!strncmp(name, remotes[i]->name, len) &&\n+\t\t\t\t   !remotes[i]->name[len]) :\n+\t\t\t    !strcmp(name, remotes[i]->name))\n+\t\t\t\treturn remotes[i];\n+\t\t}\n+\t}\n+\n+\tif (empty < 0) {\n+\t\tempty = allocated_remotes;\n+\t\tallocated_remotes += allocated_remotes ? allocated_remotes : 1;\n+\t\tremotes = xrealloc(remotes,\n+\t\t\t\t   sizeof(*remotes) * allocated_remotes);\n+\t\tmemset(remotes + empty, 0,\n+\t\t       (allocated_remotes - empty) * sizeof(*remotes));\n+\t}\n+\tremotes[empty] = xcalloc(1, sizeof(struct remote));\n+\tif (len)\n+\t\tremotes[empty]->name = xstrndup(name, len);\n+\telse\n+\t\tremotes[empty]->name = xstrdup(name);\n+\treturn remotes[empty];\n+}\n+\n+static void read_remotes_file(struct remote *remote)\n+{\n+\tFILE *f = fopen(git_path(\"remotes/%s\", remote->name), \"r\");\n+\n+\tif (!f)\n+\t\treturn;\n+\twhile (fgets(buffer, BUF_SIZE, f)) {\n+\t\tint value_list;\n+\t\tchar *s, *p;\n+\n+\t\tif (!prefixcmp(buffer, \"URL:\")) {\n+\t\t\tvalue_list = 0;\n+\t\t\ts = buffer + 4;\n+\t\t} else if (!prefixcmp(buffer, \"Push:\")) {\n+\t\t\tvalue_list = 1;\n+\t\t\ts = buffer + 5;\n+\t\t} else\n+\t\t\tcontinue;\n+\n+\t\twhile (isspace(*s))\n+\t\t\ts++;\n+\t\tif (!*s)\n+\t\t\tcontinue;\n+\n+\t\tp = s + strlen(s);\n+\t\twhile (isspace(p[-1]))\n+\t\t\t*--p = 0;\n+\n+\t\tswitch (value_list) {\n+\t\tcase 0:\n+\t\t\tadd_uri(remote, xstrdup(s));\n+\t\t\tbreak;\n+\t\tcase 1:\n+\t\t\tadd_push_refspec(remote, xstrdup(s));\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+}\n+\n+static void read_branches_file(struct remote *remote)\n+{\n+\tconst char *slash = strchr(remote->name, '/');\n+\tint n = slash ? slash - remote->name : 1000;\n+\tFILE *f = fopen(git_path(\"branches/%.*s\", n, remote->name), \"r\");\n+\tchar *s, *p;\n+\tint len;\n+\n+\tif (!f)\n+\t\treturn;\n+\ts = fgets(buffer, BUF_SIZE, f);\n+\tfclose(f);\n+\tif (!s)\n+\t\treturn;\n+\twhile (isspace(*s))\n+\t\ts++;\n+\tif (!*s)\n+\t\treturn;\n+\tp = s + strlen(s);\n+\twhile (isspace(p[-1]))\n+\t\t*--p = 0;\n+\tlen = p - s;\n+\tif (slash)\n+\t\tlen += strlen(slash);\n+\tp = xmalloc(len + 1);\n+\tstrcpy(p, s);\n+\tif (slash)\n+\t\tstrcat(p, slash);\n+\tadd_uri(remote, p);\n+}\n+\n+static char *default_remote_name = NULL;\n+static const char *current_branch = NULL;\n+static int current_branch_len = 0;\n+\n+static int handle_config(const char *key, const char *value)\n+{\n+\tconst char *name;\n+\tconst char *subkey;\n+\tstruct remote *remote;\n+\tif (!prefixcmp(key, \"branch.\") && current_branch &&\n+\t    !strncmp(key + 7, current_branch, current_branch_len) &&\n+\t    !strcmp(key + 7 + current_branch_len, \".remote\")) {\n+\t\tfree(default_remote_name);\n+\t\tdefault_remote_name = xstrdup(value);\n+\t}\n+\tif (prefixcmp(key,  \"remote.\"))\n+\t\treturn 0;\n+\tname = key + 7;\n+\tsubkey = strrchr(name, '.');\n+\tif (!subkey)\n+\t\treturn error(\"Config with no key for remote %s\", name);\n+\tremote = make_remote(name, subkey - name);\n+\tif (!strcmp(subkey, \".url\")) {\n+\t\tadd_uri(remote, xstrdup(value));\n+\t} else if (!strcmp(subkey, \".push\")) {\n+\t\tadd_push_refspec(remote, xstrdup(value));\n+\t} else if (!strcmp(subkey, \".receivepack\")) {\n+\t\tif (!remote->receivepack)\n+\t\t\tremote->receivepack = xstrdup(value);\n+\t\telse\n+\t\t\terror(\"more than one receivepack given, using the first\");\n+\t}\n+\treturn 0;\n+}\n+\n+static void read_config(void)\n+{\n+\tunsigned char sha1[20];\n+\tconst char *head_ref;\n+\tint flag;\n+\tif (default_remote_name) // did this already\n+\t\treturn;\n+\tdefault_remote_name = xstrdup(\"origin\");\n+\tcurrent_branch = NULL;\n+\thead_ref = resolve_ref(\"HEAD\", sha1, 0, &flag);\n+\tif (head_ref && (flag & REF_ISSYMREF) &&\n+\t    !prefixcmp(head_ref, \"refs/heads/\")) {\n+\t\tcurrent_branch = head_ref + strlen(\"refs/heads/\");\n+\t\tcurrent_branch_len = strlen(current_branch);\n+\t}\n+\tgit_config(handle_config);\n+}\n+\n+struct remote *remote_get(const char *name)\n+{\n+\tstruct remote *ret;\n+\n+\tread_config();\n+\tif (!name)\n+\t\tname = default_remote_name;\n+\tret = make_remote(name, 0);\n+\tif (*name == '/')\n+\t\tadd_uri(ret, name);\n+\tif (!ret->uri)\n+\t\tread_remotes_file(ret);\n+\tif (!ret->uri)\n+\t\tread_branches_file(ret);\n+\tif (!ret->uri)\n+\t\treturn NULL;\n+\treturn ret;\n+}\ndiff --git a/remote.h b/remote.h\nnew file mode 100644\nindex 0000000..73747a8\n--- /dev/null\n+++ b/remote.h\n@@ -0,0 +1,18 @@\n+#ifndef REMOTE_H\n+#define REMOTE_H\n+\n+struct remote {\n+\tconst char *name;\n+\n+\tconst char **uri;\n+\tint uri_nr;\n+\n+\tconst char **push_refspec;\n+\tint push_refspec_nr;\n+\n+\tconst char *receivepack;\n+};\n+\n+struct remote *remote_get(const char *name);\n+\n+#endif\n-- \n1.5.2.rc1.24.gf413-dirty\n"}]}