ls-remote: resurrect pattern limit support
[git] / builtin-ls-remote.c
1 #include "builtin.h"
2 #include "cache.h"
3 #include "transport.h"
4 #include "remote.h"
5
6 static const char ls_remote_usage[] =
7 "git-ls-remote [--upload-pack=<git-upload-pack>] [<host>:]<directory>";
8
9 /*
10  * pattern is a list of tail-part of accepted refnames.  Is there one
11  * among them that is a suffix of the path?  Directory boundary must
12  * be honored when checking this match.  IOW, patterns "master" and
13  * "sa/master" both match path "refs/hold/sa/master".  On the other
14  * hand, path "refs/hold/foosa/master" is matched by "master" but not
15  * by "sa/master".
16  */
17
18 static int tail_match(const char **pattern, const char *path)
19 {
20         int pathlen;
21         const char *p;
22
23         if (!*pattern)
24                 return 1; /* no restriction */
25
26         for (pathlen = strlen(path); (p = *pattern); pattern++) {
27                 int pfxlen = pathlen - strlen(p);
28                 if (pfxlen < 0)
29                         continue; /* pattern is longer, will never match */
30                 if (strcmp(path + pfxlen, p))
31                         continue; /* no tail match */
32                 if (!pfxlen || path[pfxlen - 1] == '/')
33                         return 1; /* fully match at directory boundary */
34         }
35         return 0;
36 }
37
38 int cmd_ls_remote(int argc, const char **argv, const char *prefix)
39 {
40         int i;
41         const char *dest = NULL;
42         int nongit = 0;
43         unsigned flags = 0;
44         const char *uploadpack = NULL;
45         const char **pattern = NULL;
46
47         struct remote *remote;
48         struct transport *transport;
49         const struct ref *ref;
50
51         setup_git_directory_gently(&nongit);
52
53         for (i = 1; i < argc; i++) {
54                 const char *arg = argv[i];
55
56                 if (*arg == '-') {
57                         if (!prefixcmp(arg, "--upload-pack=")) {
58                                 uploadpack = arg + 14;
59                                 continue;
60                         }
61                         if (!prefixcmp(arg, "--exec=")) {
62                                 uploadpack = arg + 7;
63                                 continue;
64                         }
65                         if (!strcmp("--tags", arg)) {
66                                 flags |= REF_TAGS;
67                                 continue;
68                         }
69                         if (!strcmp("--heads", arg)) {
70                                 flags |= REF_HEADS;
71                                 continue;
72                         }
73                         if (!strcmp("--refs", arg)) {
74                                 flags |= REF_NORMAL;
75                                 continue;
76                         }
77                         usage(ls_remote_usage);
78                 }
79                 dest = arg;
80                 break;
81         }
82
83         if (!dest)
84                 usage(ls_remote_usage);
85         pattern = argv + i + 1;
86         remote = nongit ? NULL : remote_get(dest);
87         if (remote && !remote->url_nr)
88                 die("remote %s has no configured URL", dest);
89         transport = transport_get(remote, remote ? remote->url[0] : dest);
90         if (uploadpack != NULL)
91                 transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
92
93         ref = transport_get_remote_refs(transport);
94
95         if (!ref)
96                 return 1;
97
98         for ( ; ref; ref = ref->next) {
99                 if (!check_ref_type(ref, flags))
100                         continue;
101                 if (!tail_match(pattern, ref->name))
102                         continue;
103                 printf("%s      %s\n", sha1_to_hex(ref->old_sha1), ref->name);
104         }
105         return 0;
106 }