]> git.ipfire.org Git - thirdparty/git.git/blobdiff - transport-helper.c
strmap: enable allocations to come from a mem_pool
[thirdparty/git.git] / transport-helper.c
index defafbf4c1bc6788c4f7b9692cdcfcda1181116b..b573b6c730ccf49d2805a27b14957504f2218f41 100644 (file)
@@ -128,10 +128,10 @@ static struct child_process *get_helper(struct transport *transport)
        helper->in = -1;
        helper->out = -1;
        helper->err = 0;
-       strvec_pushf(&helper->args, "git-remote-%s", data->name);
+       strvec_pushf(&helper->args, "remote-%s", data->name);
        strvec_push(&helper->args, transport->remote->name);
        strvec_push(&helper->args, remove_ext_force(transport->url));
-       helper->git_cmd = 0;
+       helper->git_cmd = 1;
        helper->silent_exec_failure = 1;
 
        if (have_git_dir())
@@ -723,13 +723,61 @@ static int fetch(struct transport *transport,
        return -1;
 }
 
+struct push_update_ref_state {
+       struct ref *hint;
+       struct ref_push_report *report;
+       int new_report;
+};
+
 static int push_update_ref_status(struct strbuf *buf,
-                                  struct ref **ref,
+                                  struct push_update_ref_state *state,
                                   struct ref *remote_refs)
 {
        char *refname, *msg;
        int status, forced = 0;
 
+       if (starts_with(buf->buf, "option ")) {
+               struct object_id old_oid, new_oid;
+               const char *key, *val;
+               char *p;
+
+               if (!state->hint || !(state->report || state->new_report))
+                       die(_("'option' without a matching 'ok/error' directive"));
+               if (state->new_report) {
+                       if (!state->hint->report) {
+                               state->hint->report = xcalloc(1, sizeof(struct ref_push_report));
+                               state->report = state->hint->report;
+                       } else {
+                               state->report = state->hint->report;
+                               while (state->report->next)
+                                       state->report = state->report->next;
+                               state->report->next = xcalloc(1, sizeof(struct ref_push_report));
+                               state->report = state->report->next;
+                       }
+                       state->new_report = 0;
+               }
+               key = buf->buf + 7;
+               p = strchr(key, ' ');
+               if (p)
+                       *p++ = '\0';
+               val = p;
+               if (!strcmp(key, "refname"))
+                       state->report->ref_name = xstrdup_or_null(val);
+               else if (!strcmp(key, "old-oid") && val &&
+                        !parse_oid_hex(val, &old_oid, &val))
+                       state->report->old_oid = oiddup(&old_oid);
+               else if (!strcmp(key, "new-oid") && val &&
+                        !parse_oid_hex(val, &new_oid, &val))
+                       state->report->new_oid = oiddup(&new_oid);
+               else if (!strcmp(key, "forced-update"))
+                       state->report->forced_update = 1;
+               /* Not update remote namespace again. */
+               return 1;
+       }
+
+       state->report = NULL;
+       state->new_report = 0;
+
        if (starts_with(buf->buf, "ok ")) {
                status = REF_STATUS_OK;
                refname = buf->buf + 3;
@@ -785,16 +833,16 @@ static int push_update_ref_status(struct strbuf *buf,
                }
        }
 
-       if (*ref)
-               *ref = find_ref_by_name(*ref, refname);
-       if (!*ref)
-               *ref = find_ref_by_name(remote_refs, refname);
-       if (!*ref) {
+       if (state->hint)
+               state->hint = find_ref_by_name(state->hint, refname);
+       if (!state->hint)
+               state->hint = find_ref_by_name(remote_refs, refname);
+       if (!state->hint) {
                warning(_("helper reported unexpected status of %s"), refname);
                return 1;
        }
 
-       if ((*ref)->status != REF_STATUS_NONE) {
+       if (state->hint->status != REF_STATUS_NONE) {
                /*
                 * Earlier, the ref was marked not to be pushed, so ignore the ref
                 * status reported by the remote helper if the latter is 'no match'.
@@ -803,9 +851,11 @@ static int push_update_ref_status(struct strbuf *buf,
                        return 1;
        }
 
-       (*ref)->status = status;
-       (*ref)->forced_update |= forced;
-       (*ref)->remote_status = msg;
+       if (status == REF_STATUS_OK)
+               state->new_report = 1;
+       state->hint->status = status;
+       state->hint->forced_update |= forced;
+       state->hint->remote_status = msg;
        return !(status == REF_STATUS_OK);
 }
 
@@ -813,37 +863,57 @@ static int push_update_refs_status(struct helper_data *data,
                                    struct ref *remote_refs,
                                    int flags)
 {
+       struct ref *ref;
+       struct ref_push_report *report;
        struct strbuf buf = STRBUF_INIT;
-       struct ref *ref = remote_refs;
-       int ret = 0;
+       struct push_update_ref_state state = { remote_refs, NULL, 0 };
 
        for (;;) {
-               char *private;
-
                if (recvline(data, &buf)) {
-                       ret = 1;
-                       break;
+                       strbuf_release(&buf);
+                       return 1;
                }
-
                if (!buf.len)
                        break;
+               push_update_ref_status(&buf, &state, remote_refs);
+       }
+       strbuf_release(&buf);
 
-               if (push_update_ref_status(&buf, &ref, remote_refs))
-                       continue;
+       if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
+               return 0;
 
-               if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
-                       continue;
+       /* propagate back the update to the remote namespace */
+       for (ref = remote_refs; ref; ref = ref->next) {
+               char *private;
 
-               /* propagate back the update to the remote namespace */
-               private = apply_refspecs(&data->rs, ref->name);
-               if (!private)
+               if (ref->status != REF_STATUS_OK)
                        continue;
-               update_ref("update by helper", private, &ref->new_oid, NULL,
-                          0, 0);
-               free(private);
+
+               if (!ref->report) {
+                       private = apply_refspecs(&data->rs, ref->name);
+                       if (!private)
+                               continue;
+                       update_ref("update by helper", private, &(ref->new_oid),
+                                  NULL, 0, 0);
+                       free(private);
+               } else {
+                       for (report = ref->report; report; report = report->next) {
+                               private = apply_refspecs(&data->rs,
+                                                        report->ref_name
+                                                        ? report->ref_name
+                                                        : ref->name);
+                               if (!private)
+                                       continue;
+                               update_ref("update by helper", private,
+                                          report->new_oid
+                                          ? report->new_oid
+                                          : &(ref->new_oid),
+                                          NULL, 0, 0);
+                               free(private);
+                       }
+               }
        }
-       strbuf_release(&buf);
-       return ret;
+       return 0;
 }
 
 static void set_common_push_options(struct transport *transport,