Skip to content

Commit ef08ef9

Browse files
spearcegitster
authored andcommitted
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 <[email protected]> CC: Daniel Barkalow <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 292ce46 commit ef08ef9

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed

Documentation/git-remote-helpers.txt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,16 @@ Commands are given by the caller on the helper's standard input, one per line.
3535
the name; unrecognized attributes are ignored. After the
3636
complete list, outputs a blank line.
3737

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+
3848
'fetch' <sha1> <name>::
3949
Fetches the given object, writing the necessary objects
4050
to the database. Fetch commands are sent in a batch, one
@@ -63,11 +73,39 @@ CAPABILITIES
6373
'fetch'::
6474
This helper supports the 'fetch' command.
6575

76+
'option'::
77+
This helper supports the option command.
78+
6679
REF LIST ATTRIBUTES
6780
-------------------
6881

6982
None are defined yet, but the caller must accept any which are supplied.
7083

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+
71109
Documentation
72110
-------------
73111
Documentation by Daniel Barkalow.

remote-curl.c

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,61 @@ static struct remote *remote;
99
static const char *url;
1010
static struct walker *walker;
1111

12+
struct options {
13+
int verbosity;
14+
unsigned long depth;
15+
unsigned progress : 1,
16+
followtags : 1;
17+
};
18+
static struct options options;
19+
1220
static void init_walker(void)
1321
{
1422
if (!walker)
1523
walker = get_http_walker(url, remote);
1624
}
1725

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+
1867
static struct ref *get_refs(void)
1968
{
2069
struct strbuf buffer = STRBUF_INIT;
@@ -99,7 +148,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
99148
walker->get_all = 1;
100149
walker->get_tree = 1;
101150
walker->get_history = 1;
102-
walker->get_verbosely = 0;
151+
walker->get_verbosely = options.verbosity >= 3;
103152
walker->get_recover = 0;
104153
ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
105154

@@ -173,6 +222,9 @@ int main(int argc, const char **argv)
173222
return 1;
174223
}
175224

225+
options.verbosity = 1;
226+
options.progress = !!isatty(2);
227+
176228
remote = remote_get(argv[1]);
177229

178230
if (argc > 2) {
@@ -198,8 +250,28 @@ int main(int argc, const char **argv)
198250
}
199251
printf("\n");
200252
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+
201272
} else if (!strcmp(buf.buf, "capabilities")) {
202273
printf("fetch\n");
274+
printf("option\n");
203275
printf("\n");
204276
fflush(stdout);
205277
} else {

transport-helper.c

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
#include "commit.h"
66
#include "diff.h"
77
#include "revision.h"
8+
#include "quote.h"
89

910
struct helper_data
1011
{
1112
const char *name;
1213
struct child_process *helper;
1314
FILE *out;
14-
unsigned fetch : 1;
15+
unsigned fetch : 1,
16+
option : 1;
1517
};
1618

1719
static struct child_process *get_helper(struct transport *transport)
@@ -48,6 +50,8 @@ static struct child_process *get_helper(struct transport *transport)
4850
break;
4951
if (!strcmp(buf.buf, "fetch"))
5052
data->fetch = 1;
53+
if (!strcmp(buf.buf, "option"))
54+
data->option = 1;
5155
}
5256
return data->helper;
5357
}
@@ -65,16 +69,97 @@ static int disconnect_helper(struct transport *transport)
6569
free(data->helper);
6670
data->helper = NULL;
6771
}
72+
free(data);
6873
return 0;
6974
}
7075

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+
71154
static int fetch_with_fetch(struct transport *transport,
72155
int nr_heads, const struct ref **to_fetch)
73156
{
74157
struct helper_data *data = transport->data;
75158
int i;
76159
struct strbuf buf = STRBUF_INIT;
77160

161+
standard_options(transport);
162+
78163
for (i = 0; i < nr_heads; i++) {
79164
const struct ref *posn = to_fetch[i];
80165
if (posn->status & REF_STATUS_UPTODATE)
@@ -178,6 +263,7 @@ int transport_helper_init(struct transport *transport, const char *name)
178263
data->name = name;
179264

180265
transport->data = data;
266+
transport->set_option = set_helper_option;
181267
transport->get_refs_list = get_refs_list;
182268
transport->fetch = fetch;
183269
transport->disconnect = disconnect_helper;

0 commit comments

Comments
 (0)