@matheusbsbs / matheus-bagliano / commits / ef08ef9ea0
Fork 0

remote-helpers: Support custom transport options

Some transports, like the native pack transport implemented by fetch-pack, support useful features like depth or include tags. These should be exposed if the underlying helper knows how to use them. Signed-off-by: Shawn O. Pearce <spearce@spearce.org> CC: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Shawn O. Pearce committed Oct 30, 2009 at 17:47 UTC ef08ef9ea0a271e5be5844408d2496a946d6e8d9
3 files changed +198 -2
Documentation/git-remote-helpers.txt
+38
@@ -35,6 +35,16 @@ Commands are given by the caller on the helper's standard input, one per line.
35 the name; unrecognized attributes are ignored. After the
36 complete list, outputs a blank line.
37
38 +'option' <name> <value>::
39 + Set the transport helper option <name> to <value>. Outputs a
40 + single line containing one of 'ok' (option successfully set),
41 + 'unsupported' (option not recognized) or 'error <msg>'
42 + (option <name> is supported but <value> is not correct
43 + for it). Options should be set before other commands,
44 + and may how those commands behave.
45 ++
46 +Supported if the helper has the "option" capability.
47 +
48 'fetch' <sha1> <name>::
49 Fetches the given object, writing the necessary objects
50 to the database. Fetch commands are sent in a batch, one
@@ -63,11 +73,39 @@ CAPABILITIES
73 'fetch'::
74 This helper supports the 'fetch' command.
75
76 +'option'::
77 + This helper supports the option command.
78 +
79 REF LIST ATTRIBUTES
80 -------------------
81
82 None are defined yet, but the caller must accept any which are supplied.
83
84 +OPTIONS
85 +-------
86 +'option verbosity' <N>::
87 + Change the level of messages displayed by the helper.
88 + When N is 0 the end-user has asked the process to be
89 + quiet, and the helper should produce only error output.
90 + N of 1 is the default level of verbosity, higher values
91 + of N correspond to the number of -v flags passed on the
92 + command line.
93 +
94 +'option progress' \{'true'|'false'\}::
95 + Enable (or disable) progress messages displayed by the
96 + transport helper during a command.
97 +
98 +'option depth' <depth>::
99 + Deepen the history of a shallow repository.
100 +
101 +'option followtags' \{'true'|'false'\}::
102 + If enabled the helper should automatically fetch annotated
103 + tag objects if the object the tag points at was transferred
104 + during the fetch command. If the tag is not fetched by
105 + the helper a second fetch command will usually be sent to
106 + ask for the tag specifically. Some helpers may be able to
107 + use this option to avoid a second network connection.
108 +
109 Documentation
110 -------------
111 Documentation by Daniel Barkalow.
remote-curl.c
+73 -1
@@ -9,12 +9,61 @@ static struct remote *remote;
9 static const char *url;
10 static struct walker *walker;
11
12 +struct options {
13 + int verbosity;
14 + unsigned long depth;
15 + unsigned progress : 1,
16 + followtags : 1;
17 +};
18 +static struct options options;
19 +
20 static void init_walker(void)
21 {
22 if (!walker)
23 walker = get_http_walker(url, remote);
24 }
25
26 +static int set_option(const char *name, const char *value)
27 +{
28 + if (!strcmp(name, "verbosity")) {
29 + char *end;
30 + int v = strtol(value, &end, 10);
31 + if (value == end || *end)
32 + return -1;
33 + options.verbosity = v;
34 + return 0;
35 + }
36 + else if (!strcmp(name, "progress")) {
37 + if (!strcmp(value, "true"))
38 + options.progress = 1;
39 + else if (!strcmp(value, "false"))
40 + options.progress = 0;
41 + else
42 + return -1;
43 + return 1 /* TODO implement later */;
44 + }
45 + else if (!strcmp(name, "depth")) {
46 + char *end;
47 + unsigned long v = strtoul(value, &end, 10);
48 + if (value == end || *end)
49 + return -1;
50 + options.depth = v;
51 + return 1 /* TODO implement later */;
52 + }
53 + else if (!strcmp(name, "followtags")) {
54 + if (!strcmp(value, "true"))
55 + options.followtags = 1;
56 + else if (!strcmp(value, "false"))
57 + options.followtags = 0;
58 + else
59 + return -1;
60 + return 1 /* TODO implement later */;
61 + }
62 + else {
63 + return 1 /* unsupported */;
64 + }
65 +}
66 +
67 static struct ref *get_refs(void)
68 {
69 struct strbuf buffer = STRBUF_INIT;
@@ -99,7 +148,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
148 walker->get_all = 1;
149 walker->get_tree = 1;
150 walker->get_history = 1;
102 - walker->get_verbosely = 0;
151 + walker->get_verbosely = options.verbosity >= 3;
152 walker->get_recover = 0;
153 ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
154
@@ -173,6 +222,9 @@ int main(int argc, const char **argv)
222 return 1;
223 }
224
225 + options.verbosity = 1;
226 + options.progress = !!isatty(2);
227 +
228 remote = remote_get(argv[1]);
229
230 if (argc > 2) {
@@ -198,8 +250,28 @@ int main(int argc, const char **argv)
250 }
251 printf("\n");
252 fflush(stdout);
253 + } else if (!prefixcmp(buf.buf, "option ")) {
254 + char *name = buf.buf + strlen("option ");
255 + char *value = strchr(name, ' ');
256 + int result;
257 +
258 + if (value)
259 + *value++ = '\0';
260 + else
261 + value = "true";
262 +
263 + result = set_option(name, value);
264 + if (!result)
265 + printf("ok\n");
266 + else if (result < 0)
267 + printf("error invalid value\n");
268 + else
269 + printf("unsupported\n");
270 + fflush(stdout);
271 +
272 } else if (!strcmp(buf.buf, "capabilities")) {
273 printf("fetch\n");
274 + printf("option\n");
275 printf("\n");
276 fflush(stdout);
277 } else {
transport-helper.c
+87 -1
@@ -5,13 +5,15 @@
5 #include "commit.h"
6 #include "diff.h"
7 #include "revision.h"
8 +#include "quote.h"
9
10 struct helper_data
11 {
12 const char *name;
13 struct child_process *helper;
14 FILE *out;
14 - unsigned fetch : 1;
15 + unsigned fetch : 1,
16 + option : 1;
17 };
18
19 static struct child_process *get_helper(struct transport *transport)
@@ -48,6 +50,8 @@ static struct child_process *get_helper(struct transport *transport)
50 break;
51 if (!strcmp(buf.buf, "fetch"))
52 data->fetch = 1;
53 + if (!strcmp(buf.buf, "option"))
54 + data->option = 1;
55 }
56 return data->helper;
57 }
@@ -65,9 +69,88 @@ static int disconnect_helper(struct transport *transport)
69 free(data->helper);
70 data->helper = NULL;
71 }
72 + free(data);
73 return 0;
74 }
75
76 +static const char *unsupported_options[] = {
77 + TRANS_OPT_UPLOADPACK,
78 + TRANS_OPT_RECEIVEPACK,
79 + TRANS_OPT_THIN,
80 + TRANS_OPT_KEEP
81 + };
82 +static const char *boolean_options[] = {
83 + TRANS_OPT_THIN,
84 + TRANS_OPT_KEEP,
85 + TRANS_OPT_FOLLOWTAGS
86 + };
87 +
88 +static int set_helper_option(struct transport *transport,
89 + const char *name, const char *value)
90 +{
91 + struct helper_data *data = transport->data;
92 + struct child_process *helper = get_helper(transport);
93 + struct strbuf buf = STRBUF_INIT;
94 + int i, ret, is_bool = 0;
95 +
96 + if (!data->option)
97 + return 1;
98 +
99 + for (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {
100 + if (!strcmp(name, unsupported_options[i]))
101 + return 1;
102 + }
103 +
104 + for (i = 0; i < ARRAY_SIZE(boolean_options); i++) {
105 + if (!strcmp(name, boolean_options[i])) {
106 + is_bool = 1;
107 + break;
108 + }
109 + }
110 +
111 + strbuf_addf(&buf, "option %s ", name);
112 + if (is_bool)
113 + strbuf_addstr(&buf, value ? "true" : "false");
114 + else
115 + quote_c_style(value, &buf, NULL, 0);
116 + strbuf_addch(&buf, '\n');
117 +
118 + if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
119 + die_errno("cannot send option to %s", data->name);
120 +
121 + strbuf_reset(&buf);
122 + if (strbuf_getline(&buf, data->out, '\n') == EOF)
123 + exit(128); /* child died, message supplied already */
124 +
125 + if (!strcmp(buf.buf, "ok"))
126 + ret = 0;
127 + else if (!prefixcmp(buf.buf, "error")) {
128 + ret = -1;
129 + } else if (!strcmp(buf.buf, "unsupported"))
130 + ret = 1;
131 + else {
132 + warning("%s unexpectedly said: '%s'", data->name, buf.buf);
133 + ret = 1;
134 + }
135 + strbuf_release(&buf);
136 + return ret;
137 +}
138 +
139 +static void standard_options(struct transport *t)
140 +{
141 + char buf[16];
142 + int n;
143 + int v = t->verbose;
144 + int no_progress = v < 0 || (!t->progress && !isatty(1));
145 +
146 + set_helper_option(t, "progress", !no_progress ? "true" : "false");
147 +
148 + n = snprintf(buf, sizeof(buf), "%d", v + 1);
149 + if (n >= sizeof(buf))
150 + die("impossibly large verbosity value");
151 + set_helper_option(t, "verbosity", buf);
152 +}
153 +
154 static int fetch_with_fetch(struct transport *transport,
155 int nr_heads, const struct ref **to_fetch)
156 {
@@ -75,6 +158,8 @@ static int fetch_with_fetch(struct transport *transport,
158 int i;
159 struct strbuf buf = STRBUF_INIT;
160
161 + standard_options(transport);
162 +
163 for (i = 0; i < nr_heads; i++) {
164 const struct ref *posn = to_fetch[i];
165 if (posn->status & REF_STATUS_UPTODATE)
@@ -178,6 +263,7 @@ int transport_helper_init(struct transport *transport, const char *name)
263 data->name = name;
264
265 transport->data = data;
266 + transport->set_option = set_helper_option;
267 transport->get_refs_list = get_refs_list;
268 transport->fetch = fetch;
269 transport->disconnect = disconnect_helper;