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>
This commit is contained in:
Ilari Liusvaara 2009-12-09 17:26:27 +02:00 committed by Junio C Hamano
parent a24a32ddb3
commit bf3c523c3f

View File

@ -8,6 +8,8 @@
#include "quote.h"
#include "remote.h"
static int debug;
struct helper_data
{
const char *name;
@ -22,6 +24,45 @@ struct helper_data
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)
{
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]);
data->helper = helper;
write_str_in_full(helper->in, "capabilities\n");
write_constant(helper->in, "capabilities\n");
data->out = xfdopen(helper->out, "r");
while (1) {
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
recvline(data, &buf);
if (!*buf.buf)
break;
if (debug)
fprintf(stderr, "Debug: Got cap %s\n", buf.buf);
if (!strcmp(buf.buf, "fetch"))
data->fetch = 1;
if (!strcmp(buf.buf, "option"))
@ -82,14 +124,21 @@ static struct child_process *get_helper(struct transport *transport)
free(refspecs);
}
strbuf_release(&buf);
if (debug)
fprintf(stderr, "Debug: Capabilities complete.\n");
return data->helper;
}
static int disconnect_helper(struct transport *transport)
{
struct helper_data *data = transport->data;
struct strbuf buf = STRBUF_INIT;
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);
fclose(data->out);
finish_command(data->helper);
@ -117,10 +166,11 @@ static int set_helper_option(struct transport *transport,
const char *name, const char *value)
{
struct helper_data *data = transport->data;
struct child_process *helper = get_helper(transport);
struct strbuf buf = STRBUF_INIT;
int i, ret, is_bool = 0;
get_helper(transport);
if (!data->option)
return 1;
@ -143,12 +193,7 @@ static int set_helper_option(struct transport *transport,
quote_c_style(value, &buf, NULL, 0);
strbuf_addch(&buf, '\n');
if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
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 */
xchgline(data, &buf);
if (!strcmp(buf.buf, "ok"))
ret = 0;
@ -208,13 +253,10 @@ static int fetch_with_fetch(struct transport *transport,
}
strbuf_addch(&buf, '\n');
if (write_in_full(data->helper->in, buf.buf, buf.len) != buf.len)
die_errno("cannot send fetch to %s", data->name);
sendline(data, &buf);
while (1) {
strbuf_reset(&buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
recvline(data, &buf);
if (!prefixcmp(buf.buf, "lock ")) {
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)
{
struct child_process fastimport;
struct child_process *helper = get_helper(transport);
struct helper_data *data = transport->data;
int i;
struct ref *posn;
struct strbuf buf = STRBUF_INIT;
get_helper(transport);
if (get_importer(transport, &fastimport))
die("Couldn't run fast-import");
@ -264,7 +307,7 @@ static int fetch_with_import(struct transport *transport,
continue;
strbuf_addf(&buf, "import %s\n", posn->name);
write_in_full(helper->in, buf.buf, buf.len);
sendline(data, &buf);
strbuf_reset(&buf);
}
disconnect_helper(transport);
@ -369,17 +412,14 @@ static int push_refs(struct transport *transport,
}
strbuf_addch(&buf, '\n');
if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
exit(128);
sendline(data, &buf);
ref = remote_refs;
while (1) {
char *refname, *msg;
int status;
strbuf_reset(&buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
recvline(data, &buf);
if (!buf.len)
break;
@ -471,8 +511,7 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
while (1) {
char *eov, *eon;
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
recvline(data, &buf);
if (!*buf.buf)
break;
@ -497,6 +536,8 @@ static struct ref *get_refs_list(struct transport *transport, int for_push)
}
tail = &((*tail)->next);
}
if (debug)
fprintf(stderr, "Debug: Read ref listing.\n");
strbuf_release(&buf);
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);
data->name = name;
if (getenv("GIT_TRANSPORT_HELPER_DEBUG"))
debug = 1;
transport->data = data;
transport->set_option = set_helper_option;
transport->get_refs_list = get_refs_list;