Support taking over transports
Add support for taking over transports that turn out to be smart. Signed-off-by: Ilari Liusvaara <ilari.liusvaara@elisanet.fi> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
aa5af9749f
commit
61b075bd3e
@ -22,6 +22,10 @@ struct helper_data
|
||||
/* These go from remote name (as in "list") to private name */
|
||||
struct refspec *refspecs;
|
||||
int refspec_nr;
|
||||
/* Transport options for fetch-pack/send-pack (should one of
|
||||
* those be invoked).
|
||||
*/
|
||||
struct git_transport_options transport_options;
|
||||
};
|
||||
|
||||
static void sendline(struct helper_data *helper, struct strbuf *buffer)
|
||||
@ -81,6 +85,7 @@ static struct child_process *get_helper(struct transport *transport)
|
||||
const char **refspecs = NULL;
|
||||
int refspec_nr = 0;
|
||||
int refspec_alloc = 0;
|
||||
int duped;
|
||||
|
||||
if (data->helper)
|
||||
return data->helper;
|
||||
@ -99,9 +104,19 @@ static struct child_process *get_helper(struct transport *transport)
|
||||
die("Unable to run helper: git %s", helper->argv[0]);
|
||||
data->helper = helper;
|
||||
|
||||
/*
|
||||
* Open the output as FILE* so strbuf_getline() can be used.
|
||||
* Do this with duped fd because fclose() will close the fd,
|
||||
* and stuff like taking over will require the fd to remain.
|
||||
*
|
||||
*/
|
||||
duped = dup(helper->out);
|
||||
if (duped < 0)
|
||||
die_errno("Can't dup helper output fd");
|
||||
data->out = xfdopen(duped, "r");
|
||||
|
||||
write_constant(helper->in, "capabilities\n");
|
||||
|
||||
data->out = xfdopen(helper->out, "r");
|
||||
while (1) {
|
||||
const char *capname;
|
||||
int mandatory = 0;
|
||||
@ -163,6 +178,7 @@ static int disconnect_helper(struct transport *transport)
|
||||
strbuf_addf(&buf, "\n");
|
||||
sendline(data, &buf);
|
||||
close(data->helper->in);
|
||||
close(data->helper->out);
|
||||
fclose(data->out);
|
||||
finish_command(data->helper);
|
||||
free((char *)data->helper->argv[0]);
|
||||
@ -583,5 +599,6 @@ int transport_helper_init(struct transport *transport, const char *name)
|
||||
transport->fetch = fetch;
|
||||
transport->push_refs = push_refs;
|
||||
transport->disconnect = release_helper;
|
||||
transport->smart_options = &(data->transport_options);
|
||||
return 0;
|
||||
}
|
||||
|
51
transport.c
51
transport.c
@ -398,6 +398,7 @@ struct git_transport_data {
|
||||
struct git_transport_options options;
|
||||
struct child_process *conn;
|
||||
int fd[2];
|
||||
unsigned got_remote_heads : 1;
|
||||
struct extra_have_objects extra_have;
|
||||
};
|
||||
|
||||
@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts,
|
||||
static int connect_setup(struct transport *transport, int for_push, int verbose)
|
||||
{
|
||||
struct git_transport_data *data = transport->data;
|
||||
|
||||
if (data->conn)
|
||||
return 0;
|
||||
|
||||
data->conn = git_connect(data->fd, transport->url,
|
||||
for_push ? data->options.receivepack :
|
||||
data->options.uploadpack,
|
||||
verbose ? CONNECT_VERBOSE : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
|
||||
connect_setup(transport, for_push, 0);
|
||||
get_remote_heads(data->fd[0], &refs, 0, NULL,
|
||||
for_push ? REF_NORMAL : 0, &data->extra_have);
|
||||
data->got_remote_heads = 1;
|
||||
|
||||
return refs;
|
||||
}
|
||||
@ -477,9 +484,10 @@ static int fetch_refs_via_pack(struct transport *transport,
|
||||
for (i = 0; i < nr_heads; i++)
|
||||
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
|
||||
|
||||
if (!data->conn) {
|
||||
if (!data->got_remote_heads) {
|
||||
connect_setup(transport, 0, 0);
|
||||
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
|
||||
data->got_remote_heads = 1;
|
||||
}
|
||||
|
||||
refs = fetch_pack(&args, data->fd, data->conn,
|
||||
@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport,
|
||||
if (finish_connect(data->conn))
|
||||
refs = NULL;
|
||||
data->conn = NULL;
|
||||
data->got_remote_heads = 0;
|
||||
|
||||
free_refs(refs_tmp);
|
||||
|
||||
@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
|
||||
struct send_pack_args args;
|
||||
int ret;
|
||||
|
||||
if (!data->conn) {
|
||||
if (!data->got_remote_heads) {
|
||||
struct ref *tmp_refs;
|
||||
connect_setup(transport, 1, 0);
|
||||
|
||||
get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
|
||||
NULL);
|
||||
data->got_remote_heads = 1;
|
||||
}
|
||||
|
||||
memset(&args, 0, sizeof(args));
|
||||
@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
|
||||
close(data->fd[0]);
|
||||
ret |= finish_connect(data->conn);
|
||||
data->conn = NULL;
|
||||
data->got_remote_heads = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport)
|
||||
{
|
||||
struct git_transport_data *data = transport->data;
|
||||
if (data->conn) {
|
||||
packet_flush(data->fd[1]);
|
||||
if (data->got_remote_heads)
|
||||
packet_flush(data->fd[1]);
|
||||
close(data->fd[0]);
|
||||
close(data->fd[1]);
|
||||
finish_connect(data->conn);
|
||||
@ -759,6 +771,32 @@ static int disconnect_git(struct transport *transport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void transport_take_over(struct transport *transport,
|
||||
struct child_process *child)
|
||||
{
|
||||
struct git_transport_data *data;
|
||||
|
||||
if (!transport->smart_options)
|
||||
die("Bug detected: Taking over transport requires non-NULL "
|
||||
"smart_options field.");
|
||||
|
||||
data = xcalloc(1, sizeof(*data));
|
||||
data->options = *transport->smart_options;
|
||||
data->conn = child;
|
||||
data->fd[0] = data->conn->out;
|
||||
data->fd[1] = data->conn->in;
|
||||
data->got_remote_heads = 0;
|
||||
transport->data = data;
|
||||
|
||||
transport->set_option = NULL;
|
||||
transport->get_refs_list = get_refs_via_connect;
|
||||
transport->fetch = fetch_refs_via_pack;
|
||||
transport->push = NULL;
|
||||
transport->push_refs = git_transport_push;
|
||||
transport->disconnect = disconnect_git;
|
||||
transport->smart_options = &(data->options);
|
||||
}
|
||||
|
||||
static int is_local(const char *url)
|
||||
{
|
||||
const char *colon = strchr(url, ':');
|
||||
@ -867,6 +905,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
|
||||
ret->smart_options = &(data->options);
|
||||
|
||||
data->conn = NULL;
|
||||
data->got_remote_heads = 0;
|
||||
} else if (!prefixcmp(url, "http://")
|
||||
|| !prefixcmp(url, "https://")
|
||||
|| !prefixcmp(url, "ftp://")) {
|
||||
@ -927,9 +966,9 @@ int transport_push(struct transport *transport,
|
||||
*nonfastforward = 0;
|
||||
verify_remote_names(refspec_nr, refspec);
|
||||
|
||||
if (transport->push)
|
||||
if (transport->push) {
|
||||
return transport->push(transport, refspec_nr, refspec, flags);
|
||||
if (transport->push_refs) {
|
||||
} else if (transport->push_refs) {
|
||||
struct ref *remote_refs =
|
||||
transport->get_refs_list(transport, 1);
|
||||
struct ref *local_refs = get_local_heads();
|
||||
@ -973,6 +1012,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
|
||||
{
|
||||
if (!transport->remote_refs)
|
||||
transport->remote_refs = transport->get_refs_list(transport, 0);
|
||||
|
||||
return transport->remote_refs;
|
||||
}
|
||||
|
||||
@ -1007,6 +1047,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
|
||||
}
|
||||
|
||||
rc = transport->fetch(transport, nr_heads, heads);
|
||||
|
||||
free(heads);
|
||||
return rc;
|
||||
}
|
||||
|
@ -130,6 +130,8 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs);
|
||||
void transport_unlock_pack(struct transport *transport);
|
||||
int transport_disconnect(struct transport *transport);
|
||||
char *transport_anonymize_url(const char *url);
|
||||
void transport_take_over(struct transport *transport,
|
||||
struct child_process *child);
|
||||
|
||||
/* Transport methods defined outside transport.c */
|
||||
int transport_helper_init(struct transport *transport, const char *name);
|
||||
|
Loading…
Reference in New Issue
Block a user