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
parent
a24a32ddb3
commit
bf3c523c3f
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue