ls-remote: pass ref prefixes when requesting a remote's refs

Construct an argv_array of ref prefixes based on the patterns supplied via the command line and pass them to 'transport_get_remote_refs()' to be used when communicating protocol v2 so that the server can limit the ref advertisement based on those prefixes. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Mar 15, 2018 at 10:31 UTC b4be74105febef5c6235e1e2f1e468e76166cad8
4 files changed +60 -2
builtin/ls-remote.c
+13 -2
@@ -2,6 +2,7 @@
2 #include "cache.h"
3 #include "transport.h"
4 #include "remote.h"
5 +#include "refs.h"
6
7 static const char * const ls_remote_usage[] = {
8 N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
@@ -43,6 +44,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
44 int show_symref_target = 0;
45 const char *uploadpack = NULL;
46 const char **pattern = NULL;
47 + struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
48
49 struct remote *remote;
50 struct transport *transport;
@@ -74,8 +76,17 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
76 if (argc > 1) {
77 int i;
78 pattern = xcalloc(argc, sizeof(const char *));
77 - for (i = 1; i < argc; i++)
79 + for (i = 1; i < argc; i++) {
80 + const char *glob;
81 pattern[i - 1] = xstrfmt("*/%s", argv[i]);
82 +
83 + glob = strchr(argv[i], '*');
84 + if (glob)
85 + argv_array_pushf(&ref_prefixes, "%.*s",
86 + (int)(glob - argv[i]), argv[i]);
87 + else
88 + expand_ref_prefix(&ref_prefixes, argv[i]);
89 + }
90 }
91
92 remote = remote_get(dest);
@@ -96,7 +107,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
107 if (uploadpack != NULL)
108 transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
109
99 - ref = transport_get_remote_refs(transport, NULL);
110 + ref = transport_get_remote_refs(transport, &ref_prefixes);
111 if (transport_disconnect(transport))
112 return 1;
113
refs.c
+14
@@ -13,6 +13,7 @@
13 #include "tag.h"
14 #include "submodule.h"
15 #include "worktree.h"
16 +#include "argv-array.h"
17
18 /*
19 * List of all available backends
@@ -501,6 +502,19 @@ int refname_match(const char *abbrev_name, const char *full_name)
502 return 0;
503 }
504
505 +/*
506 + * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add
507 + * the results to 'prefixes'
508 + */
509 +void expand_ref_prefix(struct argv_array *prefixes, const char *prefix)
510 +{
511 + const char **p;
512 + int len = strlen(prefix);
513 +
514 + for (p = ref_rev_parse_rules; *p; p++)
515 + argv_array_pushf(prefixes, *p, len, prefix);
516 +}
517 +
518 /*
519 * *string and *len will only be substituted, and *string returned (for
520 * later free()ing) if the string passed in is a magic short-hand form
refs.h
+7
@@ -139,6 +139,13 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
139 */
140 int refname_match(const char *abbrev_name, const char *full_name);
141
142 +/*
143 + * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add
144 + * the results to 'prefixes'
145 + */
146 +struct argv_array;
147 +void expand_ref_prefix(struct argv_array *prefixes, const char *prefix);
148 +
149 int expand_ref(const char *str, int len, struct object_id *oid, char **ref);
150 int dwim_ref(const char *str, int len, struct object_id *oid, char **ref);
151 int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
t/t5702-protocol-v2.sh
+26
@@ -32,6 +32,19 @@ test_expect_success 'list refs with git:// using protocol v2' '
32 test_cmp actual expect
33 '
34
35 +test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
36 + test_when_finished "rm -f log" &&
37 +
38 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
39 + ls-remote "$GIT_DAEMON_URL/parent" master >actual &&
40 +
41 + cat >expect <<-EOF &&
42 + $(git -C "$daemon_parent" rev-parse refs/heads/master)$(printf "\t")refs/heads/master
43 + EOF
44 +
45 + test_cmp actual expect
46 +'
47 +
48 stop_git_daemon
49
50 # Test protocol v2 with 'file://' transport
@@ -54,4 +67,17 @@ test_expect_success 'list refs with file:// using protocol v2' '
67 test_cmp actual expect
68 '
69
70 +test_expect_success 'ref advertisment is filtered with ls-remote using protocol v2' '
71 + test_when_finished "rm -f log" &&
72 +
73 + GIT_TRACE_PACKET="$(pwd)/log" git -c protocol.version=2 \
74 + ls-remote "file://$(pwd)/file_parent" master >actual &&
75 +
76 + cat >expect <<-EOF &&
77 + $(git -C file_parent rev-parse refs/heads/master)$(printf "\t")refs/heads/master
78 + EOF
79 +
80 + test_cmp actual expect
81 +'
82 +
83 test_done