git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 12/29] bisect--helper: reimplement `bisect_next` and `bisect_auto_next` shell functions in C

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Feb 17, 2020, 22:00 UTC
Message-ID
<nycvar.QRO.7.76.6.2002172245430.46@tvgsbejvaqbjf.bet>
In-Reply-To
<CAP8UFD1UBPwYLUEdUJj3k1Yj0Y9dD6RyGh1dFL=wsSNihErqZQ@mail.gmail.com>
Hi Chris,
On Mon, 17 Feb 2020, Christian Couder wrote:
Show 30 quoted lines
> On Thu, Jan 30, 2020 at 11:47 PM Johannes Schindelin
> <Johannes.Schindelin@gmx.de> wrote:
> >
> > On Mon, 20 Jan 2020, Miriam Rubio wrote:
>
> > > +static void prepare_rev_argv(struct bisect_terms *terms, struct argv_array *rev_argv)> > +{
> > > +     struct string_list good_revs = STRING_LIST_INIT_DUP;
> > > +     char *term_good = xstrfmt("%s-*", terms->term_good);
> > > +
> > > +     for_each_glob_ref_in(register_good_ref, term_good,
> > > +                          "refs/bisect/", &good_revs);
> > > +
> > > +     argv_array_pushl(rev_argv, "skipped_commits", "refs/bisect/bad", "--not", NULL);
> > > +     for (int i = 0; i < good_revs.nr; i++)
> > > +             argv_array_push(rev_argv, good_revs.items[i].string);
> > > +
> > > +     string_list_clear(&good_revs, 0);
> > > +     free(term_good);
> > > +}
> >
> > Maybe we should fold that into `prepare_revs()`? We could then render the
> > arguments directly into `revs` (via `add_pending_object()`, after setting
> > obj->flags |= UNINTERESTING`) rather than formatting them into a string
> > list, then deep-copy them into an `argv_array` only to parse them back
> > into OIDs that we already had in the first place.
>
> The current code is a straightforward port from shell. If we do what
> you suggest, yeah, it will be less wasteful, but on the other hand it
> will be less easy to see that we are doing a good job of properly
> porting code from shell.

If you reason that way, you will have to use tons of `run_command()` calls to translate the shell code as verbatim as possible.

However, as you can see from our commit history, we do not do that. Instead, we use the more powerful expressiveness of C to come up with more elegant code than to slavishly convert shell code to inelegant C code.

> I suggest we try to focus on the later rather than the former right now,
> especially as performance is not very important here.

Oh, but my comment was totally not about performance, and pretty much exclusively about readability.

If Miriam goes with my suggestion, it will result in more readable code that is easier to review and therefore much more likely to be free of unintentional bugs.

> Using small functions also makes it easy to see that we are properly
> releasing memory. A previous version of this code had everything into
> a big function that used goto statements and it was less clear that we
> released everything.

If you want to make it easier to avoid double-free()s and memory leaks, I am a bit puzzled how you want to claim that the current "we're copying the strings so often that pretty much everybody loses track of them" approach should be superior to adding the strings once, and once only, to a string array.

Show 28 quoted lines
> > > +static int bisect_skipped_commits(struct bisect_terms *terms)
> > > +{
> > > +     int res = 0;
> > > +     FILE *fp = NULL;
> > > +     struct rev_info revs;
> > > +
> > > +     fp = fopen(git_path_bisect_log(), "a");
> > > +     if (!fp)
> > > +             return error_errno(_("could not open '%s' for appending"),
> > > +                               git_path_bisect_log());
> > > +
> > > +     res = prepare_revs(terms, &revs);
> > > +
> > > +     if (!res)
> > > +             res = process_skipped_commits(fp, terms, &revs);
> > > +
> > > +     fclose(fp);
> > > +     return res;
> > > +}
> >
> > This is again a very short wrapper around another function, so it will
> > probably make sense to merge the two, otherwise the boilerplate might very
> > well outweigh the actual code doing actual work.
>
> Yeah, there is perhaps a significant amount of boiler plate, but the
> code is much easier to check for leaks than when everything was in the
> same big function and there were goto statements, so I think it's a
> reasonable trade-off
Given this snippet, I would strongly disagree with this assessment:
    fp = fopen(git_path_bisect_log(), "a");
    if (!fp)
            res = error_errno(_("could not open '%s' for appending"),
                              git_path_bisect_log());
    else
            res = prepare_revs(terms, &revs);
    if (!res)
            res = process_skipped_commits(fp, terms, &revs);
    if (fp)
            fclose(fp);
There is positively no need for a `goto` whatsoever.
Show 14 quoted lines
> > > +             fclose(fp);
> > > +     } else {
> > > +             res = error_errno(_("could not open '%s' for "
> > > +                                 "appending"),
> > > +                               git_path_bisect_log());
> > > +     }
> >
> > This pattern of opening a file, writing something into it, and then return
> > success, otherwise failure, seems like a repeated pattern. In other words,
> > it would be a good candidate for factoring out into its own function.
>
> Yeah, but it seems that in this patch series we use the pattern only
> once. So I think it's fair to leave that for another patch series with
> cleanups and performance improvements or perhaps for microprojects.
Sure, we could repeat past mistakes in this patch series, too.

If, on the other hand, we use this patch series as "an excuse" to introduce such a helper, no future patch series will have to use the same kind of argument as you just offered. Instead, we will have an improved API that will help not only this patch series, but many more to come.

There is tons of precedent for this kind of thing, where we add an introductory patch at the beginning of a patch series, factoring out already-existing code into a more reusable shape, and then use it.

So why not repeat that pattern and do the same thing here?

Ciao, Johannes

Previous: Christian CouderNext: Miriam Rubio
Message 27 of 54 in “Finish converting git bisect to C part 1”
  1. Miriam RubioJan 20, 2020
  2. 03/29 bisect: use the standard 'if (!var)' way to check for 0Miriam Rubio, Jan 20, 2020
  3. 01/29 bisect--helper: convert `vocab_*` char pointers to char arraysMiriam Rubio, Jan 20, 2020
  4. 02/29 bisect--helper: change `retval` to `res`Miriam Rubio, Jan 20, 2020
  5. 07/29 bisect: libify `bisect_checkout`Miriam Rubio, Jan 20, 2020
  6. 08/29 bisect: libify `check_merge_bases` and its dependentsMiriam Rubio, Jan 20, 2020
  7. Johannes SchindelinJan 20, 2020
  8. Miriam R.Jan 21, 2020
  9. 04/29 run-command: make `exists_in_PATH()` non-staticMiriam Rubio, Jan 20, 2020
  10. 09/29 bisect: libify `check_good_are_ancestors_of_bad` and its dependentsMiriam Rubio, Jan 20, 2020
  11. Johannes SchindelinJan 20, 2020
  12. Christian CouderJan 21, 2020
  13. Miriam R.Jan 21, 2020
  14. 05/29 bisect--helper: introduce new `decide_next()` functionMiriam Rubio, Jan 20, 2020
  15. 10/29 bisect: libify `handle_bad_merge_base` and its dependentsMiriam Rubio, Jan 20, 2020
  16. Johannes SchindelinJan 20, 2020
  17. Christian CouderJan 21, 2020
  18. Miriam R.Jan 21, 2020
  19. 11/29 bisect: libify `bisect_next_all`Miriam Rubio, Jan 20, 2020
  20. Johannes SchindelinJan 20, 2020
  21. Christian CouderJan 21, 2020
  22. Johannes SchindelinJan 30, 2020
  23. 12/29 bisect--helper: reimplement `bisect_next` and `bisect_auto_next` shell functions in CMiriam Rubio, Jan 20, 2020
  24. Johannes SchindelinJan 30, 2020
  25. Miriam R.Jan 31, 2020
  26. Christian CouderFeb 17, 2020
  27. Johannes SchindelinFeb 17, 2020
  28. 13/29 bisect--helper: finish porting `bisect_start()` to CMiriam Rubio, Jan 20, 2020
  29. 06/29 bisect: libify `exit_if_skipped_commits` to `error_if_skipped*` and its dependentsMiriam Rubio, Jan 20, 2020
  30. Johannes SchindelinJan 20, 2020
  31. Christian CouderJan 21, 2020
  32. Miriam R.Jan 21, 2020
  33. 14/29 bisect--helper: retire `--bisect-clean-state` subcommandMiriam Rubio, Jan 20, 2020
  34. 15/29 bisect--helper: retire `--next-all` subcommandMiriam Rubio, Jan 20, 2020
  35. 17/29 bisect--helper: reimplement `bisect_state` & `bisect_head` shell functions in CMiriam Rubio, Jan 20, 2020
  36. 16/29 bisect--helper: reimplement `bisect_autostart` shell function in CMiriam Rubio, Jan 20, 2020
  37. 19/29 bisect--helper: retire `--write-terms` subcommandMiriam Rubio, Jan 20, 2020
  38. 18/29 bisect--helper: retire `--check-expected-revs` subcommandMiriam Rubio, Jan 20, 2020
  39. 20/29 bisect--helper: reimplement `bisect_log` shell function in CMiriam Rubio, Jan 20, 2020
  40. 21/29 bisect--helper: reimplement `bisect_replay` shell function in CMiriam Rubio, Jan 20, 2020
  41. 22/29 bisect--helper: retire `--bisect-write` subcommandMiriam Rubio, Jan 20, 2020
  42. 24/29 bisect--helper: retire `--bisect-autostart` subcommandMiriam Rubio, Jan 20, 2020
  43. 25/29 bisect--helper: retire `--bisect-auto-next` subcommandMiriam Rubio, Jan 20, 2020
  44. 23/29 bisect--helper: use `res` instead of return in BISECT_RESET case optionMiriam Rubio, Jan 20, 2020
  45. 26/29 bisect--helper: reimplement `bisect_skip` shell function in CMiriam Rubio, Jan 20, 2020
  46. 27/29 bisect--helper: retire `--check-and-set-terms` subcommandMiriam Rubio, Jan 20, 2020
  47. 28/29 bisect--helper: reimplement `bisect_visualize()`shell function in CMiriam Rubio, Jan 20, 2020
  48. 29/29 bisect--helper: reimplement `bisect_run` shell function in CMiriam Rubio, Jan 20, 2020
  49. Johannes SchindelinJan 20, 2020
  50. Christian CouderJan 20, 2020
  51. Johannes SchindelinJan 30, 2020
  52. Junio C HamanoJan 30, 2020
  53. Miriam R.Jan 21, 2020
  54. Johannes SchindelinJan 30, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.