#include "cache.h" #include "transport.h" #include "run-command.h" #include "commit.h" #include "diff.h" #include "revision.h" struct helper_data { const char *name; struct child_process *helper; unsigned fetch : 1; }; static struct child_process *get_helper(struct transport *transport) { struct helper_data *data = transport->data; struct strbuf buf = STRBUF_INIT; struct child_process *helper; FILE *file; if (data->helper) return data->helper; helper = xcalloc(1, sizeof(*helper)); helper->in = -1; helper->out = -1; helper->err = 0; helper->argv = xcalloc(4, sizeof(*helper->argv)); strbuf_addf(&buf, "remote-%s", data->name); helper->argv[0] = strbuf_detach(&buf, NULL); helper->argv[1] = transport->remote->name; helper->argv[2] = transport->url; helper->git_cmd = 1; if (start_command(helper)) die("Unable to run helper: git %s", helper->argv[0]); data->helper = helper; write_str_in_full(helper->in, "capabilities\n"); file = xfdopen(helper->out, "r"); while (1) { if (strbuf_getline(&buf, file, '\n') == EOF) exit(128); /* child died, message supplied already */ if (!*buf.buf) break; if (!strcmp(buf.buf, "fetch")) data->fetch = 1; } return data->helper; } static int disconnect_helper(struct transport *transport) { struct helper_data *data = transport->data; if (data->helper) { write_str_in_full(data->helper->in, "\n"); close(data->helper->in); finish_command(data->helper); free((char *)data->helper->argv[0]); free(data->helper->argv); free(data->helper); data->helper = NULL; } return 0; } static int fetch_with_fetch(struct transport *transport, int nr_heads, const struct ref **to_fetch) { struct child_process *helper = get_helper(transport); FILE *file = xfdopen(helper->out, "r"); int i; struct strbuf buf = STRBUF_INIT; for (i = 0; i < nr_heads; i++) { const struct ref *posn = to_fetch[i]; if (posn->status & REF_STATUS_UPTODATE) continue; strbuf_addf(&buf, "fetch %s %s\n", sha1_to_hex(posn->old_sha1), posn->name); write_in_full(helper->in, buf.buf, buf.len); strbuf_reset(&buf); if (strbuf_getline(&buf, file, '\n') == EOF) exit(128); /* child died, message supplied already */ } return 0; } static int fetch(struct transport *transport, int nr_heads, const struct ref **to_fetch) { struct helper_data *data = transport->data; int i, count; count = 0; for (i = 0; i < nr_heads; i++) if (!(to_fetch[i]->status & REF_STATUS_UPTODATE)) count++; if (!count) return 0; if (data->fetch) return fetch_with_fetch(transport, nr_heads, to_fetch); return -1; } static struct ref *get_refs_list(struct transport *transport, int for_push) { struct child_process *helper; struct ref *ret = NULL; struct ref **tail = &ret; struct ref *posn; struct strbuf buf = STRBUF_INIT; FILE *file; helper = get_helper(transport); write_str_in_full(helper->in, "list\n"); file = xfdopen(helper->out, "r"); while (1) { char *eov, *eon; if (strbuf_getline(&buf, file, '\n') == EOF) exit(128); /* child died, message supplied already */ if (!*buf.buf) break; eov = strchr(buf.buf, ' '); if (!eov) die("Malformed response in ref list: %s", buf.buf); eon = strchr(eov + 1, ' '); *eov = '\0'; if (eon) *eon = '\0'; *tail = alloc_ref(eov + 1); if (buf.buf[0] == '@') (*tail)->symref = xstrdup(buf.buf + 1); else if (buf.buf[0] != '?') get_sha1_hex(buf.buf, (*tail)->old_sha1); tail = &((*tail)->next); } strbuf_release(&buf); for (posn = ret; posn; posn = posn->next) resolve_remote_symref(posn, ret); return ret; } int transport_helper_init(struct transport *transport, const char *name) { struct helper_data *data = xcalloc(sizeof(*data), 1); data->name = name; transport->data = data; transport->get_refs_list = get_refs_list; transport->fetch = fetch; transport->disconnect = disconnect_helper; return 0; }