Add remote helper debug mode

Remote helpers deadlock easily, so support debug mode which shows the
interaction steps.

Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Ilari Liusvaara 2009-12-09 17:26:27 +02:00 committed by Junio C Hamano
parent a24a32ddb3
commit bf3c523c3f
1 changed files with 69 additions and 25 deletions

View File

@ -8,6 +8,8 @@
#include "quote.h" #include "quote.h"
#include "remote.h" #include "remote.h"


static int debug;

struct helper_data struct helper_data
{ {
const char *name; const char *name;
@ -22,6 +24,45 @@ struct helper_data
int refspec_nr; int refspec_nr;
}; };


static void sendline(struct helper_data *helper, struct strbuf *buffer)
{
if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", buffer->buf);
if (write_in_full(helper->helper->in, buffer->buf, buffer->len)
!= buffer->len)
die_errno("Full write to remote helper failed");
}

static int recvline(struct helper_data *helper, struct strbuf *buffer)
{
strbuf_reset(buffer);
if (debug)
fprintf(stderr, "Debug: Remote helper: Waiting...\n");
if (strbuf_getline(buffer, helper->out, '\n') == EOF) {
if (debug)
fprintf(stderr, "Debug: Remote helper quit.\n");
exit(128);
}

if (debug)
fprintf(stderr, "Debug: Remote helper: <- %s\n", buffer->buf);
return 0;
}

static void xchgline(struct helper_data *helper, struct strbuf *buffer)
{
sendline(helper, buffer);
recvline(helper, buffer);
}

static void write_constant(int fd, const char *str)
{
if (debug)
fprintf(stderr, "Debug: Remote helper: -> %s", str);
if (write_in_full(fd, str, strlen(str)) != strlen(str))
die_errno("Full write to remote helper failed");
}

static struct child_process *get_helper(struct transport *transport) static struct child_process *get_helper(struct transport *transport)
{ {
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
@ -48,15 +89,16 @@ static struct child_process *get_helper(struct transport *transport)
die("Unable to run helper: git %s", helper->argv[0]); die("Unable to run helper: git %s", helper->argv[0]);
data->helper = helper; data->helper = helper;


write_str_in_full(helper->in, "capabilities\n"); write_constant(helper->in, "capabilities\n");


data->out = xfdopen(helper->out, "r"); data->out = xfdopen(helper->out, "r");
while (1) { while (1) {
if (strbuf_getline(&buf, data->out, '\n') == EOF) recvline(data, &buf);
exit(128); /* child died, message supplied already */


if (!*buf.buf) if (!*buf.buf)
break; break;
if (debug)
fprintf(stderr, "Debug: Got cap %s\n", buf.buf);
if (!strcmp(buf.buf, "fetch")) if (!strcmp(buf.buf, "fetch"))
data->fetch = 1; data->fetch = 1;
if (!strcmp(buf.buf, "option")) if (!strcmp(buf.buf, "option"))
@ -82,14 +124,21 @@ static struct child_process *get_helper(struct transport *transport)
free(refspecs); free(refspecs);
} }
strbuf_release(&buf); strbuf_release(&buf);
if (debug)
fprintf(stderr, "Debug: Capabilities complete.\n");
return data->helper; return data->helper;
} }


static int disconnect_helper(struct transport *transport) static int disconnect_helper(struct transport *transport)
{ {
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
struct strbuf buf = STRBUF_INIT;

if (data->helper) { if (data->helper) {
write_str_in_full(data->helper->in, "\n"); if (debug)
fprintf(stderr, "Debug: Disconnecting.\n");
strbuf_addf(&buf, "\n");
sendline(data, &buf);
close(data->helper->in); close(data->helper->in);
fclose(data->out); fclose(data->out);
finish_command(data->helper); finish_command(data->helper);
@ -117,10 +166,11 @@ static int set_helper_option(struct transport *transport,
const char *name, const char *value) const char *name, const char *value)
{ {
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
struct child_process *helper = get_helper(transport);
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
int i, ret, is_bool = 0; int i, ret, is_bool = 0;


get_helper(transport);

if (!data->option) if (!data->option)
return 1; return 1;


@ -143,12 +193,7 @@ static int set_helper_option(struct transport *transport,
quote_c_style(value, &buf, NULL, 0); quote_c_style(value, &buf, NULL, 0);
strbuf_addch(&buf, '\n'); strbuf_addch(&buf, '\n');


if (write_in_full(helper->in, buf.buf, buf.len) != buf.len) xchgline(data, &buf);
die_errno("cannot send option to %s", data->name);

strbuf_reset(&buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */


if (!strcmp(buf.buf, "ok")) if (!strcmp(buf.buf, "ok"))
ret = 0; ret = 0;
@ -208,13 +253,10 @@ static int fetch_with_fetch(struct transport *transport,
} }


strbuf_addch(&buf, '\n'); strbuf_addch(&buf, '\n');
if (write_in_full(data->helper->in, buf.buf, buf.len) != buf.len) sendline(data, &buf);
die_errno("cannot send fetch to %s", data->name);


while (1) { while (1) {
strbuf_reset(&buf); recvline(data, &buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */


if (!prefixcmp(buf.buf, "lock ")) { if (!prefixcmp(buf.buf, "lock ")) {
const char *name = buf.buf + 5; const char *name = buf.buf + 5;
@ -249,12 +291,13 @@ static int fetch_with_import(struct transport *transport,
int nr_heads, struct ref **to_fetch) int nr_heads, struct ref **to_fetch)
{ {
struct child_process fastimport; struct child_process fastimport;
struct child_process *helper = get_helper(transport);
struct helper_data *data = transport->data; struct helper_data *data = transport->data;
int i; int i;
struct ref *posn; struct ref *posn;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;


get_helper(transport);

if (get_importer(transport, &fastimport)) if (get_importer(transport, &fastimport))
die("Couldn't run fast-import"); die("Couldn't run fast-import");


@ -264,7 +307,7 @@ static int fetch_with_import(struct transport *transport,
continue; continue;


strbuf_addf(&buf, "import %s\n", posn->name); strbuf_addf(&buf, "import %s\n", posn->name);
write_in_full(helper->in, buf.buf, buf.len); sendline(data, &buf);
strbuf_reset(&buf); strbuf_reset(&buf);
} }
disconnect_helper(transport); disconnect_helper(transport);
@ -369,17 +412,14 @@ static int push_refs(struct transport *transport,
} }


strbuf_addch(&buf, '\n'); strbuf_addch(&buf, '\n');
if (write_in_full(helper->in, buf.buf, buf.len) != buf.len) sendline(data, &buf);
exit(128);


ref = remote_refs; ref = remote_refs;
while (1) { while (1) {
char *refname, *msg; char *refname, *msg;
int status; int status;


strbuf_reset(&buf); recvline(data, &buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
if (!buf.len) if (!buf.len)
break; break;


@ -471,8 +511,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)


while (1) { while (1) {
char *eov, *eon; char *eov, *eon;
if (strbuf_getline(&buf, data->out, '\n') == EOF) recvline(data, &buf);
exit(128); /* child died, message supplied already */


if (!*buf.buf) if (!*buf.buf)
break; break;
@ -497,6 +536,8 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
} }
tail = &((*tail)->next); tail = &((*tail)->next);
} }
if (debug)
fprintf(stderr, "Debug: Read ref listing.\n");
strbuf_release(&buf); strbuf_release(&buf);


for (posn = ret; posn; posn = posn->next) for (posn = ret; posn; posn = posn->next)
@ -510,6 +551,9 @@ int transport_helper_init(struct transport *transport, const char *name)
struct helper_data *data = xcalloc(sizeof(*data), 1); struct helper_data *data = xcalloc(sizeof(*data), 1);
data->name = name; data->name = name;


if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
debug = 1;

transport->data = data; transport->data = data;
transport->set_option = set_helper_option; transport->set_option = set_helper_option;
transport->get_refs_list = get_refs_list; transport->get_refs_list = get_refs_list;