Connect fast-import to the remote-helper via pipe, adding 'bidi-import' capability

The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers to retrieve information about blobs and trees that already exist in fast-import's memory. This requires a channel from fast-import to the remote-helper. remote-helpers that use these features shall advertise the new 'bidi-import' capability to signal that they require the communication channel. When forking fast-import in transport-helper.c connect it to a dup of the remote-helper's stdin-pipe. The additional file descriptor is passed to fast-import via its command line (--cat-blob-fd). It follows that git and fast-import are connected to the remote-helpers's stdin. Because git can send multiple commands to the remote-helper on it's stdin, it is required that helpers that advertise 'bidi-import' buffer all input commands until the batch of 'import' commands is ended by a newline before sending data to fast-import. This is to prevent mixing commands and fast-import responses on the helper's stdin. Signed-off-by: Florian Achleitner <florian.achleitner.2.6.31@gmail.com> Acked-by: David Michael Barr <b@rr-dav.id.au> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Florian Achleitner committed Sep 19, 2012 at 17:21 UTC bfc366d9315561166861bc97a395afc054c976c3
1 file changed +31 -13
transport-helper.c
+31 -13
@@ -10,6 +10,7 @@
10 #include "string-list.h"
11 #include "thread-utils.h"
12 #include "sigchain.h"
13 +#include "argv-array.h"
14
15 static int debug;
16
@@ -19,6 +20,7 @@ struct helper_data {
20 FILE *out;
21 unsigned fetch : 1,
22 import : 1,
23 + bidi_import : 1,
24 export : 1,
25 option : 1,
26 push : 1,
@@ -101,6 +103,7 @@ static void do_take_over(struct transport *transport)
103 static struct child_process *get_helper(struct transport *transport)
104 {
105 struct helper_data *data = transport->data;
106 + struct argv_array argv = ARGV_ARRAY_INIT;
107 struct strbuf buf = STRBUF_INIT;
108 struct child_process *helper;
109 const char **refspecs = NULL;
@@ -122,11 +125,10 @@ static struct child_process *get_helper(struct transport *transport)
125 helper->in = -1;
126 helper->out = -1;
127 helper->err = 0;
125 - helper->argv = xcalloc(4, sizeof(*helper->argv));
126 - strbuf_addf(&buf, "git-remote-%s", data->name);
127 - helper->argv[0] = strbuf_detach(&buf, NULL);
128 - helper->argv[1] = transport->remote->name;
129 - helper->argv[2] = remove_ext_force(transport->url);
128 + argv_array_pushf(&argv, "git-remote-%s", data->name);
129 + argv_array_push(&argv, transport->remote->name);
130 + argv_array_push(&argv, remove_ext_force(transport->url));
131 + helper->argv = argv_array_detach(&argv, NULL);
132 helper->git_cmd = 0;
133 helper->silent_exec_failure = 1;
134
@@ -178,6 +180,8 @@ static struct child_process *get_helper(struct transport *transport)
180 data->push = 1;
181 else if (!strcmp(capname, "import"))
182 data->import = 1;
183 + else if (!strcmp(capname, "bidi-import"))
184 + data->bidi_import = 1;
185 else if (!strcmp(capname, "export"))
186 data->export = 1;
187 else if (!data->refspecs && !prefixcmp(capname, "refspec ")) {
@@ -241,8 +245,7 @@ static int disconnect_helper(struct transport *transport)
245 close(data->helper->out);
246 fclose(data->out);
247 res = finish_command(data->helper);
244 - free((char *)data->helper->argv[0]);
245 - free(data->helper->argv);
248 + argv_array_free_detached(data->helper->argv);
249 free(data->helper);
250 data->helper = NULL;
251 }
@@ -376,14 +379,23 @@ static int fetch_with_fetch(struct transport *transport,
379 static int get_importer(struct transport *transport, struct child_process *fastimport)
380 {
381 struct child_process *helper = get_helper(transport);
382 + struct helper_data *data = transport->data;
383 + struct argv_array argv = ARGV_ARRAY_INIT;
384 + int cat_blob_fd, code;
385 memset(fastimport, 0, sizeof(*fastimport));
386 fastimport->in = helper->out;
381 - fastimport->argv = xcalloc(5, sizeof(*fastimport->argv));
382 - fastimport->argv[0] = "fast-import";
383 - fastimport->argv[1] = "--quiet";
387 + argv_array_push(&argv, "fast-import");
388 + argv_array_push(&argv, "--quiet");
389
390 + if (data->bidi_import) {
391 + cat_blob_fd = xdup(helper->in);
392 + argv_array_pushf(&argv, "--cat-blob-fd=%d", cat_blob_fd);
393 + }
394 + fastimport->argv = argv.argv;
395 fastimport->git_cmd = 1;
386 - return start_command(fastimport);
396 +
397 + code = start_command(fastimport);
398 + return code;
399 }
400
401 static int get_exporter(struct transport *transport,
@@ -438,11 +450,17 @@ static int fetch_with_import(struct transport *transport,
450 }
451
452 write_constant(data->helper->in, "\n");
453 + /*
454 + * remote-helpers that advertise the bidi-import capability are required to
455 + * buffer the complete batch of import commands until this newline before
456 + * sending data to fast-import.
457 + * These helpers read back data from fast-import on their stdin, which could
458 + * be mixed with import commands, otherwise.
459 + */
460
461 if (finish_command(&fastimport))
462 die("Error while running fast-import");
444 - free(fastimport.argv);
445 - fastimport.argv = NULL;
463 + argv_array_free_detached(fastimport.argv);
464
465 /*
466 * The fast-import stream of a remote helper that advertises