bisect--helper: reimplement `bisect_state` & `bisect_head` shell functions in C
[git] / builtin / bisect--helper.c
1 #include "builtin.h"
2 #include "cache.h"
3 #include "parse-options.h"
4 #include "bisect.h"
5 #include "refs.h"
6 #include "dir.h"
7 #include "strvec.h"
8 #include "run-command.h"
9 #include "prompt.h"
10 #include "quote.h"
11 #include "revision.h"
12
13 static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
14 static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
15 static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
16 static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
17 static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
18 static GIT_PATH_FUNC(git_path_head_name, "head-name")
19 static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
20 static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
21
22 static const char * const git_bisect_helper_usage[] = {
23         N_("git bisect--helper --write-terms <bad_term> <good_term>"),
24         N_("git bisect--helper --bisect-reset [<commit>]"),
25         N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"),
26         N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"),
27         N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
28         N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"),
29         N_("git bisect--helper --bisect-start [--term-{old,good}=<term> --term-{new,bad}=<term>]"
30                                             " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
31         N_("git bisect--helper --bisect-next"),
32         N_("git bisect--helper --bisect-auto-next"),
33         N_("git bisect--helper --bisect-autostart"),
34         N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
35         N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
36         NULL
37 };
38
39 struct add_bisect_ref_data {
40         struct rev_info *revs;
41         unsigned int object_flags;
42 };
43
44 struct bisect_terms {
45         char *term_good;
46         char *term_bad;
47 };
48
49 static void free_terms(struct bisect_terms *terms)
50 {
51         FREE_AND_NULL(terms->term_good);
52         FREE_AND_NULL(terms->term_bad);
53 }
54
55 static void set_terms(struct bisect_terms *terms, const char *bad,
56                       const char *good)
57 {
58         free((void *)terms->term_good);
59         terms->term_good = xstrdup(good);
60         free((void *)terms->term_bad);
61         terms->term_bad = xstrdup(bad);
62 }
63
64 static const char vocab_bad[] = "bad|new";
65 static const char vocab_good[] = "good|old";
66
67 static int bisect_autostart(struct bisect_terms *terms);
68
69 /*
70  * Check whether the string `term` belongs to the set of strings
71  * included in the variable arguments.
72  */
73 LAST_ARG_MUST_BE_NULL
74 static int one_of(const char *term, ...)
75 {
76         int res = 0;
77         va_list matches;
78         const char *match;
79
80         va_start(matches, term);
81         while (!res && (match = va_arg(matches, const char *)))
82                 res = !strcmp(term, match);
83         va_end(matches);
84
85         return res;
86 }
87
88 /*
89  * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
90  * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
91  * that indicate special success.
92  */
93
94 static int is_bisect_success(enum bisect_error res)
95 {
96         return !res ||
97                 res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
98                 res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
99 }
100
101 static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
102 {
103         FILE *fp = NULL;
104         int res = 0;
105
106         if (strcmp(mode, "w") && strcmp(mode, "a"))
107                 BUG("write-in-file does not support '%s' mode", mode);
108         fp = fopen(path, mode);
109         if (!fp)
110                 return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
111         res = vfprintf(fp, format, args);
112
113         if (res < 0) {
114                 int saved_errno = errno;
115                 fclose(fp);
116                 errno = saved_errno;
117                 return error_errno(_("could not write to file '%s'"), path);
118         }
119
120         return fclose(fp);
121 }
122
123 static int write_to_file(const char *path, const char *format, ...)
124 {
125         int res;
126         va_list args;
127
128         va_start(args, format);
129         res = write_in_file(path, "w", format, args);
130         va_end(args);
131
132         return res;
133 }
134
135 static int append_to_file(const char *path, const char *format, ...)
136 {
137         int res;
138         va_list args;
139
140         va_start(args, format);
141         res = write_in_file(path, "a", format, args);
142         va_end(args);
143
144         return res;
145 }
146
147 static int check_term_format(const char *term, const char *orig_term)
148 {
149         int res;
150         char *new_term = xstrfmt("refs/bisect/%s", term);
151
152         res = check_refname_format(new_term, 0);
153         free(new_term);
154
155         if (res)
156                 return error(_("'%s' is not a valid term"), term);
157
158         if (one_of(term, "help", "start", "skip", "next", "reset",
159                         "visualize", "view", "replay", "log", "run", "terms", NULL))
160                 return error(_("can't use the builtin command '%s' as a term"), term);
161
162         /*
163          * In theory, nothing prevents swapping completely good and bad,
164          * but this situation could be confusing and hasn't been tested
165          * enough. Forbid it for now.
166          */
167
168         if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
169                  (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
170                 return error(_("can't change the meaning of the term '%s'"), term);
171
172         return 0;
173 }
174
175 static int write_terms(const char *bad, const char *good)
176 {
177         int res;
178
179         if (!strcmp(bad, good))
180                 return error(_("please use two different terms"));
181
182         if (check_term_format(bad, "bad") || check_term_format(good, "good"))
183                 return -1;
184
185         res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
186
187         return res;
188 }
189
190 static int is_expected_rev(const char *expected_hex)
191 {
192         struct strbuf actual_hex = STRBUF_INIT;
193         int res = 0;
194         if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
195                 strbuf_trim(&actual_hex);
196                 res = !strcmp(actual_hex.buf, expected_hex);
197         }
198         strbuf_release(&actual_hex);
199         return res;
200 }
201
202 static void check_expected_revs(const char **revs, int rev_nr)
203 {
204         int i;
205
206         for (i = 0; i < rev_nr; i++) {
207                 if (!is_expected_rev(revs[i])) {
208                         unlink_or_warn(git_path_bisect_ancestors_ok());
209                         unlink_or_warn(git_path_bisect_expected_rev());
210                 }
211         }
212 }
213
214 static int bisect_reset(const char *commit)
215 {
216         struct strbuf branch = STRBUF_INIT;
217
218         if (!commit) {
219                 if (strbuf_read_file(&branch, git_path_bisect_start(), 0) < 1) {
220                         printf(_("We are not bisecting.\n"));
221                         return 0;
222                 }
223                 strbuf_rtrim(&branch);
224         } else {
225                 struct object_id oid;
226
227                 if (get_oid_commit(commit, &oid))
228                         return error(_("'%s' is not a valid commit"), commit);
229                 strbuf_addstr(&branch, commit);
230         }
231
232         if (!ref_exists("BISECT_HEAD")) {
233                 struct strvec argv = STRVEC_INIT;
234
235                 strvec_pushl(&argv, "checkout", branch.buf, "--", NULL);
236                 if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
237                         error(_("could not check out original"
238                                 " HEAD '%s'. Try 'git bisect"
239                                 " reset <commit>'."), branch.buf);
240                         strbuf_release(&branch);
241                         strvec_clear(&argv);
242                         return -1;
243                 }
244                 strvec_clear(&argv);
245         }
246
247         strbuf_release(&branch);
248         return bisect_clean_state();
249 }
250
251 static void log_commit(FILE *fp, char *fmt, const char *state,
252                        struct commit *commit)
253 {
254         struct pretty_print_context pp = {0};
255         struct strbuf commit_msg = STRBUF_INIT;
256         char *label = xstrfmt(fmt, state);
257
258         format_commit_message(commit, "%s", &commit_msg, &pp);
259
260         fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
261                 commit_msg.buf);
262
263         strbuf_release(&commit_msg);
264         free(label);
265 }
266
267 static int bisect_write(const char *state, const char *rev,
268                         const struct bisect_terms *terms, int nolog)
269 {
270         struct strbuf tag = STRBUF_INIT;
271         struct object_id oid;
272         struct commit *commit;
273         FILE *fp = NULL;
274         int res = 0;
275
276         if (!strcmp(state, terms->term_bad)) {
277                 strbuf_addf(&tag, "refs/bisect/%s", state);
278         } else if (one_of(state, terms->term_good, "skip", NULL)) {
279                 strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
280         } else {
281                 res = error(_("Bad bisect_write argument: %s"), state);
282                 goto finish;
283         }
284
285         if (get_oid(rev, &oid)) {
286                 res = error(_("couldn't get the oid of the rev '%s'"), rev);
287                 goto finish;
288         }
289
290         if (update_ref(NULL, tag.buf, &oid, NULL, 0,
291                        UPDATE_REFS_MSG_ON_ERR)) {
292                 res = -1;
293                 goto finish;
294         }
295
296         fp = fopen(git_path_bisect_log(), "a");
297         if (!fp) {
298                 res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
299                 goto finish;
300         }
301
302         commit = lookup_commit_reference(the_repository, &oid);
303         log_commit(fp, "%s", state, commit);
304
305         if (!nolog)
306                 fprintf(fp, "git bisect %s %s\n", state, rev);
307
308 finish:
309         if (fp)
310                 fclose(fp);
311         strbuf_release(&tag);
312         return res;
313 }
314
315 static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
316 {
317         int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
318
319         if (one_of(cmd, "skip", "start", "terms", NULL))
320                 return 0;
321
322         if (has_term_file && strcmp(cmd, terms->term_bad) &&
323             strcmp(cmd, terms->term_good))
324                 return error(_("Invalid command: you're currently in a "
325                                 "%s/%s bisect"), terms->term_bad,
326                                 terms->term_good);
327
328         if (!has_term_file) {
329                 if (one_of(cmd, "bad", "good", NULL)) {
330                         set_terms(terms, "bad", "good");
331                         return write_terms(terms->term_bad, terms->term_good);
332                 }
333                 if (one_of(cmd, "new", "old", NULL)) {
334                         set_terms(terms, "new", "old");
335                         return write_terms(terms->term_bad, terms->term_good);
336                 }
337         }
338
339         return 0;
340 }
341
342 static int mark_good(const char *refname, const struct object_id *oid,
343                      int flag, void *cb_data)
344 {
345         int *m_good = (int *)cb_data;
346         *m_good = 0;
347         return 1;
348 }
349
350 static const char need_bad_and_good_revision_warning[] =
351         N_("You need to give me at least one %s and %s revision.\n"
352            "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
353
354 static const char need_bisect_start_warning[] =
355         N_("You need to start by \"git bisect start\".\n"
356            "You then need to give me at least one %s and %s revision.\n"
357            "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
358
359 static int decide_next(const struct bisect_terms *terms,
360                        const char *current_term, int missing_good,
361                        int missing_bad)
362 {
363         if (!missing_good && !missing_bad)
364                 return 0;
365         if (!current_term)
366                 return -1;
367
368         if (missing_good && !missing_bad &&
369             !strcmp(current_term, terms->term_good)) {
370                 char *yesno;
371                 /*
372                  * have bad (or new) but not good (or old). We could bisect
373                  * although this is less optimum.
374                  */
375                 warning(_("bisecting only with a %s commit"), terms->term_bad);
376                 if (!isatty(0))
377                         return 0;
378                 /*
379                  * TRANSLATORS: Make sure to include [Y] and [n] in your
380                  * translation. The program will only accept English input
381                  * at this point.
382                  */
383                 yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
384                 if (starts_with(yesno, "N") || starts_with(yesno, "n"))
385                         return -1;
386                 return 0;
387         }
388
389         if (!is_empty_or_missing_file(git_path_bisect_start()))
390                 return error(_(need_bad_and_good_revision_warning),
391                              vocab_bad, vocab_good, vocab_bad, vocab_good);
392         else
393                 return error(_(need_bisect_start_warning),
394                              vocab_good, vocab_bad, vocab_good, vocab_bad);
395 }
396
397 static int bisect_next_check(const struct bisect_terms *terms,
398                              const char *current_term)
399 {
400         int missing_good = 1, missing_bad = 1;
401         char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
402         char *good_glob = xstrfmt("%s-*", terms->term_good);
403
404         if (ref_exists(bad_ref))
405                 missing_bad = 0;
406
407         for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
408                              (void *) &missing_good);
409
410         free(good_glob);
411         free(bad_ref);
412
413         return decide_next(terms, current_term, missing_good, missing_bad);
414 }
415
416 static int get_terms(struct bisect_terms *terms)
417 {
418         struct strbuf str = STRBUF_INIT;
419         FILE *fp = NULL;
420         int res = 0;
421
422         fp = fopen(git_path_bisect_terms(), "r");
423         if (!fp) {
424                 res = -1;
425                 goto finish;
426         }
427
428         free_terms(terms);
429         strbuf_getline_lf(&str, fp);
430         terms->term_bad = strbuf_detach(&str, NULL);
431         strbuf_getline_lf(&str, fp);
432         terms->term_good = strbuf_detach(&str, NULL);
433
434 finish:
435         if (fp)
436                 fclose(fp);
437         strbuf_release(&str);
438         return res;
439 }
440
441 static int bisect_terms(struct bisect_terms *terms, const char *option)
442 {
443         if (get_terms(terms))
444                 return error(_("no terms defined"));
445
446         if (option == NULL) {
447                 printf(_("Your current terms are %s for the old state\n"
448                          "and %s for the new state.\n"),
449                        terms->term_good, terms->term_bad);
450                 return 0;
451         }
452         if (one_of(option, "--term-good", "--term-old", NULL))
453                 printf("%s\n", terms->term_good);
454         else if (one_of(option, "--term-bad", "--term-new", NULL))
455                 printf("%s\n", terms->term_bad);
456         else
457                 return error(_("invalid argument %s for 'git bisect terms'.\n"
458                                "Supported options are: "
459                                "--term-good|--term-old and "
460                                "--term-bad|--term-new."), option);
461
462         return 0;
463 }
464
465 static int bisect_append_log_quoted(const char **argv)
466 {
467         int res = 0;
468         FILE *fp = fopen(git_path_bisect_log(), "a");
469         struct strbuf orig_args = STRBUF_INIT;
470
471         if (!fp)
472                 return -1;
473
474         if (fprintf(fp, "git bisect start") < 1) {
475                 res = -1;
476                 goto finish;
477         }
478
479         sq_quote_argv(&orig_args, argv);
480         if (fprintf(fp, "%s\n", orig_args.buf) < 1)
481                 res = -1;
482
483 finish:
484         fclose(fp);
485         strbuf_release(&orig_args);
486         return res;
487 }
488
489 static int add_bisect_ref(const char *refname, const struct object_id *oid,
490                           int flags, void *cb)
491 {
492         struct add_bisect_ref_data *data = cb;
493
494         add_pending_oid(data->revs, refname, oid, data->object_flags);
495
496         return 0;
497 }
498
499 static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
500 {
501         int res = 0;
502         struct add_bisect_ref_data cb = { revs };
503         char *good = xstrfmt("%s-*", terms->term_good);
504
505         /*
506          * We cannot use terms->term_bad directly in
507          * for_each_glob_ref_in() and we have to append a '*' to it,
508          * otherwise for_each_glob_ref_in() will append '/' and '*'.
509          */
510         char *bad = xstrfmt("%s*", terms->term_bad);
511
512         /*
513          * It is important to reset the flags used by revision walks
514          * as the previous call to bisect_next_all() in turn
515          * sets up a revision walk.
516          */
517         reset_revision_walk();
518         init_revisions(revs, NULL);
519         setup_revisions(0, NULL, revs, NULL);
520         for_each_glob_ref_in(add_bisect_ref, bad, "refs/bisect/", &cb);
521         cb.object_flags = UNINTERESTING;
522         for_each_glob_ref_in(add_bisect_ref, good, "refs/bisect/", &cb);
523         if (prepare_revision_walk(revs))
524                 res = error(_("revision walk setup failed\n"));
525
526         free(good);
527         free(bad);
528         return res;
529 }
530
531 static int bisect_skipped_commits(struct bisect_terms *terms)
532 {
533         int res;
534         FILE *fp = NULL;
535         struct rev_info revs;
536         struct commit *commit;
537         struct pretty_print_context pp = {0};
538         struct strbuf commit_name = STRBUF_INIT;
539
540         res = prepare_revs(terms, &revs);
541         if (res)
542                 return res;
543
544         fp = fopen(git_path_bisect_log(), "a");
545         if (!fp)
546                 return error_errno(_("could not open '%s' for appending"),
547                                   git_path_bisect_log());
548
549         if (fprintf(fp, "# only skipped commits left to test\n") < 0)
550                 return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
551
552         while ((commit = get_revision(&revs)) != NULL) {
553                 strbuf_reset(&commit_name);
554                 format_commit_message(commit, "%s",
555                                       &commit_name, &pp);
556                 fprintf(fp, "# possible first %s commit: [%s] %s\n",
557                         terms->term_bad, oid_to_hex(&commit->object.oid),
558                         commit_name.buf);
559         }
560
561         /*
562          * Reset the flags used by revision walks in case
563          * there is another revision walk after this one.
564          */
565         reset_revision_walk();
566
567         strbuf_release(&commit_name);
568         fclose(fp);
569         return 0;
570 }
571
572 static int bisect_successful(struct bisect_terms *terms)
573 {
574         struct object_id oid;
575         struct commit *commit;
576         struct pretty_print_context pp = {0};
577         struct strbuf commit_name = STRBUF_INIT;
578         char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
579         int res;
580
581         read_ref(bad_ref, &oid);
582         commit = lookup_commit_reference_by_name(bad_ref);
583         format_commit_message(commit, "%s", &commit_name, &pp);
584
585         res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
586                             terms->term_bad, oid_to_hex(&commit->object.oid),
587                             commit_name.buf);
588
589         strbuf_release(&commit_name);
590         free(bad_ref);
591         return res;
592 }
593
594 static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
595 {
596         enum bisect_error res;
597
598         if (bisect_autostart(terms))
599                 return BISECT_FAILED;
600
601         if (bisect_next_check(terms, terms->term_good))
602                 return BISECT_FAILED;
603
604         /* Perform all bisection computation */
605         res = bisect_next_all(the_repository, prefix);
606
607         if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
608                 res = bisect_successful(terms);
609                 return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
610         } else if (res == BISECT_ONLY_SKIPPED_LEFT) {
611                 res = bisect_skipped_commits(terms);
612                 return res ? res : BISECT_ONLY_SKIPPED_LEFT;
613         }
614         return res;
615 }
616
617 static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
618 {
619         if (bisect_next_check(terms, NULL))
620                 return BISECT_OK;
621
622         return bisect_next(terms, prefix);
623 }
624
625 static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
626 {
627         int no_checkout = 0;
628         int first_parent_only = 0;
629         int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
630         int flags, pathspec_pos;
631         enum bisect_error res = BISECT_OK;
632         struct string_list revs = STRING_LIST_INIT_DUP;
633         struct string_list states = STRING_LIST_INIT_DUP;
634         struct strbuf start_head = STRBUF_INIT;
635         struct strbuf bisect_names = STRBUF_INIT;
636         struct object_id head_oid;
637         struct object_id oid;
638         const char *head;
639
640         if (is_bare_repository())
641                 no_checkout = 1;
642
643         /*
644          * Check for one bad and then some good revisions
645          */
646         for (i = 0; i < argc; i++) {
647                 if (!strcmp(argv[i], "--")) {
648                         has_double_dash = 1;
649                         break;
650                 }
651         }
652
653         for (i = 0; i < argc; i++) {
654                 const char *arg = argv[i];
655                 if (!strcmp(argv[i], "--")) {
656                         break;
657                 } else if (!strcmp(arg, "--no-checkout")) {
658                         no_checkout = 1;
659                 } else if (!strcmp(arg, "--first-parent")) {
660                         first_parent_only = 1;
661                 } else if (!strcmp(arg, "--term-good") ||
662                          !strcmp(arg, "--term-old")) {
663                         i++;
664                         if (argc <= i)
665                                 return error(_("'' is not a valid term"));
666                         must_write_terms = 1;
667                         free((void *) terms->term_good);
668                         terms->term_good = xstrdup(argv[i]);
669                 } else if (skip_prefix(arg, "--term-good=", &arg) ||
670                            skip_prefix(arg, "--term-old=", &arg)) {
671                         must_write_terms = 1;
672                         free((void *) terms->term_good);
673                         terms->term_good = xstrdup(arg);
674                 } else if (!strcmp(arg, "--term-bad") ||
675                          !strcmp(arg, "--term-new")) {
676                         i++;
677                         if (argc <= i)
678                                 return error(_("'' is not a valid term"));
679                         must_write_terms = 1;
680                         free((void *) terms->term_bad);
681                         terms->term_bad = xstrdup(argv[i]);
682                 } else if (skip_prefix(arg, "--term-bad=", &arg) ||
683                            skip_prefix(arg, "--term-new=", &arg)) {
684                         must_write_terms = 1;
685                         free((void *) terms->term_bad);
686                         terms->term_bad = xstrdup(arg);
687                 } else if (starts_with(arg, "--")) {
688                         return error(_("unrecognized option: '%s'"), arg);
689                 } else {
690                         char *commit_id = xstrfmt("%s^{commit}", arg);
691                         if (get_oid(commit_id, &oid) && has_double_dash)
692                                 die(_("'%s' does not appear to be a valid "
693                                       "revision"), arg);
694
695                         string_list_append(&revs, oid_to_hex(&oid));
696                         free(commit_id);
697                 }
698         }
699         pathspec_pos = i;
700
701         /*
702          * The user ran "git bisect start <sha1> <sha1>", hence did not
703          * explicitly specify the terms, but we are already starting to
704          * set references named with the default terms, and won't be able
705          * to change afterwards.
706          */
707         if (revs.nr)
708                 must_write_terms = 1;
709         for (i = 0; i < revs.nr; i++) {
710                 if (bad_seen) {
711                         string_list_append(&states, terms->term_good);
712                 } else {
713                         bad_seen = 1;
714                         string_list_append(&states, terms->term_bad);
715                 }
716         }
717
718         /*
719          * Verify HEAD
720          */
721         head = resolve_ref_unsafe("HEAD", 0, &head_oid, &flags);
722         if (!head)
723                 if (get_oid("HEAD", &head_oid))
724                         return error(_("bad HEAD - I need a HEAD"));
725
726         /*
727          * Check if we are bisecting
728          */
729         if (!is_empty_or_missing_file(git_path_bisect_start())) {
730                 /* Reset to the rev from where we started */
731                 strbuf_read_file(&start_head, git_path_bisect_start(), 0);
732                 strbuf_trim(&start_head);
733                 if (!no_checkout) {
734                         struct strvec argv = STRVEC_INIT;
735
736                         strvec_pushl(&argv, "checkout", start_head.buf,
737                                      "--", NULL);
738                         if (run_command_v_opt(argv.v, RUN_GIT_CMD)) {
739                                 res = error(_("checking out '%s' failed."
740                                                  " Try 'git bisect start "
741                                                  "<valid-branch>'."),
742                                                start_head.buf);
743                                 goto finish;
744                         }
745                 }
746         } else {
747                 /* Get the rev from where we start. */
748                 if (!get_oid(head, &head_oid) &&
749                     !starts_with(head, "refs/heads/")) {
750                         strbuf_reset(&start_head);
751                         strbuf_addstr(&start_head, oid_to_hex(&head_oid));
752                 } else if (!get_oid(head, &head_oid) &&
753                            skip_prefix(head, "refs/heads/", &head)) {
754                         /*
755                          * This error message should only be triggered by
756                          * cogito usage, and cogito users should understand
757                          * it relates to cg-seek.
758                          */
759                         if (!is_empty_or_missing_file(git_path_head_name()))
760                                 return error(_("won't bisect on cg-seek'ed tree"));
761                         strbuf_addstr(&start_head, head);
762                 } else {
763                         return error(_("bad HEAD - strange symbolic ref"));
764                 }
765         }
766
767         /*
768          * Get rid of any old bisect state.
769          */
770         if (bisect_clean_state())
771                 return BISECT_FAILED;
772
773         /*
774          * Write new start state
775          */
776         write_file(git_path_bisect_start(), "%s\n", start_head.buf);
777
778         if (first_parent_only)
779                 write_file(git_path_bisect_first_parent(), "\n");
780
781         if (no_checkout) {
782                 if (get_oid(start_head.buf, &oid) < 0) {
783                         res = error(_("invalid ref: '%s'"), start_head.buf);
784                         goto finish;
785                 }
786                 if (update_ref(NULL, "BISECT_HEAD", &oid, NULL, 0,
787                                UPDATE_REFS_MSG_ON_ERR)) {
788                         res = BISECT_FAILED;
789                         goto finish;
790                 }
791         }
792
793         if (pathspec_pos < argc - 1)
794                 sq_quote_argv(&bisect_names, argv + pathspec_pos);
795         write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
796
797         for (i = 0; i < states.nr; i++)
798                 if (bisect_write(states.items[i].string,
799                                  revs.items[i].string, terms, 1)) {
800                         res = BISECT_FAILED;
801                         goto finish;
802                 }
803
804         if (must_write_terms && write_terms(terms->term_bad,
805                                             terms->term_good)) {
806                 res = BISECT_FAILED;
807                 goto finish;
808         }
809
810         res = bisect_append_log_quoted(argv);
811         if (res)
812                 res = BISECT_FAILED;
813
814 finish:
815         string_list_clear(&revs, 0);
816         string_list_clear(&states, 0);
817         strbuf_release(&start_head);
818         strbuf_release(&bisect_names);
819         if (res)
820                 return res;
821
822         res = bisect_auto_next(terms, NULL);
823         if (!is_bisect_success(res))
824                 bisect_clean_state();
825         return res;
826 }
827
828 static inline int file_is_not_empty(const char *path)
829 {
830         return !is_empty_or_missing_file(path);
831 }
832
833 static int bisect_autostart(struct bisect_terms *terms)
834 {
835         int res;
836         const char *yesno;
837
838         if (file_is_not_empty(git_path_bisect_start()))
839                 return 0;
840
841         fprintf_ln(stderr, _("You need to start by \"git bisect "
842                           "start\"\n"));
843
844         if (!isatty(STDIN_FILENO))
845                 return -1;
846
847         /*
848          * TRANSLATORS: Make sure to include [Y] and [n] in your
849          * translation. The program will only accept English input
850          * at this point.
851          */
852         yesno = git_prompt(_("Do you want me to do it for you "
853                              "[Y/n]? "), PROMPT_ECHO);
854         res = tolower(*yesno) == 'n' ?
855                 -1 : bisect_start(terms, empty_strvec, 0);
856
857         return res;
858 }
859
860 static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
861                                       int argc)
862 {
863         const char *state;
864         int i, verify_expected = 1;
865         struct object_id oid, expected;
866         struct strbuf buf = STRBUF_INIT;
867         struct oid_array revs = OID_ARRAY_INIT;
868
869         if (!argc)
870                 return error(_("Please call `--bisect-state` with at least one argument"));
871
872         if (bisect_autostart(terms))
873                 return BISECT_FAILED;
874
875         state = argv[0];
876         if (check_and_set_terms(terms, state) ||
877             !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
878                 return BISECT_FAILED;
879
880         argv++;
881         argc--;
882         if (argc > 1 && !strcmp(state, terms->term_bad))
883                 return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
884
885         if (argc == 0) {
886                 const char *head = "BISECT_HEAD";
887                 enum get_oid_result res_head = get_oid(head, &oid);
888
889                 if (res_head == MISSING_OBJECT) {
890                         head = "HEAD";
891                         res_head = get_oid(head, &oid);
892                 }
893
894                 if (res_head)
895                         error(_("Bad rev input: %s"), head);
896                 oid_array_append(&revs, &oid);
897         }
898
899         /*
900          * All input revs must be checked before executing bisect_write()
901          * to discard junk revs.
902          */
903
904         for (; argc; argc--, argv++) {
905                 if (get_oid(*argv, &oid)){
906                         error(_("Bad rev input: %s"), *argv);
907                         oid_array_clear(&revs);
908                         return BISECT_FAILED;
909                 }
910                 oid_array_append(&revs, &oid);
911         }
912
913         if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz ||
914             get_oid_hex(buf.buf, &expected) < 0)
915                 verify_expected = 0; /* Ignore invalid file contents */
916         strbuf_release(&buf);
917
918         for (i = 0; i < revs.nr; i++) {
919                 if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
920                         oid_array_clear(&revs);
921                         return BISECT_FAILED;
922                 }
923                 if (verify_expected && !oideq(&revs.oid[i], &expected)) {
924                         unlink_or_warn(git_path_bisect_ancestors_ok());
925                         unlink_or_warn(git_path_bisect_expected_rev());
926                         verify_expected = 0;
927                 }
928         }
929
930         oid_array_clear(&revs);
931         return bisect_auto_next(terms, NULL);
932 }
933
934 int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
935 {
936         enum {
937                 WRITE_TERMS = 1,
938                 CHECK_EXPECTED_REVS,
939                 BISECT_RESET,
940                 BISECT_WRITE,
941                 CHECK_AND_SET_TERMS,
942                 BISECT_NEXT_CHECK,
943                 BISECT_TERMS,
944                 BISECT_START,
945                 BISECT_AUTOSTART,
946                 BISECT_NEXT,
947                 BISECT_AUTO_NEXT,
948                 BISECT_STATE
949         } cmdmode = 0;
950         int res = 0, nolog = 0;
951         struct option options[] = {
952                 OPT_CMDMODE(0, "write-terms", &cmdmode,
953                          N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
954                 OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
955                          N_("check for expected revs"), CHECK_EXPECTED_REVS),
956                 OPT_CMDMODE(0, "bisect-reset", &cmdmode,
957                          N_("reset the bisection state"), BISECT_RESET),
958                 OPT_CMDMODE(0, "bisect-write", &cmdmode,
959                          N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
960                 OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
961                          N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
962                 OPT_CMDMODE(0, "bisect-next-check", &cmdmode,
963                          N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK),
964                 OPT_CMDMODE(0, "bisect-terms", &cmdmode,
965                          N_("print out the bisect terms"), BISECT_TERMS),
966                 OPT_CMDMODE(0, "bisect-start", &cmdmode,
967                          N_("start the bisect session"), BISECT_START),
968                 OPT_CMDMODE(0, "bisect-next", &cmdmode,
969                          N_("find the next bisection commit"), BISECT_NEXT),
970                 OPT_CMDMODE(0, "bisect-auto-next", &cmdmode,
971                          N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT),
972                 OPT_CMDMODE(0, "bisect-autostart", &cmdmode,
973                          N_("start the bisection if it has not yet been started"), BISECT_AUTOSTART),
974                 OPT_CMDMODE(0, "bisect-state", &cmdmode,
975                          N_("mark the state of ref (or refs)"), BISECT_STATE),
976                 OPT_BOOL(0, "no-log", &nolog,
977                          N_("no log for BISECT_WRITE")),
978                 OPT_END()
979         };
980         struct bisect_terms terms = { .term_good = NULL, .term_bad = NULL };
981
982         argc = parse_options(argc, argv, prefix, options,
983                              git_bisect_helper_usage,
984                              PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_UNKNOWN);
985
986         if (!cmdmode)
987                 usage_with_options(git_bisect_helper_usage, options);
988
989         switch (cmdmode) {
990         case WRITE_TERMS:
991                 if (argc != 2)
992                         return error(_("--write-terms requires two arguments"));
993                 return write_terms(argv[0], argv[1]);
994         case CHECK_EXPECTED_REVS:
995                 check_expected_revs(argv, argc);
996                 return 0;
997         case BISECT_RESET:
998                 if (argc > 1)
999                         return error(_("--bisect-reset requires either no argument or a commit"));
1000                 return !!bisect_reset(argc ? argv[0] : NULL);
1001         case BISECT_WRITE:
1002                 if (argc != 4 && argc != 5)
1003                         return error(_("--bisect-write requires either 4 or 5 arguments"));
1004                 set_terms(&terms, argv[3], argv[2]);
1005                 res = bisect_write(argv[0], argv[1], &terms, nolog);
1006                 break;
1007         case CHECK_AND_SET_TERMS:
1008                 if (argc != 3)
1009                         return error(_("--check-and-set-terms requires 3 arguments"));
1010                 set_terms(&terms, argv[2], argv[1]);
1011                 res = check_and_set_terms(&terms, argv[0]);
1012                 break;
1013         case BISECT_NEXT_CHECK:
1014                 if (argc != 2 && argc != 3)
1015                         return error(_("--bisect-next-check requires 2 or 3 arguments"));
1016                 set_terms(&terms, argv[1], argv[0]);
1017                 res = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);
1018                 break;
1019         case BISECT_TERMS:
1020                 if (argc > 1)
1021                         return error(_("--bisect-terms requires 0 or 1 argument"));
1022                 res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
1023                 break;
1024         case BISECT_START:
1025                 set_terms(&terms, "bad", "good");
1026                 res = bisect_start(&terms, argv, argc);
1027                 break;
1028         case BISECT_NEXT:
1029                 if (argc)
1030                         return error(_("--bisect-next requires 0 arguments"));
1031                 get_terms(&terms);
1032                 res = bisect_next(&terms, prefix);
1033                 break;
1034         case BISECT_AUTO_NEXT:
1035                 if (argc)
1036                         return error(_("--bisect-auto-next requires 0 arguments"));
1037                 get_terms(&terms);
1038                 res = bisect_auto_next(&terms, prefix);
1039                 break;
1040         case BISECT_AUTOSTART:
1041                 if (argc)
1042                         return error(_("--bisect-autostart does not accept arguments"));
1043                 set_terms(&terms, "bad", "good");
1044                 res = bisect_autostart(&terms);
1045                 break;
1046         case BISECT_STATE:
1047                 set_terms(&terms, "bad", "good");
1048                 get_terms(&terms);
1049                 res = bisect_state(&terms, argv, argc);
1050                 break;
1051         default:
1052                 BUG("unknown subcommand %d", cmdmode);
1053         }
1054         free_terms(&terms);
1055
1056         /*
1057          * Handle early success
1058          * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
1059          */
1060         if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
1061                 res = BISECT_OK;
1062
1063         return -res;
1064 }