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

Re: [GSoC][PATCH v6 2/2] submodule: port subcommand foreach from shell to C

From
Stefan Beller <sbeller@google.com>
Date
Jun 3, 2017, 02:13 UTC
Message-ID
<CAGZ79kbDpyO5uRCPnhCWmaFKhyLEUN7mYO9PhU3xF0f=W35ofw@mail.gmail.com>
In-Reply-To
<20170602112428.11131-2-pc44800@gmail.com>
On Fri, Jun 2, 2017 at 4:24 AM, Prathamesh Chavan <pc44800@gmail.com> wrote:
Show 31 quoted lines
> This aims to make git-submodule foreach a builtin. This is the very
> first step taken in this direction. Hence, 'foreach' is ported to
> submodule--helper, and submodule--helper is called from git-submodule.sh.
> The code is split up to have one function to obtain all the list of
> submodules. This function acts as the front-end of git-submodule foreach
> subcommand. It calls the function for_each_submodule_list, which basically
> loops through the list and calls function fn, which in this case is
> runcommand_in_submodule. This third function is a calling function that
> takes care of running the command in that submodule, and recursively
> perform the same when --recursive is flagged.
>
> The first function module_foreach first parses the options present in
> argv, and then with the help of module_list_compute, generates the list of
> submodules present in the current working tree.
>
> The second function for_each_submodule_list traverses through the
> list, and calls function fn (which in case of submodule subcommand
> foreach is runcommand_in_submodule) is called for each entry.
>
> The third function runcommand_in_submodule, generates a submodule struct sub
> for $name, value and then later prepends name=sub->name; and other
> value assignment to the env argv_array structure of a child_process.
> Also the <command> of submodule-foreach is push to args argv_array
> structure and finally, using run_command the commands are executed
> using a shell.
>
> The third function also takes care of the recursive flag, by creating
> a separate child_process structure and prepending "--super-prefix displaypath",
> to the args argv_array structure. Other required arguments and the
> input <command> of submodule-foreach is also appended to this argv_array.
>

Is the commit message still accurate? You describe the changes between the versions below the --- line, that is not recorded in the permanent commit history.

In the commit message is less important to write "what" is happening, because that can easily be read from the patch/commit itself, but rather "why" things happen, such as design choices, maybe:

    This aims to make git-submodule foreach a builtin. This is the very
    first step taken in this direction. Hence, 'foreach' is ported to
    submodule--helper, and submodule--helper is called from git-submodule.sh.
    We'll introduce 3 functions, one that is exposed to the command line
    and handles command line arguments, one to iterate over a set of
    submodules, and finally one to execute an arbitrary shell command
    in the submodule.
    Attention must be paid to the 'path' variable, see 64394e3ae9
    (git-submodule.sh: Don't use $path variable in eval_gettext string,
    2012-04-17) details. The path varialbe is not exposed into the environment
    of the invoked shell, but we just give "path=%s;" as the first argument.
    We do not need to condition on the number of arguments as in 1c4fb136db
    (submodule foreach: skip eval for more than one argument, 2013-09-27)
    as we will run exactly one shell in the submodules directory.
    Sign-off-...
Show 10 quoted lines
>
> Other than that, additionally the case of no. of arugments in <command>
> being equal to 1 is also considered separetly.
> THe reason of having this change in the shell script was given in the
> commit 1c4fb136db.
> According to my understanding, eval "$1" executes $1 in same shell,
> whereas "$@" gets executed in a separate shell, which doesn't allow
> "$@" to access the env variables $name, $path, etc.
> Hence, to keep the ported function similar, this condition is also
> added.

This paragraph would be a good candidate for the commit message, too. However as we rewrite it in C, we will spawn exactly one shell no matter how many arguments we have (well for 0 we have no shell, but for 1 or more arguments we'll spawn exactly one shell?)

Show 5 quoted lines
> +       } else if (prefix) {
> +               struct strbuf sb = STRBUF_INIT;
> +               char *displaypath = xstrdup(relative_path(path, prefix, &sb));
> +               strbuf_release(&sb);
> +               return displaypath;
Note to self (or any other that is interested in long term clean code):
    I have seen this pattern a couple of times, a strbuf just to appease
    the argument list of relative_path.
    (init_submodule, prepare_to_clone_next_submodule,
    resolve_relative_path in submodule--helper
    cmd_rev_parse in builtin/rev-parse
    connect_work_tree_and_git_dir in dir.c
    write_name_quoted_relative in quote.c
    get_superproject_working_tree in submodule.c
    cmd_main in test-path-utils;
    actually all uses of this function :( )
    We should really make a relative_path function that can work
    without the need of a strbuf, maybe just wrap the 3 lines into a new
    function, or remove the strbuf from the argument list.
    (The potential memleak is horrible to fix though. But as seen here
    we could just always return an allocated string and
    mandate the caller to free it)
Show 11 quoted lines
> +struct cb_foreach {
> +       int argc;
> +       const char **argv;
> +       const char *prefix;
> +       unsigned int quiet: 1;
> +       unsigned int recursive: 1;
> +};
> +#define CB_FOREACH_INIT { 0, NULL, NULL, 0, 0 }
> +
> +static void runcommand_in_submodule(const struct cache_entry *list_item,
> +                                   void *cb_data)

As we only ever use list_item->name, we could also change the argument list to take a "const char *[submodule_]path".

Show 13 quoted lines
> +       prepare_submodule_repo_env(&cp.env_array);
> +       cp.use_shell = 1;
> +       cp.dir = list_item->name;
> +
> +       if (info->argc == 1) {
> +               argv_array_pushf(&cp.env_array, "name=%s", sub->name);
> +               argv_array_pushf(&cp.env_array, "sm_path=%s", displaypath);
> +               argv_array_pushf(&cp.env_array, "sha1=%s",
> +                                oid_to_hex(&list_item->oid));
> +               argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel);
> +
> +               argv_array_pushf(&cp.args, "path=%s; %s", list_item->name,
> +                                info->argv[0]);
In the argc != 1 case we also want to have the env_array filled with
useful variables. (It seems we do not have tests for that?)
To test for that we'd need a test similar as in 1c4fb136d,
just with
    git submodule foreach echo \$sm_path \$dpath
for example.

So I think you can move the pushes to the env array outside this condition. As we set cp.use_shell unconditionally, we do not need to construct the first argument specially with path preset, but instead we can just prepend it in the array:

    argv_array_pushf(&cp.env_array, "name=%s", sub->name);
    ... // more env stuff
    argv_array_pushf(&cp.args, "path=%s;", list_item->name);
    for (i = 0; i < info->argc; i++)
        argv_array_push(&cp.args, info->argv[i]);
should do?
> +
> +       if (info->argv[0] && run_command(&cp))
> +               die(_("run_command returned non-zero status for %s\n."),
This would rather be
    die(_("Stopping at '%s'; script returned non-zero status."), displaypath);
to imitate the shell version faithfully?
Show 5 quoted lines
> +
> +               if (run_command(&cpr))
> +                       die(_("run_command returned non-zero status while"
> +                             "recursing in the nested submodules of %s\n."),
> +                             displaypath);

same here. As the inner process would have already printed the "Stopping..." we would not need to repeat it, though.

So maybe
    /* no need to report error, child does: */
    run_command(&cpr);
The rest below looks good. :)

Thanks, Stefan

Previous: Prathamesh ChavanNext: Prathamesh Chavan
Message 42 of 48 in “submodule: port subcommand foreach from shell to C”
  1. Prathamesh ChavanApr 19, 2017
  2. Stefan BellerApr 19, 2017
  3. [GSoC][RFC/PATCH v2] submodule: port subcommand foreach from shell to CPrathamesh Chavan, Apr 22, 2017
  4. Junio C HamanoApr 24, 2017
  5. Stefan BellerApr 24, 2017
  6. Ramsay JonesApr 24, 2017
  7. Stefan BellerApr 24, 2017
  8. Ramsay JonesApr 24, 2017
  9. [GSoC][RFC/PATCH v3 1/2] t7407: test "submodule foreach --recursive" from subdirectory addedPrathamesh Chavan, May 12, 2017
  10. [GSoC][RFC/PATCH v3 2/2] submodule: port subcommand foreach from shell to CPrathamesh Chavan, May 12, 2017
  11. Stefan BellerMay 15, 2017
  12. Brandon WilliamsMay 15, 2017
  13. [GSoC][PATCH v4 1/2] t7407: test "submodule foreach --recursive" from subdirectory addedPrathamesh Chavan, May 21, 2017
  14. [GSoC][PATCH v4 2/2] submodule: port subcommand foreach from shell to CPrathamesh Chavan, May 21, 2017
  15. Stefan BellerMay 22, 2017
  16. Brandon WilliamsMay 23, 2017
  17. Brandon WilliamsMay 23, 2017
  18. Stefan BellerMay 23, 2017
  19. Brandon WilliamsMay 23, 2017
  20. [GSoC][PATCH v5 1/3] submodule: fix buggy $path and $sm_path variable's valuePrathamesh Chavan, May 26, 2017
  21. [GSoC][PATCH v5 3/3] submodule: port subcommand foreach from shell to CPrathamesh Chavan, May 26, 2017
  22. Stefan BellerMay 26, 2017
  23. Brandon WilliamsMay 26, 2017
  24. Johannes SixtMay 26, 2017
  25. Ramsay JonesMay 27, 2017
  26. Ramsay JonesMay 27, 2017
  27. Johannes SixtMay 27, 2017
  28. Brandon WilliamsMay 26, 2017
  29. [GSoC][PATCH v5 2/3] t7407: test "submodule foreach --recursive" from subdirectory addedPrathamesh Chavan, May 26, 2017
  30. Stefan BellerMay 26, 2017
  31. Brandon WilliamsMay 26, 2017
  32. Ramsay JonesMay 26, 2017
  33. Stefan BellerMay 26, 2017
  34. Ramsay JonesMay 27, 2017
  35. Stefan BellerMay 30, 2017
  36. Ramsay JonesMay 30, 2017
  37. Stefan BellerMay 30, 2017
  38. Ramsay JonesMay 31, 2017
  39. Ramsay JonesMay 31, 2017
  40. [GSoC][PATCH v6 1/2] submodule: fix buggy $path and $sm_path variable's valuePrathamesh Chavan, Jun 2, 2017
  41. [GSoC][PATCH v6 2/2] submodule: port subcommand foreach from shell to CPrathamesh Chavan, Jun 2, 2017
  42. Stefan BellerJun 3, 2017
  43. Prathamesh ChavanJun 4, 2017
  44. Brandon WilliamsMay 23, 2017
  45. submodule foreach: correct $sm_path in nested submodules from a dirStefan Beller, Jun 3, 2017
  46. Ramsay JonesJun 3, 2017
  47. Ramsay JonesJun 4, 2017
  48. Jonathan NiederJun 5, 2017

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.