1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-10-28 12:59:41 +01:00

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>
This commit is contained in:
Shawn O. Pearce 2009-10-30 17:47:29 -07:00 committed by Junio C Hamano
parent 292ce46b60
commit ef08ef9ea0
3 changed files with 198 additions and 2 deletions

View file

@ -35,6 +35,16 @@ Commands are given by the caller on the helper's standard input, one per line.
the name; unrecognized attributes are ignored. After the
complete list, outputs a blank line.
'option' <name> <value>::
Set the transport helper option <name> to <value>. Outputs a
single line containing one of 'ok' (option successfully set),
'unsupported' (option not recognized) or 'error <msg>'
(option <name> is supported but <value> is not correct
for it). Options should be set before other commands,
and may how those commands behave.
+
Supported if the helper has the "option" capability.
'fetch' <sha1> <name>::
Fetches the given object, writing the necessary objects
to the database. Fetch commands are sent in a batch, one
@ -63,11 +73,39 @@ CAPABILITIES
'fetch'::
This helper supports the 'fetch' command.
'option'::
This helper supports the option command.
REF LIST ATTRIBUTES
-------------------
None are defined yet, but the caller must accept any which are supplied.
OPTIONS
-------
'option verbosity' <N>::
Change the level of messages displayed by the helper.
When N is 0 the end-user has asked the process to be
quiet, and the helper should produce only error output.
N of 1 is the default level of verbosity, higher values
of N correspond to the number of -v flags passed on the
command line.
'option progress' \{'true'|'false'\}::
Enable (or disable) progress messages displayed by the
transport helper during a command.
'option depth' <depth>::
Deepen the history of a shallow repository.
'option followtags' \{'true'|'false'\}::
If enabled the helper should automatically fetch annotated
tag objects if the object the tag points at was transferred
during the fetch command. If the tag is not fetched by
the helper a second fetch command will usually be sent to
ask for the tag specifically. Some helpers may be able to
use this option to avoid a second network connection.
Documentation
-------------
Documentation by Daniel Barkalow.

View file

@ -9,12 +9,61 @@ static struct remote *remote;
static const char *url;
static struct walker *walker;
struct options {
int verbosity;
unsigned long depth;
unsigned progress : 1,
followtags : 1;
};
static struct options options;
static void init_walker(void)
{
if (!walker)
walker = get_http_walker(url, remote);
}
static int set_option(const char *name, const char *value)
{
if (!strcmp(name, "verbosity")) {
char *end;
int v = strtol(value, &end, 10);
if (value == end || *end)
return -1;
options.verbosity = v;
return 0;
}
else if (!strcmp(name, "progress")) {
if (!strcmp(value, "true"))
options.progress = 1;
else if (!strcmp(value, "false"))
options.progress = 0;
else
return -1;
return 1 /* TODO implement later */;
}
else if (!strcmp(name, "depth")) {
char *end;
unsigned long v = strtoul(value, &end, 10);
if (value == end || *end)
return -1;
options.depth = v;
return 1 /* TODO implement later */;
}
else if (!strcmp(name, "followtags")) {
if (!strcmp(value, "true"))
options.followtags = 1;
else if (!strcmp(value, "false"))
options.followtags = 0;
else
return -1;
return 1 /* TODO implement later */;
}
else {
return 1 /* unsupported */;
}
}
static struct ref *get_refs(void)
{
struct strbuf buffer = STRBUF_INIT;
@ -99,7 +148,7 @@ static int fetch_dumb(int nr_heads, struct ref **to_fetch)
walker->get_all = 1;
walker->get_tree = 1;
walker->get_history = 1;
walker->get_verbosely = 0;
walker->get_verbosely = options.verbosity >= 3;
walker->get_recover = 0;
ret = walker_fetch(walker, nr_heads, targets, NULL, NULL);
@ -173,6 +222,9 @@ int main(int argc, const char **argv)
return 1;
}
options.verbosity = 1;
options.progress = !!isatty(2);
remote = remote_get(argv[1]);
if (argc > 2) {
@ -198,8 +250,28 @@ int main(int argc, const char **argv)
}
printf("\n");
fflush(stdout);
} else if (!prefixcmp(buf.buf, "option ")) {
char *name = buf.buf + strlen("option ");
char *value = strchr(name, ' ');
int result;
if (value)
*value++ = '\0';
else
value = "true";
result = set_option(name, value);
if (!result)
printf("ok\n");
else if (result < 0)
printf("error invalid value\n");
else
printf("unsupported\n");
fflush(stdout);
} else if (!strcmp(buf.buf, "capabilities")) {
printf("fetch\n");
printf("option\n");
printf("\n");
fflush(stdout);
} else {

View file

@ -5,13 +5,15 @@
#include "commit.h"
#include "diff.h"
#include "revision.h"
#include "quote.h"
struct helper_data
{
const char *name;
struct child_process *helper;
FILE *out;
unsigned fetch : 1;
unsigned fetch : 1,
option : 1;
};
static struct child_process *get_helper(struct transport *transport)
@ -48,6 +50,8 @@ static struct child_process *get_helper(struct transport *transport)
break;
if (!strcmp(buf.buf, "fetch"))
data->fetch = 1;
if (!strcmp(buf.buf, "option"))
data->option = 1;
}
return data->helper;
}
@ -65,9 +69,88 @@ static int disconnect_helper(struct transport *transport)
free(data->helper);
data->helper = NULL;
}
free(data);
return 0;
}
static const char *unsupported_options[] = {
TRANS_OPT_UPLOADPACK,
TRANS_OPT_RECEIVEPACK,
TRANS_OPT_THIN,
TRANS_OPT_KEEP
};
static const char *boolean_options[] = {
TRANS_OPT_THIN,
TRANS_OPT_KEEP,
TRANS_OPT_FOLLOWTAGS
};
static int set_helper_option(struct transport *transport,
const char *name, const char *value)
{
struct helper_data *data = transport->data;
struct child_process *helper = get_helper(transport);
struct strbuf buf = STRBUF_INIT;
int i, ret, is_bool = 0;
if (!data->option)
return 1;
for (i = 0; i < ARRAY_SIZE(unsupported_options); i++) {
if (!strcmp(name, unsupported_options[i]))
return 1;
}
for (i = 0; i < ARRAY_SIZE(boolean_options); i++) {
if (!strcmp(name, boolean_options[i])) {
is_bool = 1;
break;
}
}
strbuf_addf(&buf, "option %s ", name);
if (is_bool)
strbuf_addstr(&buf, value ? "true" : "false");
else
quote_c_style(value, &buf, NULL, 0);
strbuf_addch(&buf, '\n');
if (write_in_full(helper->in, buf.buf, buf.len) != buf.len)
die_errno("cannot send option to %s", data->name);
strbuf_reset(&buf);
if (strbuf_getline(&buf, data->out, '\n') == EOF)
exit(128); /* child died, message supplied already */
if (!strcmp(buf.buf, "ok"))
ret = 0;
else if (!prefixcmp(buf.buf, "error")) {
ret = -1;
} else if (!strcmp(buf.buf, "unsupported"))
ret = 1;
else {
warning("%s unexpectedly said: '%s'", data->name, buf.buf);
ret = 1;
}
strbuf_release(&buf);
return ret;
}
static void standard_options(struct transport *t)
{
char buf[16];
int n;
int v = t->verbose;
int no_progress = v < 0 || (!t->progress && !isatty(1));
set_helper_option(t, "progress", !no_progress ? "true" : "false");
n = snprintf(buf, sizeof(buf), "%d", v + 1);
if (n >= sizeof(buf))
die("impossibly large verbosity value");
set_helper_option(t, "verbosity", buf);
}
static int fetch_with_fetch(struct transport *transport,
int nr_heads, const struct ref **to_fetch)
{
@ -75,6 +158,8 @@ static int fetch_with_fetch(struct transport *transport,
int i;
struct strbuf buf = STRBUF_INIT;
standard_options(transport);
for (i = 0; i < nr_heads; i++) {
const struct ref *posn = to_fetch[i];
if (posn->status & REF_STATUS_UPTODATE)
@ -178,6 +263,7 @@ int transport_helper_init(struct transport *transport, const char *name)
data->name = name;
transport->data = data;
transport->set_option = set_helper_option;
transport->get_refs_list = get_refs_list;
transport->fetch = fetch;
transport->disconnect = disconnect_helper;