diff options
-rw-r--r-- | builtin/bisect--helper.c | 183 | ||||
-rwxr-xr-x | git-bisect.sh | 58 |
2 files changed, 155 insertions, 86 deletions
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index 709eb713a3..d69e13335d 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c @@ -21,16 +21,15 @@ static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT") static const char * const git_bisect_helper_usage[] = { N_("git bisect--helper --bisect-reset [<commit>]"), - N_("git bisect--helper --bisect-write [--no-log] <state> <revision> <good_term> <bad_term>"), - N_("git bisect--helper --bisect-check-and-set-terms <command> <good_term> <bad_term>"), N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"), N_("git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]"), N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]" " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"), N_("git bisect--helper --bisect-next"), - N_("git bisect--helper --bisect-auto-next"), N_("git bisect--helper --bisect-state (bad|new) [<rev>]"), N_("git bisect--helper --bisect-state (good|old) [<rev>...]"), + N_("git bisect--helper --bisect-replay <filename>"), + N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"), NULL }; @@ -904,28 +903,148 @@ static enum bisect_error bisect_state(struct bisect_terms *terms, const char **a return bisect_auto_next(terms, NULL); } +static enum bisect_error bisect_log(void) +{ + int fd, status; + const char* filename = git_path_bisect_log(); + + if (is_empty_or_missing_file(filename)) + return error(_("We are not bisecting.")); + + fd = open(filename, O_RDONLY); + if (fd < 0) + return BISECT_FAILED; + + status = copy_fd(fd, STDOUT_FILENO); + close(fd); + return status ? BISECT_FAILED : BISECT_OK; +} + +static int process_replay_line(struct bisect_terms *terms, struct strbuf *line) +{ + const char *p = line->buf + strspn(line->buf, " \t"); + char *word_end, *rev; + + if ((!skip_prefix(p, "git bisect", &p) && + !skip_prefix(p, "git-bisect", &p)) || !isspace(*p)) + return 0; + p += strspn(p, " \t"); + + word_end = (char *)p + strcspn(p, " \t"); + rev = word_end + strspn(word_end, " \t"); + *word_end = '\0'; /* NUL-terminate the word */ + + get_terms(terms); + if (check_and_set_terms(terms, p)) + return -1; + + if (!strcmp(p, "start")) { + struct strvec argv = STRVEC_INIT; + int res; + sq_dequote_to_strvec(rev, &argv); + res = bisect_start(terms, argv.v, argv.nr); + strvec_clear(&argv); + return res; + } + + if (one_of(p, terms->term_good, + terms->term_bad, "skip", NULL)) + return bisect_write(p, rev, terms, 0); + + if (!strcmp(p, "terms")) { + struct strvec argv = STRVEC_INIT; + int res; + sq_dequote_to_strvec(rev, &argv); + res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL); + strvec_clear(&argv); + return res; + } + error(_("'%s'?? what are you talking about?"), p); + + return -1; +} + +static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename) +{ + FILE *fp = NULL; + enum bisect_error res = BISECT_OK; + struct strbuf line = STRBUF_INIT; + + if (is_empty_or_missing_file(filename)) + return error(_("cannot read file '%s' for replaying"), filename); + + if (bisect_reset(NULL)) + return BISECT_FAILED; + + fp = fopen(filename, "r"); + if (!fp) + return BISECT_FAILED; + + while ((strbuf_getline(&line, fp) != EOF) && !res) + res = process_replay_line(terms, &line); + + strbuf_release(&line); + fclose(fp); + + if (res) + return BISECT_FAILED; + + return bisect_auto_next(terms, NULL); +} + +static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc) +{ + int i; + enum bisect_error res; + struct strvec argv_state = STRVEC_INIT; + + strvec_push(&argv_state, "skip"); + + for (i = 0; i < argc; i++) { + const char *dotdot = strstr(argv[i], ".."); + + if (dotdot) { + struct rev_info revs; + struct commit *commit; + + init_revisions(&revs, NULL); + setup_revisions(2, argv + i - 1, &revs, NULL); + + if (prepare_revision_walk(&revs)) + die(_("revision walk setup failed\n")); + while ((commit = get_revision(&revs)) != NULL) + strvec_push(&argv_state, + oid_to_hex(&commit->object.oid)); + + reset_revision_walk(); + } else { + strvec_push(&argv_state, argv[i]); + } + } + res = bisect_state(terms, argv_state.v, argv_state.nr); + + strvec_clear(&argv_state); + return res; +} + int cmd_bisect__helper(int argc, const char **argv, const char *prefix) { enum { BISECT_RESET = 1, - BISECT_WRITE, - CHECK_AND_SET_TERMS, BISECT_NEXT_CHECK, BISECT_TERMS, BISECT_START, BISECT_AUTOSTART, BISECT_NEXT, - BISECT_AUTO_NEXT, - BISECT_STATE + BISECT_STATE, + BISECT_LOG, + BISECT_REPLAY, + BISECT_SKIP } cmdmode = 0; int res = 0, nolog = 0; struct option options[] = { OPT_CMDMODE(0, "bisect-reset", &cmdmode, N_("reset the bisection state"), BISECT_RESET), - OPT_CMDMODE(0, "bisect-write", &cmdmode, - N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE), - OPT_CMDMODE(0, "check-and-set-terms", &cmdmode, - N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS), OPT_CMDMODE(0, "bisect-next-check", &cmdmode, N_("check whether bad or good terms exist"), BISECT_NEXT_CHECK), OPT_CMDMODE(0, "bisect-terms", &cmdmode, @@ -934,10 +1053,14 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) N_("start the bisect session"), BISECT_START), OPT_CMDMODE(0, "bisect-next", &cmdmode, N_("find the next bisection commit"), BISECT_NEXT), - OPT_CMDMODE(0, "bisect-auto-next", &cmdmode, - N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT), OPT_CMDMODE(0, "bisect-state", &cmdmode, N_("mark the state of ref (or refs)"), BISECT_STATE), + OPT_CMDMODE(0, "bisect-log", &cmdmode, + N_("list the bisection steps so far"), BISECT_LOG), + OPT_CMDMODE(0, "bisect-replay", &cmdmode, + N_("replay the bisection process from the given file"), BISECT_REPLAY), + OPT_CMDMODE(0, "bisect-skip", &cmdmode, + N_("skip some commits for checkout"), BISECT_SKIP), OPT_BOOL(0, "no-log", &nolog, N_("no log for BISECT_WRITE")), OPT_END() @@ -955,18 +1078,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) case BISECT_RESET: if (argc > 1) return error(_("--bisect-reset requires either no argument or a commit")); - return !!bisect_reset(argc ? argv[0] : NULL); - case BISECT_WRITE: - if (argc != 4 && argc != 5) - return error(_("--bisect-write requires either 4 or 5 arguments")); - set_terms(&terms, argv[3], argv[2]); - res = bisect_write(argv[0], argv[1], &terms, nolog); - break; - case CHECK_AND_SET_TERMS: - if (argc != 3) - return error(_("--check-and-set-terms requires 3 arguments")); - set_terms(&terms, argv[2], argv[1]); - res = check_and_set_terms(&terms, argv[0]); + res = bisect_reset(argc ? argv[0] : NULL); break; case BISECT_NEXT_CHECK: if (argc != 2 && argc != 3) @@ -989,17 +1101,26 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) get_terms(&terms); res = bisect_next(&terms, prefix); break; - case BISECT_AUTO_NEXT: - if (argc) - return error(_("--bisect-auto-next requires 0 arguments")); - get_terms(&terms); - res = bisect_auto_next(&terms, prefix); - break; case BISECT_STATE: set_terms(&terms, "bad", "good"); get_terms(&terms); res = bisect_state(&terms, argv, argc); break; + case BISECT_LOG: + if (argc) + return error(_("--bisect-log requires 0 arguments")); + res = bisect_log(); + break; + case BISECT_REPLAY: + if (argc != 1) + return error(_("no logfile given")); + set_terms(&terms, "bad", "good"); + res = bisect_replay(&terms, argv[0]); + break; + case BISECT_SKIP: + set_terms(&terms, "bad", "good"); + res = bisect_skip(&terms, argv, argc); + break; default: BUG("unknown subcommand %d", cmdmode); } diff --git a/git-bisect.sh b/git-bisect.sh index 1f3f6e9fc5..6a7afaea8d 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -39,21 +39,6 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" TERM_BAD=bad TERM_GOOD=good -bisect_skip() { - all='' - for arg in "$@" - do - case "$arg" in - *..*) - revs=$(git rev-list "$arg") || die "$(eval_gettext "Bad rev input: \$arg")" ;; - *) - revs=$(git rev-parse --sq-quote "$arg") ;; - esac - all="$all $revs" - done - eval git bisect--helper --bisect-state 'skip' $all -} - bisect_visualize() { git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit @@ -77,38 +62,6 @@ bisect_visualize() { eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES") } -bisect_replay () { - file="$1" - test "$#" -eq 1 || die "$(gettext "No logfile given")" - test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")" - git bisect--helper --bisect-reset || exit - oIFS="$IFS" IFS="$IFS$(printf '\015')" - while read git bisect command rev tail - do - test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue - if test "$git" = "git-bisect" - then - rev="$command" - command="$bisect" - fi - get_terms - git bisect--helper --check-and-set-terms "$command" "$TERM_GOOD" "$TERM_BAD" || exit - get_terms - case "$command" in - start) - eval "git bisect--helper --bisect-start $rev $tail" ;; - "$TERM_GOOD"|"$TERM_BAD"|skip) - git bisect--helper --bisect-write "$command" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit;; - terms) - git bisect--helper --bisect-terms $rev || exit;; - *) - die "$(gettext "?? what are you talking about?")" ;; - esac - done <"$file" - IFS="$oIFS" - git bisect--helper --bisect-auto-next || exit -} - bisect_run () { git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit @@ -169,11 +122,6 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2 done } -bisect_log () { - test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")" - cat "$GIT_DIR/BISECT_LOG" -} - get_terms () { if test -s "$GIT_DIR/BISECT_TERMS" then @@ -199,7 +147,7 @@ case "$#" in bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") git bisect--helper --bisect-state "$cmd" "$@" ;; skip) - bisect_skip "$@" ;; + git bisect--helper --bisect-skip "$@" || exit;; next) # Not sure we want "next" at the UI level anymore. git bisect--helper --bisect-next "$@" || exit ;; @@ -208,9 +156,9 @@ case "$#" in reset) git bisect--helper --bisect-reset "$@" ;; replay) - bisect_replay "$@" ;; + git bisect--helper --bisect-replay "$@" || exit;; log) - bisect_log ;; + git bisect--helper --bisect-log || exit ;; run) bisect_run "$@" ;; terms) |