Merge branch 'bw/server-options'

The transport protocol v2 is getting updated further.

* bw/server-options:
  fetch: send server options when using protocol v2
  ls-remote: send server options when using protocol v2
  serve: introduce the server-option capability
This commit is contained in:
Junio C Hamano 2018-05-23 14:38:15 +09:00
commit 41267e9697
14 changed files with 116 additions and 3 deletions

View File

@ -188,6 +188,14 @@ endif::git-pull[]
is specified. This flag forces progress status even if the is specified. This flag forces progress status even if the
standard error stream is not directed to a terminal. standard error stream is not directed to a terminal.
-o <option>::
--server-option=<option>::
Transmit the given string to the server when communicating using
protocol version 2. The given string must not contain a NUL or LF
character.
When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line.
-4:: -4::
--ipv4:: --ipv4::
Use IPv4 addresses only, ignoring IPv6 addresses. Use IPv4 addresses only, ignoring IPv6 addresses.

View File

@ -70,6 +70,14 @@ OPTIONS
themselves will not work for refs whose objects have not yet been themselves will not work for refs whose objects have not yet been
fetched from the remote, and will give a `missing object` error. fetched from the remote, and will give a `missing object` error.
-o <option>::
--server-option=<option>::
Transmit the given string to the server when communicating using
protocol version 2. The given string must not contain a NUL or LF
character.
When multiple `--server-option=<option>` are given, they are all
sent to the other side in the order listed on the command line.
<repository>:: <repository>::
The "remote" repository to query. This parameter can be The "remote" repository to query. This parameter can be
either a URL or the name of a remote (see the GIT URLS and either a URL or the name of a remote (see the GIT URLS and

View File

@ -393,3 +393,13 @@ header.
1 - pack data 1 - pack data
2 - progress messages 2 - progress messages
3 - fatal error message just before stream aborts 3 - fatal error message just before stream aborts
server-option
~~~~~~~~~~~~~~~
If advertised, indicates that any number of server specific options can be
included in a request. This is done by sending each option as a
"server-option=<option>" capability line in the capability-list section of
a request.
The provided options must not contain a NUL or LF character.

View File

@ -62,6 +62,7 @@ static int shown_url = 0;
static int refmap_alloc, refmap_nr; static int refmap_alloc, refmap_nr;
static const char **refmap_array; static const char **refmap_array;
static struct list_objects_filter_options filter_options; static struct list_objects_filter_options filter_options;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static int git_fetch_config(const char *k, const char *v, void *cb) static int git_fetch_config(const char *k, const char *v, void *cb)
{ {
@ -170,6 +171,7 @@ static struct option builtin_fetch_options[] = {
N_("accept refs that update .git/shallow")), N_("accept refs that update .git/shallow")),
{ OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"), { OPTION_CALLBACK, 0, "refmap", NULL, N_("refmap"),
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg }, N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg },
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"), OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4), TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"), OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
@ -1417,6 +1419,9 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
} }
} }
if (server_options.nr)
gtransport->server_options = &server_options;
sigchain_push_common(unlock_pack_on_signal); sigchain_push_common(unlock_pack_on_signal);
atexit(unlock_pack); atexit(unlock_pack);
refspec = parse_fetch_refspec(ref_nr, refs); refspec = parse_fetch_refspec(ref_nr, refs);

View File

@ -47,6 +47,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
const char **pattern = NULL; const char **pattern = NULL;
struct argv_array ref_prefixes = ARGV_ARRAY_INIT; struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
int i; int i;
struct string_list server_options = STRING_LIST_INIT_DUP;
struct remote *remote; struct remote *remote;
struct transport *transport; struct transport *transport;
@ -73,6 +74,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
2, PARSE_OPT_NOCOMPLETE), 2, PARSE_OPT_NOCOMPLETE),
OPT_BOOL(0, "symref", &show_symref_target, OPT_BOOL(0, "symref", &show_symref_target,
N_("show underlying ref in addition to the object pointed by it")), N_("show underlying ref in addition to the object pointed by it")),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_END() OPT_END()
}; };
@ -116,6 +118,8 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
transport = transport_get(remote, NULL); transport = transport_get(remote, NULL);
if (uploadpack != NULL) if (uploadpack != NULL)
transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack); transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
if (server_options.nr)
transport->server_options = &server_options;
ref = transport_get_remote_refs(transport, &ref_prefixes); ref = transport_get_remote_refs(transport, &ref_prefixes);
if (transport_disconnect(transport)) { if (transport_disconnect(transport)) {

View File

@ -408,7 +408,8 @@ out:
struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
struct ref **list, int for_push, struct ref **list, int for_push,
const struct argv_array *ref_prefixes) const struct argv_array *ref_prefixes,
const struct string_list *server_options)
{ {
int i; int i;
*list = NULL; *list = NULL;
@ -419,6 +420,12 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
if (server_supports_v2("agent", 0)) if (server_supports_v2("agent", 0))
packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized()); packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
if (server_options && server_options->nr &&
server_supports_v2("server-option", 1))
for (i = 0; i < server_options->nr; i++)
packet_write_fmt(fd_out, "server-option=%s",
server_options->items[i].string);
packet_delim(fd_out); packet_delim(fd_out);
/* When pushing we don't want to request the peeled tags */ /* When pushing we don't want to request the peeled tags */
if (!for_push) if (!for_push)

View File

@ -1174,6 +1174,13 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
packet_buf_write(&req_buf, "command=fetch"); packet_buf_write(&req_buf, "command=fetch");
if (server_supports_v2("agent", 0)) if (server_supports_v2("agent", 0))
packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized()); packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized());
if (args->server_options && args->server_options->nr &&
server_supports_v2("server-option", 1)) {
int i;
for (i = 0; i < args->server_options->nr; i++)
packet_write_fmt(fd_out, "server-option=%s",
args->server_options->items[i].string);
}
packet_buf_delim(&req_buf); packet_buf_delim(&req_buf);
if (args->use_thin_pack) if (args->use_thin_pack)

View File

@ -15,6 +15,7 @@ struct fetch_pack_args {
const char *deepen_since; const char *deepen_since;
const struct string_list *deepen_not; const struct string_list *deepen_not;
struct list_objects_filter_options filter_options; struct list_objects_filter_options filter_options;
const struct string_list *server_options;
unsigned deepen_relative:1; unsigned deepen_relative:1;
unsigned quiet:1; unsigned quiet:1;
unsigned keep_pack:1; unsigned keep_pack:1;

View File

@ -153,6 +153,7 @@ void free_refs(struct ref *ref);
struct oid_array; struct oid_array;
struct packet_reader; struct packet_reader;
struct argv_array; struct argv_array;
struct string_list;
extern struct ref **get_remote_heads(struct packet_reader *reader, extern struct ref **get_remote_heads(struct packet_reader *reader,
struct ref **list, unsigned int flags, struct ref **list, unsigned int flags,
struct oid_array *extra_have, struct oid_array *extra_have,
@ -161,7 +162,8 @@ extern struct ref **get_remote_heads(struct packet_reader *reader,
/* Used for protocol v2 in order to retrieve refs from a remote */ /* Used for protocol v2 in order to retrieve refs from a remote */
extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader, extern struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
struct ref **list, int for_push, struct ref **list, int for_push,
const struct argv_array *ref_prefixes); const struct argv_array *ref_prefixes,
const struct string_list *server_options);
int resolve_remote_symref(struct ref *ref, struct ref *list); int resolve_remote_symref(struct ref *ref, struct ref *list);
int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);

View File

@ -56,6 +56,7 @@ static struct protocol_capability capabilities[] = {
{ "agent", agent_advertise, NULL }, { "agent", agent_advertise, NULL },
{ "ls-refs", always_advertise, ls_refs }, { "ls-refs", always_advertise, ls_refs },
{ "fetch", upload_pack_advertise, upload_pack_v2 }, { "fetch", upload_pack_advertise, upload_pack_v2 },
{ "server-option", always_advertise, NULL },
}; };
static void advertise_capabilities(void) static void advertise_capabilities(void)

View File

@ -10,6 +10,7 @@ test_expect_success 'test capability advertisement' '
agent=git/$(git version | cut -d" " -f3) agent=git/$(git version | cut -d" " -f3)
ls-refs ls-refs
fetch=shallow fetch=shallow
server-option
0000 0000
EOF EOF
@ -173,4 +174,24 @@ test_expect_success 'symrefs parameter' '
test_cmp actual expect test_cmp actual expect
' '
test_expect_success 'sending server-options' '
test-pkt-line pack >in <<-EOF &&
command=ls-refs
server-option=hello
server-option=world
0001
ref-prefix HEAD
0000
EOF
cat >expect <<-EOF &&
$(git rev-parse HEAD) HEAD
0000
EOF
git serve --stateless-rpc <in >out &&
test-pkt-line unpack <out >actual &&
test_cmp actual expect
'
test_done test_done

View File

@ -154,6 +154,22 @@ test_expect_success 'ref advertisment is filtered with ls-remote using protocol
test_cmp actual expect test_cmp actual expect
' '
test_expect_success 'server-options are sent when using ls-remote' '
test_when_finished "rm -f log" &&
GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
ls-remote -o hello -o world "file://$(pwd)/file_parent" master >actual &&
cat >expect <<-EOF &&
$(git -C file_parent rev-parse refs/heads/master)$(printf "\t")refs/heads/master
EOF
test_cmp actual expect &&
grep "server-option=hello" log &&
grep "server-option=world" log
'
test_expect_success 'clone with file:// using protocol v2' ' test_expect_success 'clone with file:// using protocol v2' '
test_when_finished "rm -f log" && test_when_finished "rm -f log" &&
@ -201,6 +217,22 @@ test_expect_success 'ref advertisment is filtered during fetch using protocol v2
! grep "refs/tags/three" log ! grep "refs/tags/three" log
' '
test_expect_success 'server-options are sent when fetching' '
test_when_finished "rm -f log" &&
test_commit -C file_parent four &&
GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \
fetch -o hello -o world origin master &&
git -C file_child log -1 --format=%s origin/master >actual &&
git -C file_parent log -1 --format=%s >expect &&
test_cmp expect actual &&
grep "server-option=hello" log &&
grep "server-option=world" log
'
# Test protocol v2 with 'http://' transport # Test protocol v2 with 'http://' transport
# #
. "$TEST_DIRECTORY"/lib-httpd.sh . "$TEST_DIRECTORY"/lib-httpd.sh

View File

@ -268,7 +268,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
switch (data->version) { switch (data->version) {
case protocol_v2: case protocol_v2:
get_remote_refs(data->fd[1], &reader, &refs, for_push, get_remote_refs(data->fd[1], &reader, &refs, for_push,
ref_prefixes); ref_prefixes, transport->server_options);
break; break;
case protocol_v1: case protocol_v1:
case protocol_v0: case protocol_v0:
@ -316,6 +316,7 @@ static int fetch_refs_via_pack(struct transport *transport,
args.no_dependents = data->options.no_dependents; args.no_dependents = data->options.no_dependents;
args.filter_options = data->options.filter_options; args.filter_options = data->options.filter_options;
args.stateless_rpc = transport->stateless_rpc; args.stateless_rpc = transport->stateless_rpc;
args.server_options = transport->server_options;
if (!data->got_remote_heads) if (!data->got_remote_heads)
refs_tmp = get_refs_via_connect(transport, 0, NULL); refs_tmp = get_refs_via_connect(transport, 0, NULL);

View File

@ -71,6 +71,12 @@ struct transport {
*/ */
const struct string_list *push_options; const struct string_list *push_options;
/*
* These strings will be passed to the remote side on each command
* request, if both sides support the server-option capability.
*/
const struct string_list *server_options;
char *pack_lockfile; char *pack_lockfile;
signed verbose : 3; signed verbose : 3;
/** /**