t1400: add some more tests of "update-ref --stdin"'s verify command
[gitweb.git] / transport-helper.c
index d9063d714591bad2e44a4e58fdffc3bb1708157d..0224687a2316798c57315093315eafae0da0b1aa 100644 (file)
@@ -108,17 +108,12 @@ 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;
@@ -128,8 +123,8 @@ static struct child_process *get_helper(struct transport *transport)
        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)
@@ -153,7 +148,7 @@ 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;
                if (recvline(data, &buf))
                        exit(128);
@@ -183,19 +178,19 @@ 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 && starts_with(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 (starts_with(capname, "export-marks ")) {
-                       data->export_marks = xstrdup(capname + strlen("export-marks "));
-               } else if (starts_with(capname, "import-marks")) {
-                       data->import_marks = xstrdup(capname + strlen("import-marks "));
+               } 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) {
@@ -259,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,
@@ -395,7 +391,7 @@ static int get_importer(struct transport *transport, struct child_process *fasti
        struct child_process *helper = get_helper(transport);
        struct helper_data *data = transport->data;
        int cat_blob_fd, code;
-       memset(fastimport, 0, sizeof(*fastimport));
+       child_process_init(fastimport);
        fastimport->in = helper->out;
        argv_array_push(&fastimport->args, "fast-import");
        argv_array_push(&fastimport->args, debug ? "--stats" : "--quiet");
@@ -418,7 +414,7 @@ static int get_exporter(struct transport *transport,
        struct child_process *helper = get_helper(transport);
        int i;
 
-       memset(fastexport, 0, sizeof(*fastexport));
+       child_process_init(fastexport);
 
        /* we need to duplicate helper->in because we want to use it after
         * fastexport is done with it. */
@@ -835,6 +831,9 @@ 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');
@@ -850,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)
@@ -859,6 +858,9 @@ 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) {
@@ -870,15 +872,10 @@ static int push_refs_with_export(struct transport *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);
@@ -888,15 +885,37 @@ static int push_refs_with_export(struct transport *transport,
                free(private);
 
                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");
        if (push_update_refs_status(data, remote_refs, flags))
@@ -1014,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"))