diff options
Diffstat (limited to 'transport-helper.c')
-rw-r--r-- | transport-helper.c | 210 |
1 files changed, 123 insertions, 87 deletions
diff --git a/transport-helper.c b/transport-helper.c index 673b7c214f..0224687a23 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -58,7 +58,7 @@ static int recvline_fh(FILE *helper, struct strbuf *buffer, const char *name) if (strbuf_getline(buffer, helper, '\n') == EOF) { if (debug) fprintf(stderr, "Debug: Remote helper quit.\n"); - exit(128); + return 1; } if (debug) @@ -71,12 +71,6 @@ static int recvline(struct helper_data *helper, struct strbuf *buffer) return recvline_fh(helper->out, buffer, helper->name); } -static void xchgline(struct helper_data *helper, struct strbuf *buffer) -{ - sendline(helper, buffer); - recvline(helper, buffer); -} - static void write_constant(int fd, const char *str) { if (debug) @@ -107,7 +101,6 @@ static void do_take_over(struct transport *transport) static struct child_process *get_helper(struct transport *transport) { struct helper_data *data = transport->data; - struct argv_array argv = ARGV_ARRAY_INIT; struct strbuf buf = STRBUF_INIT; struct child_process *helper; const char **refspecs = NULL; @@ -115,29 +108,23 @@ static struct child_process *get_helper(struct transport *transport) int refspec_alloc = 0; int duped; int code; - char git_dir_buf[sizeof(GIT_DIR_ENVIRONMENT) + PATH_MAX + 1]; - const char *helper_env[] = { - git_dir_buf, - NULL - }; - if (data->helper) return data->helper; - helper = xcalloc(1, sizeof(*helper)); + helper = xmalloc(sizeof(*helper)); + child_process_init(helper); helper->in = -1; helper->out = -1; helper->err = 0; - argv_array_pushf(&argv, "git-remote-%s", data->name); - argv_array_push(&argv, transport->remote->name); - argv_array_push(&argv, remove_ext_force(transport->url)); - helper->argv = argv_array_detach(&argv, NULL); + argv_array_pushf(&helper->args, "git-remote-%s", data->name); + argv_array_push(&helper->args, transport->remote->name); + argv_array_push(&helper->args, remove_ext_force(transport->url)); helper->git_cmd = 0; helper->silent_exec_failure = 1; - snprintf(git_dir_buf, sizeof(git_dir_buf), "%s=%s", GIT_DIR_ENVIRONMENT, get_git_dir()); - helper->env = helper_env; + argv_array_pushf(&helper->env_array, "%s=%s", GIT_DIR_ENVIRONMENT, + get_git_dir()); code = start_command(helper); if (code < 0 && errno == ENOENT) @@ -161,9 +148,10 @@ static struct child_process *get_helper(struct transport *transport) write_constant(helper->in, "capabilities\n"); while (1) { - const char *capname; + const char *capname, *arg; int mandatory = 0; - recvline(data, &buf); + if (recvline(data, &buf)) + exit(128); if (!*buf.buf) break; @@ -190,26 +178,20 @@ static struct child_process *get_helper(struct transport *transport) data->export = 1; else if (!strcmp(capname, "check-connectivity")) data->check_connectivity = 1; - else if (!data->refspecs && !prefixcmp(capname, "refspec ")) { + else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) { ALLOC_GROW(refspecs, refspec_nr + 1, refspec_alloc); - refspecs[refspec_nr++] = xstrdup(capname + strlen("refspec ")); + refspecs[refspec_nr++] = xstrdup(arg); } else if (!strcmp(capname, "connect")) { data->connect = 1; } else if (!strcmp(capname, "signed-tags")) { data->signed_tags = 1; - } else if (!prefixcmp(capname, "export-marks ")) { - struct strbuf arg = STRBUF_INIT; - strbuf_addstr(&arg, "--export-marks="); - strbuf_addstr(&arg, capname + strlen("export-marks ")); - data->export_marks = strbuf_detach(&arg, NULL); - } else if (!prefixcmp(capname, "import-marks")) { - struct strbuf arg = STRBUF_INIT; - strbuf_addstr(&arg, "--import-marks="); - strbuf_addstr(&arg, capname + strlen("import-marks ")); - data->import_marks = strbuf_detach(&arg, NULL); - } else if (!prefixcmp(capname, "no-private-update")) { + } else if (skip_prefix(capname, "export-marks ", &arg)) { + data->export_marks = xstrdup(arg); + } else if (skip_prefix(capname, "import-marks ", &arg)) { + data->import_marks = xstrdup(arg); + } else if (starts_with(capname, "no-private-update")) { data->no_private_update = 1; } else if (mandatory) { die("Unknown mandatory capability %s. This remote " @@ -256,7 +238,6 @@ static int disconnect_helper(struct transport *transport) close(data->helper->out); fclose(data->out); res = finish_command(data->helper); - argv_array_free_detached(data->helper->argv); free(data->helper); data->helper = NULL; } @@ -273,7 +254,8 @@ static const char *unsupported_options[] = { static const char *boolean_options[] = { TRANS_OPT_THIN, TRANS_OPT_KEEP, - TRANS_OPT_FOLLOWTAGS + TRANS_OPT_FOLLOWTAGS, + TRANS_OPT_PUSH_CERT }; static int set_helper_option(struct transport *transport, @@ -307,11 +289,13 @@ static int set_helper_option(struct transport *transport, quote_c_style(value, &buf, NULL, 0); strbuf_addch(&buf, '\n'); - xchgline(data, &buf); + sendline(data, &buf); + if (recvline(data, &buf)) + exit(128); if (!strcmp(buf.buf, "ok")) ret = 0; - else if (!prefixcmp(buf.buf, "error")) { + else if (starts_with(buf.buf, "error")) { ret = -1; } else if (!strcmp(buf.buf, "unsupported")) ret = 1; @@ -360,6 +344,12 @@ static int fetch_with_fetch(struct transport *transport, data->transport_options.check_self_contained_and_connected) set_helper_option(transport, "check-connectivity", "true"); + if (transport->cloning) + set_helper_option(transport, "cloning", "true"); + + if (data->transport_options.update_shallow) + set_helper_option(transport, "update-shallow", "true"); + for (i = 0; i < nr_heads; i++) { const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) @@ -373,9 +363,10 @@ static int fetch_with_fetch(struct transport *transport, sendline(data, &buf); while (1) { - recvline(data, &buf); + if (recvline(data, &buf)) + exit(128); - if (!prefixcmp(buf.buf, "lock ")) { + if (starts_with(buf.buf, "lock ")) { const char *name = buf.buf + 5; if (transport->pack_lockfile) warning("%s also locked %s", data->name, name); @@ -399,18 +390,16 @@ static int get_importer(struct transport *transport, struct child_process *fasti { struct child_process *helper = get_helper(transport); struct helper_data *data = transport->data; - struct argv_array argv = ARGV_ARRAY_INIT; int cat_blob_fd, code; - memset(fastimport, 0, sizeof(*fastimport)); + child_process_init(fastimport); fastimport->in = helper->out; - argv_array_push(&argv, "fast-import"); - argv_array_push(&argv, debug ? "--stats" : "--quiet"); + argv_array_push(&fastimport->args, "fast-import"); + argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet"); if (data->bidi_import) { cat_blob_fd = xdup(helper->in); - argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd); + argv_array_pushf(&fastimport->args, "--cat-blob-fd=%d", cat_blob_fd); } - fastimport->argv = argv.argv; fastimport->git_cmd = 1; code = start_command(fastimport); @@ -423,24 +412,24 @@ static int get_exporter(struct transport *transport, { struct helper_data *data = transport->data; struct child_process *helper = get_helper(transport); - int argc = 0, i; - memset(fastexport, 0, sizeof(*fastexport)); + int i; + + child_process_init(fastexport); /* we need to duplicate helper->in because we want to use it after * fastexport is done with it. */ fastexport->out = dup(helper->in); - fastexport->argv = xcalloc(6 + revlist_args->nr, sizeof(*fastexport->argv)); - fastexport->argv[argc++] = "fast-export"; - fastexport->argv[argc++] = "--use-done-feature"; - fastexport->argv[argc++] = data->signed_tags ? - "--signed-tags=verbatim" : "--signed-tags=warn-strip"; + argv_array_push(&fastexport->args, "fast-export"); + argv_array_push(&fastexport->args, "--use-done-feature"); + argv_array_push(&fastexport->args, data->signed_tags ? + "--signed-tags=verbatim" : "--signed-tags=warn-strip"); if (data->export_marks) - fastexport->argv[argc++] = data->export_marks; + argv_array_pushf(&fastexport->args, "--export-marks=%s.tmp", data->export_marks); if (data->import_marks) - fastexport->argv[argc++] = data->import_marks; + argv_array_pushf(&fastexport->args, "--import-marks=%s", data->import_marks); for (i = 0; i < revlist_args->nr; i++) - fastexport->argv[argc++] = revlist_args->items[i].string; + argv_array_push(&fastexport->args, revlist_args->items[i].string); fastexport->git_cmd = 1; return start_command(fastexport); @@ -481,7 +470,6 @@ static int fetch_with_import(struct transport *transport, if (finish_command(&fastimport)) die("Error while running fast-import"); - argv_array_free_detached(fastimport.argv); /* * The fast-import stream of a remote helper that advertises @@ -557,7 +545,9 @@ static int process_connect_service(struct transport *transport, goto exit; sendline(data, &cmdbuf); - recvline_fh(input, &cmdbuf, name); + if (recvline_fh(input, &cmdbuf, name)) + exit(128); + if (!strcmp(cmdbuf.buf, "")) { data->no_disconnect_req = 1; if (debug) @@ -644,12 +634,12 @@ static int push_update_ref_status(struct strbuf *buf, struct ref *remote_refs) { char *refname, *msg; - int status; + int status, forced = 0; - if (!prefixcmp(buf->buf, "ok ")) { + if (starts_with(buf->buf, "ok ")) { status = REF_STATUS_OK; refname = buf->buf + 3; - } else if (!prefixcmp(buf->buf, "error ")) { + } else if (starts_with(buf->buf, "error ")) { status = REF_STATUS_REMOTE_REJECT; refname = buf->buf + 6; } else @@ -702,6 +692,11 @@ static int push_update_ref_status(struct strbuf *buf, free(msg); msg = NULL; } + else if (!strcmp(msg, "forced update")) { + forced = 1; + free(msg); + msg = NULL; + } } if (*ref) @@ -723,26 +718,34 @@ static int push_update_ref_status(struct strbuf *buf, } (*ref)->status = status; + (*ref)->forced_update |= forced; (*ref)->remote_status = msg; return !(status == REF_STATUS_OK); } -static void push_update_refs_status(struct helper_data *data, - struct ref *remote_refs) +static int push_update_refs_status(struct helper_data *data, + struct ref *remote_refs, + int flags) { struct strbuf buf = STRBUF_INIT; struct ref *ref = remote_refs; + int ret = 0; + for (;;) { char *private; - recvline(data, &buf); + if (recvline(data, &buf)) { + ret = 1; + break; + } + if (!buf.len) break; if (push_update_ref_status(&buf, &ref, remote_refs)) continue; - if (!data->refspecs || data->no_private_update) + if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update) continue; /* propagate back the update to the remote namespace */ @@ -753,6 +756,7 @@ static void push_update_refs_status(struct helper_data *data, free(private); } strbuf_release(&buf); + return ret; } static int push_refs_with_push(struct transport *transport, @@ -827,14 +831,16 @@ static int push_refs_with_push(struct transport *transport, if (flags & TRANSPORT_PUSH_DRY_RUN) { if (set_helper_option(transport, "dry-run", "true") != 0) die("helper %s does not support dry-run", data->name); + } else if (flags & TRANSPORT_PUSH_CERT) { + if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0) + die("helper %s does not support --signed", data->name); } strbuf_addch(&buf, '\n'); sendline(data, &buf); strbuf_release(&buf); - push_update_refs_status(data, remote_refs); - return 0; + return push_update_refs_status(data, remote_refs, flags); } static int push_refs_with_export(struct transport *transport, @@ -843,7 +849,7 @@ static int push_refs_with_export(struct transport *transport, struct ref *ref; struct child_process *helper, exporter; struct helper_data *data = transport->data; - struct string_list revlist_args = STRING_LIST_INIT_NODUP; + struct string_list revlist_args = STRING_LIST_INIT_DUP; struct strbuf buf = STRBUF_INIT; if (!data->refspecs) @@ -852,21 +858,24 @@ static int push_refs_with_export(struct transport *transport, if (flags & TRANSPORT_PUSH_DRY_RUN) { if (set_helper_option(transport, "dry-run", "true") != 0) die("helper %s does not support dry-run", data->name); + } else if (flags & TRANSPORT_PUSH_CERT) { + if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0) + die("helper %s does not support dry-run", data->name); + } + + if (flags & TRANSPORT_PUSH_FORCE) { + if (set_helper_option(transport, "force", "true") != 0) + warning("helper %s does not support 'force'", data->name); } helper = get_helper(transport); write_constant(helper->in, "export\n"); - strbuf_reset(&buf); - for (ref = remote_refs; ref; ref = ref->next) { char *private; unsigned char sha1[20]; - if (ref->deletion) - die("remote-helpers do not support ref deletion"); - private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name); if (private && !get_sha1(private, sha1)) { strbuf_addf(&buf, "^%s", private); @@ -875,22 +884,49 @@ static int push_refs_with_export(struct transport *transport, } free(private); - if (ref->deletion) - die("remote-helpers do not support ref deletion"); - if (ref->peer_ref) { - if (strcmp(ref->peer_ref->name, ref->name)) - die("remote-helpers do not support old:new syntax"); - string_list_append(&revlist_args, ref->peer_ref->name); + if (strcmp(ref->name, ref->peer_ref->name)) { + if (!ref->deletion) { + const char *name; + int flag; + + /* Follow symbolic refs (mainly for HEAD). */ + name = resolve_ref_unsafe( + ref->peer_ref->name, + RESOLVE_REF_READING, + sha1, &flag); + if (!name || !(flag & REF_ISSYMREF)) + name = ref->peer_ref->name; + + strbuf_addf(&buf, "%s:%s", name, ref->name); + } else + strbuf_addf(&buf, ":%s", ref->name); + + string_list_append(&revlist_args, "--refspec"); + string_list_append(&revlist_args, buf.buf); + strbuf_release(&buf); + } + if (!ref->deletion) + string_list_append(&revlist_args, ref->peer_ref->name); } } if (get_exporter(transport, &exporter, &revlist_args)) die("Couldn't run fast-export"); + string_list_clear(&revlist_args, 1); + if (finish_command(&exporter)) die("Error while running fast-export"); - push_update_refs_status(data, remote_refs); + if (push_update_refs_status(data, remote_refs, flags)) + return 1; + + if (data->export_marks) { + strbuf_addf(&buf, "%s.tmp", data->export_marks); + rename(buf.buf, data->export_marks); + strbuf_release(&buf); + } + return 0; } @@ -959,7 +995,8 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) while (1) { char *eov, *eon; - recvline(data, &buf); + if (recvline(data, &buf)) + exit(128); if (!*buf.buf) break; @@ -996,7 +1033,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push) int transport_helper_init(struct transport *transport, const char *name) { - struct helper_data *data = xcalloc(sizeof(*data), 1); + struct helper_data *data = xcalloc(1, sizeof(*data)); data->name = name; if (getenv("GIT_TRANSPORT_HELPER_DEBUG")) @@ -1129,9 +1166,8 @@ static int udt_do_write(struct unidirectional_transfer *t) return 0; /* Nothing to write. */ transfer_debug("%s is writable", t->dest_name); - bytes = write(t->dest, t->buf, t->bufuse); - if (bytes < 0 && errno != EWOULDBLOCK && errno != EAGAIN && - errno != EINTR) { + bytes = xwrite(t->dest, t->buf, t->bufuse); + if (bytes < 0 && errno != EWOULDBLOCK) { error("write(%s) failed: %s", t->dest_name, strerror(errno)); return -1; } else if (bytes > 0) { |