bisect--helper: bisect_next_check
shell function in C
Reimplement `bisect_next_check` shell function in C and add `bisect-next-check` subcommand to `git bisect--helper` to call it from git-bisect.sh . `bisect_voc` shell function is no longer useful now and is replaced by using a char *[] of "new|bad" and "good|old" values. Using `--bisect-next-check` is a temporary measure to port shell function to C so as to use the existing test suite. As more functions are ported, this subcommand will be retired but its implementation will be called by some other methods. Helped-by: Stephan Beyer <s-beyer@gmx.net> Mentored-by: Lars Schneider <larsxschneider@gmail.com> Mentored-by: Christian Couder <chriscool@tuxfamily.org> Mentored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Pranit Bauva <pranit.bauva@gmail.com> Signed-off-by: Tanushree Tumane <tanushreetumane@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
4fbdbd5bff
commit
129a6cf344
@ -6,6 +6,7 @@
|
|||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "argv-array.h"
|
#include "argv-array.h"
|
||||||
#include "run-command.h"
|
#include "run-command.h"
|
||||||
|
#include "prompt.h"
|
||||||
|
|
||||||
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
|
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
|
||||||
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
|
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
|
||||||
@ -21,6 +22,7 @@ static const char * const git_bisect_helper_usage[] = {
|
|||||||
N_("git bisect--helper --bisect-reset [<commit>]"),
|
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-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-check-and-set-terms <command> <good_term> <bad_term>"),
|
||||||
|
N_("git bisect--helper --bisect-next-check <good_term> <bad_term> [<term>]"),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -44,6 +46,9 @@ static void set_terms(struct bisect_terms *terms, const char *bad,
|
|||||||
terms->term_bad = xstrdup(bad);
|
terms->term_bad = xstrdup(bad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *vocab_bad = "bad|new";
|
||||||
|
static const char *vocab_good = "good|old";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the string `term` belongs to the set of strings
|
* Check whether the string `term` belongs to the set of strings
|
||||||
* included in the variable arguments.
|
* included in the variable arguments.
|
||||||
@ -262,6 +267,78 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mark_good(const char *refname, const struct object_id *oid,
|
||||||
|
int flag, void *cb_data)
|
||||||
|
{
|
||||||
|
int *m_good = (int *)cb_data;
|
||||||
|
*m_good = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *need_bad_and_good_revision_warning =
|
||||||
|
N_("You need to give me at least one %s and %s revision.\n"
|
||||||
|
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
|
||||||
|
|
||||||
|
static const char *need_bisect_start_warning =
|
||||||
|
N_("You need to start by \"git bisect start\".\n"
|
||||||
|
"You then need to give me at least one %s and %s revision.\n"
|
||||||
|
"You can use \"git bisect %s\" and \"git bisect %s\" for that.");
|
||||||
|
|
||||||
|
static int bisect_next_check(const struct bisect_terms *terms,
|
||||||
|
const char *current_term)
|
||||||
|
{
|
||||||
|
int missing_good = 1, missing_bad = 1, retval = 0;
|
||||||
|
const char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
|
||||||
|
const char *good_glob = xstrfmt("%s-*", terms->term_good);
|
||||||
|
|
||||||
|
if (ref_exists(bad_ref))
|
||||||
|
missing_bad = 0;
|
||||||
|
|
||||||
|
for_each_glob_ref_in(mark_good, good_glob, "refs/bisect/",
|
||||||
|
(void *) &missing_good);
|
||||||
|
|
||||||
|
if (!missing_good && !missing_bad)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
if (!current_term) {
|
||||||
|
retval = -1;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing_good && !missing_bad &&
|
||||||
|
!strcmp(current_term, terms->term_good)) {
|
||||||
|
char *yesno;
|
||||||
|
/*
|
||||||
|
* have bad (or new) but not good (or old). We could bisect
|
||||||
|
* although this is less optimum.
|
||||||
|
*/
|
||||||
|
warning(_("bisecting only with a %s commit"), terms->term_bad);
|
||||||
|
if (!isatty(0))
|
||||||
|
goto finish;
|
||||||
|
/*
|
||||||
|
* TRANSLATORS: Make sure to include [Y] and [n] in your
|
||||||
|
* translation. The program will only accept English input
|
||||||
|
* at this point.
|
||||||
|
*/
|
||||||
|
yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
|
||||||
|
if (starts_with(yesno, "N") || starts_with(yesno, "n"))
|
||||||
|
retval = -1;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if (!is_empty_or_missing_file(git_path_bisect_start())) {
|
||||||
|
retval = error(_(need_bad_and_good_revision_warning),
|
||||||
|
vocab_bad, vocab_good, vocab_bad, vocab_good);
|
||||||
|
} else {
|
||||||
|
retval = error(_(need_bisect_start_warning),
|
||||||
|
vocab_good, vocab_bad, vocab_good, vocab_bad);
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
free((void *) good_glob);
|
||||||
|
free((void *) bad_ref);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
enum {
|
enum {
|
||||||
@ -271,7 +348,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
|||||||
CHECK_EXPECTED_REVS,
|
CHECK_EXPECTED_REVS,
|
||||||
BISECT_RESET,
|
BISECT_RESET,
|
||||||
BISECT_WRITE,
|
BISECT_WRITE,
|
||||||
CHECK_AND_SET_TERMS
|
CHECK_AND_SET_TERMS,
|
||||||
|
BISECT_NEXT_CHECK
|
||||||
} cmdmode = 0;
|
} cmdmode = 0;
|
||||||
int no_checkout = 0, res = 0, nolog = 0;
|
int no_checkout = 0, res = 0, nolog = 0;
|
||||||
struct option options[] = {
|
struct option options[] = {
|
||||||
@ -289,6 +367,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
|||||||
N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
|
N_("write out the bisection state in BISECT_LOG"), BISECT_WRITE),
|
||||||
OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
|
OPT_CMDMODE(0, "check-and-set-terms", &cmdmode,
|
||||||
N_("check and set terms in a bisection state"), CHECK_AND_SET_TERMS),
|
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_BOOL(0, "no-checkout", &no_checkout,
|
OPT_BOOL(0, "no-checkout", &no_checkout,
|
||||||
N_("update BISECT_HEAD instead of checking out the current commit")),
|
N_("update BISECT_HEAD instead of checking out the current commit")),
|
||||||
OPT_BOOL(0, "no-log", &nolog,
|
OPT_BOOL(0, "no-log", &nolog,
|
||||||
@ -333,6 +413,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
|
|||||||
set_terms(&terms, argv[2], argv[1]);
|
set_terms(&terms, argv[2], argv[1]);
|
||||||
res = check_and_set_terms(&terms, argv[0]);
|
res = check_and_set_terms(&terms, argv[0]);
|
||||||
break;
|
break;
|
||||||
|
case BISECT_NEXT_CHECK:
|
||||||
|
if (argc != 2 && argc != 3)
|
||||||
|
return error(_("--bisect-next-check requires 2 or 3 arguments"));
|
||||||
|
set_terms(&terms, argv[1], argv[0]);
|
||||||
|
res = bisect_next_check(&terms, argc == 3 ? argv[2] : NULL);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return error("BUG: unknown subcommand '%d'", cmdmode);
|
return error("BUG: unknown subcommand '%d'", cmdmode);
|
||||||
}
|
}
|
||||||
|
@ -271,59 +271,14 @@ bisect_state() {
|
|||||||
bisect_auto_next
|
bisect_auto_next
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_next_check() {
|
|
||||||
missing_good= missing_bad=
|
|
||||||
git show-ref -q --verify refs/bisect/$TERM_BAD || missing_bad=t
|
|
||||||
test -n "$(git for-each-ref "refs/bisect/$TERM_GOOD-*")" || missing_good=t
|
|
||||||
|
|
||||||
case "$missing_good,$missing_bad,$1" in
|
|
||||||
,,*)
|
|
||||||
: have both $TERM_GOOD and $TERM_BAD - ok
|
|
||||||
;;
|
|
||||||
*,)
|
|
||||||
# do not have both but not asked to fail - just report.
|
|
||||||
false
|
|
||||||
;;
|
|
||||||
t,,"$TERM_GOOD")
|
|
||||||
# have bad (or new) but not good (or old). we could bisect although
|
|
||||||
# this is less optimum.
|
|
||||||
eval_gettextln "Warning: bisecting only with a \$TERM_BAD commit." >&2
|
|
||||||
if test -t 0
|
|
||||||
then
|
|
||||||
# TRANSLATORS: Make sure to include [Y] and [n] in your
|
|
||||||
# translation. The program will only accept English input
|
|
||||||
# at this point.
|
|
||||||
gettext "Are you sure [Y/n]? " >&2
|
|
||||||
read yesno
|
|
||||||
case "$yesno" in [Nn]*) exit 1 ;; esac
|
|
||||||
fi
|
|
||||||
: bisect without $TERM_GOOD...
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
bad_syn=$(bisect_voc bad)
|
|
||||||
good_syn=$(bisect_voc good)
|
|
||||||
if test -s "$GIT_DIR/BISECT_START"
|
|
||||||
then
|
|
||||||
|
|
||||||
eval_gettextln "You need to give me at least one \$bad_syn and one \$good_syn revision.
|
|
||||||
(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
|
|
||||||
else
|
|
||||||
eval_gettextln "You need to start by \"git bisect start\".
|
|
||||||
You then need to give me at least one \$good_syn and one \$bad_syn revision.
|
|
||||||
(You can use \"git bisect \$bad_syn\" and \"git bisect \$good_syn\" for that.)" >&2
|
|
||||||
fi
|
|
||||||
exit 1 ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_auto_next() {
|
bisect_auto_next() {
|
||||||
bisect_next_check && bisect_next || :
|
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD && bisect_next || :
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_next() {
|
bisect_next() {
|
||||||
case "$#" in 0) ;; *) usage ;; esac
|
case "$#" in 0) ;; *) usage ;; esac
|
||||||
bisect_autostart
|
bisect_autostart
|
||||||
bisect_next_check $TERM_GOOD
|
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD $TERM_GOOD|| exit
|
||||||
|
|
||||||
# Perform all bisection computation, display and checkout
|
# Perform all bisection computation, display and checkout
|
||||||
git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
|
git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
|
||||||
@ -355,7 +310,7 @@ bisect_next() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bisect_visualize() {
|
bisect_visualize() {
|
||||||
bisect_next_check fail
|
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
|
||||||
|
|
||||||
if test $# = 0
|
if test $# = 0
|
||||||
then
|
then
|
||||||
@ -409,7 +364,7 @@ bisect_replay () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bisect_run () {
|
bisect_run () {
|
||||||
bisect_next_check fail
|
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
|
||||||
|
|
||||||
test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
|
test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
|
||||||
|
|
||||||
@ -484,13 +439,6 @@ get_terms () {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
bisect_voc () {
|
|
||||||
case "$1" in
|
|
||||||
bad) echo "bad|new" ;;
|
|
||||||
good) echo "good|old" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
bisect_terms () {
|
bisect_terms () {
|
||||||
get_terms
|
get_terms
|
||||||
if ! test -s "$GIT_DIR/BISECT_TERMS"
|
if ! test -s "$GIT_DIR/BISECT_TERMS"
|
||||||
|
Loading…
Reference in New Issue
Block a user