From: Stefan Beller <sbeller@google.com>
To: gitster@pobox.com
Cc: git@vger.kernel.org, jonathantanmy@google.com,
christian.couder@gmail.com, pc44800@gmail.com,
Stefan Beller <sbeller@google.com>
Subject: [PATCH 5/5] submodule: port submodule subcommand 'foreach' from shell to C
Date: Wed, 2 May 2018 17:53:58 -0700 [thread overview]
Message-ID: <20180503005358.89082-6-sbeller@google.com> (raw)
In-Reply-To: <20180503005358.89082-1-sbeller@google.com>
From: Prathamesh Chavan <pc44800@gmail.com>
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>
---
builtin/submodule--helper.c | 148 ++++++++++++++++++++++++++++++++++++
git-submodule.sh | 39 +---------
2 files changed, 149 insertions(+), 38 deletions(-)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a404df3ea49..bbbea5868de 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -439,6 +439,153 @@ static void for_each_listed_submodule(const struct module_list *list,
fn(list->entries[i], cb_data);
}
+struct cb_foreach {
+ int argc;
+ const char **argv;
+ const char *prefix;
+ char *toplevel;
+ 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(&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();
+
+ 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.
+ */
+ argv_array_pushf(&cp.args, "path=%s; %s",
+ path, info->argv[0]);
+
+ 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");
+
+ if (info->toplevel)
+ argv_array_pushf(&cpr.args, "--toplevel=%s", info->toplevel);
+
+ 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_STRING(0, "toplevel", &info.toplevel, N_("path"),
+ N_("path from the top level of the invocation")),
+ 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 {
const char *prefix;
unsigned int flags;
@@ -1838,6 +1985,7 @@ static struct cmd_struct commands[] = {
{"relative-path", resolve_relative_path, 0},
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
+ {"foreach", module_foreach, SUPPORT_SUPER_PREFIX},
{"init", module_init, SUPPORT_SUPER_PREFIX},
{"status", module_status, SUPPORT_SUPER_PREFIX},
{"print-default-remote", print_default_remote, 0},
diff --git a/git-submodule.sh b/git-submodule.sh
index 331d71c908b..cba585f0754 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -323,44 +323,7 @@ cmd_foreach()
shift
done
- toplevel=$(pwd)
-
- # 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
+ git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper foreach ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@"
}
#
--
2.17.0.441.gb46fe60e1d-goog
next prev parent reply other threads:[~2018-05-03 0:54 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-03 0:53 [PATCH 0/5] Rebooting pc/submodule-helper-foreach Stefan Beller
2018-05-03 0:53 ` [PATCH 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Stefan Beller
2018-05-03 13:29 ` Ramsay Jones
2018-05-03 17:47 ` Jonathan Tan
2018-05-03 18:12 ` Stefan Beller
2018-05-04 21:03 ` Jonathan Tan
2018-05-03 0:53 ` [PATCH 2/5] submodule foreach: document '$sm_path' instead of '$path' Stefan Beller
2018-05-03 17:50 ` Jonathan Tan
2018-05-03 0:53 ` [PATCH 3/5] submodule foreach: clarify the '$toplevel' variable documentation Stefan Beller
2018-05-03 17:51 ` Jonathan Tan
2018-05-03 0:53 ` [PATCH 4/5] submodule foreach: document variable '$displaypath' Stefan Beller
2018-05-03 0:53 ` Stefan Beller [this message]
2018-05-03 1:06 ` [PATCH 5/5] submodule: port submodule subcommand 'foreach' from shell to C Stefan Beller
2018-05-03 18:05 ` Jonathan Tan
2018-05-09 0:29 ` [PATCHv2 0/4] Rebooting pc/submodule-helper-foreach Stefan Beller
2018-05-09 0:29 ` [PATCH 1/4] submodule foreach: correct '$path' in nested submodules from a subdirectory Stefan Beller
2018-05-09 0:29 ` [PATCH 2/4] submodule foreach: document '$sm_path' instead of '$path' Stefan Beller
2018-05-09 0:29 ` [PATCH 3/4] submodule foreach: document variable '$displaypath' Stefan Beller
2018-05-09 0:29 ` [PATCH 4/4] submodule: port submodule subcommand 'foreach' from shell to C Stefan Beller
2018-05-10 6:37 ` Junio C Hamano
2018-05-10 21:25 ` [PATCH] " Stefan Beller
2018-05-09 17:13 ` [PATCHv2 0/4] Rebooting pc/submodule-helper-foreach Jonathan Tan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180503005358.89082-6-sbeller@google.com \
--to=sbeller@google.com \
--cc=christian.couder@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jonathantanmy@google.com \
--cc=pc44800@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).