diff options
author | Daniel Barkalow <barkalow@iabervon.org> | 2009-08-05 01:01:53 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2009-08-05 10:34:01 -0700 |
commit | 6eb996b5707b6d14cf9875a9231f4e909a443665 (patch) | |
tree | cd45ef2caf0a45dfe7a5b3f9d5b5cc7dcda2b6fe /transport-helper.c | |
parent | 07a4a3b4962e1fd4e40fd877427cddd7428c1bc3 (diff) | |
download | git-6eb996b5707b6d14cf9875a9231f4e909a443665.tar.gz |
Add support for external programs for handling native fetches
transport_get() can call transport_native_helper_init() to have list and
fetch-ref operations handled by running a separate program as:
git remote-<something> <remote> [<url>]
This program then accepts, on its stdin, "list" and "fetch <hex>
<name>" commands; the former prints out a list of available refs and
either their hashes or what they are symrefs to, while the latter
fetches them into the local object database and prints a newline when done.
Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'transport-helper.c')
-rw-r--r-- | transport-helper.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/transport-helper.c b/transport-helper.c new file mode 100644 index 0000000000..c982bb2575 --- /dev/null +++ b/transport-helper.c @@ -0,0 +1,168 @@ +#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_in_full(data->helper->in, "capabilities\n", 13); + file = fdopen(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_in_full(data->helper->in, "\n", 1); + 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 = fdopen(helper->out, "r"); + int i; + struct strbuf buf = STRBUF_INIT; + + for (i = 0; i < nr_heads; i++) { + struct ref *posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + write_in_full(helper->in, "fetch ", 6); + write_in_full(helper->in, sha1_to_hex(posn->old_sha1), 40); + write_in_full(helper->in, " ", 1); + write_in_full(helper->in, posn->name, strlen(posn->name)); + write_in_full(helper->in, "\n", 1); + 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_in_full(helper->in, "list\n", 5); + + file = fdopen(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) +{ + struct helper_data *data = xcalloc(sizeof(*data), 1); + char *eom = strchr(transport->url, ':'); + if (!eom) + return -1; + data->name = xstrndup(transport->url, eom - transport->url); + + transport->data = data; + transport->get_refs_list = get_refs_list; + transport->fetch = fetch; + transport->disconnect = disconnect_helper; + return 0; +} |