@matheusbsbs / matheus-bagliano / commits / 61b075bd3e
Fork 0

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>

Ilari Liusvaara committed Dec 9, 2009 at 17:26 UTC 61b075bd3e69cbdc9010a7f817b2017455dd36a7
3 files changed +66 -6
transport-helper.c
+18 -1
@@ -22,6 +22,10 @@ struct helper_data
22 /* These go from remote name (as in "list") to private name */
23 struct refspec *refspecs;
24 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;
29 };
30
31 static void sendline(struct helper_data *helper, struct strbuf *buffer)
@@ -81,6 +85,7 @@ static struct child_process *get_helper(struct transport *transport)
85 const char **refspecs = NULL;
86 int refspec_nr = 0;
87 int refspec_alloc = 0;
88 + int duped;
89
90 if (data->helper)
91 return data->helper;
@@ -99,9 +104,19 @@ static struct child_process *get_helper(struct transport *transport)
104 die("Unable to run helper: git %s", helper->argv[0]);
105 data->helper = helper;
106
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 +
118 write_constant(helper->in, "capabilities\n");
119
104 - data->out = xfdopen(helper->out, "r");
120 while (1) {
121 const char *capname;
122 int mandatory = 0;
@@ -163,6 +178,7 @@ static int disconnect_helper(struct transport *transport)
178 strbuf_addf(&buf, "\n");
179 sendline(data, &buf);
180 close(data->helper->in);
181 + close(data->helper->out);
182 fclose(data->out);
183 finish_command(data->helper);
184 free((char *)data->helper->argv[0]);
@@ -583,5 +599,6 @@ int transport_helper_init(struct transport *transport, const char *name)
599 transport->fetch = fetch;
600 transport->push_refs = push_refs;
601 transport->disconnect = release_helper;
602 + transport->smart_options = &(data->transport_options);
603 return 0;
604 }
transport.c
+46 -5
@@ -398,6 +398,7 @@ struct git_transport_data {
398 struct git_transport_options options;
399 struct child_process *conn;
400 int fd[2];
401 + unsigned got_remote_heads : 1;
402 struct extra_have_objects extra_have;
403 };
404
@@ -432,10 +433,15 @@ static int set_git_option(struct git_transport_options *opts,
433 static int connect_setup(struct transport *transport, int for_push, int verbose)
434 {
435 struct git_transport_data *data = transport->data;
436 +
437 + if (data->conn)
438 + return 0;
439 +
440 data->conn = git_connect(data->fd, transport->url,
441 for_push ? data->options.receivepack :
442 data->options.uploadpack,
443 verbose ? CONNECT_VERBOSE : 0);
444 +
445 return 0;
446 }
447
@@ -447,6 +453,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
453 connect_setup(transport, for_push, 0);
454 get_remote_heads(data->fd[0], &refs, 0, NULL,
455 for_push ? REF_NORMAL : 0, &data->extra_have);
456 + data->got_remote_heads = 1;
457
458 return refs;
459 }
@@ -477,9 +484,10 @@ static int fetch_refs_via_pack(struct transport *transport,
484 for (i = 0; i < nr_heads; i++)
485 origh[i] = heads[i] = xstrdup(to_fetch[i]->name);
486
480 - if (!data->conn) {
487 + if (!data->got_remote_heads) {
488 connect_setup(transport, 0, 0);
489 get_remote_heads(data->fd[0], &refs_tmp, 0, NULL, 0, NULL);
490 + data->got_remote_heads = 1;
491 }
492
493 refs = fetch_pack(&args, data->fd, data->conn,
@@ -490,6 +498,7 @@ static int fetch_refs_via_pack(struct transport *transport,
498 if (finish_connect(data->conn))
499 refs = NULL;
500 data->conn = NULL;
501 + data->got_remote_heads = 0;
502
503 free_refs(refs_tmp);
504
@@ -718,12 +727,13 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
727 struct send_pack_args args;
728 int ret;
729
721 - if (!data->conn) {
730 + if (!data->got_remote_heads) {
731 struct ref *tmp_refs;
732 connect_setup(transport, 1, 0);
733
734 get_remote_heads(data->fd[0], &tmp_refs, 0, NULL, REF_NORMAL,
735 NULL);
736 + data->got_remote_heads = 1;
737 }
738
739 memset(&args, 0, sizeof(args));
@@ -741,6 +751,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
751 close(data->fd[0]);
752 ret |= finish_connect(data->conn);
753 data->conn = NULL;
754 + data->got_remote_heads = 0;
755
756 return ret;
757 }
@@ -749,7 +760,8 @@ static int disconnect_git(struct transport *transport)
760 {
761 struct git_transport_data *data = transport->data;
762 if (data->conn) {
752 - packet_flush(data->fd[1]);
763 + if (data->got_remote_heads)
764 + packet_flush(data->fd[1]);
765 close(data->fd[0]);
766 close(data->fd[1]);
767 finish_connect(data->conn);
@@ -759,6 +771,32 @@ static int disconnect_git(struct transport *transport)
771 return 0;
772 }
773
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 +
800 static int is_local(const char *url)
801 {
802 const char *colon = strchr(url, ':');
@@ -867,6 +905,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
905 ret->smart_options = &(data->options);
906
907 data->conn = NULL;
908 + data->got_remote_heads = 0;
909 } else if (!prefixcmp(url, "http://")
910 || !prefixcmp(url, "https://")
911 || !prefixcmp(url, "ftp://")) {
@@ -927,9 +966,9 @@ int transport_push(struct transport *transport,
966 *nonfastforward = 0;
967 verify_remote_names(refspec_nr, refspec);
968
930 - if (transport->push)
969 + if (transport->push) {
970 return transport->push(transport, refspec_nr, refspec, flags);
932 - if (transport->push_refs) {
971 + } else if (transport->push_refs) {
972 struct ref *remote_refs =
973 transport->get_refs_list(transport, 1);
974 struct ref *local_refs = get_local_heads();
@@ -973,6 +1012,7 @@ const struct ref *transport_get_remote_refs(struct transport *transport)
1012 {
1013 if (!transport->remote_refs)
1014 transport->remote_refs = transport->get_refs_list(transport, 0);
1015 +
1016 return transport->remote_refs;
1017 }
1018
@@ -1007,6 +1047,7 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
1047 }
1048
1049 rc = transport->fetch(transport, nr_heads, heads);
1050 +
1051 free(heads);
1052 return rc;
1053 }
transport.h
+2
@@ -130,6 +130,8 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs);
130 void transport_unlock_pack(struct transport *transport);
131 int transport_disconnect(struct transport *transport);
132 char *transport_anonymize_url(const char *url);
133 +void transport_take_over(struct transport *transport,
134 + struct child_process *child);
135
136 /* Transport methods defined outside transport.c */
137 int transport_helper_init(struct transport *transport, const char *name);