Move refspec parser from connect.c and cache.h to remote.{c,h}
[git/git.git] / remote.c
CommitLineData
5751f490
DB
1#include "cache.h"
2#include "remote.h"
3#include "refs.h"
4
5static struct remote **remotes;
6static int allocated_remotes;
7
8#define BUF_SIZE (2048)
9static char buffer[BUF_SIZE];
10
11static void add_push_refspec(struct remote *remote, const char *ref)
12{
13 int nr = remote->push_refspec_nr + 1;
14 remote->push_refspec =
15 xrealloc(remote->push_refspec, nr * sizeof(char *));
16 remote->push_refspec[nr-1] = ref;
17 remote->push_refspec_nr = nr;
18}
19
20static void add_uri(struct remote *remote, const char *uri)
21{
22 int nr = remote->uri_nr + 1;
23 remote->uri =
24 xrealloc(remote->uri, nr * sizeof(char *));
25 remote->uri[nr-1] = uri;
26 remote->uri_nr = nr;
27}
28
29static struct remote *make_remote(const char *name, int len)
30{
31 int i, empty = -1;
32
33 for (i = 0; i < allocated_remotes; i++) {
34 if (!remotes[i]) {
35 if (empty < 0)
36 empty = i;
37 } else {
38 if (len ? (!strncmp(name, remotes[i]->name, len) &&
39 !remotes[i]->name[len]) :
40 !strcmp(name, remotes[i]->name))
41 return remotes[i];
42 }
43 }
44
45 if (empty < 0) {
46 empty = allocated_remotes;
47 allocated_remotes += allocated_remotes ? allocated_remotes : 1;
48 remotes = xrealloc(remotes,
49 sizeof(*remotes) * allocated_remotes);
50 memset(remotes + empty, 0,
51 (allocated_remotes - empty) * sizeof(*remotes));
52 }
53 remotes[empty] = xcalloc(1, sizeof(struct remote));
54 if (len)
55 remotes[empty]->name = xstrndup(name, len);
56 else
57 remotes[empty]->name = xstrdup(name);
58 return remotes[empty];
59}
60
61static void read_remotes_file(struct remote *remote)
62{
63 FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
64
65 if (!f)
66 return;
67 while (fgets(buffer, BUF_SIZE, f)) {
68 int value_list;
69 char *s, *p;
70
71 if (!prefixcmp(buffer, "URL:")) {
72 value_list = 0;
73 s = buffer + 4;
74 } else if (!prefixcmp(buffer, "Push:")) {
75 value_list = 1;
76 s = buffer + 5;
77 } else
78 continue;
79
80 while (isspace(*s))
81 s++;
82 if (!*s)
83 continue;
84
85 p = s + strlen(s);
86 while (isspace(p[-1]))
87 *--p = 0;
88
89 switch (value_list) {
90 case 0:
91 add_uri(remote, xstrdup(s));
92 break;
93 case 1:
94 add_push_refspec(remote, xstrdup(s));
95 break;
96 }
97 }
98 fclose(f);
99}
100
101static void read_branches_file(struct remote *remote)
102{
103 const char *slash = strchr(remote->name, '/');
104 int n = slash ? slash - remote->name : 1000;
105 FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
106 char *s, *p;
107 int len;
108
109 if (!f)
110 return;
111 s = fgets(buffer, BUF_SIZE, f);
112 fclose(f);
113 if (!s)
114 return;
115 while (isspace(*s))
116 s++;
117 if (!*s)
118 return;
119 p = s + strlen(s);
120 while (isspace(p[-1]))
121 *--p = 0;
122 len = p - s;
123 if (slash)
124 len += strlen(slash);
125 p = xmalloc(len + 1);
126 strcpy(p, s);
127 if (slash)
128 strcat(p, slash);
129 add_uri(remote, p);
130}
131
132static char *default_remote_name = NULL;
133static const char *current_branch = NULL;
134static int current_branch_len = 0;
135
136static int handle_config(const char *key, const char *value)
137{
138 const char *name;
139 const char *subkey;
140 struct remote *remote;
141 if (!prefixcmp(key, "branch.") && current_branch &&
142 !strncmp(key + 7, current_branch, current_branch_len) &&
143 !strcmp(key + 7 + current_branch_len, ".remote")) {
144 free(default_remote_name);
145 default_remote_name = xstrdup(value);
146 }
147 if (prefixcmp(key, "remote."))
148 return 0;
149 name = key + 7;
150 subkey = strrchr(name, '.');
151 if (!subkey)
152 return error("Config with no key for remote %s", name);
153 if (*subkey == '/') {
154 warning("Config remote shorthand cannot begin with '/': %s", name);
155 return 0;
156 }
157 remote = make_remote(name, subkey - name);
158 if (!value) {
159 /* if we ever have a boolean variable, e.g. "remote.*.disabled"
160 * [remote "frotz"]
161 * disabled
162 * is a valid way to set it to true; we get NULL in value so
163 * we need to handle it here.
164 *
165 * if (!strcmp(subkey, ".disabled")) {
166 * val = git_config_bool(key, value);
167 * return 0;
168 * } else
169 *
170 */
171 return 0; /* ignore unknown booleans */
172 }
173 if (!strcmp(subkey, ".url")) {
174 add_uri(remote, xstrdup(value));
175 } else if (!strcmp(subkey, ".push")) {
176 add_push_refspec(remote, xstrdup(value));
177 } else if (!strcmp(subkey, ".receivepack")) {
178 if (!remote->receivepack)
179 remote->receivepack = xstrdup(value);
180 else
181 error("more than one receivepack given, using the first");
182 }
183 return 0;
184}
185
186static void read_config(void)
187{
188 unsigned char sha1[20];
189 const char *head_ref;
190 int flag;
191 if (default_remote_name) // did this already
192 return;
193 default_remote_name = xstrdup("origin");
194 current_branch = NULL;
195 head_ref = resolve_ref("HEAD", sha1, 0, &flag);
196 if (head_ref && (flag & REF_ISSYMREF) &&
197 !prefixcmp(head_ref, "refs/heads/")) {
198 current_branch = head_ref + strlen("refs/heads/");
199 current_branch_len = strlen(current_branch);
200 }
201 git_config(handle_config);
202}
203
6b62816c
DB
204static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
205{
206 int i;
207 struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
208 for (i = 0; i < nr_refspec; i++) {
209 const char *sp, *ep, *gp;
210 sp = refspec[i];
211 if (*sp == '+') {
212 rs[i].force = 1;
213 sp++;
214 }
215 gp = strchr(sp, '*');
216 ep = strchr(sp, ':');
217 if (gp && ep && gp > ep)
218 gp = NULL;
219 if (ep) {
220 if (ep[1]) {
221 const char *glob = strchr(ep + 1, '*');
222 if (!glob)
223 gp = NULL;
224 if (gp)
225 rs[i].dst = xstrndup(ep + 1,
226 glob - ep - 1);
227 else
228 rs[i].dst = xstrdup(ep + 1);
229 }
230 } else {
231 ep = sp + strlen(sp);
232 }
233 if (gp) {
234 rs[i].pattern = 1;
235 ep = gp;
236 }
237 rs[i].src = xstrndup(sp, ep - sp);
238 }
239 return rs;
240}
241
5751f490
DB
242struct remote *remote_get(const char *name)
243{
244 struct remote *ret;
245
246 read_config();
247 if (!name)
248 name = default_remote_name;
249 ret = make_remote(name, 0);
250 if (name[0] != '/') {
251 if (!ret->uri)
252 read_remotes_file(ret);
253 if (!ret->uri)
254 read_branches_file(ret);
255 }
256 if (!ret->uri)
257 add_uri(ret, name);
258 if (!ret->uri)
259 return NULL;
6b62816c 260 ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
5751f490
DB
261 return ret;
262}
6b62816c
DB
263
264static int count_refspec_match(const char *pattern,
265 struct ref *refs,
266 struct ref **matched_ref)
267{
268 int patlen = strlen(pattern);
269 struct ref *matched_weak = NULL;
270 struct ref *matched = NULL;
271 int weak_match = 0;
272 int match = 0;
273
274 for (weak_match = match = 0; refs; refs = refs->next) {
275 char *name = refs->name;
276 int namelen = strlen(name);
277 int weak_match;
278
279 if (namelen < patlen ||
280 memcmp(name + namelen - patlen, pattern, patlen))
281 continue;
282 if (namelen != patlen && name[namelen - patlen - 1] != '/')
283 continue;
284
285 /* A match is "weak" if it is with refs outside
286 * heads or tags, and did not specify the pattern
287 * in full (e.g. "refs/remotes/origin/master") or at
288 * least from the toplevel (e.g. "remotes/origin/master");
289 * otherwise "git push $URL master" would result in
290 * ambiguity between remotes/origin/master and heads/master
291 * at the remote site.
292 */
293 if (namelen != patlen &&
294 patlen != namelen - 5 &&
295 prefixcmp(name, "refs/heads/") &&
296 prefixcmp(name, "refs/tags/")) {
297 /* We want to catch the case where only weak
298 * matches are found and there are multiple
299 * matches, and where more than one strong
300 * matches are found, as ambiguous. One
301 * strong match with zero or more weak matches
302 * are acceptable as a unique match.
303 */
304 matched_weak = refs;
305 weak_match++;
306 }
307 else {
308 matched = refs;
309 match++;
310 }
311 }
312 if (!matched) {
313 *matched_ref = matched_weak;
314 return weak_match;
315 }
316 else {
317 *matched_ref = matched;
318 return match;
319 }
320}
321
322static void link_dst_tail(struct ref *ref, struct ref ***tail)
323{
324 **tail = ref;
325 *tail = &ref->next;
326 **tail = NULL;
327}
328
329static struct ref *try_explicit_object_name(const char *name)
330{
331 unsigned char sha1[20];
332 struct ref *ref;
333 int len;
334
335 if (!*name) {
336 ref = xcalloc(1, sizeof(*ref) + 20);
337 strcpy(ref->name, "(delete)");
338 hashclr(ref->new_sha1);
339 return ref;
340 }
341 if (get_sha1(name, sha1))
342 return NULL;
343 len = strlen(name) + 1;
344 ref = xcalloc(1, sizeof(*ref) + len);
345 memcpy(ref->name, name, len);
346 hashcpy(ref->new_sha1, sha1);
347 return ref;
348}
349
350static int match_explicit_refs(struct ref *src, struct ref *dst,
351 struct ref ***dst_tail, struct refspec *rs,
352 int rs_nr)
353{
354 int i, errs;
355 for (i = errs = 0; i < rs_nr; i++) {
356 struct ref *matched_src, *matched_dst;
357
358 const char *dst_value = rs[i].dst;
359 if (dst_value == NULL)
360 dst_value = rs[i].src;
361
362 matched_src = matched_dst = NULL;
363 switch (count_refspec_match(rs[i].src, src, &matched_src)) {
364 case 1:
365 break;
366 case 0:
367 /* The source could be in the get_sha1() format
368 * not a reference name. :refs/other is a
369 * way to delete 'other' ref at the remote end.
370 */
371 matched_src = try_explicit_object_name(rs[i].src);
372 if (matched_src)
373 break;
374 errs = 1;
375 error("src refspec %s does not match any.",
376 rs[i].src);
377 break;
378 default:
379 errs = 1;
380 error("src refspec %s matches more than one.",
381 rs[i].src);
382 break;
383 }
384 switch (count_refspec_match(dst_value, dst, &matched_dst)) {
385 case 1:
386 break;
387 case 0:
388 if (!memcmp(dst_value, "refs/", 5)) {
389 int len = strlen(dst_value) + 1;
390 matched_dst = xcalloc(1, sizeof(*dst) + len);
391 memcpy(matched_dst->name, dst_value, len);
392 link_dst_tail(matched_dst, dst_tail);
393 }
394 else if (!strcmp(rs[i].src, dst_value) &&
395 matched_src) {
396 /* pushing "master:master" when
397 * remote does not have master yet.
398 */
399 int len = strlen(matched_src->name) + 1;
400 matched_dst = xcalloc(1, sizeof(*dst) + len);
401 memcpy(matched_dst->name, matched_src->name,
402 len);
403 link_dst_tail(matched_dst, dst_tail);
404 }
405 else {
406 errs = 1;
407 error("dst refspec %s does not match any "
408 "existing ref on the remote and does "
409 "not start with refs/.", dst_value);
410 }
411 break;
412 default:
413 errs = 1;
414 error("dst refspec %s matches more than one.",
415 dst_value);
416 break;
417 }
418 if (errs)
419 continue;
420 if (matched_dst->peer_ref) {
421 errs = 1;
422 error("dst ref %s receives from more than one src.",
423 matched_dst->name);
424 }
425 else {
426 matched_dst->peer_ref = matched_src;
427 matched_dst->force = rs[i].force;
428 }
429 }
430 return -errs;
431}
432
433static struct ref *find_ref_by_name(struct ref *list, const char *name)
434{
435 for ( ; list; list = list->next)
436 if (!strcmp(list->name, name))
437 return list;
438 return NULL;
439}
440
441int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
442 int nr_refspec, char **refspec, int all)
443{
444 struct refspec *rs =
445 parse_ref_spec(nr_refspec, (const char **) refspec);
446
447 if (nr_refspec)
448 return match_explicit_refs(src, dst, dst_tail, rs, nr_refspec);
449
450 /* pick the remainder */
451 for ( ; src; src = src->next) {
452 struct ref *dst_peer;
453 if (src->peer_ref)
454 continue;
455 dst_peer = find_ref_by_name(dst, src->name);
456 if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
457 continue;
458 if (!dst_peer) {
459 /* Create a new one and link it */
460 int len = strlen(src->name) + 1;
461 dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
462 memcpy(dst_peer->name, src->name, len);
463 hashcpy(dst_peer->new_sha1, src->new_sha1);
464 link_dst_tail(dst_peer, dst_tail);
465 }
466 dst_peer->peer_ref = src;
467 }
468 return 0;
469}