transport_get() can call transport_shim_init() to have list and fetch-ref operations handled by running a separate program as: git shim-<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@xxxxxxxxxxxx> --- This version uses the more traditional ordering for listing refs and fixes a memory leak. Documentation/git-shim.txt | 37 +++++++++++ Makefile | 1 + transport-shim.c | 142 ++++++++++++++++++++++++++++++++++++++++++++ transport.h | 3 + 4 files changed, 183 insertions(+), 0 deletions(-) create mode 100644 Documentation/git-shim.txt create mode 100644 transport-shim.c diff --git a/Documentation/git-shim.txt b/Documentation/git-shim.txt new file mode 100644 index 0000000..dd80c6d --- /dev/null +++ b/Documentation/git-shim.txt @@ -0,0 +1,37 @@ +git-shim(1) +============ + +NAME +---- +git-shim - Helper programs for interoperation with remote git + +SYNOPSIS +-------- +'git shim-<transport>' <remote> + +DESCRIPTION +----------- + +These programs are normally not used directly by end users, but are +invoked by various git programs that interact with remote repositories +when the repository they would operate on will be accessed using +transport code not linked into the main git binary. + +COMMANDS +-------- + +Commands are given by the caller on the helper's standard input, one per line. + +'list':: + Lists the refs, one per line, if the format "<value> + <name>". The value is either a hex sha1 hash or "@<dest>" for + symrefs. After the complete list, outputs a blank line. + +'fetch' ref:: + Fetches the given ref, writing the necessary objects to the + database. Outputs a blank line when the fetch is complete. ++ +If a fatal error occurs, the program writes the error message to +stderr and exits. The caller should expect that a suitable error +message has been printed if the child closes the connection without +completing a valid response for the current command. diff --git a/Makefile b/Makefile index bde27ed..01efc73 100644 --- a/Makefile +++ b/Makefile @@ -549,6 +549,7 @@ LIB_OBJS += symlinks.o LIB_OBJS += tag.o LIB_OBJS += trace.o LIB_OBJS += transport.o +LIB_OBJS += transport-shim.o LIB_OBJS += tree-diff.o LIB_OBJS += tree.o LIB_OBJS += tree-walk.o diff --git a/transport-shim.c b/transport-shim.c new file mode 100644 index 0000000..2518aba --- /dev/null +++ b/transport-shim.c @@ -0,0 +1,142 @@ +#include "cache.h" +#include "transport.h" + +#include "run-command.h" +#include "commit.h" +#include "diff.h" +#include "revision.h" + +struct shim_data +{ + const char *name; + struct child_process *shim; +}; + +static struct child_process *get_shim(struct transport *transport) +{ + struct shim_data *data = transport->data; + if (!data->shim) { + struct strbuf buf = STRBUF_INIT; + struct child_process *shim = xcalloc(1, sizeof(*shim)); + shim->in = -1; + shim->out = -1; + shim->err = 0; + shim->argv = xcalloc(4, sizeof(*shim->argv)); + strbuf_addf(&buf, "shim-%s", data->name); + shim->argv[0] = buf.buf; + shim->argv[1] = transport->remote->name; + shim->argv[2] = transport->url; + shim->git_cmd = 1; + start_command(shim); + data->shim = shim; + } + return data->shim; +} + +static int disconnect_shim(struct transport *transport) +{ + struct shim_data *data = transport->data; + if (data->shim) { + write(data->shim->in, "\n", 1); + close(data->shim->in); + finish_command(data->shim); + free(data->shim->argv); + free(data->shim); + transport->data = NULL; + } + return 0; +} + +static int fetch_refs_via_shim(struct transport *transport, + int nr_heads, const struct ref **to_fetch) +{ + struct child_process *shim; + const struct ref *posn; + struct strbuf buf = STRBUF_INIT; + int i, count; + FILE *file; + + count = 0; + for (i = 0; i < nr_heads; i++) { + posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + count++; + } + + if (count) { + shim = get_shim(transport); + for (i = 0; i < nr_heads; i++) { + posn = to_fetch[i]; + if (posn->status & REF_STATUS_UPTODATE) + continue; + write(shim->in, "fetch ", 6); + write(shim->in, sha1_to_hex(posn->old_sha1), 40); + write(shim->in, " ", 1); + write(shim->in, posn->name, strlen(posn->name)); + write(shim->in, "\n", 1); + } + file = fdopen(shim->out, "r"); + while (count) { + if (strbuf_getline(&buf, file, '\n') == EOF) + exit(128); /* child died, message supplied already */ + + count--; + } + } + return 0; +} + +static struct ref *get_refs_via_shim(struct transport *transport, int for_push) +{ + struct child_process *shim; + struct ref *ret = NULL; + struct ref **end = &ret; + struct ref *posn; + struct strbuf buf = STRBUF_INIT; + FILE *file; + + shim = get_shim(transport); + write(shim->in, "list\n", 5); + + file = fdopen(shim->out, "r"); + while (1) { + char *eov; + 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); + *eov = '\0'; + *end = alloc_ref(eov + 1); + if (eov) { + if (buf.buf[0] == '@') + (*end)->symref = xstrdup(buf.buf + 1); + else + get_sha1_hex(buf.buf, (*end)->old_sha1); + } + end = &((*end)->next); + strbuf_reset(&buf); + } + strbuf_release(&buf); + + for (posn = ret; posn; posn = posn->next) + resolve_remote_symref(posn, ret); + + return ret; +} + +void transport_shim_init(struct transport *transport, const char *name) +{ + struct shim_data *data = xmalloc(sizeof(*data)); + data->shim = NULL; + data->name = name; + transport->data = data; + transport->get_refs_list = get_refs_via_shim; + transport->fetch = fetch_refs_via_shim; + transport->disconnect = disconnect_shim; +} diff --git a/transport.h b/transport.h index 51b5397..01f650d 100644 --- a/transport.h +++ b/transport.h @@ -77,4 +77,7 @@ void transport_unlock_pack(struct transport *transport); int transport_disconnect(struct transport *transport); char *transport_anonymize_url(const char *url); +/* Transport methods defined outside transport.c */ +void transport_shim_init(struct transport *transport, const char *name); + #endif -- 1.6.4.rc2.13.ga9762.dirty -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html