bisect--helper: reimplement `bisect_state` & `bisect_head` shell functions in C
Reimplement the `bisect_state()` shell functions in C and also add a subcommand `--bisect-state` to `git-bisect--helper` to call them from git-bisect.sh . Using `--bisect-state` subcommand 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 and will be called by some other methods. `bisect_head()` is only called from `bisect_state()`, thus it is not required to introduce another subcommand. Note that the `eval` in the changed line of `git-bisect.sh` cannot be dropped: it is necessary because the `rev` and the `tail` variables may contain multiple, quoted arguments that need to be passed to `bisect--helper` (without the quotes, naturally). 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: Miriam Rubio <mirucam@gmail.com> Reviewed-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
							parent
							
								
									04774b4e70
								
							
						
					
					
						commit
						27257bc466
					
				|  | @ -31,6 +31,8 @@ static const char * const git_bisect_helper_usage[] = { | ||||||
| 	N_("git bisect--helper --bisect-next"), | 	N_("git bisect--helper --bisect-next"), | ||||||
| 	N_("git bisect--helper --bisect-auto-next"), | 	N_("git bisect--helper --bisect-auto-next"), | ||||||
| 	N_("git bisect--helper --bisect-autostart"), | 	N_("git bisect--helper --bisect-autostart"), | ||||||
|  | 	N_("git bisect--helper --bisect-state (bad|new) [<rev>]"), | ||||||
|  | 	N_("git bisect--helper --bisect-state (good|old) [<rev>...]"), | ||||||
| 	NULL | 	NULL | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -855,6 +857,80 @@ static int bisect_autostart(struct bisect_terms *terms) | ||||||
| 	return res; | 	return res; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv, | ||||||
|  | 				      int argc) | ||||||
|  | { | ||||||
|  | 	const char *state; | ||||||
|  | 	int i, verify_expected = 1; | ||||||
|  | 	struct object_id oid, expected; | ||||||
|  | 	struct strbuf buf = STRBUF_INIT; | ||||||
|  | 	struct oid_array revs = OID_ARRAY_INIT; | ||||||
|  |  | ||||||
|  | 	if (!argc) | ||||||
|  | 		return error(_("Please call `--bisect-state` with at least one argument")); | ||||||
|  |  | ||||||
|  | 	if (bisect_autostart(terms)) | ||||||
|  | 		return BISECT_FAILED; | ||||||
|  |  | ||||||
|  | 	state = argv[0]; | ||||||
|  | 	if (check_and_set_terms(terms, state) || | ||||||
|  | 	    !one_of(state, terms->term_good, terms->term_bad, "skip", NULL)) | ||||||
|  | 		return BISECT_FAILED; | ||||||
|  |  | ||||||
|  | 	argv++; | ||||||
|  | 	argc--; | ||||||
|  | 	if (argc > 1 && !strcmp(state, terms->term_bad)) | ||||||
|  | 		return error(_("'git bisect %s' can take only one argument."), terms->term_bad); | ||||||
|  |  | ||||||
|  | 	if (argc == 0) { | ||||||
|  | 		const char *head = "BISECT_HEAD"; | ||||||
|  | 		enum get_oid_result res_head = get_oid(head, &oid); | ||||||
|  |  | ||||||
|  | 		if (res_head == MISSING_OBJECT) { | ||||||
|  | 			head = "HEAD"; | ||||||
|  | 			res_head = get_oid(head, &oid); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (res_head) | ||||||
|  | 			error(_("Bad rev input: %s"), head); | ||||||
|  | 		oid_array_append(&revs, &oid); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * All input revs must be checked before executing bisect_write() | ||||||
|  | 	 * to discard junk revs. | ||||||
|  | 	 */ | ||||||
|  |  | ||||||
|  | 	for (; argc; argc--, argv++) { | ||||||
|  | 		if (get_oid(*argv, &oid)){ | ||||||
|  | 			error(_("Bad rev input: %s"), *argv); | ||||||
|  | 			oid_array_clear(&revs); | ||||||
|  | 			return BISECT_FAILED; | ||||||
|  | 		} | ||||||
|  | 		oid_array_append(&revs, &oid); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (strbuf_read_file(&buf, git_path_bisect_expected_rev(), 0) < the_hash_algo->hexsz || | ||||||
|  | 	    get_oid_hex(buf.buf, &expected) < 0) | ||||||
|  | 		verify_expected = 0; /* Ignore invalid file contents */ | ||||||
|  | 	strbuf_release(&buf); | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < revs.nr; i++) { | ||||||
|  | 		if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) { | ||||||
|  | 			oid_array_clear(&revs); | ||||||
|  | 			return BISECT_FAILED; | ||||||
|  | 		} | ||||||
|  | 		if (verify_expected && !oideq(&revs.oid[i], &expected)) { | ||||||
|  | 			unlink_or_warn(git_path_bisect_ancestors_ok()); | ||||||
|  | 			unlink_or_warn(git_path_bisect_expected_rev()); | ||||||
|  | 			verify_expected = 0; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	oid_array_clear(&revs); | ||||||
|  | 	return bisect_auto_next(terms, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
| 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 { | ||||||
|  | @ -868,7 +944,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) | ||||||
| 		BISECT_START, | 		BISECT_START, | ||||||
| 		BISECT_AUTOSTART, | 		BISECT_AUTOSTART, | ||||||
| 		BISECT_NEXT, | 		BISECT_NEXT, | ||||||
| 		BISECT_AUTO_NEXT | 		BISECT_AUTO_NEXT, | ||||||
|  | 		BISECT_STATE | ||||||
| 	} cmdmode = 0; | 	} cmdmode = 0; | ||||||
| 	int res = 0, nolog = 0; | 	int res = 0, nolog = 0; | ||||||
| 	struct option options[] = { | 	struct option options[] = { | ||||||
|  | @ -894,6 +971,8 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) | ||||||
| 			 N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT), | 			 N_("verify the next bisection state then checkout the next bisection commit"), BISECT_AUTO_NEXT), | ||||||
| 		OPT_CMDMODE(0, "bisect-autostart", &cmdmode, | 		OPT_CMDMODE(0, "bisect-autostart", &cmdmode, | ||||||
| 			 N_("start the bisection if it has not yet been started"), BISECT_AUTOSTART), | 			 N_("start the bisection if it has not yet been started"), BISECT_AUTOSTART), | ||||||
|  | 		OPT_CMDMODE(0, "bisect-state", &cmdmode, | ||||||
|  | 			 N_("mark the state of ref (or refs)"), BISECT_STATE), | ||||||
| 		OPT_BOOL(0, "no-log", &nolog, | 		OPT_BOOL(0, "no-log", &nolog, | ||||||
| 			 N_("no log for BISECT_WRITE")), | 			 N_("no log for BISECT_WRITE")), | ||||||
| 		OPT_END() | 		OPT_END() | ||||||
|  | @ -964,6 +1043,11 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) | ||||||
| 		set_terms(&terms, "bad", "good"); | 		set_terms(&terms, "bad", "good"); | ||||||
| 		res = bisect_autostart(&terms); | 		res = bisect_autostart(&terms); | ||||||
| 		break; | 		break; | ||||||
|  | 	case BISECT_STATE: | ||||||
|  | 		set_terms(&terms, "bad", "good"); | ||||||
|  | 		get_terms(&terms); | ||||||
|  | 		res = bisect_state(&terms, argv, argc); | ||||||
|  | 		break; | ||||||
| 	default: | 	default: | ||||||
| 		BUG("unknown subcommand %d", cmdmode); | 		BUG("unknown subcommand %d", cmdmode); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -39,16 +39,6 @@ _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" | ||||||
| TERM_BAD=bad | TERM_BAD=bad | ||||||
| TERM_GOOD=good | TERM_GOOD=good | ||||||
|  |  | ||||||
| bisect_head() |  | ||||||
| { |  | ||||||
| 	if git rev-parse --verify -q BISECT_HEAD > /dev/null |  | ||||||
| 	then |  | ||||||
| 		echo BISECT_HEAD |  | ||||||
| 	else |  | ||||||
| 		echo HEAD |  | ||||||
| 	fi |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bisect_skip() { | bisect_skip() { | ||||||
| 	all='' | 	all='' | ||||||
| 	for arg in "$@" | 	for arg in "$@" | ||||||
|  | @ -61,43 +51,7 @@ bisect_skip() { | ||||||
| 		esac | 		esac | ||||||
| 		all="$all $revs" | 		all="$all $revs" | ||||||
| 	done | 	done | ||||||
| 	eval bisect_state 'skip' $all | 	eval git bisect--helper --bisect-state 'skip' $all | ||||||
| } |  | ||||||
|  |  | ||||||
| bisect_state() { |  | ||||||
| 	git bisect--helper --bisect-autostart || exit |  | ||||||
| 	state=$1 |  | ||||||
| 	git bisect--helper --check-and-set-terms $state $TERM_GOOD $TERM_BAD || exit |  | ||||||
| 	get_terms |  | ||||||
| 	case "$#,$state" in |  | ||||||
| 	0,*) |  | ||||||
| 		die "Please call 'bisect_state' with at least one argument." ;; |  | ||||||
| 	1,"$TERM_BAD"|1,"$TERM_GOOD"|1,skip) |  | ||||||
| 		bisected_head=$(bisect_head) |  | ||||||
| 		rev=$(git rev-parse --verify "$bisected_head") || |  | ||||||
| 			die "$(eval_gettext "Bad rev input: \$bisected_head")" |  | ||||||
| 		git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit |  | ||||||
| 		git bisect--helper --check-expected-revs "$rev" ;; |  | ||||||
| 	2,"$TERM_BAD"|*,"$TERM_GOOD"|*,skip) |  | ||||||
| 		shift |  | ||||||
| 		hash_list='' |  | ||||||
| 		for rev in "$@" |  | ||||||
| 		do |  | ||||||
| 			sha=$(git rev-parse --verify "$rev^{commit}") || |  | ||||||
| 				die "$(eval_gettext "Bad rev input: \$rev")" |  | ||||||
| 			hash_list="$hash_list $sha" |  | ||||||
| 		done |  | ||||||
| 		for rev in $hash_list |  | ||||||
| 		do |  | ||||||
| 			git bisect--helper --bisect-write "$state" "$rev" "$TERM_GOOD" "$TERM_BAD" || exit |  | ||||||
| 		done |  | ||||||
| 		git bisect--helper --check-expected-revs $hash_list ;; |  | ||||||
| 	*,"$TERM_BAD") |  | ||||||
| 		die "$(eval_gettext "'git bisect \$TERM_BAD' can take only one argument.")" ;; |  | ||||||
| 	*) |  | ||||||
| 		usage ;; |  | ||||||
| 	esac |  | ||||||
| 	git bisect--helper --bisect-auto-next |  | ||||||
| } | } | ||||||
|  |  | ||||||
| bisect_visualize() { | bisect_visualize() { | ||||||
|  | @ -187,8 +141,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2 | ||||||
| 			state="$TERM_GOOD" | 			state="$TERM_GOOD" | ||||||
| 		fi | 		fi | ||||||
|  |  | ||||||
| 		# We have to use a subshell because "bisect_state" can exit. | 		git bisect--helper --bisect-state $state >"$GIT_DIR/BISECT_RUN" | ||||||
| 		( bisect_state $state >"$GIT_DIR/BISECT_RUN" ) |  | ||||||
| 		res=$? | 		res=$? | ||||||
|  |  | ||||||
| 		cat "$GIT_DIR/BISECT_RUN" | 		cat "$GIT_DIR/BISECT_RUN" | ||||||
|  | @ -203,7 +156,7 @@ exit code \$res from '\$command' is < 0 or >= 128" >&2 | ||||||
| 		if [ $res -ne 0 ] | 		if [ $res -ne 0 ] | ||||||
| 		then | 		then | ||||||
| 			eval_gettextln "bisect run failed: | 			eval_gettextln "bisect run failed: | ||||||
| 'bisect_state \$state' exited with error code \$res" >&2 | 'bisect-state \$state' exited with error code \$res" >&2 | ||||||
| 			exit $res | 			exit $res | ||||||
| 		fi | 		fi | ||||||
|  |  | ||||||
|  | @ -244,7 +197,7 @@ case "$#" in | ||||||
| 	start) | 	start) | ||||||
| 		git bisect--helper --bisect-start "$@" ;; | 		git bisect--helper --bisect-start "$@" ;; | ||||||
| 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") | 	bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") | ||||||
| 		bisect_state "$cmd" "$@" ;; | 		git bisect--helper --bisect-state "$cmd" "$@" ;; | ||||||
| 	skip) | 	skip) | ||||||
| 		bisect_skip "$@" ;; | 		bisect_skip "$@" ;; | ||||||
| 	next) | 	next) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Pranit Bauva
						Pranit Bauva