Stefan Beller <sbeller@xxxxxxxxxx> writes: > +static void runcommand_in_submodule_cb(const struct cache_entry *list_item, > + void *cb_data) > +{ > + struct cb_foreach *info = cb_data; > + const char *path = list_item->name; > + const struct object_id *ce_oid = &list_item->oid; > + > + const struct submodule *sub; > + struct child_process cp = CHILD_PROCESS_INIT; > + char *displaypath; > + > + displaypath = get_submodule_displaypath(path, info->prefix); > + > + sub = submodule_from_path(the_repository, &null_oid, path); > + > + if (!sub) > + die(_("No url found for submodule path '%s' in .gitmodules"), > + displaypath); > + > + if (!is_submodule_populated_gently(path, NULL)) > + goto cleanup; > + > + prepare_submodule_repo_env(&cp.env_array); > + > + /* > + * For the purpose of executing <command> in the submodule, > + * separate shell is used for the purpose of running the > + * child process. > + */ Micronit: this multi-line comment is indented in a funny way. > + cp.use_shell = 1; > + cp.dir = path; > + > + /* > + * NEEDSWORK: the command currently has access to the variables $name, > + * $sm_path, $displaypath, $sha1 and $toplevel only when the command > + * contains a single argument. This is done for maintaining a faithful > + * translation from shell script. > + */ Same micronit. The scripted version does 'eval "$1"', so $1 could be something like for-each 'echo "$name:$sm_path:$displaypath:$sha1:$toplevel"' and it can see any variable, not just these 5 (i.e. we could have fed e.g. $wt_prefix and $mode to the above 'echo' and with the scripted version the script would have learned their values; with this version it no longer does, but only these 5 are part of the documented API, so we choose not to consider it a regression). > + if (info->argc == 1) { > + char *toplevel = xgetcwd(); > + struct strbuf sb = STRBUF_INIT; > + > + argv_array_pushf(&cp.env_array, "name=%s", sub->name); > + argv_array_pushf(&cp.env_array, "sm_path=%s", path); > + argv_array_pushf(&cp.env_array, "displaypath=%s", displaypath); > + argv_array_pushf(&cp.env_array, "sha1=%s", > + oid_to_hex(ce_oid)); > + argv_array_pushf(&cp.env_array, "toplevel=%s", toplevel); > + > + /* > + * Since the path variable was accessible from the script > + * before porting, it is also made available after porting. > + * The environment variable "PATH" has a very special purpose > + * on windows. And since environment variables are > + * case-insensitive in windows, it interferes with the > + * existing PATH variable. Hence, to avoid that, we expose > + * path via the args argv_array and not via env_array. > + */ > + sq_quote_buf(&sb, path); > + argv_array_pushf(&cp.args, "path=%s; %s", > + sb.buf, info->argv[0]); OK, so we do the equivalent of name=... sm_path=... displaypath=... sha1=... toplevel=... \ sh -c 'path=...; echo "$name:$sm_path:..."' when doing for-each 'echo "$name:$sm_path:..."' with parts denoted with ... correctly quoted as necessary. I guess it would be the best we could do. I myself do not know if it is true that bash ported to Windows won't get confused with the above "we use path (all lowercase) only as a pure shell variable without exporting it ourselves"; I'd trust those who are more familiar with the platform to raise objections and suggest a better alternative if it is not the case. Thanks for the (malformatted;-) leading comment to highlight why the 'path' variable alone is treated differently from the others. > + strbuf_release(&sb); > + free(toplevel); > + } else { > + argv_array_pushv(&cp.args, info->argv); > + } > + > + if (!info->quiet) > + printf(_("Entering '%s'\n"), displaypath); > + > + if (info->argv[0] && run_command(&cp)) > + die(_("run_command returned non-zero status for %s\n."), > + displaypath); > + > + if (info->recursive) { > + struct child_process cpr = CHILD_PROCESS_INIT; > + > + cpr.git_cmd = 1; > + cpr.dir = path; > + prepare_submodule_repo_env(&cpr.env_array); > + > + argv_array_pushl(&cpr.args, "--super-prefix", NULL); > + argv_array_pushf(&cpr.args, "%s/", displaypath); > + argv_array_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive", > + NULL); > + > + if (info->quiet) > + argv_array_push(&cpr.args, "--quiet"); > + > + argv_array_pushv(&cpr.args, info->argv); > + > + if (run_command(&cpr)) > + die(_("run_command returned non-zero status while" > + "recursing in the nested submodules of %s\n."), > + displaypath); > + } > + > +cleanup: > + free(displaypath); > +}