Skip to content

Commit d1bbbe4

Browse files
tanushree27gitster
authored andcommitted
bisect--helper: reimplement bisect_run shell function in C
Reimplement the `bisect_run()` shell function in C and also add `--bisect-run` subcommand to `git bisect--helper` to call it from git-bisect.sh. Mentored-by: Christian Couder <[email protected]> Signed-off-by: Tanushree Tumane <[email protected]> Signed-off-by: Miriam Rubio <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5e1f28d commit d1bbbe4

File tree

2 files changed

+106
-61
lines changed

2 files changed

+106
-61
lines changed

builtin/bisect--helper.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
1818
static GIT_PATH_FUNC(git_path_head_name, "head-name")
1919
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
2020
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
21+
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
2122

2223
static const char * const git_bisect_helper_usage[] = {
2324
N_("git bisect--helper --bisect-reset [<commit>]"),
@@ -31,6 +32,7 @@ static const char * const git_bisect_helper_usage[] = {
3132
N_("git bisect--helper --bisect-replay <filename>"),
3233
N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
3334
N_("git bisect--helper --bisect-visualize"),
35+
N_("git bisect--helper --bisect-run <cmd>..."),
3436
NULL
3537
};
3638

@@ -144,6 +146,19 @@ static int append_to_file(const char *path, const char *format, ...)
144146
return res;
145147
}
146148

149+
static int print_file_to_stdout(const char *path)
150+
{
151+
int fd = open(path, O_RDONLY);
152+
int ret = 0;
153+
154+
if (fd < 0)
155+
return error_errno(_("cannot open file '%s' for reading"), path);
156+
if (copy_fd(fd, 1) < 0)
157+
ret = error_errno(_("failed to read '%s'"), path);
158+
close(fd);
159+
return ret;
160+
}
161+
147162
static int check_term_format(const char *term, const char *orig_term)
148163
{
149164
int res;
@@ -1075,6 +1090,87 @@ static int bisect_visualize(struct bisect_terms *terms, const char **argv, int a
10751090
return res;
10761091
}
10771092

1093+
static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
1094+
{
1095+
int res = BISECT_OK;
1096+
struct strbuf command = STRBUF_INIT;
1097+
struct strvec args = STRVEC_INIT;
1098+
struct strvec run_args = STRVEC_INIT;
1099+
const char *new_state;
1100+
int temporary_stdout_fd, saved_stdout;
1101+
1102+
if (bisect_next_check(terms, NULL))
1103+
return BISECT_FAILED;
1104+
1105+
if (argc)
1106+
sq_quote_argv(&command, argv);
1107+
else {
1108+
error(_("bisect run failed: no command provided."));
1109+
return BISECT_FAILED;
1110+
}
1111+
1112+
strvec_push(&run_args, command.buf);
1113+
1114+
while (1) {
1115+
strvec_clear(&args);
1116+
1117+
printf(_("running %s\n"), command.buf);
1118+
res = run_command_v_opt(run_args.v, RUN_USING_SHELL);
1119+
1120+
if (res < 0 || 128 <= res) {
1121+
error(_("bisect run failed: exit code %d from"
1122+
" '%s' is < 0 or >= 128"), res, command.buf);
1123+
strbuf_release(&command);
1124+
return res;
1125+
}
1126+
1127+
if (res == 125)
1128+
new_state = "skip";
1129+
else if (!res)
1130+
new_state = terms->term_good;
1131+
else
1132+
new_state = terms->term_bad;
1133+
1134+
temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
1135+
1136+
if (temporary_stdout_fd < 0)
1137+
return error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
1138+
1139+
fflush(stdout);
1140+
saved_stdout = dup(1);
1141+
dup2(temporary_stdout_fd, 1);
1142+
1143+
res = bisect_state(terms, &new_state, 1);
1144+
1145+
fflush(stdout);
1146+
dup2(saved_stdout, 1);
1147+
close(saved_stdout);
1148+
close(temporary_stdout_fd);
1149+
1150+
print_file_to_stdout(git_path_bisect_run());
1151+
1152+
if (res == BISECT_ONLY_SKIPPED_LEFT)
1153+
error(_("bisect run cannot continue any more"));
1154+
else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
1155+
printf(_("bisect run success"));
1156+
res = BISECT_OK;
1157+
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
1158+
printf(_("bisect found first bad commit"));
1159+
res = BISECT_OK;
1160+
} else if (res) {
1161+
error(_("bisect run failed:'git bisect--helper --bisect-state"
1162+
" %s' exited with error code %d"), args.v[0], res);
1163+
} else {
1164+
continue;
1165+
}
1166+
1167+
strbuf_release(&command);
1168+
strvec_clear(&args);
1169+
strvec_clear(&run_args);
1170+
return res;
1171+
}
1172+
}
1173+
10781174
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
10791175
{
10801176
enum {
@@ -1089,6 +1185,7 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
10891185
BISECT_REPLAY,
10901186
BISECT_SKIP,
10911187
BISECT_VISUALIZE,
1188+
BISECT_RUN,
10921189
} cmdmode = 0;
10931190
int res = 0, nolog = 0;
10941191
struct option options[] = {
@@ -1112,6 +1209,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
11121209
N_("skip some commits for checkout"), BISECT_SKIP),
11131210
OPT_CMDMODE(0, "bisect-visualize", &cmdmode,
11141211
N_("visualize the bisection"), BISECT_VISUALIZE),
1212+
OPT_CMDMODE(0, "bisect-run", &cmdmode,
1213+
N_("use <cmd>... to automatically bisect."), BISECT_RUN),
11151214
OPT_BOOL(0, "no-log", &nolog,
11161215
N_("no log for BISECT_WRITE")),
11171216
OPT_END()
@@ -1177,6 +1276,12 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
11771276
get_terms(&terms);
11781277
res = bisect_visualize(&terms, argv, argc);
11791278
break;
1279+
case BISECT_RUN:
1280+
if (!argc)
1281+
return error(_("bisect run failed: no command provided."));
1282+
get_terms(&terms);
1283+
res = bisect_run(&terms, argv, argc);
1284+
break;
11801285
default:
11811286
BUG("unknown subcommand %d", cmdmode);
11821287
}

git-bisect.sh

Lines changed: 1 addition & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -39,66 +39,6 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
3939
TERM_BAD=bad
4040
TERM_GOOD=good
4141

42-
bisect_run () {
43-
git bisect--helper --bisect-next-check $TERM_GOOD $TERM_BAD fail || exit
44-
45-
test -n "$*" || die "$(gettext "bisect run failed: no command provided.")"
46-
47-
while true
48-
do
49-
command="$@"
50-
eval_gettextln "running \$command"
51-
"$@"
52-
res=$?
53-
54-
# Check for really bad run error.
55-
if [ $res -lt 0 -o $res -ge 128 ]
56-
then
57-
eval_gettextln "bisect run failed:
58-
exit code \$res from '\$command' is < 0 or >= 128" >&2
59-
exit $res
60-
fi
61-
62-
# Find current state depending on run success or failure.
63-
# A special exit code of 125 means cannot test.
64-
if [ $res -eq 125 ]
65-
then
66-
state='skip'
67-
elif [ $res -gt 0 ]
68-
then
69-
state="$TERM_BAD"
70-
else
71-
state="$TERM_GOOD"
72-
fi
73-
74-
git bisect--helper --bisect-state $state >"$GIT_DIR/BISECT_RUN"
75-
res=$?
76-
77-
cat "$GIT_DIR/BISECT_RUN"
78-
79-
if sane_grep "first $TERM_BAD commit could be any of" "$GIT_DIR/BISECT_RUN" \
80-
>/dev/null
81-
then
82-
gettextln "bisect run cannot continue any more" >&2
83-
exit $res
84-
fi
85-
86-
if [ $res -ne 0 ]
87-
then
88-
eval_gettextln "bisect run failed:
89-
'bisect-state \$state' exited with error code \$res" >&2
90-
exit $res
91-
fi
92-
93-
if sane_grep "is the first $TERM_BAD commit" "$GIT_DIR/BISECT_RUN" >/dev/null
94-
then
95-
gettextln "bisect run success"
96-
exit 0;
97-
fi
98-
99-
done
100-
}
101-
10242
get_terms () {
10343
if test -s "$GIT_DIR/BISECT_TERMS"
10444
then
@@ -137,7 +77,7 @@ case "$#" in
13777
log)
13878
git bisect--helper --bisect-log || exit ;;
13979
run)
140-
bisect_run "$@" ;;
80+
git bisect--helper --bisect-run "$@" || exit;;
14181
terms)
14282
git bisect--helper --bisect-terms "$@" || exit;;
14383
*)

0 commit comments

Comments
 (0)