X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=builtin-push.c;h=70b1168fa677fc889543e87b2a3f964b175375c6;hb=5b5fe9a526e3841ff6f61dda743b9624dc8f6426;hp=53bc378f73e752a58542a1fb8b9ddedcf9301acf;hpb=f3c5b39567535a41a371aad8a6affbeea0d4c0b9;p=git.git diff --git a/builtin-push.c b/builtin-push.c index 53bc378f7..70b1168fa 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -8,16 +8,16 @@ #define MAX_URI (16) -static const char push_usage[] = "git-push [--all] [--tags] [-f | --force] [...]"; +static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=] [--repo=all] [-f | --force] [-v] [ ...]"; -static int all = 0, tags = 0, force = 0, thin = 1; -static const char *execute = NULL; +static int all, tags, force, thin = 1, verbose; +static const char *receivepack; #define BUF_SIZE (2084) static char buffer[BUF_SIZE]; -static const char **refspec = NULL; -static int refspec_nr = 0; +static const char **refspec; +static int refspec_nr; static void add_refspec(const char *ref) { @@ -27,15 +27,13 @@ static void add_refspec(const char *ref) refspec_nr = nr; } -static int expand_one_ref(const char *ref, const unsigned char *sha1) +static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data) { /* Ignore the "refs/" at the beginning of the refname */ ref += 5; - if (strncmp(ref, "tags/", 5)) - return 0; - - add_refspec(strdup(ref)); + if (!prefixcmp(ref, "tags/")) + add_refspec(xstrdup(ref)); return 0; } @@ -53,17 +51,88 @@ static void expand_refspecs(void) } if (!tags) return; - for_each_ref(expand_one_ref); + for_each_ref(expand_one_ref, NULL); +} + +struct wildcard_cb { + const char *from_prefix; + int from_prefix_len; + const char *to_prefix; + int to_prefix_len; + int force; +}; + +static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data) +{ + struct wildcard_cb *cb = cb_data; + int len = strlen(ref); + char *expanded, *newref; + + if (len < cb->from_prefix_len || + memcmp(cb->from_prefix, ref, cb->from_prefix_len)) + return 0; + expanded = xmalloc(len * 2 + cb->force + + (cb->to_prefix_len - cb->from_prefix_len) + 2); + newref = expanded + cb->force; + if (cb->force) + expanded[0] = '+'; + memcpy(newref, ref, len); + newref[len] = ':'; + memcpy(newref + len + 1, cb->to_prefix, cb->to_prefix_len); + strcpy(newref + len + 1 + cb->to_prefix_len, + ref + cb->from_prefix_len); + add_refspec(expanded); + return 0; +} + +static int wildcard_ref(const char *ref) +{ + int len; + const char *colon; + struct wildcard_cb cb; + + memset(&cb, 0, sizeof(cb)); + if (ref[0] == '+') { + cb.force = 1; + ref++; + } + len = strlen(ref); + colon = strchr(ref, ':'); + if (! (colon && ref < colon && + colon[-2] == '/' && colon[-1] == '*' && + /* "/:/" is at least 7 bytes */ + 7 <= len && + ref[len-2] == '/' && ref[len-1] == '*') ) + return 0 ; + cb.from_prefix = ref; + cb.from_prefix_len = colon - ref - 1; + cb.to_prefix = colon + 1; + cb.to_prefix_len = len - (colon - ref) - 2; + for_each_ref(expand_wildcard_ref, &cb); + return 1; } static void set_refspecs(const char **refs, int nr) { if (nr) { - size_t bytes = nr * sizeof(char *); - - refspec = xrealloc(refspec, bytes); - memcpy(refspec, refs, bytes); - refspec_nr = nr; + int i; + for (i = 0; i < nr; i++) { + const char *ref = refs[i]; + if (!strcmp("tag", ref)) { + char *tag; + int len; + if (nr <= ++i) + die("tag shorthand without "); + len = strlen(refs[i]) + 11; + tag = xmalloc(len); + strcpy(tag, "refs/tags/"); + strcat(tag, refs[i]); + ref = tag; + } + else if (wildcard_ref(ref)) + continue; + add_refspec(ref); + } } expand_refspecs(); } @@ -80,12 +149,12 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI]) int is_refspec; char *s, *p; - if (!strncmp("URL: ", buffer, 5)) { + if (!prefixcmp(buffer, "URL:")) { is_refspec = 0; - s = buffer + 5; - } else if (!strncmp("Push: ", buffer, 6)) { + s = buffer + 4; + } else if (!prefixcmp(buffer, "Push:")) { is_refspec = 1; - s = buffer + 6; + s = buffer + 5; } else continue; @@ -102,12 +171,14 @@ static int get_remotes_uri(const char *repo, const char *uri[MAX_URI]) if (!is_refspec) { if (n < MAX_URI) - uri[n++] = strdup(s); + uri[n++] = xstrdup(s); else error("more than %d URL's specified, ignoring the rest", MAX_URI); } - else if (is_refspec && !has_explicit_refspec) - add_refspec(strdup(s)); + else if (is_refspec && !has_explicit_refspec) { + if (!wildcard_ref(s)) + add_refspec(xstrdup(s)); + } } fclose(f); if (!n) @@ -120,20 +191,32 @@ static const char *config_repo; static int config_repo_len; static int config_current_uri; static int config_get_refspecs; +static int config_get_receivepack; static int get_remote_config(const char* key, const char* value) { - if (!strncmp(key, "remote.", 7) && + if (!prefixcmp(key, "remote.") && !strncmp(key + 7, config_repo, config_repo_len)) { if (!strcmp(key + 7 + config_repo_len, ".url")) { if (config_current_uri < MAX_URI) - config_uri[config_current_uri++] = strdup(value); + config_uri[config_current_uri++] = xstrdup(value); else error("more than %d URL's specified, ignoring the rest", MAX_URI); } else if (config_get_refspecs && - !strcmp(key + 7 + config_repo_len, ".push")) - add_refspec(strdup(value)); + !strcmp(key + 7 + config_repo_len, ".push")) { + if (!wildcard_ref(value)) + add_refspec(xstrdup(value)); + } + else if (config_get_receivepack && + !strcmp(key + 7 + config_repo_len, ".receivepack")) { + if (!receivepack) { + char *rp = xmalloc(strlen(value) + 16); + sprintf(rp, "--receive-pack=%s", value); + receivepack = rp; + } else + error("more than one receivepack given, using the first"); + } } return 0; } @@ -145,6 +228,7 @@ static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI]) config_current_uri = 0; config_uri = uri; config_get_refspecs = !(refspec_nr || all || tags); + config_get_receivepack = (receivepack == NULL); git_config(get_remote_config); return config_current_uri; @@ -229,20 +313,20 @@ static int do_push(const char *repo) argv[argc++] = "--all"; if (force) argv[argc++] = "--force"; - if (execute) - argv[argc++] = execute; + if (receivepack) + argv[argc++] = receivepack; common_argc = argc; for (i = 0; i < n; i++) { - int error; + int err; int dest_argc = common_argc; int dest_refspec_nr = refspec_nr; const char **dest_refspec = refspec; const char *dest = uri[i]; - const char *sender = "git-send-pack"; - if (!strncmp(dest, "http://", 7) || - !strncmp(dest, "https://", 8)) - sender = "git-http-push"; + const char *sender = "send-pack"; + if (!prefixcmp(dest, "http://") || + !prefixcmp(dest, "https://")) + sender = "http-push"; else if (thin) argv[dest_argc++] = "--thin"; argv[0] = sender; @@ -250,10 +334,12 @@ static int do_push(const char *repo) while (dest_refspec_nr--) argv[dest_argc++] = *dest_refspec++; argv[dest_argc] = NULL; - error = run_command_v(argc, argv); - if (!error) + if (verbose) + fprintf(stderr, "Pushing to %s\n", dest); + err = run_command_v_opt(argv, RUN_GIT_CMD); + if (!err) continue; - switch (error) { + switch (err) { case -ERR_RUN_COMMAND_FORK: die("unable to fork for %s", sender); case -ERR_RUN_COMMAND_EXEC: @@ -264,7 +350,7 @@ static int do_push(const char *repo) case -ERR_RUN_COMMAND_WAITPID_NOEXIT: die("%s died with strange error", sender); default: - return -error; + return -err; } } return 0; @@ -283,6 +369,14 @@ int cmd_push(int argc, const char **argv, const char *prefix) i++; break; } + if (!strcmp(arg, "-v")) { + verbose=1; + continue; + } + if (!prefixcmp(arg, "--repo=")) { + repo = arg+7; + continue; + } if (!strcmp(arg, "--all")) { all = 1; continue; @@ -303,8 +397,12 @@ int cmd_push(int argc, const char **argv, const char *prefix) thin = 0; continue; } - if (!strncmp(arg, "--exec=", 7)) { - execute = arg; + if (!prefixcmp(arg, "--receive-pack=")) { + receivepack = arg; + continue; + } + if (!prefixcmp(arg, "--exec=")) { + receivepack = arg; continue; } usage(push_usage);