Re: [PATCH v15 15/27] bisect--helper: `bisect_next` and `bisect_auto_next` shell function in C
From: Stephan Beyer <hidden>
Date: 2016-11-21 21:35:43
Hi Pranit, in this mail I review the "second part" of your patch: the transition of bisect_next and bisect_auto_next to C. On 10/14/2016 04:14 PM, Pranit Bauva wrote:
quoted hunk ↗ jump to hunk
diff --git a/builtin/bisect--helper.c b/builtin/bisect--helper.c index 1d3e17f..fcd7574 100644 --- a/builtin/bisect--helper.c +++ b/builtin/bisect--helper.c@@ -408,6 +411,136 @@ static int bisect_terms(struct bisect_terms *terms, const char **argv, int argc) return 0; } +static int register_good_ref(const char *refname, + const struct object_id *oid, int flags, + void *cb_data) +{ + struct string_list *good_refs = cb_data; + string_list_append(good_refs, oid_to_hex(oid)); + return 0; +} + +static int bisect_next(struct bisect_terms *terms, const char *prefix) +{ + int res, no_checkout; + + /* + * In case of mistaken revs or checkout error, or signals received, + * "bisect_auto_next" below may exit or misbehave. + * We have to trap this to be able to clean up using + * "bisect_clean_state". + */
The comment above makes no sense here, or does it?
+ if (bisect_next_check(terms, terms->term_good)) + return -1; + + no_checkout = !is_empty_or_missing_file(git_path_bisect_head()); + + /* Perform all bisection computation, display and checkout */ + res = bisect_next_all(prefix , no_checkout);
Style: there is a space left of the comma.
+
+ if (res == 10) {
+ FILE *fp = NULL;
+ unsigned char sha1[20];
+ struct commit *commit;
+ struct pretty_print_context pp = {0};
+ struct strbuf commit_name = STRBUF_INIT;
+ char *bad_ref = xstrfmt("refs/bisect/%s",
+ terms->term_bad);
+ int retval = 0;
+
+ read_ref(bad_ref, sha1);
+ commit = lookup_commit_reference(sha1);
+ format_commit_message(commit, "%s", &commit_name, &pp);
+ fp = fopen(git_path_bisect_log(), "a");
+ if (!fp) {
+ retval = -1;
+ goto finish_10;
+ }
+ if (fprintf(fp, "# first %s commit: [%s] %s\n",
+ terms->term_bad, sha1_to_hex(sha1),
+ commit_name.buf) < 1){
+ retval = -1;
+ goto finish_10;
+ }
+ goto finish_10;
+ finish_10:
+ if (fp)
+ fclose(fp);
+ strbuf_release(&commit_name);
+ free(bad_ref);
+ return retval;
+ }
+ else if (res == 2) {
+ FILE *fp = NULL;
+ struct rev_info revs;
+ struct argv_array rev_argv = ARGV_ARRAY_INIT;
+ struct string_list good_revs = STRING_LIST_INIT_DUP;
+ struct pretty_print_context pp = {0};
+ struct commit *commit;
+ char *term_good = xstrfmt("%s-*", terms->term_good);
+ int i, retval = 0;
+
+ fp = fopen(git_path_bisect_log(), "a");
+ if (!fp) {
+ retval = -1;
+ goto finish_2;
+ }
+ if (fprintf(fp, "# only skipped commits left to test\n") < 1) {
+ retval = -1;
+ goto finish_2;
+ }
+ for_each_glob_ref_in(register_good_ref, term_good,
+ "refs/bisect/", (void *) &good_revs);
+
+ argv_array_pushl(&rev_argv, "skipped_commits", "refs/bisect/bad", "--not", NULL);
+ for (i = 0; i < good_revs.nr; i++)
+ argv_array_push(&rev_argv, good_revs.items[i].string);
+
+ /* It is important to reset the flags used by revision walks
+ * as the previous call to bisect_next_all() in turn
+ * setups a revision walk.
+ */
+ reset_revision_walk();
+ init_revisions(&revs, NULL);
+ rev_argv.argc = setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL);
+ argv_array_clear(&rev_argv);
+ string_list_clear(&good_revs, 0);
+ if (prepare_revision_walk(&revs))
+ die(_("revision walk setup failed\n"));
+
+ while ((commit = get_revision(&revs)) != NULL) {
+ struct strbuf commit_name = STRBUF_INIT;
+ format_commit_message(commit, "%s",
+ &commit_name, &pp);
+ fprintf(fp, "# possible first %s commit: "
+ "[%s] %s\n", terms->term_bad,
+ oid_to_hex(&commit->object.oid),
+ commit_name.buf);
+ strbuf_release(&commit_name);
+ }
+ goto finish_2;
+ finish_2:
+ if (fp)
+ fclose(fp);
+ string_list_clear(&good_revs, 0);
+ argv_array_clear(&rev_argv);
+ free(term_good);
+ if (retval)
+ return retval;
+ else
+ return res;
+ }
+ return res;
+}It would be much nicer if you put the (res == 10) branch and the (res == 2) branch into separate functions and just call them. Then you also won't need ugly label naming like finish_10 or finish_2. I'd also (again) recommend to use goto fail instead of setting retval to -1 separately each time. I'd also recommend to use a separate function to append to the bisect log file. There is a lot of duplicated opening, checking, closing code; IIRC such a function would also already be handy for some of the previous patches.
+
+static int bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+{
+ if (!bisect_next_check(terms, NULL))
+ return bisect_next(terms, prefix);
+
+ return 0;
+}Hmm, the handling of the return values is a little confusing. However, if I understand the sh source correctly, it always returns success, no matter if bisect_next failed or not. I do not know if you had something special in mind here.
quoted hunk ↗ jump to hunk
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)@@ -643,6 +794,10 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix) N_("print out the bisect terms"), BISECT_TERMS), OPT_CMDMODE(0, "bisect-start", &cmdmode, 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 find the next bisection state"), BISECT_AUTO_NEXT),
The next bisection *state* is found?
quoted hunk ↗ jump to hunk
diff --git a/git-bisect.sh b/git-bisect.sh index f0896b3..d574c44 100755 --- a/git-bisect.sh +++ b/git-bisect.sh@@ -139,45 +119,7 @@ bisect_state() { *) usage ;; esac - bisect_auto_next
[...deleted lines...]
+ git bisect--helper --bisect-auto-next || exit
Why is the "|| exit" necessary?
quoted hunk ↗ jump to hunk
@@ -319,14 +260,15 @@ case "$#" in help) git bisect -h ;; start) - bisect_start "$@" ;; + git bisect--helper --bisect-start "$@" ;; bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD") bisect_state "$cmd" "$@" ;; skip) bisect_skip "$@" ;; next) # Not sure we want "next" at the UI level anymore. - bisect_next "$@" ;; + get_terms + git bisect--helper --bisect-next "$@" || exit ;;
Why is the "|| exit" necessary? ;) Furthermore: Where is the bisect_autostart call from bisect_next() sh source gone? Was it not necessary? ~Stephan