git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v1 0/5] Incremental rewrite of git-submodules
@ 2018-02-02  4:57 Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Prathamesh Chavan
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

Following series of patches focuses on porting submodule subcommand
git-foreach from shell to C.
An initial attempt for porting was introduced about 9 months back,
and since then then patches have undergone many changes. Some of the 
notable discussion thread which I would like to point out is: [1] 
The previous version of this patch series which was floated is
available at: [2].

The following changes were made to that:
* As it was observed in other submodule subcommand's ported function
  that the number of params increased a lot, the variables quiet and 
  recursive, were replaced in the cb_foreach struct with a single
  unsigned integer variable called flags.

* To accomodate the possiblity of a direct call to the functions
  runcommand_in_submodule(), callback function
  runcommand_in_submodule_cb() was introduced.

[1]: https://public-inbox.org/git/20170419170513.16475-1-pc44800@gmail.com/T/#u
[2]: https://public-inbox.org/git/20170807211900.15001-14-pc44800@gmail.com/

As before you can find this series at: 
https://github.com/pratham-pc/git/commits/patch-series-3

And its build report is available at: 
https://travis-ci.org/pratham-pc/git/builds/
Branch: patch-series-3
Build #202

Prathamesh Chavan (5):
  submodule foreach: correct '$path' in nested submodules from a
    subdirectory
  submodule foreach: document '$sm_path' instead of '$path'
  submodule foreach: clarify the '$toplevel' variable documentation
  submodule foreach: document variable '$displaypath'
  submodule: port submodule subcommand 'foreach' from shell to C

 Documentation/git-submodule.txt |  15 ++--
 builtin/submodule--helper.c     | 151 ++++++++++++++++++++++++++++++++++++++++
 git-submodule.sh                |  40 +----------
 t/t7407-submodule-foreach.sh    |  38 +++++++++-
 4 files changed, 197 insertions(+), 47 deletions(-)

-- 
2.15.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory
  2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
@ 2018-02-02  4:57 ` Prathamesh Chavan
  2018-02-06 22:54   ` Jonathan Tan
  2018-02-02  4:57 ` [PATCH v1 2/5] submodule foreach: document '$sm_path' instead of '$path' Prathamesh Chavan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

When running 'git submodule foreach' from a subdirectory of your
repository, nested submodules get a bogus value for $sm_path:
For a submodule 'sub' that contains a nested submodule 'nested',
running 'git -C dir submodule foreach echo $path' would report
path='../nested' for the nested submodule. The first part '../' is
derived from the logic computing the relative path from $pwd to the
root of the superproject. The second part is the submodule path inside
the submodule. This value is of little use and is hard to document.

There are two different possible solutions that have more value:
(a) The path value is documented as the path from the toplevel of the
    superproject to the mount point of the submodule.
    In this case we would want to have path='sub/nested'.

(b) As Ramsay noticed the documented value is wrong. For the non-nested
    case the path is equal to the relative path from $pwd to the
    submodules working directory. When following this model,
    the expected value would be path='../sub/nested'.

The behavior for (b) was introduced in 091a6eb0fe (submodule: drop the
top-level requirement, 2013-06-16) the intent for $path seemed to be
relative to $cwd to the submodule worktree, but that did not work for
nested submodules, as the intermittent submodules were not included in
the path.

If we were to fix the meaning of the $path using (a) such that "path"
is "the path from the toplevel of the superproject to the mount point
of the submodule", we would break any existing submodule user that runs
foreach from non-root of the superproject as the non-nested submodule
'../sub' would change its path to 'sub'.

If we would fix the meaning of the $path using (b), such that "path"
is "the relative path from $pwd to the submodule", then we would break
any user that uses nested submodules (even from the root directory) as
the 'nested' would become 'sub/nested'.

Both groups can be found in the wild.  The author has no data if one group
outweighs the other by large margin, and offending each one seems equally
bad at first.  However in the authors imagination it is better to go with
(a) as running from a sub directory sounds like it is carried out
by a human rather than by some automation task.  With a human on
the keyboard the feedback loop is short and the changed behavior can be
adapted to quickly unlike some automation that can break silently.

Discussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 git-submodule.sh             |  1 -
 t/t7407-submodule-foreach.sh | 36 ++++++++++++++++++++++++++++++++++--
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 156255a9e..7305ee25f 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -345,7 +345,6 @@ cmd_foreach()
 				prefix="$prefix$sm_path/"
 				sanitize_submodule_env
 				cd "$sm_path" &&
-				sm_path=$(git submodule--helper relative-path "$sm_path" "$wt_prefix") &&
 				# we make $path available to scripts ...
 				path=$sm_path &&
 				if test $# -eq 1
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 6ba5daf42..0663622a4 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -82,9 +82,9 @@ test_expect_success 'test basic "submodule foreach" usage' '
 
 cat >expect <<EOF
 Entering '../sub1'
-$pwd/clone-foo1-../sub1-$sub1sha1
+$pwd/clone-foo1-sub1-$sub1sha1
 Entering '../sub3'
-$pwd/clone-foo3-../sub3-$sub3sha1
+$pwd/clone-foo3-sub3-$sub3sha1
 EOF
 
 test_expect_success 'test "submodule foreach" from subdirectory' '
@@ -196,6 +196,38 @@ test_expect_success 'test messages from "foreach --recursive" from subdirectory'
 	) &&
 	test_i18ncmp expect actual
 '
+sub1sha1=$(cd clone2/sub1 && git rev-parse HEAD)
+sub2sha1=$(cd clone2/sub2 && git rev-parse HEAD)
+sub3sha1=$(cd clone2/sub3 && git rev-parse HEAD)
+nested1sha1=$(cd clone2/nested1 && git rev-parse HEAD)
+nested2sha1=$(cd clone2/nested1/nested2 && git rev-parse HEAD)
+nested3sha1=$(cd clone2/nested1/nested2/nested3 && git rev-parse HEAD)
+submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEAD)
+
+cat >expect <<EOF
+Entering '../nested1'
+$pwd/clone2-nested1-nested1-$nested1sha1
+Entering '../nested1/nested2'
+$pwd/clone2/nested1-nested2-nested2-$nested2sha1
+Entering '../nested1/nested2/nested3'
+$pwd/clone2/nested1/nested2-nested3-nested3-$nested3sha1
+Entering '../nested1/nested2/nested3/submodule'
+$pwd/clone2/nested1/nested2/nested3-submodule-submodule-$submodulesha1
+Entering '../sub1'
+$pwd/clone2-foo1-sub1-$sub1sha1
+Entering '../sub2'
+$pwd/clone2-foo2-sub2-$sub2sha1
+Entering '../sub3'
+$pwd/clone2-foo3-sub3-$sub3sha1
+EOF
+
+test_expect_success 'test "submodule foreach --recursive" from subdirectory' '
+	(
+		cd clone2/untracked &&
+		git submodule foreach --recursive "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual
+	) &&
+	test_i18ncmp expect actual
+'
 
 cat > expect <<EOF
 nested1-nested1
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 2/5] submodule foreach: document '$sm_path' instead of '$path'
  2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Prathamesh Chavan
@ 2018-02-02  4:57 ` Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 3/5] submodule foreach: clarify the '$toplevel' variable documentation Prathamesh Chavan
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

As using a variable '$path' may be harmful to users due to
capitalization issues, see 64394e3ae9 (git-submodule.sh: Don't
use $path variable in eval_gettext string, 2012-04-17). Adjust
the documentation to advocate for using $sm_path,  which contains
the same value. We still make the 'path' variable available and
document it as a deprecated synonym of 'sm_path'.

Discussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
---
 Documentation/git-submodule.txt | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index ff612001d..a23baef62 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -183,12 +183,14 @@ information too.
 
 foreach [--recursive] <command>::
 	Evaluates an arbitrary shell command in each checked out submodule.
-	The command has access to the variables $name, $path, $sha1 and
+	The command has access to the variables $name, $sm_path, $sha1 and
 	$toplevel:
 	$name is the name of the relevant submodule section in `.gitmodules`,
-	$path is the name of the submodule directory relative to the
-	superproject, $sha1 is the commit as recorded in the superproject,
-	and $toplevel is the absolute path to the top-level of the superproject.
+	$sm_path is the path of the submodule as recorded in the superproject,
+	$sha1 is the commit as recorded in the superproject, and
+	$toplevel is the absolute path to the top-level of the superproject.
+	Note that to avoid conflicts with '$PATH' on Windows, the '$path'
+	variable is now a deprecated synonym of '$sm_path' variable.
 	Any submodules defined in the superproject but not checked out are
 	ignored by this command. Unless given `--quiet`, foreach prints the name
 	of each submodule before evaluating the command.
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 3/5] submodule foreach: clarify the '$toplevel' variable documentation
  2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 2/5] submodule foreach: document '$sm_path' instead of '$path' Prathamesh Chavan
@ 2018-02-02  4:57 ` Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 4/5] submodule foreach: document variable '$displaypath' Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 5/5] submodule: port submodule subcommand 'foreach' from shell to C Prathamesh Chavan
  4 siblings, 0 replies; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

It does not contain the topmost superproject as the author assumed,
but the direct superproject, such that $toplevel/$sm_path is the
actual absolute path of the submodule.

Discussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
---
 Documentation/git-submodule.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index a23baef62..8e7930ebc 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -188,7 +188,8 @@ foreach [--recursive] <command>::
 	$name is the name of the relevant submodule section in `.gitmodules`,
 	$sm_path is the path of the submodule as recorded in the superproject,
 	$sha1 is the commit as recorded in the superproject, and
-	$toplevel is the absolute path to the top-level of the superproject.
+	$toplevel is the absolute path to its superproject, such that
+	$toplevel/$sm_path is the absolute path of the submodule.
 	Note that to avoid conflicts with '$PATH' on Windows, the '$path'
 	variable is now a deprecated synonym of '$sm_path' variable.
 	Any submodules defined in the superproject but not checked out are
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 4/5] submodule foreach: document variable '$displaypath'
  2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
                   ` (2 preceding siblings ...)
  2018-02-02  4:57 ` [PATCH v1 3/5] submodule foreach: clarify the '$toplevel' variable documentation Prathamesh Chavan
@ 2018-02-02  4:57 ` Prathamesh Chavan
  2018-02-02  4:57 ` [PATCH v1 5/5] submodule: port submodule subcommand 'foreach' from shell to C Prathamesh Chavan
  4 siblings, 0 replies; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

It was observed that the variable '$displaypath' was accessible but
undocumented. Hence, document it.

Discussed-with: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Stefan Beller <sbeller@google.com>
Signed-off-by: Prathamesh Chavan <pc44800@gmail.com>
---
 Documentation/git-submodule.txt |  6 ++++--
 t/t7407-submodule-foreach.sh    | 22 +++++++++++-----------
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 8e7930ebc..0cca702cb 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -183,10 +183,12 @@ information too.
 
 foreach [--recursive] <command>::
 	Evaluates an arbitrary shell command in each checked out submodule.
-	The command has access to the variables $name, $sm_path, $sha1 and
-	$toplevel:
+	The command has access to the variables $name, $sm_path, $displaypath,
+	$sha1 and $toplevel:
 	$name is the name of the relevant submodule section in `.gitmodules`,
 	$sm_path is the path of the submodule as recorded in the superproject,
+	$displaypath contains the relative path from the current working
+	directory to the submodules root directory,
 	$sha1 is the commit as recorded in the superproject, and
 	$toplevel is the absolute path to its superproject, such that
 	$toplevel/$sm_path is the absolute path of the submodule.
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 0663622a4..6ad57e061 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -82,16 +82,16 @@ test_expect_success 'test basic "submodule foreach" usage' '
 
 cat >expect <<EOF
 Entering '../sub1'
-$pwd/clone-foo1-sub1-$sub1sha1
+$pwd/clone-foo1-sub1-../sub1-$sub1sha1
 Entering '../sub3'
-$pwd/clone-foo3-sub3-$sub3sha1
+$pwd/clone-foo3-sub3-../sub3-$sub3sha1
 EOF
 
 test_expect_success 'test "submodule foreach" from subdirectory' '
 	mkdir clone/sub &&
 	(
 		cd clone/sub &&
-		git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual
+		git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$displaypath-\$sha1" >../../actual
 	) &&
 	test_i18ncmp expect actual
 '
@@ -206,25 +206,25 @@ submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEA
 
 cat >expect <<EOF
 Entering '../nested1'
-$pwd/clone2-nested1-nested1-$nested1sha1
+$pwd/clone2-nested1-nested1-../nested1-$nested1sha1
 Entering '../nested1/nested2'
-$pwd/clone2/nested1-nested2-nested2-$nested2sha1
+$pwd/clone2/nested1-nested2-nested2-../nested1/nested2-$nested2sha1
 Entering '../nested1/nested2/nested3'
-$pwd/clone2/nested1/nested2-nested3-nested3-$nested3sha1
+$pwd/clone2/nested1/nested2-nested3-nested3-../nested1/nested2/nested3-$nested3sha1
 Entering '../nested1/nested2/nested3/submodule'
-$pwd/clone2/nested1/nested2/nested3-submodule-submodule-$submodulesha1
+$pwd/clone2/nested1/nested2/nested3-submodule-submodule-../nested1/nested2/nested3/submodule-$submodulesha1
 Entering '../sub1'
-$pwd/clone2-foo1-sub1-$sub1sha1
+$pwd/clone2-foo1-sub1-../sub1-$sub1sha1
 Entering '../sub2'
-$pwd/clone2-foo2-sub2-$sub2sha1
+$pwd/clone2-foo2-sub2-../sub2-$sub2sha1
 Entering '../sub3'
-$pwd/clone2-foo3-sub3-$sub3sha1
+$pwd/clone2-foo3-sub3-../sub3-$sub3sha1
 EOF
 
 test_expect_success 'test "submodule foreach --recursive" from subdirectory' '
 	(
 		cd clone2/untracked &&
-		git submodule foreach --recursive "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual
+		git submodule foreach --recursive "echo \$toplevel-\$name-\$sm_path-\$displaypath-\$sha1" >../../actual
 	) &&
 	test_i18ncmp expect actual
 '
-- 
2.15.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 5/5] submodule: port submodule subcommand 'foreach' from shell to C
  2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
                   ` (3 preceding siblings ...)
  2018-02-02  4:57 ` [PATCH v1 4/5] submodule foreach: document variable '$displaypath' Prathamesh Chavan
@ 2018-02-02  4:57 ` Prathamesh Chavan
  4 siblings, 0 replies; 9+ messages in thread
From: Prathamesh Chavan @ 2018-02-02  4:57 UTC (permalink / raw)
  To: git; +Cc: christian.couder, gitster, sbeller, Prathamesh Chavan

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_listed_submodule(), which basically
loops through the list and calls function fn, which in this case is
runcommand_in_submodule_cb(). This third function is a callback function that
calls runcommand_in_submodule() with the appropriate parameters and then
takes care of running the command in that submodule, and recursively
performing 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_listed_submodule() traverses through the
list, and calls function fn (which in case of submodule subcommand
foreach is runcommand_in_submodule_cb()) is called for each entry.

The third function runcommand_in_submodule_cb() calls the function
runcommand_in_submodule() after passing appropraite parameters.

The fourth 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 fourth 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.

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>
---
 builtin/submodule--helper.c | 151 ++++++++++++++++++++++++++++++++++++++++++++
 git-submodule.sh            |  39 +-----------
 2 files changed, 152 insertions(+), 38 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index a5c4a8a69..46dee6bf5 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -718,6 +718,156 @@ static int module_name(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
+struct cb_foreach {
+	int argc;
+	const char **argv;
+	const char *prefix;
+	unsigned int flags;
+};
+#define CB_FOREACH_INIT { 0, NULL, NULL, 0 }
+
+static void runcommand_in_submodule(const char *path, const struct object_id *ce_oid,
+				    int argc, const char **argv, const char *prefix,
+				    unsigned int flags)
+{
+	const struct submodule *sub;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char *displaypath;
+
+	displaypath = get_submodule_displaypath(path, 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 maintianing a faithful
+	 * translation from shell script.
+	 */
+	if (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, argv[0]);
+		free(toplevel);
+	} else {
+		argv_array_pushv(&cp.args, argv);
+	}
+
+	if (!(flags & OPT_QUIET))
+		printf(_("Entering '%s'\n"), displaypath);
+
+	if (argv[0] && run_command(&cp))
+		die(_("run_command returned non-zero status for %s\n."),
+		      displaypath);
+
+	if (flags & OPT_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 (flags & OPT_QUIET)
+			argv_array_push(&cpr.args, "--quiet");
+
+		argv_array_pushv(&cpr.args, 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 void runcommand_in_submodule_cb(const struct cache_entry *list_item,
+				       void *cb_data)
+{
+	struct cb_foreach *info = cb_data;
+	runcommand_in_submodule(list_item->name, &list_item->oid, info->argc,
+				info->argv, info->prefix, info->flags);
+}
+
+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;
+	int quiet = 0;
+	int recursive = 0;
+
+	struct option module_foreach_options[] = {
+		OPT__QUIET(&quiet, N_("Suppress output of entering each submodule command")),
+		OPT_BOOL(0, "recursive", &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)
+		BUG("module_list_compute should not choke on empty pathspec");
+
+	info.argc = argc;
+	info.argv = argv;
+	info.prefix = prefix;
+	if (quiet)
+		info.flags |= OPT_QUIET;
+	if (recursive)
+		info.flags |= OPT_RECURSIVE;
+
+	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
+
+	return 0;
+}
+
 static int clone_submodule(const char *path, const char *gitdir, const char *url,
 			   const char *depth, struct string_list *reference,
 			   int quiet, int progress)
@@ -1496,6 +1646,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},
 	{"remote-branch", resolve_remote_submodule_branch, 0},
diff --git a/git-submodule.sh b/git-submodule.sh
index 7305ee25f..7627e27c8 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.15.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory
  2018-02-02  4:57 ` [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Prathamesh Chavan
@ 2018-02-06 22:54   ` Jonathan Tan
  2018-02-06 23:00     ` Jonathan Tan
  2018-02-06 23:11     ` Stefan Beller
  0 siblings, 2 replies; 9+ messages in thread
From: Jonathan Tan @ 2018-02-06 22:54 UTC (permalink / raw)
  To: Prathamesh Chavan; +Cc: git, christian.couder, gitster, sbeller

On Fri,  2 Feb 2018 10:27:41 +0530
Prathamesh Chavan <pc44800@gmail.com> wrote:

> When running 'git submodule foreach' from a subdirectory of your

Add "--recursive".

> repository, nested submodules get a bogus value for $sm_path:

Maybe call it $path for now, since $sm_path starts to be recommended
only in patches after this one.

> For a submodule 'sub' that contains a nested submodule 'nested',
> running 'git -C dir submodule foreach echo $path' would report

Add "from the root of the superproject", maybe?

> path='../nested' for the nested submodule. The first part '../' is
> derived from the logic computing the relative path from $pwd to the
> root of the superproject. The second part is the submodule path inside
> the submodule. This value is of little use and is hard to document.
> 
> There are two different possible solutions that have more value:
> (a) The path value is documented as the path from the toplevel of the
>     superproject to the mount point of the submodule.
>     In this case we would want to have path='sub/nested'.
> 
> (b) As Ramsay noticed the documented value is wrong. For the non-nested
>     case the path is equal to the relative path from $pwd to the
>     submodules working directory. When following this model,
>     the expected value would be path='../sub/nested'.

A third solution is to use "nested" - that is, the name of the submodule
directory relative to its superproject. (It's currently documented as
"the name of the submodule directory relative to the superproject".)
Having said that, (b) is probably better.

> Both groups can be found in the wild.  The author has no data if one group
> outweighs the other by large margin, and offending each one seems equally
> bad at first.  However in the authors imagination it is better to go with
> (a) as running from a sub directory sounds like it is carried out
> by a human rather than by some automation task.  With a human on
> the keyboard the feedback loop is short and the changed behavior can be
> adapted to quickly unlike some automation that can break silently.

Thanks - this is a good analysis.

>  git-submodule.sh             |  1 -
>  t/t7407-submodule-foreach.sh | 36 ++++++++++++++++++++++++++++++++++--

I think the documentation should be changed too - $path is the name of
the submodule directory relative to the current directory?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory
  2018-02-06 22:54   ` Jonathan Tan
@ 2018-02-06 23:00     ` Jonathan Tan
  2018-02-06 23:11     ` Stefan Beller
  1 sibling, 0 replies; 9+ messages in thread
From: Jonathan Tan @ 2018-02-06 23:00 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: Prathamesh Chavan, git, christian.couder, gitster, sbeller

On Tue, 6 Feb 2018 14:54:06 -0800
Jonathan Tan <jonathantanmy@google.com> wrote:

> > There are two different possible solutions that have more value:
> > (a) The path value is documented as the path from the toplevel of the
> >     superproject to the mount point of the submodule.
> >     In this case we would want to have path='sub/nested'.
> > 
> > (b) As Ramsay noticed the documented value is wrong. For the non-nested
> >     case the path is equal to the relative path from $pwd to the
> >     submodules working directory. When following this model,
> >     the expected value would be path='../sub/nested'.
>
> A third solution is to use "nested" - that is, the name of the submodule
> directory relative to its superproject. (It's currently documented as
> "the name of the submodule directory relative to the superproject".)
> Having said that, (b) is probably better.

[snip]

> > +cat >expect <<EOF
> > +Entering '../nested1'
> > +$pwd/clone2-nested1-nested1-$nested1sha1
> > +Entering '../nested1/nested2'
> > +$pwd/clone2/nested1-nested2-nested2-$nested2sha1
> > +Entering '../nested1/nested2/nested3'
> > +$pwd/clone2/nested1/nested2-nested3-nested3-$nested3sha1
> > +Entering '../nested1/nested2/nested3/submodule'
> > +$pwd/clone2/nested1/nested2/nested3-submodule-submodule-$submodulesha1
> > +Entering '../sub1'
> > +$pwd/clone2-foo1-sub1-$sub1sha1
> > +Entering '../sub2'
> > +$pwd/clone2-foo2-sub2-$sub2sha1
> > +Entering '../sub3'
> > +$pwd/clone2-foo3-sub3-$sub3sha1
> > +EOF
> > +
> > +test_expect_success 'test "submodule foreach --recursive" from subdirectory' '
> > +	(
> > +		cd clone2/untracked &&
> > +		git submodule foreach --recursive "echo \$toplevel-\$name-\$sm_path-\$sha1" >../../actual
> > +	) &&
> > +	test_i18ncmp expect actual
> > +'

Wait a minute...this seems like you're using my "third solution". If we
were using either (a) or (b), $sm_path would contain slashes in the case
of nested submodules, right?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory
  2018-02-06 22:54   ` Jonathan Tan
  2018-02-06 23:00     ` Jonathan Tan
@ 2018-02-06 23:11     ` Stefan Beller
  1 sibling, 0 replies; 9+ messages in thread
From: Stefan Beller @ 2018-02-06 23:11 UTC (permalink / raw)
  To: Jonathan Tan; +Cc: Prathamesh Chavan, git, Christian Couder, Junio C Hamano

On Tue, Feb 6, 2018 at 2:54 PM, Jonathan Tan <jonathantanmy@google.com> wrote:
> On Fri,  2 Feb 2018 10:27:41 +0530
> Prathamesh Chavan <pc44800@gmail.com> wrote:
>
>> When running 'git submodule foreach' from a subdirectory of your
>
> Add "--recursive".
>
>> repository, nested submodules get a bogus value for $sm_path:
>
> Maybe call it $path for now, since $sm_path starts to be recommended
> only in patches after this one.
>
>> For a submodule 'sub' that contains a nested submodule 'nested',
>> running 'git -C dir submodule foreach echo $path' would report
>
> Add "from the root of the superproject", maybe?

This command is run from the root, though the
"-C dir" should indicate that the git command runs from the subdirectory.
Not sure how much slang this is, or if it can be made easier to understand
by writing

  cd dir && git submodule foreach --recursive echo $path

but adding the "from root" part sounds like a clarification nevertheless.

>> path='../nested' for the nested submodule. The first part '../' is
>> derived from the logic computing the relative path from $pwd to the
>> root of the superproject. The second part is the submodule path inside
>> the submodule. This value is of little use and is hard to document.
>>
>> There are two different possible solutions that have more value:
>> (a) The path value is documented as the path from the toplevel of the
>>     superproject to the mount point of the submodule.
>>     In this case we would want to have path='sub/nested'.
>>
>> (b) As Ramsay noticed the documented value is wrong. For the non-nested
>>     case the path is equal to the relative path from $pwd to the
>>     submodules working directory. When following this model,
>>     the expected value would be path='../sub/nested'.
>
> A third solution is to use "nested" - that is, the name of the submodule
> directory relative to its superproject. (It's currently documented as
> "the name of the submodule directory relative to the superproject".)
> Having said that, (b) is probably better.

Oh, so the nested would just report "nested/" as that is the path
from its superproject to its location. The value does not change depending
on where the command is invoked, or whether it is an actual nested or direct
submodule? The latter part sounds like a slight modification of (a), but the
former part sounds like a completely new version (c).

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-02-06 23:11 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-02  4:57 [PATCH v1 0/5] Incremental rewrite of git-submodules Prathamesh Chavan
2018-02-02  4:57 ` [PATCH v1 1/5] submodule foreach: correct '$path' in nested submodules from a subdirectory Prathamesh Chavan
2018-02-06 22:54   ` Jonathan Tan
2018-02-06 23:00     ` Jonathan Tan
2018-02-06 23:11     ` Stefan Beller
2018-02-02  4:57 ` [PATCH v1 2/5] submodule foreach: document '$sm_path' instead of '$path' Prathamesh Chavan
2018-02-02  4:57 ` [PATCH v1 3/5] submodule foreach: clarify the '$toplevel' variable documentation Prathamesh Chavan
2018-02-02  4:57 ` [PATCH v1 4/5] submodule foreach: document variable '$displaypath' Prathamesh Chavan
2018-02-02  4:57 ` [PATCH v1 5/5] submodule: port submodule subcommand 'foreach' from shell to C Prathamesh Chavan

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).