mirror of
https://github.com/git/git
synced 2024-08-27 11:39:22 +00:00
submodule: port submodule subcommand 'foreach' from shell to C
This aims to make git-submodule foreach a builtin. 'foreach' is ported to the submodule--helper, and submodule--helper is called from git-submodule.sh. Helped-by: Brandon Williams <bmwill@google.com> Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Stefan Beller <sbeller@google.com> Signed-off-by: Prathamesh Chavan <pc44800@gmail.com> Signed-off-by: Stefan Beller <sbeller@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
b6f7ac8fd5
commit
fc1b9243cd
|
@ -439,6 +439,149 @@ static void for_each_listed_submodule(const struct module_list *list,
|
||||||
fn(list->entries[i], cb_data);
|
fn(list->entries[i], cb_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct cb_foreach {
|
||||||
|
int argc;
|
||||||
|
const char **argv;
|
||||||
|
const char *prefix;
|
||||||
|
int quiet;
|
||||||
|
int recursive;
|
||||||
|
};
|
||||||
|
#define CB_FOREACH_INIT { 0 }
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
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]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int module_foreach(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
struct cb_foreach info = CB_FOREACH_INIT;
|
||||||
|
struct pathspec pathspec;
|
||||||
|
struct module_list list = MODULE_LIST_INIT;
|
||||||
|
|
||||||
|
struct option module_foreach_options[] = {
|
||||||
|
OPT__QUIET(&info.quiet, N_("Suppress output of entering each submodule command")),
|
||||||
|
OPT_BOOL(0, "recursive", &info.recursive,
|
||||||
|
N_("Recurse into nested submodules")),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const git_submodule_helper_usage[] = {
|
||||||
|
N_("git submodule--helper foreach [--quiet] [--recursive] <command>"),
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
argc = parse_options(argc, argv, prefix, module_foreach_options,
|
||||||
|
git_submodule_helper_usage, PARSE_OPT_KEEP_UNKNOWN);
|
||||||
|
|
||||||
|
if (module_list_compute(0, NULL, prefix, &pathspec, &list) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
info.argc = argc;
|
||||||
|
info.argv = argv;
|
||||||
|
info.prefix = prefix;
|
||||||
|
|
||||||
|
for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct init_cb {
|
struct init_cb {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -1841,6 +1984,7 @@ static struct cmd_struct commands[] = {
|
||||||
{"relative-path", resolve_relative_path, 0},
|
{"relative-path", resolve_relative_path, 0},
|
||||||
{"resolve-relative-url", resolve_relative_url, 0},
|
{"resolve-relative-url", resolve_relative_url, 0},
|
||||||
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
||||||
|
{"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
|
||||||
{"init", module_init, SUPPORT_SUPER_PREFIX},
|
{"init", module_init, SUPPORT_SUPER_PREFIX},
|
||||||
{"status", module_status, SUPPORT_SUPER_PREFIX},
|
{"status", module_status, SUPPORT_SUPER_PREFIX},
|
||||||
{"print-default-remote", print_default_remote, 0},
|
{"print-default-remote", print_default_remote, 0},
|
||||||
|
|
|
@ -323,44 +323,7 @@ cmd_foreach()
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
toplevel=$(pwd)
|
git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@"
|
||||||
|
|
||||||
# dup stdin so that it can be restored when running the external
|
|
||||||
# command in the subshell (and a recursive call to this function)
|
|
||||||
exec 3<&0
|
|
||||||
|
|
||||||
{
|
|
||||||
git submodule--helper list --prefix "$wt_prefix" ||
|
|
||||||
echo "#unmatched" $?
|
|
||||||
} |
|
|
||||||
while read -r mode sha1 stage sm_path
|
|
||||||
do
|
|
||||||
die_if_unmatched "$mode" "$sha1"
|
|
||||||
if test -e "$sm_path"/.git
|
|
||||||
then
|
|
||||||
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
|
|
||||||
say "$(eval_gettext "Entering '\$displaypath'")"
|
|
||||||
name=$(git submodule--helper name "$sm_path")
|
|
||||||
(
|
|
||||||
prefix="$prefix$sm_path/"
|
|
||||||
sanitize_submodule_env
|
|
||||||
cd "$sm_path" &&
|
|
||||||
# we make $path available to scripts ...
|
|
||||||
path=$sm_path &&
|
|
||||||
if test $# -eq 1
|
|
||||||
then
|
|
||||||
eval "$1"
|
|
||||||
else
|
|
||||||
"$@"
|
|
||||||
fi &&
|
|
||||||
if test -n "$recursive"
|
|
||||||
then
|
|
||||||
cmd_foreach "--recursive" "$@"
|
|
||||||
fi
|
|
||||||
) <&3 3<&- ||
|
|
||||||
die "$(eval_gettext "Stopping at '\$displaypath'; script returned non-zero status.")"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in a new issue