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