Skip to content

Commit 61b075b

Browse files
Ilari Liusvaaragitster
authored andcommitted
Support taking over transports
Add support for taking over transports that turn out to be smart. Signed-off-by: Ilari Liusvaara <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent aa5af97 commit 61b075b

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

transport-helper.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ struct helper_data
2222
/* These go from remote name (as in "list") to private name */
2323
struct refspec *refspecs;
2424
int refspec_nr;
25+
/* Transport options for fetch-pack/send-pack (should one of
26+
* those be invoked).
27+
*/
28+
struct git_transport_options transport_options;
2529
};
2630

2731
static void sendline(struct helper_data *helper, struct strbuf *buffer)
@@ -81,6 +85,7 @@ static struct child_process *get_helper(struct transport *transport)
8185
const char **refspecs = NULL;
8286
int refspec_nr = 0;
8387
int refspec_alloc = 0;
88+
int duped;
8489

8590
if (data->helper)
8691
return data->helper;
@@ -99,9 +104,19 @@ static struct child_process *get_helper(struct transport *transport)
99104
die("Unable to run helper: git %s", helper->argv[0]);
100105
data->helper = helper;
101106

107+
/*
108+
* Open the output as FILE* so strbuf_getline() can be used.
109+
* Do this with duped fd because fclose() will close the fd,
110+
* and stuff like taking over will require the fd to remain.
111+
*
112+
*/
113+
duped = dup(helper->out);
114+
if (duped < 0)
115+
die_errno("Can't dup helper output fd");
116+
data->out = xfdopen(duped, "r");
117+
102118
write_constant(helper->in, "capabilities\n");
103119

104-
data->out = xfdopen(helper->out, "r");
105120
while (1) {
106121
const char *capname;
107122
int mandatory = 0;
@@ -163,6 +178,7 @@ static int disconnect_helper(struct transport *transport)
163178
strbuf_addf(&buf, "\n");
164179
sendline(data, &buf);
165180
close(data->helper->in);
181+
close(data->helper->out);
166182
fclose(data->out);
167183
finish_command(data->helper);
168184
free((char *)data->helper->argv[0]);
@@ -583,5 +599,6 @@ int transport_helper_init(struct transport *transport, const char *name)
583599
transport->fetch = fetch;
584600
transport->push_refs = push_refs;
585601
transport->disconnect = release_helper;
602+
transport->smart_options = &(data->transport_options);
586603
return 0;
587604
}

transport.c

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ struct git_transport_data {
398398
struct git_transport_options options;
399399
struct child_process *conn;
400400
int fd[2];
401+
unsigned got_remote_heads : 1;
401402
struct extra_have_objects extra_have;
402403
};
403404

@@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts,
432433
static int connect_setup(struct transport *transport, int for_push, int verbose)
433434
{
434435
struct git_transport_data *data = transport->data;
436+
437+
if (data->conn)
438+
return 0;
439+
435440
data->conn = git_connect(data->fd, transport->url,
436441
for_push ? data->options.receivepack :
437442
data->options.uploadpack,
438443
verbose ? CONNECT_VERBOSE : 0);
444+
439445
return 0;
440446
}
441447

@@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
447453
connect_setup(transport, for_push, 0);
448454
get_remote_heads(data->fd[0], &refs, 0, NULL,
449455
for_push ? REF_NORMAL : 0, &data->extra_have);
456+
data->got_remote_heads = 1;
450457

451458
return refs;
452459
}
@@ -477,9 +484,10 @@ static int fetch_refs_via_pack(struct transport *transport,
477484
for (i = 0; i < nr_heads; i++)
478485
origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
479486

480-
if (!data->conn) {
487+
if (!data->got_remote_heads) {
481488
connect_setup(transport, 0, 0);
482489
get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
490+
data->got_remote_heads = 1;
483491
}
484492

485493
refs = fetch_pack(&args, data->fd, data->conn,
@@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport,
490498
if (finish_connect(data->conn))
491499
refs = NULL;
492500
data->conn = NULL;
501+
data->got_remote_heads = 0;
493502

494503
free_refs(refs_tmp);
495504

@@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
718727
struct send_pack_args args;
719728
int ret;
720729

721-
if (!data->conn) {
730+
if (!data->got_remote_heads) {
722731
struct ref *tmp_refs;
723732
connect_setup(transport, 1, 0);
724733

725734
get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
726735
NULL);
736+
data->got_remote_heads = 1;
727737
}
728738

729739
memset(&args, 0, sizeof(args));
@@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
741751
close(data->fd[0]);
742752
ret |= finish_connect(data->conn);
743753
data->conn = NULL;
754+
data->got_remote_heads = 0;
744755

745756
return ret;
746757
}
@@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport)
749760
{
750761
struct git_transport_data *data = transport->data;
751762
if (data->conn) {
752-
packet_flush(data->fd[1]);
763+
if (data->got_remote_heads)
764+
packet_flush(data->fd[1]);
753765
close(data->fd[0]);
754766
close(data->fd[1]);
755767
finish_connect(data->conn);
@@ -759,6 +771,32 @@ static int disconnect_git(struct transport *transport)
759771
return 0;
760772
}
761773

774+
void transport_take_over(struct transport *transport,
775+
struct child_process *child)
776+
{
777+
struct git_transport_data *data;
778+
779+
if (!transport->smart_options)
780+
die("Bug detected: Taking over transport requires non-NULL "
781+
"smart_options field.");
782+
783+
data = xcalloc(1, sizeof(*data));
784+
data->options = *transport->smart_options;
785+
data->conn = child;
786+
data->fd[0] = data->conn->out;
787+
data->fd[1] = data->conn->in;
788+
data->got_remote_heads = 0;
789+
transport->data = data;
790+
791+
transport->set_option = NULL;
792+
transport->get_refs_list = get_refs_via_connect;
793+
transport->fetch = fetch_refs_via_pack;
794+
transport->push = NULL;
795+
transport->push_refs = git_transport_push;
796+
transport->disconnect = disconnect_git;
797+
transport->smart_options = &(data->options);
798+
}
799+
762800
static int is_local(const char *url)
763801
{
764802
const char *colon = strchr(url, ':');
@@ -867,6 +905,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
867905
ret->smart_options = &(data->options);
868906

869907
data->conn = NULL;
908+
data->got_remote_heads = 0;
870909
} else if (!prefixcmp(url, "http://")
871910
|| !prefixcmp(url, "https://")
872911
|| !prefixcmp(url, "ftp://")) {
@@ -927,9 +966,9 @@ int transport_push(struct transport *transport,
927966
*nonfastforward = 0;
928967
verify_remote_names(refspec_nr, refspec);
929968

930-
if (transport->push)
969+
if (transport->push) {
931970
return transport->push(transport, refspec_nr, refspec, flags);
932-
if (transport->push_refs) {
971+
} else if (transport->push_refs) {
933972
struct ref *remote_refs =
934973
transport->get_refs_list(transport, 1);
935974
struct ref *local_refs = get_local_heads();
@@ -973,6 +1012,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
9731012
{
9741013
if (!transport->remote_refs)
9751014
transport->remote_refs = transport->get_refs_list(transport, 0);
1015+
9761016
return transport->remote_refs;
9771017
}
9781018

@@ -1007,6 +1047,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
10071047
}
10081048

10091049
rc = transport->fetch(transport, nr_heads, heads);
1050+
10101051
free(heads);
10111052
return rc;
10121053
}

transport.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs);
130130
void transport_unlock_pack(struct transport *transport);
131131
int transport_disconnect(struct transport *transport);
132132
char *transport_anonymize_url(const char *url);
133+
void transport_take_over(struct transport *transport,
134+
struct child_process *child);
133135

134136
/* Transport methods defined outside transport.c */
135137
int transport_helper_init(struct transport *transport, const char *name);

0 commit comments

Comments
 (0)