]>
Commit | Line | Data |
---|---|---|
1bf072e3 CC |
1 | #include "builtin.h" |
2 | #include "cache.h" | |
3 | #include "parse-options.h" | |
4 | #include "bisect.h" | |
4ba1e5c4 | 5 | #include "refs.h" |
1bf072e3 | 6 | |
ecb3f373 PB |
7 | static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS") |
8 | ||
1bf072e3 | 9 | static const char * const git_bisect_helper_usage[] = { |
9e7bbe2d | 10 | N_("git bisect--helper --next-all [--no-checkout]"), |
ecb3f373 | 11 | N_("git bisect--helper --write-terms <bad_term> <good_term>"), |
fb71a329 | 12 | N_("git bisect--helper --bisect-clean-state"), |
1bf072e3 CC |
13 | NULL |
14 | }; | |
15 | ||
4ba1e5c4 PB |
16 | /* |
17 | * Check whether the string `term` belongs to the set of strings | |
18 | * included in the variable arguments. | |
19 | */ | |
20 | LAST_ARG_MUST_BE_NULL | |
21 | static int one_of(const char *term, ...) | |
22 | { | |
23 | int res = 0; | |
24 | va_list matches; | |
25 | const char *match; | |
26 | ||
27 | va_start(matches, term); | |
28 | while (!res && (match = va_arg(matches, const char *))) | |
29 | res = !strcmp(term, match); | |
30 | va_end(matches); | |
31 | ||
32 | return res; | |
33 | } | |
34 | ||
35 | static int check_term_format(const char *term, const char *orig_term) | |
36 | { | |
37 | int res; | |
38 | char *new_term = xstrfmt("refs/bisect/%s", term); | |
39 | ||
40 | res = check_refname_format(new_term, 0); | |
41 | free(new_term); | |
42 | ||
43 | if (res) | |
44 | return error(_("'%s' is not a valid term"), term); | |
45 | ||
46 | if (one_of(term, "help", "start", "skip", "next", "reset", | |
47 | "visualize", "replay", "log", "run", "terms", NULL)) | |
48 | return error(_("can't use the builtin command '%s' as a term"), term); | |
49 | ||
50 | /* | |
51 | * In theory, nothing prevents swapping completely good and bad, | |
52 | * but this situation could be confusing and hasn't been tested | |
53 | * enough. Forbid it for now. | |
54 | */ | |
55 | ||
56 | if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) || | |
57 | (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL))) | |
58 | return error(_("can't change the meaning of the term '%s'"), term); | |
59 | ||
60 | return 0; | |
61 | } | |
62 | ||
ecb3f373 PB |
63 | static int write_terms(const char *bad, const char *good) |
64 | { | |
65 | FILE *fp = NULL; | |
66 | int res; | |
67 | ||
68 | if (!strcmp(bad, good)) | |
69 | return error(_("please use two different terms")); | |
70 | ||
71 | if (check_term_format(bad, "bad") || check_term_format(good, "good")) | |
72 | return -1; | |
73 | ||
74 | fp = fopen(git_path_bisect_terms(), "w"); | |
75 | if (!fp) | |
76 | return error_errno(_("could not open the file BISECT_TERMS")); | |
77 | ||
78 | res = fprintf(fp, "%s\n%s\n", bad, good); | |
79 | res |= fclose(fp); | |
80 | return (res < 0) ? -1 : 0; | |
81 | } | |
82 | ||
1bf072e3 CC |
83 | int cmd_bisect__helper(int argc, const char **argv, const char *prefix) |
84 | { | |
4ba1e5c4 PB |
85 | enum { |
86 | NEXT_ALL = 1, | |
fb71a329 PB |
87 | WRITE_TERMS, |
88 | BISECT_CLEAN_STATE | |
4ba1e5c4 | 89 | } cmdmode = 0; |
fee92fc1 | 90 | int no_checkout = 0; |
1bf072e3 | 91 | struct option options[] = { |
9e1c84df PB |
92 | OPT_CMDMODE(0, "next-all", &cmdmode, |
93 | N_("perform 'git bisect next'"), NEXT_ALL), | |
ecb3f373 PB |
94 | OPT_CMDMODE(0, "write-terms", &cmdmode, |
95 | N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS), | |
fb71a329 PB |
96 | OPT_CMDMODE(0, "bisect-clean-state", &cmdmode, |
97 | N_("cleanup the bisection state"), BISECT_CLEAN_STATE), | |
d5d09d47 SB |
98 | OPT_BOOL(0, "no-checkout", &no_checkout, |
99 | N_("update BISECT_HEAD instead of checking out the current commit")), | |
1bf072e3 CC |
100 | OPT_END() |
101 | }; | |
102 | ||
37782920 SB |
103 | argc = parse_options(argc, argv, prefix, options, |
104 | git_bisect_helper_usage, 0); | |
1bf072e3 | 105 | |
9e1c84df | 106 | if (!cmdmode) |
1bf072e3 CC |
107 | usage_with_options(git_bisect_helper_usage, options); |
108 | ||
9e1c84df PB |
109 | switch (cmdmode) { |
110 | case NEXT_ALL: | |
111 | return bisect_next_all(prefix, no_checkout); | |
ecb3f373 | 112 | case WRITE_TERMS: |
4ba1e5c4 | 113 | if (argc != 2) |
ecb3f373 PB |
114 | return error(_("--write-terms requires two arguments")); |
115 | return write_terms(argv[0], argv[1]); | |
fb71a329 PB |
116 | case BISECT_CLEAN_STATE: |
117 | if (argc != 0) | |
118 | return error(_("--bisect-clean-state requires no arguments")); | |
119 | return bisect_clean_state(); | |
9e1c84df PB |
120 | default: |
121 | return error("BUG: unknown subcommand '%d'", cmdmode); | |
122 | } | |
123 | return 0; | |
1bf072e3 | 124 | } |