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:
> 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.

>  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?

> 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?

> @@ -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

Reply via email to