]>
Commit | Line | Data |
---|---|---|
d4289fff JH |
1 | #include "cache.h" |
2 | #include "refs.h" | |
3 | #include "commit.h" | |
4 | ||
dec56c8c | 5 | #define CHUNK_SIZE 1024 |
46ce8b6d JP |
6 | |
7 | static char *get_stdin(void) | |
8 | { | |
dec56c8c | 9 | int offset = 0; |
46ce8b6d | 10 | char *data = xmalloc(CHUNK_SIZE); |
dec56c8c JH |
11 | |
12 | while (1) { | |
13 | int cnt = xread(0, data + offset, CHUNK_SIZE); | |
14 | if (cnt < 0) | |
15 | die("error reading standard input: %s", | |
16 | strerror(errno)); | |
17 | if (cnt == 0) { | |
18 | data[offset] = 0; | |
19 | break; | |
20 | } | |
21 | offset += cnt; | |
46ce8b6d | 22 | data = xrealloc(data, offset + CHUNK_SIZE); |
46ce8b6d JP |
23 | } |
24 | return data; | |
25 | } | |
26 | ||
dcf01c6e | 27 | static void show_new(enum object_type type, unsigned char *sha1_new) |
d4289fff | 28 | { |
dcf01c6e | 29 | fprintf(stderr, " %s: %s\n", typename(type), |
d4289fff JH |
30 | find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); |
31 | } | |
32 | ||
33 | static int update_ref(const char *action, | |
34 | const char *refname, | |
35 | unsigned char *sha1, | |
36 | unsigned char *oldval) | |
37 | { | |
d4289fff JH |
38 | char msg[1024]; |
39 | char *rla = getenv("GIT_REFLOG_ACTION"); | |
40 | static struct ref_lock *lock; | |
41 | ||
42 | if (!rla) | |
43 | rla = "(reflog update)"; | |
4e6380e5 | 44 | snprintf(msg, sizeof(msg), "%s: %s", rla, action); |
d4289fff JH |
45 | lock = lock_any_ref_for_update(refname, oldval); |
46 | if (!lock) | |
47 | return 1; | |
48 | if (write_ref_sha1(lock, sha1, msg) < 0) | |
49 | return 1; | |
50 | return 0; | |
51 | } | |
52 | ||
53 | static int update_local_ref(const char *name, | |
54 | const char *new_head, | |
55 | const char *note, | |
56 | int verbose, int force) | |
57 | { | |
d4289fff JH |
58 | unsigned char sha1_old[20], sha1_new[20]; |
59 | char oldh[41], newh[41]; | |
60 | struct commit *current, *updated; | |
dcf01c6e | 61 | enum object_type type; |
d4289fff JH |
62 | |
63 | if (get_sha1_hex(new_head, sha1_new)) | |
64 | die("malformed object name %s", new_head); | |
dcf01c6e JH |
65 | |
66 | type = sha1_object_info(sha1_new, NULL); | |
67 | if (type < 0) | |
d4289fff JH |
68 | die("object %s not found", new_head); |
69 | ||
70 | if (!*name) { | |
71 | /* Not storing */ | |
72 | if (verbose) { | |
73 | fprintf(stderr, "* fetched %s\n", note); | |
74 | show_new(type, sha1_new); | |
75 | } | |
76 | return 0; | |
77 | } | |
78 | ||
79 | if (get_sha1(name, sha1_old)) { | |
80 | char *msg; | |
81 | just_store: | |
82 | /* new ref */ | |
83 | if (!strncmp(name, "refs/tags/", 10)) | |
84 | msg = "storing tag"; | |
85 | else | |
86 | msg = "storing head"; | |
87 | fprintf(stderr, "* %s: storing %s\n", | |
88 | name, note); | |
89 | show_new(type, sha1_new); | |
90 | return update_ref(msg, name, sha1_new, NULL); | |
91 | } | |
92 | ||
93 | if (!hashcmp(sha1_old, sha1_new)) { | |
94 | if (verbose) { | |
95 | fprintf(stderr, "* %s: same as %s\n", name, note); | |
96 | show_new(type, sha1_new); | |
97 | } | |
98 | return 0; | |
99 | } | |
100 | ||
101 | if (!strncmp(name, "refs/tags/", 10)) { | |
102 | fprintf(stderr, "* %s: updating with %s\n", name, note); | |
103 | show_new(type, sha1_new); | |
104 | return update_ref("updating tag", name, sha1_new, NULL); | |
105 | } | |
106 | ||
107 | current = lookup_commit_reference(sha1_old); | |
108 | updated = lookup_commit_reference(sha1_new); | |
109 | if (!current || !updated) | |
110 | goto just_store; | |
111 | ||
112 | strcpy(oldh, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV)); | |
113 | strcpy(newh, find_unique_abbrev(sha1_new, DEFAULT_ABBREV)); | |
114 | ||
115 | if (in_merge_bases(current, &updated, 1)) { | |
116 | fprintf(stderr, "* %s: fast forward to %s\n", | |
117 | name, note); | |
118 | fprintf(stderr, " old..new: %s..%s\n", oldh, newh); | |
119 | return update_ref("fast forward", name, sha1_new, sha1_old); | |
120 | } | |
121 | if (!force) { | |
122 | fprintf(stderr, | |
123 | "* %s: not updating to non-fast forward %s\n", | |
124 | name, note); | |
125 | fprintf(stderr, | |
126 | " old...new: %s...%s\n", oldh, newh); | |
127 | return 1; | |
128 | } | |
129 | fprintf(stderr, | |
130 | "* %s: forcing update to non-fast forward %s\n", | |
131 | name, note); | |
132 | fprintf(stderr, " old...new: %s...%s\n", oldh, newh); | |
133 | return update_ref("forced-update", name, sha1_new, sha1_old); | |
134 | } | |
135 | ||
136 | static int append_fetch_head(FILE *fp, | |
137 | const char *head, const char *remote, | |
138 | const char *remote_name, const char *remote_nick, | |
139 | const char *local_name, int not_for_merge, | |
140 | int verbose, int force) | |
141 | { | |
142 | struct commit *commit; | |
143 | int remote_len, i, note_len; | |
144 | unsigned char sha1[20]; | |
145 | char note[1024]; | |
146 | const char *what, *kind; | |
147 | ||
148 | if (get_sha1(head, sha1)) | |
149 | return error("Not a valid object name: %s", head); | |
150 | commit = lookup_commit_reference(sha1); | |
151 | if (!commit) | |
152 | not_for_merge = 1; | |
153 | ||
154 | if (!strcmp(remote_name, "HEAD")) { | |
155 | kind = ""; | |
156 | what = ""; | |
157 | } | |
158 | else if (!strncmp(remote_name, "refs/heads/", 11)) { | |
159 | kind = "branch"; | |
160 | what = remote_name + 11; | |
161 | } | |
162 | else if (!strncmp(remote_name, "refs/tags/", 10)) { | |
163 | kind = "tag"; | |
164 | what = remote_name + 10; | |
165 | } | |
166 | else if (!strncmp(remote_name, "refs/remotes/", 13)) { | |
167 | kind = "remote branch"; | |
168 | what = remote_name + 13; | |
169 | } | |
170 | else { | |
171 | kind = ""; | |
172 | what = remote_name; | |
173 | } | |
174 | ||
175 | remote_len = strlen(remote); | |
176 | for (i = remote_len - 1; remote[i] == '/' && 0 <= i; i--) | |
177 | ; | |
178 | remote_len = i + 1; | |
179 | if (4 < i && !strncmp(".git", remote + i - 3, 4)) | |
180 | remote_len = i - 3; | |
855b3468 JH |
181 | |
182 | note_len = 0; | |
d4289fff JH |
183 | if (*what) { |
184 | if (*kind) | |
185 | note_len += sprintf(note + note_len, "%s ", kind); | |
186 | note_len += sprintf(note + note_len, "'%s' of ", what); | |
187 | } | |
188 | note_len += sprintf(note + note_len, "%.*s", remote_len, remote); | |
855b3468 JH |
189 | fprintf(fp, "%s\t%s\t%s\n", |
190 | sha1_to_hex(commit ? commit->object.sha1 : sha1), | |
191 | not_for_merge ? "not-for-merge" : "", | |
192 | note); | |
d4289fff JH |
193 | return update_local_ref(local_name, head, note, verbose, force); |
194 | } | |
195 | ||
fbe2687e JH |
196 | static char *keep; |
197 | static void remove_keep(void) | |
198 | { | |
199 | if (keep && *keep) | |
200 | unlink(keep); | |
201 | } | |
202 | ||
203 | static void remove_keep_on_signal(int signo) | |
204 | { | |
205 | remove_keep(); | |
206 | signal(SIGINT, SIG_DFL); | |
207 | raise(signo); | |
208 | } | |
209 | ||
210 | static char *find_local_name(const char *remote_name, const char *refs, | |
211 | int *force_p, int *not_for_merge_p) | |
212 | { | |
213 | const char *ref = refs; | |
214 | int len = strlen(remote_name); | |
215 | ||
216 | while (ref) { | |
217 | const char *next; | |
218 | int single_force, not_for_merge; | |
219 | ||
220 | while (*ref == '\n') | |
221 | ref++; | |
222 | if (!*ref) | |
223 | break; | |
224 | next = strchr(ref, '\n'); | |
225 | ||
226 | single_force = not_for_merge = 0; | |
227 | if (*ref == '+') { | |
228 | single_force = 1; | |
229 | ref++; | |
230 | } | |
231 | if (*ref == '.') { | |
232 | not_for_merge = 1; | |
233 | ref++; | |
234 | if (*ref == '+') { | |
235 | single_force = 1; | |
236 | ref++; | |
237 | } | |
238 | } | |
239 | if (!strncmp(remote_name, ref, len) && ref[len] == ':') { | |
240 | const char *local_part = ref + len + 1; | |
241 | char *ret; | |
242 | int retlen; | |
243 | ||
244 | if (!next) | |
245 | retlen = strlen(local_part); | |
246 | else | |
247 | retlen = next - local_part; | |
248 | ret = xmalloc(retlen + 1); | |
249 | memcpy(ret, local_part, retlen); | |
250 | ret[retlen] = 0; | |
251 | *force_p = single_force; | |
252 | *not_for_merge_p = not_for_merge; | |
253 | return ret; | |
254 | } | |
255 | ref = next; | |
256 | } | |
257 | return NULL; | |
258 | } | |
259 | ||
260 | static int fetch_native_store(FILE *fp, | |
261 | const char *remote, | |
262 | const char *remote_nick, | |
263 | const char *refs, | |
264 | int verbose, int force) | |
265 | { | |
266 | char buffer[1024]; | |
267 | int err = 0; | |
268 | ||
269 | signal(SIGINT, remove_keep_on_signal); | |
270 | atexit(remove_keep); | |
271 | ||
272 | while (fgets(buffer, sizeof(buffer), stdin)) { | |
273 | int len; | |
274 | char *cp; | |
275 | char *local_name; | |
276 | int single_force, not_for_merge; | |
277 | ||
278 | for (cp = buffer; *cp && !isspace(*cp); cp++) | |
279 | ; | |
280 | if (*cp) | |
281 | *cp++ = 0; | |
282 | len = strlen(cp); | |
283 | if (len && cp[len-1] == '\n') | |
284 | cp[--len] = 0; | |
285 | if (!strcmp(buffer, "failed")) | |
286 | die("Fetch failure: %s", remote); | |
287 | if (!strcmp(buffer, "pack")) | |
288 | continue; | |
289 | if (!strcmp(buffer, "keep")) { | |
290 | char *od = get_object_directory(); | |
291 | int len = strlen(od) + strlen(cp) + 50; | |
292 | keep = xmalloc(len); | |
293 | sprintf(keep, "%s/pack/pack-%s.keep", od, cp); | |
294 | continue; | |
295 | } | |
296 | ||
297 | local_name = find_local_name(cp, refs, | |
298 | &single_force, ¬_for_merge); | |
299 | if (!local_name) | |
300 | continue; | |
301 | err |= append_fetch_head(fp, | |
302 | buffer, remote, cp, remote_nick, | |
303 | local_name, not_for_merge, | |
304 | verbose, force || single_force); | |
305 | } | |
306 | return err; | |
307 | } | |
308 | ||
d1e0ef6c JH |
309 | static int parse_reflist(const char *reflist) |
310 | { | |
311 | const char *ref; | |
312 | ||
313 | printf("refs='"); | |
314 | for (ref = reflist; ref; ) { | |
315 | const char *next; | |
316 | while (*ref && isspace(*ref)) | |
317 | ref++; | |
318 | if (!*ref) | |
319 | break; | |
320 | for (next = ref; *next && !isspace(*next); next++) | |
321 | ; | |
322 | printf("\n%.*s", (int)(next - ref), ref); | |
323 | ref = next; | |
324 | } | |
325 | printf("'\n"); | |
326 | ||
327 | printf("rref='"); | |
328 | for (ref = reflist; ref; ) { | |
329 | const char *next, *colon; | |
330 | while (*ref && isspace(*ref)) | |
331 | ref++; | |
332 | if (!*ref) | |
333 | break; | |
334 | for (next = ref; *next && !isspace(*next); next++) | |
335 | ; | |
336 | if (*ref == '.') | |
337 | ref++; | |
338 | if (*ref == '+') | |
339 | ref++; | |
340 | colon = strchr(ref, ':'); | |
341 | putchar('\n'); | |
342 | printf("%.*s", (int)((colon ? colon : next) - ref), ref); | |
343 | ref = next; | |
344 | } | |
345 | printf("'\n"); | |
346 | return 0; | |
347 | } | |
348 | ||
86551586 JH |
349 | static int expand_refs_wildcard(const char *ls_remote_result, int numrefs, |
350 | const char **refs) | |
351 | { | |
352 | int i, matchlen, replacelen; | |
353 | int found_one = 0; | |
354 | const char *remote = *refs++; | |
355 | numrefs--; | |
356 | ||
357 | if (numrefs == 0) { | |
358 | fprintf(stderr, "Nothing specified for fetching with remote.%s.fetch\n", | |
359 | remote); | |
360 | printf("empty\n"); | |
361 | } | |
362 | ||
363 | for (i = 0; i < numrefs; i++) { | |
364 | const char *ref = refs[i]; | |
365 | const char *lref = ref; | |
366 | const char *colon; | |
367 | const char *tail; | |
368 | const char *ls; | |
369 | const char *next; | |
370 | ||
371 | if (*lref == '+') | |
372 | lref++; | |
373 | colon = strchr(lref, ':'); | |
374 | tail = lref + strlen(lref); | |
375 | if (!(colon && | |
376 | 2 < colon - lref && | |
377 | colon[-1] == '*' && | |
378 | colon[-2] == '/' && | |
379 | 2 < tail - (colon + 1) && | |
380 | tail[-1] == '*' && | |
381 | tail[-2] == '/')) { | |
382 | /* not a glob */ | |
383 | if (!found_one++) | |
384 | printf("explicit\n"); | |
385 | printf("%s\n", ref); | |
386 | continue; | |
387 | } | |
388 | ||
389 | /* glob */ | |
390 | if (!found_one++) | |
391 | printf("glob\n"); | |
392 | ||
393 | /* lref to colon-2 is remote hierarchy name; | |
394 | * colon+1 to tail-2 is local. | |
395 | */ | |
396 | matchlen = (colon-1) - lref; | |
397 | replacelen = (tail-1) - (colon+1); | |
398 | for (ls = ls_remote_result; ls; ls = next) { | |
399 | const char *eol; | |
400 | unsigned char sha1[20]; | |
401 | int namelen; | |
402 | ||
403 | while (*ls && isspace(*ls)) | |
404 | ls++; | |
405 | next = strchr(ls, '\n'); | |
406 | eol = !next ? (ls + strlen(ls)) : next; | |
407 | if (!memcmp("^{}", eol-3, 3)) | |
408 | continue; | |
c7d68c80 JH |
409 | if (eol - ls < 40) |
410 | continue; | |
86551586 JH |
411 | if (get_sha1_hex(ls, sha1)) |
412 | continue; | |
413 | ls += 40; | |
414 | while (ls < eol && isspace(*ls)) | |
415 | ls++; | |
416 | /* ls to next (or eol) is the name. | |
417 | * is it identical to lref to colon-2? | |
418 | */ | |
419 | if ((eol - ls) <= matchlen || | |
420 | strncmp(ls, lref, matchlen)) | |
421 | continue; | |
422 | ||
423 | /* Yes, it is a match */ | |
424 | namelen = eol - ls; | |
425 | if (lref != ref) | |
426 | putchar('+'); | |
427 | printf("%.*s:%.*s%.*s\n", | |
428 | namelen, ls, | |
429 | replacelen, colon + 1, | |
430 | namelen - matchlen, ls + matchlen); | |
431 | } | |
432 | } | |
433 | return 0; | |
434 | } | |
435 | ||
d4289fff JH |
436 | int cmd_fetch__tool(int argc, const char **argv, const char *prefix) |
437 | { | |
438 | int verbose = 0; | |
439 | int force = 0; | |
440 | ||
441 | while (1 < argc) { | |
442 | const char *arg = argv[1]; | |
443 | if (!strcmp("-v", arg)) | |
444 | verbose = 1; | |
445 | else if (!strcmp("-f", arg)) | |
446 | force = 1; | |
447 | else | |
448 | break; | |
449 | argc--; | |
450 | argv++; | |
451 | } | |
452 | ||
453 | if (argc <= 1) | |
454 | return error("Missing subcommand"); | |
455 | ||
456 | if (!strcmp("append-fetch-head", argv[1])) { | |
457 | int result; | |
458 | FILE *fp; | |
459 | ||
460 | if (argc != 8) | |
461 | return error("append-fetch-head takes 6 args"); | |
462 | fp = fopen(git_path("FETCH_HEAD"), "a"); | |
463 | result = append_fetch_head(fp, argv[2], argv[3], | |
464 | argv[4], argv[5], | |
465 | argv[6], !!argv[7][0], | |
466 | verbose, force); | |
467 | fclose(fp); | |
468 | return result; | |
469 | } | |
fbe2687e JH |
470 | if (!strcmp("native-store", argv[1])) { |
471 | int result; | |
472 | FILE *fp; | |
473 | ||
474 | if (argc != 5) | |
475 | return error("fetch-native-store takes 3 args"); | |
476 | fp = fopen(git_path("FETCH_HEAD"), "a"); | |
477 | result = fetch_native_store(fp, argv[2], argv[3], argv[4], | |
478 | verbose, force); | |
479 | fclose(fp); | |
480 | return result; | |
481 | } | |
d1e0ef6c | 482 | if (!strcmp("parse-reflist", argv[1])) { |
46ce8b6d | 483 | const char *reflist; |
d1e0ef6c JH |
484 | if (argc != 3) |
485 | return error("parse-reflist takes 1 arg"); | |
46ce8b6d JP |
486 | reflist = argv[2]; |
487 | if (!strcmp(reflist, "-")) | |
488 | reflist = get_stdin(); | |
489 | return parse_reflist(reflist); | |
d1e0ef6c | 490 | } |
86551586 | 491 | if (!strcmp("expand-refs-wildcard", argv[1])) { |
46ce8b6d | 492 | const char *reflist; |
86551586 JH |
493 | if (argc < 4) |
494 | return error("expand-refs-wildcard takes at least 2 args"); | |
46ce8b6d JP |
495 | reflist = argv[2]; |
496 | if (!strcmp(reflist, "-")) | |
497 | reflist = get_stdin(); | |
498 | return expand_refs_wildcard(reflist, argc - 3, argv + 3); | |
86551586 | 499 | } |
d1e0ef6c | 500 | |
d4289fff JH |
501 | return error("Unknown subcommand: %s", argv[1]); |
502 | } |