chainlint.pl: only start threads if jobs > 1
[git/debian.git] / refspec.c
blob1df5de6c2f1f7fe8bb7192b25342266dadb3ed8c
1 #include "git-compat-util.h"
2 #include "gettext.h"
3 #include "hash.h"
4 #include "hex.h"
5 #include "strvec.h"
6 #include "refs.h"
7 #include "refspec.h"
8 #include "strbuf.h"
11 * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
12 * Returns 1 if successful and 0 if the refspec is invalid.
14 static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
16 size_t llen;
17 int is_glob;
18 const char *lhs, *rhs;
19 int flags;
21 is_glob = 0;
23 lhs = refspec;
24 if (*lhs == '+') {
25 item->force = 1;
26 lhs++;
27 } else if (*lhs == '^') {
28 item->negative = 1;
29 lhs++;
32 rhs = strrchr(lhs, ':');
34 /* negative refspecs only have one side */
35 if (item->negative && rhs)
36 return 0;
39 * Before going on, special case ":" (or "+:") as a refspec
40 * for pushing matching refs.
42 if (!fetch && rhs == lhs && rhs[1] == '\0') {
43 item->matching = 1;
44 return 1;
47 if (rhs) {
48 size_t rlen = strlen(++rhs);
49 is_glob = (1 <= rlen && strchr(rhs, '*'));
50 item->dst = xstrndup(rhs, rlen);
51 } else {
52 item->dst = NULL;
55 llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
56 if (1 <= llen && memchr(lhs, '*', llen)) {
57 if ((rhs && !is_glob) || (!rhs && !item->negative && fetch))
58 return 0;
59 is_glob = 1;
60 } else if (rhs && is_glob) {
61 return 0;
64 item->pattern = is_glob;
65 if (llen == 1 && *lhs == '@')
66 item->src = xstrdup("HEAD");
67 else
68 item->src = xstrndup(lhs, llen);
69 flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
71 if (item->negative) {
72 struct object_id unused;
75 * Negative refspecs only have a LHS, which indicates a ref
76 * (or pattern of refs) to exclude from other matches. This
77 * can either be a simple ref, or a glob pattern. Exact sha1
78 * match is not currently supported.
80 if (!*item->src)
81 return 0; /* negative refspecs must not be empty */
82 else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
83 return 0; /* negative refpsecs cannot be exact sha1 */
84 else if (!check_refname_format(item->src, flags))
85 ; /* valid looking ref is ok */
86 else
87 return 0;
89 /* the other rules below do not apply to negative refspecs */
90 return 1;
93 if (fetch) {
94 struct object_id unused;
96 /* LHS */
97 if (!*item->src)
98 ; /* empty is ok; it means "HEAD" */
99 else if (llen == the_hash_algo->hexsz && !get_oid_hex(item->src, &unused))
100 item->exact_sha1 = 1; /* ok */
101 else if (!check_refname_format(item->src, flags))
102 ; /* valid looking ref is ok */
103 else
104 return 0;
105 /* RHS */
106 if (!item->dst)
107 ; /* missing is ok; it is the same as empty */
108 else if (!*item->dst)
109 ; /* empty is ok; it means "do not store" */
110 else if (!check_refname_format(item->dst, flags))
111 ; /* valid looking ref is ok */
112 else
113 return 0;
114 } else {
116 * LHS
117 * - empty is allowed; it means delete.
118 * - when wildcarded, it must be a valid looking ref.
119 * - otherwise, it must be an extended SHA-1, but
120 * there is no existing way to validate this.
122 if (!*item->src)
123 ; /* empty is ok */
124 else if (is_glob) {
125 if (check_refname_format(item->src, flags))
126 return 0;
128 else
129 ; /* anything goes, for now */
131 * RHS
132 * - missing is allowed, but LHS then must be a
133 * valid looking ref.
134 * - empty is not allowed.
135 * - otherwise it must be a valid looking ref.
137 if (!item->dst) {
138 if (check_refname_format(item->src, flags))
139 return 0;
140 } else if (!*item->dst) {
141 return 0;
142 } else {
143 if (check_refname_format(item->dst, flags))
144 return 0;
148 return 1;
151 int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
153 memset(item, 0, sizeof(*item));
154 return parse_refspec(item, refspec, fetch);
157 void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
158 int fetch)
160 if (!refspec_item_init(item, refspec, fetch))
161 die(_("invalid refspec '%s'"), refspec);
164 void refspec_item_clear(struct refspec_item *item)
166 FREE_AND_NULL(item->src);
167 FREE_AND_NULL(item->dst);
168 item->force = 0;
169 item->pattern = 0;
170 item->matching = 0;
171 item->exact_sha1 = 0;
174 void refspec_init(struct refspec *rs, int fetch)
176 memset(rs, 0, sizeof(*rs));
177 rs->fetch = fetch;
180 static void refspec_append_nodup(struct refspec *rs, char *refspec)
182 struct refspec_item item;
184 refspec_item_init_or_die(&item, refspec, rs->fetch);
186 ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
187 rs->items[rs->nr++] = item;
189 ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
190 rs->raw[rs->raw_nr++] = refspec;
193 void refspec_append(struct refspec *rs, const char *refspec)
195 refspec_append_nodup(rs, xstrdup(refspec));
198 void refspec_appendf(struct refspec *rs, const char *fmt, ...)
200 va_list ap;
202 va_start(ap, fmt);
203 refspec_append_nodup(rs, xstrvfmt(fmt, ap));
204 va_end(ap);
207 void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
209 int i;
210 for (i = 0; i < nr; i++)
211 refspec_append(rs, refspecs[i]);
214 void refspec_clear(struct refspec *rs)
216 int i;
218 for (i = 0; i < rs->nr; i++)
219 refspec_item_clear(&rs->items[i]);
221 FREE_AND_NULL(rs->items);
222 rs->alloc = 0;
223 rs->nr = 0;
225 for (i = 0; i < rs->raw_nr; i++)
226 free((char *)rs->raw[i]);
227 FREE_AND_NULL(rs->raw);
228 rs->raw_alloc = 0;
229 rs->raw_nr = 0;
231 rs->fetch = 0;
234 int valid_fetch_refspec(const char *fetch_refspec_str)
236 struct refspec_item refspec;
237 int ret = refspec_item_init(&refspec, fetch_refspec_str, REFSPEC_FETCH);
238 refspec_item_clear(&refspec);
239 return ret;
242 int valid_remote_name(const char *name)
244 int result;
245 struct strbuf refspec = STRBUF_INIT;
246 strbuf_addf(&refspec, "refs/heads/test:refs/remotes/%s/test", name);
247 result = valid_fetch_refspec(refspec.buf);
248 strbuf_release(&refspec);
249 return result;
252 void refspec_ref_prefixes(const struct refspec *rs,
253 struct strvec *ref_prefixes)
255 int i;
256 for (i = 0; i < rs->nr; i++) {
257 const struct refspec_item *item = &rs->items[i];
258 const char *prefix = NULL;
260 if (item->exact_sha1 || item->negative)
261 continue;
262 if (rs->fetch == REFSPEC_FETCH)
263 prefix = item->src;
264 else if (item->dst)
265 prefix = item->dst;
266 else if (item->src && !item->exact_sha1)
267 prefix = item->src;
269 if (!prefix)
270 continue;
272 if (item->pattern) {
273 const char *glob = strchr(prefix, '*');
274 strvec_pushf(ref_prefixes, "%.*s",
275 (int)(glob - prefix),
276 prefix);
277 } else {
278 expand_ref_prefix(ref_prefixes, prefix);