git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out
@ 2018-10-25 16:18 Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 01/10] submodule: add a print_config_from_gitmodules() helper Antonio Ospite
                   ` (10 more replies)
  0 siblings, 11 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Hi,

this series teaches git to try and read the .gitmodules file from the
index (:.gitmodules) or from the current branch (HEAD:.gitmodules) when
the file is not readily available in the working tree.

This can be used, together with sparse checkouts, to enable submodule
usage with programs like vcsh[1] which manage multiple repositories with
their working trees sharing the same path.

[1] https://github.com/RichiH/vcsh

In the previous series there were some comments about not using the enum
in patch 8, but I decided to leave the code as it was as I still think
that it make sense to use an enum there, and have the default value
unnamed; during the discussion I pointed out that other code in git do
the same.

In this series I am addressing the comments by Stefan Beller about the
tests in patch 9.

If the new tests look OK, I'd say we try moving the series to "next" and
see what happens?

I am available to address any further concerns in follow-up patches.

v6 of the series is here:
https://public-inbox.org/git/20181005130601.15879-1-ao2@ao2.it/

v5 of the series is here:
https://public-inbox.org/git/20180917140940.3839-1-ao2@ao2.it/

v4 of the series is here:
https://public-inbox.org/git/20180824132951.8000-1-ao2@ao2.it/

v3 of the series is here:
https://public-inbox.org/git/20180814110525.17801-1-ao2@ao2.it/

v2 of the series is here:
https://public-inbox.org/git/20180802134634.10300-1-ao2@ao2.it/

v1 of the series, with some background info, is here:
https://public-inbox.org/git/20180514105823.8378-1-ao2@ao2.it/

Changes since v6:

  * Renamed t7416-submodule-sparse-gitmodules.sh to
    t7418-submodule-sparse-gitmodules.sh because t7416 was already
    taken.  This has been already taken care of by Junio in "pu".

  * Improved tests in t7418: now, instead of just testing the return
    value of "git submodule ..." commands when .gitmodules is not in the
    working tree, the actual use case is checked in each test, with pre-
    and post-conditions.

Thank you,
   Antonio

Antonio Ospite (10):
  submodule: add a print_config_from_gitmodules() helper
  submodule: factor out a config_set_in_gitmodules_file_gently function
  t7411: merge tests 5 and 6
  t7411: be nicer to future tests and really clean things up
  submodule--helper: add a new 'config' subcommand
  submodule: use the 'submodule--helper config' command
  t7506: clean up .gitmodules properly before setting up new scenario
  submodule: add a helper to check if it is safe to write to .gitmodules
  submodule: support reading .gitmodules when it's not in the working
    tree
  t/helper: add test-submodule-nested-repo-config

 Makefile                                     |   1 +
 builtin/grep.c                               |  17 ++-
 builtin/submodule--helper.c                  |  40 ++++++
 cache.h                                      |   2 +
 git-submodule.sh                             |  13 +-
 submodule-config.c                           |  68 ++++++++-
 submodule-config.h                           |   2 +
 submodule.c                                  |  28 +++-
 submodule.h                                  |   1 +
 t/helper/test-submodule-nested-repo-config.c |  30 ++++
 t/helper/test-tool.c                         |   1 +
 t/helper/test-tool.h                         |   1 +
 t/t7411-submodule-config.sh                  | 141 +++++++++++++++++--
 t/t7418-submodule-sparse-gitmodules.sh       | 122 ++++++++++++++++
 t/t7506-status-submodule.sh                  |   3 +-
 t/t7814-grep-recurse-submodules.sh           |  16 +++
 16 files changed, 454 insertions(+), 32 deletions(-)
 create mode 100644 t/helper/test-submodule-nested-repo-config.c
 create mode 100755 t/t7418-submodule-sparse-gitmodules.sh

-- 
Antonio Ospite
https://ao2.it
https://twitter.com/ao2it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

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

* [PATCH v7 01/10] submodule: add a print_config_from_gitmodules() helper
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 02/10] submodule: factor out a config_set_in_gitmodules_file_gently function Antonio Ospite
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Add a new print_config_from_gitmodules() helper function to print values
from .gitmodules just like "git config -f .gitmodules" would.

This will be used by a new submodule--helper subcommand to be able to
access the .gitmodules file in a more controlled way.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 submodule-config.c | 25 +++++++++++++++++++++++++
 submodule-config.h |  1 +
 2 files changed, 26 insertions(+)

diff --git a/submodule-config.c b/submodule-config.c
index b132f7a80b..e36d4e2271 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -692,6 +692,31 @@ void submodule_free(struct repository *r)
 		submodule_cache_clear(r->submodule_cache);
 }
 
+static int config_print_callback(const char *var, const char *value, void *cb_data)
+{
+	char *wanted_key = cb_data;
+
+	if (!strcmp(wanted_key, var))
+		printf("%s\n", value);
+
+	return 0;
+}
+
+int print_config_from_gitmodules(struct repository *repo, const char *key)
+{
+	int ret;
+	char *store_key;
+
+	ret = git_config_parse_key(key, &store_key, NULL);
+	if (ret < 0)
+		return CONFIG_INVALID_KEY;
+
+	config_from_gitmodules(config_print_callback, repo, store_key);
+
+	free(store_key);
+	return 0;
+}
+
 struct fetch_config {
 	int *max_children;
 	int *recurse_submodules;
diff --git a/submodule-config.h b/submodule-config.h
index dc7278eea4..031747ccf8 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -48,6 +48,7 @@ const struct submodule *submodule_from_path(struct repository *r,
 					    const struct object_id *commit_or_tree,
 					    const char *path);
 void submodule_free(struct repository *r);
+int print_config_from_gitmodules(struct repository *repo, const char *key);
 
 /*
  * Returns 0 if the name is syntactically acceptable as a submodule "name"
-- 
2.19.1


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

* [PATCH v7 02/10] submodule: factor out a config_set_in_gitmodules_file_gently function
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 01/10] submodule: add a print_config_from_gitmodules() helper Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 03/10] t7411: merge tests 5 and 6 Antonio Ospite
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Introduce a new config_set_in_gitmodules_file_gently() function to write
config values to the .gitmodules file.

This is in preparation for a future change which will use the function
to write to the .gitmodules file in a more controlled way instead of
using "git config -f .gitmodules".

The purpose of the change is mainly to centralize the code that writes
to the .gitmodules file to avoid some duplication.

The naming follows git_config_set_in_file_gently() but the git_ prefix
is removed to communicate that this is not a generic git-config API.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 submodule-config.c | 12 ++++++++++++
 submodule-config.h |  1 +
 submodule.c        | 10 +++-------
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/submodule-config.c b/submodule-config.c
index e36d4e2271..329c0b44f6 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -717,6 +717,18 @@ int print_config_from_gitmodules(struct repository *repo, const char *key)
 	return 0;
 }
 
+int config_set_in_gitmodules_file_gently(const char *key, const char *value)
+{
+	int ret;
+
+	ret = git_config_set_in_file_gently(GITMODULES_FILE, key, value);
+	if (ret < 0)
+		/* Maybe the user already did that, don't error out here */
+		warning(_("Could not update .gitmodules entry %s"), key);
+
+	return ret;
+}
+
 struct fetch_config {
 	int *max_children;
 	int *recurse_submodules;
diff --git a/submodule-config.h b/submodule-config.h
index 031747ccf8..4dc9b0771c 100644
--- a/submodule-config.h
+++ b/submodule-config.h
@@ -49,6 +49,7 @@ const struct submodule *submodule_from_path(struct repository *r,
 					    const char *path);
 void submodule_free(struct repository *r);
 int print_config_from_gitmodules(struct repository *repo, const char *key);
+int config_set_in_gitmodules_file_gently(const char *key, const char *value);
 
 /*
  * Returns 0 if the name is syntactically acceptable as a submodule "name"
diff --git a/submodule.c b/submodule.c
index d9d3046689..24a49eae61 100644
--- a/submodule.c
+++ b/submodule.c
@@ -89,6 +89,7 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
 {
 	struct strbuf entry = STRBUF_INIT;
 	const struct submodule *submodule;
+	int ret;
 
 	if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
 		return -1;
@@ -104,14 +105,9 @@ int update_path_in_gitmodules(const char *oldpath, const char *newpath)
 	strbuf_addstr(&entry, "submodule.");
 	strbuf_addstr(&entry, submodule->name);
 	strbuf_addstr(&entry, ".path");
-	if (git_config_set_in_file_gently(GITMODULES_FILE, entry.buf, newpath) < 0) {
-		/* Maybe the user already did that, don't error out here */
-		warning(_("Could not update .gitmodules entry %s"), entry.buf);
-		strbuf_release(&entry);
-		return -1;
-	}
+	ret = config_set_in_gitmodules_file_gently(entry.buf, newpath);
 	strbuf_release(&entry);
-	return 0;
+	return ret;
 }
 
 /*
-- 
2.19.1


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

* [PATCH v7 03/10] t7411: merge tests 5 and 6
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 01/10] submodule: add a print_config_from_gitmodules() helper Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 02/10] submodule: factor out a config_set_in_gitmodules_file_gently function Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 04/10] t7411: be nicer to future tests and really clean things up Antonio Ospite
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Tests 5 and 6 check for the effects of the same commit, merge the two
tests to make it more straightforward to clean things up after the test
has finished.

The cleanup will be added in a future commit.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 t/t7411-submodule-config.sh | 18 +++++-------------
 1 file changed, 5 insertions(+), 13 deletions(-)

diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index 0bde5850ac..f2cd1f4a2c 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -82,29 +82,21 @@ Submodule name: 'a' for path 'b'
 Submodule name: 'submodule' for path 'submodule'
 EOF
 
-test_expect_success 'error in one submodule config lets continue' '
+test_expect_success 'error in history of one submodule config lets continue, stderr message contains blob ref' '
 	(cd super &&
 		cp .gitmodules .gitmodules.bak &&
 		echo "	value = \"" >>.gitmodules &&
 		git add .gitmodules &&
 		mv .gitmodules.bak .gitmodules &&
 		git commit -m "add error" &&
-		test-tool submodule-config \
-			HEAD b \
-			HEAD submodule \
-				>actual &&
-		test_cmp expect_error actual
-	)
-'
-
-test_expect_success 'error message contains blob reference' '
-	(cd super &&
 		sha1=$(git rev-parse HEAD) &&
 		test-tool submodule-config \
 			HEAD b \
 			HEAD submodule \
-				2>actual_err &&
-		test_i18ngrep "submodule-blob $sha1:.gitmodules" actual_err >/dev/null
+				>actual \
+				2>actual_stderr &&
+		test_cmp expect_error actual &&
+		test_i18ngrep "submodule-blob $sha1:.gitmodules" actual_stderr >/dev/null
 	)
 '
 
-- 
2.19.1


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

* [PATCH v7 04/10] t7411: be nicer to future tests and really clean things up
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (2 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 03/10] t7411: merge tests 5 and 6 Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 05/10] submodule--helper: add a new 'config' subcommand Antonio Ospite
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Tests 5 and 7 in t/t7411-submodule-config.sh add two commits with
invalid lines in .gitmodules but then only the second commit is removed.

This may affect future subsequent tests if they assume that the
.gitmodules file has no errors.

Remove both the commits as soon as they are not needed anymore.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 t/t7411-submodule-config.sh | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index f2cd1f4a2c..b1f3c6489b 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -83,6 +83,8 @@ Submodule name: 'submodule' for path 'submodule'
 EOF
 
 test_expect_success 'error in history of one submodule config lets continue, stderr message contains blob ref' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
 	(cd super &&
 		cp .gitmodules .gitmodules.bak &&
 		echo "	value = \"" >>.gitmodules &&
@@ -115,6 +117,8 @@ test_expect_success 'using different treeishs works' '
 '
 
 test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
 	(cd super &&
 		git config -f .gitmodules \
 			submodule.submodule.fetchrecursesubmodules blabla &&
@@ -126,8 +130,7 @@ test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
 			HEAD b \
 			HEAD submodule \
 				>actual &&
-		test_cmp expect_error actual  &&
-		git reset --hard HEAD^
+		test_cmp expect_error actual
 	)
 '
 
-- 
2.19.1


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

* [PATCH v7 05/10] submodule--helper: add a new 'config' subcommand
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (3 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 04/10] t7411: be nicer to future tests and really clean things up Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 06/10] submodule: use the 'submodule--helper config' command Antonio Ospite
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Add a new 'config' subcommand to 'submodule--helper', this extra level
of indirection makes it possible to add some flexibility to how the
submodules configuration is handled.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 builtin/submodule--helper.c | 14 ++++++++++++++
 t/t7411-submodule-config.sh | 27 +++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 80474c3ff5..9af6626e32 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2126,6 +2126,19 @@ static int check_name(int argc, const char **argv, const char *prefix)
 	return 0;
 }
 
+static int module_config(int argc, const char **argv, const char *prefix)
+{
+	/* Equivalent to ACTION_GET in builtin/config.c */
+	if (argc == 2)
+		return print_config_from_gitmodules(the_repository, argv[1]);
+
+	/* Equivalent to ACTION_SET in builtin/config.c */
+	if (argc == 3)
+		return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
+
+	die("submodule--helper config takes 1 or 2 arguments: name [value]");
+}
+
 #define SUPPORT_SUPER_PREFIX (1<<0)
 
 struct cmd_struct {
@@ -2155,6 +2168,7 @@ static struct cmd_struct commands[] = {
 	{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
 	{"is-active", is_active, 0},
 	{"check-name", check_name, 0},
+	{"config", module_config, 0},
 };
 
 int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index b1f3c6489b..791245f18d 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -134,4 +134,31 @@ test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
 	)
 '
 
+test_expect_success 'reading submodules config with "submodule--helper config"' '
+	(cd super &&
+		echo "../submodule" >expect &&
+		git submodule--helper config submodule.submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'writing submodules config with "submodule--helper config"' '
+	(cd super &&
+		echo "new_url" >expect &&
+		git submodule--helper config submodule.submodule.url "new_url" &&
+		git submodule--helper config submodule.submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'overwriting unstaged submodules config with "submodule--helper config"' '
+	test_when_finished "git -C super checkout .gitmodules" &&
+	(cd super &&
+		echo "newer_url" >expect &&
+		git submodule--helper config submodule.submodule.url "newer_url" &&
+		git submodule--helper config submodule.submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_done
-- 
2.19.1


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

* [PATCH v7 06/10] submodule: use the 'submodule--helper config' command
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (4 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 05/10] submodule--helper: add a new 'config' subcommand Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 07/10] t7506: clean up .gitmodules properly before setting up new scenario Antonio Ospite
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Use the 'submodule--helper config' command in git-submodules.sh to avoid
referring explicitly to .gitmodules by the hardcoded file path.

This makes it possible to access the submodules configuration in a more
controlled way.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 git-submodule.sh | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index 1b568e29b9..0805fadf47 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -72,7 +72,7 @@ get_submodule_config () {
 	value=$(git config submodule."$name"."$option")
 	if test -z "$value"
 	then
-		value=$(git config -f .gitmodules submodule."$name"."$option")
+		value=$(git submodule--helper config submodule."$name"."$option")
 	fi
 	printf '%s' "${value:-$default}"
 }
@@ -283,11 +283,11 @@ or you are unsure what this means choose another name with the '--name' option."
 	git add --no-warn-embedded-repo $force "$sm_path" ||
 	die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
 
-	git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
-	git config -f .gitmodules submodule."$sm_name".url "$repo" &&
+	git submodule--helper config submodule."$sm_name".path "$sm_path" &&
+	git submodule--helper config submodule."$sm_name".url "$repo" &&
 	if test -n "$branch"
 	then
-		git config -f .gitmodules submodule."$sm_name".branch "$branch"
+		git submodule--helper config submodule."$sm_name".branch "$branch"
 	fi &&
 	git add --force .gitmodules ||
 	die "$(eval_gettext "Failed to register submodule '\$sm_path'")"
-- 
2.19.1


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

* [PATCH v7 07/10] t7506: clean up .gitmodules properly before setting up new scenario
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (5 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 06/10] submodule: use the 'submodule--helper config' command Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 08/10] submodule: add a helper to check if it is safe to write to .gitmodules Antonio Ospite
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

In t/t7506-status-submodule.sh at some point a new scenario is set up to
test different things, in particular new submodules are added which are
meant to completely replace the previous ones.

However before calling the "git submodule add" commands for the new
layout, the .gitmodules file is removed only from the working tree still
leaving the previous content in current branch.

This can break if, in the future, "git submodule add" starts
differentiating between the following two cases:

  - .gitmodules is not in the working tree but it is in the current
    branch (it may not be safe to add new submodules in this case);

  - .gitmodules is neither in the working tree nor anywhere in the
    current branch (it is safe to add new submodules).

Since the test intends to get rid of .gitmodules anyways, let's
completely remove it from the current branch, to actually start afresh
in the new scenario.

This is more future-proof and does not break current tests.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 t/t7506-status-submodule.sh | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh
index 943708fb04..08629a6e70 100755
--- a/t/t7506-status-submodule.sh
+++ b/t/t7506-status-submodule.sh
@@ -325,7 +325,8 @@ test_expect_success 'setup superproject with untracked file in nested submodule'
 	(
 		cd super &&
 		git clean -dfx &&
-		rm .gitmodules &&
+		git rm .gitmodules &&
+		git commit -m "remove .gitmodules" &&
 		git submodule add -f ./sub1 &&
 		git submodule add -f ./sub2 &&
 		git submodule add -f ./sub1 sub3 &&
-- 
2.19.1


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

* [PATCH v7 08/10] submodule: add a helper to check if it is safe to write to .gitmodules
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (6 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 07/10] t7506: clean up .gitmodules properly before setting up new scenario Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 16:18 ` [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree Antonio Ospite
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Introduce a helper function named is_writing_gitmodules_ok() to verify
that the .gitmodules file is safe to write.

The function name follows the scheme of is_staging_gitmodules_ok().

The two symbolic constants GITMODULES_INDEX and GITMODULES_HEAD are used
to get help from the C preprocessor in preventing typos, especially for
future users.

This is in preparation for a future change which teaches git how to read
.gitmodules from the index or from the current branch if the file is not
available in the working tree.

The rationale behind the check is that writing to .gitmodules requires
the file to be present in the working tree, unless a brand new
.gitmodules is being created (in which case the .gitmodules file would
not exist at all: neither in the working tree nor in the index or in the
current branch).

Expose the functionality also via a "submodule-helper config
--check-writeable" command, as git scripts may want to perform the check
before modifying submodules configuration.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 builtin/submodule--helper.c | 24 +++++++++++++++++++++++-
 cache.h                     |  2 ++
 submodule.c                 | 18 ++++++++++++++++++
 submodule.h                 |  1 +
 t/t7411-submodule-config.sh | 31 +++++++++++++++++++++++++++++++
 5 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 9af6626e32..b272a78801 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2128,6 +2128,28 @@ static int check_name(int argc, const char **argv, const char *prefix)
 
 static int module_config(int argc, const char **argv, const char *prefix)
 {
+	enum {
+		CHECK_WRITEABLE = 1
+	} command = 0;
+
+	struct option module_config_options[] = {
+		OPT_CMDMODE(0, "check-writeable", &command,
+			    N_("check if it is safe to write to the .gitmodules file"),
+			    CHECK_WRITEABLE),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper config name [value]"),
+		N_("git submodule--helper config --check-writeable"),
+		NULL
+	};
+
+	argc = parse_options(argc, argv, prefix, module_config_options,
+			     git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0);
+
+	if (argc == 1 && command == CHECK_WRITEABLE)
+		return is_writing_gitmodules_ok() ? 0 : -1;
+
 	/* Equivalent to ACTION_GET in builtin/config.c */
 	if (argc == 2)
 		return print_config_from_gitmodules(the_repository, argv[1]);
@@ -2136,7 +2158,7 @@ static int module_config(int argc, const char **argv, const char *prefix)
 	if (argc == 3)
 		return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
 
-	die("submodule--helper config takes 1 or 2 arguments: name [value]");
+	usage_with_options(git_submodule_helper_usage, module_config_options);
 }
 
 #define SUPPORT_SUPER_PREFIX (1<<0)
diff --git a/cache.h b/cache.h
index 59c8a93046..4c1f827c54 100644
--- a/cache.h
+++ b/cache.h
@@ -486,6 +486,8 @@ static inline enum object_type object_type(unsigned int mode)
 #define INFOATTRIBUTES_FILE "info/attributes"
 #define ATTRIBUTE_MACRO_PREFIX "[attr]"
 #define GITMODULES_FILE ".gitmodules"
+#define GITMODULES_INDEX ":.gitmodules"
+#define GITMODULES_HEAD "HEAD:.gitmodules"
 #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
 #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
 #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
diff --git a/submodule.c b/submodule.c
index 24a49eae61..9516685478 100644
--- a/submodule.c
+++ b/submodule.c
@@ -51,6 +51,24 @@ int is_gitmodules_unmerged(const struct index_state *istate)
 	return 0;
 }
 
+/*
+ * Check if the .gitmodules file is safe to write.
+ *
+ * Writing to the .gitmodules file requires that the file exists in the
+ * working tree or, if it doesn't, that a brand new .gitmodules file is going
+ * to be created (i.e. it's neither in the index nor in the current branch).
+ *
+ * It is not safe to write to .gitmodules if it's not in the working tree but
+ * it is in the index or in the current branch, because writing new values
+ * (and staging them) would blindly overwrite ALL the old content.
+ */
+int is_writing_gitmodules_ok(void)
+{
+	struct object_id oid;
+	return file_exists(GITMODULES_FILE) ||
+		(get_oid(GITMODULES_INDEX, &oid) < 0 && get_oid(GITMODULES_HEAD, &oid) < 0);
+}
+
 /*
  * Check if the .gitmodules file has unstaged modifications.  This must be
  * checked before allowing modifications to the .gitmodules file with the
diff --git a/submodule.h b/submodule.h
index 4826601ff2..ea6e115f16 100644
--- a/submodule.h
+++ b/submodule.h
@@ -40,6 +40,7 @@ struct submodule_update_strategy {
 #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
 
 int is_gitmodules_unmerged(const struct index_state *istate);
+int is_writing_gitmodules_ok(void);
 int is_staging_gitmodules_ok(struct index_state *istate);
 int update_path_in_gitmodules(const char *oldpath, const char *newpath);
 int remove_path_from_gitmodules(const char *path);
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index 791245f18d..45953f9300 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -161,4 +161,35 @@ test_expect_success 'overwriting unstaged submodules config with "submodule--hel
 	)
 '
 
+test_expect_success 'writeable .gitmodules when it is in the working tree' '
+	git -C super submodule--helper config --check-writeable
+'
+
+test_expect_success 'writeable .gitmodules when it is nowhere in the repository' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
+	(cd super &&
+		git rm .gitmodules &&
+		git commit -m "remove .gitmodules from the current branch" &&
+		git submodule--helper config --check-writeable
+	)
+'
+
+test_expect_success 'non-writeable .gitmodules when it is in the index but not in the working tree' '
+	test_when_finished "git -C super checkout .gitmodules" &&
+	(cd super &&
+		rm -f .gitmodules &&
+		test_must_fail git submodule--helper config --check-writeable
+	)
+'
+
+test_expect_success 'non-writeable .gitmodules when it is in the current branch but not in the index' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
+	(cd super &&
+		git rm .gitmodules &&
+		test_must_fail git submodule--helper config --check-writeable
+	)
+'
+
 test_done
-- 
2.19.1


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

* [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (7 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 08/10] submodule: add a helper to check if it is safe to write to .gitmodules Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-30  9:57   ` Johannes Schindelin
  2018-10-25 16:18 ` [PATCH v7 10/10] t/helper: add test-submodule-nested-repo-config Antonio Ospite
  2018-10-25 18:49 ` [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Stefan Beller
  10 siblings, 1 reply; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

When the .gitmodules file is not available in the working tree, try
using the content from the index and from the current branch. This
covers the case when the file is part of the repository but for some
reason it is not checked out, for example because of a sparse checkout.

This makes it possible to use at least the 'git submodule' commands
which *read* the gitmodules configuration file without fully populating
the working tree.

Writing to .gitmodules will still require that the file is checked out,
so check for that before calling config_set_in_gitmodules_file_gently.

Add a similar check also in git-submodule.sh::cmd_add() to anticipate
the eventual failure of the "git submodule add" command when .gitmodules
is not safely writeable; this prevents the command from leaving the
repository in a spurious state (e.g. the submodule repository was cloned
but .gitmodules was not updated because
config_set_in_gitmodules_file_gently failed).

Moreover, since config_from_gitmodules() now accesses the global object
store, it is necessary to protect all code paths which call the function
against concurrent access to the global object store. Currently this
only happens in builtin/grep.c::grep_submodules(), so call
grep_read_lock() before invoking code involving
config_from_gitmodules().

Finally, add t7418-submodule-sparse-gitmodules.sh to verify that reading
from .gitmodules succeeds and that writing to it fails when the file is
not checked out.

NOTE: there is one rare case where this new feature does not work
properly yet: nested submodules without .gitmodules in their working
tree.  This has been documented with a warning and a test_expect_failure
item in t7814, and in this case the current behavior is not altered: no
config is read.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 builtin/grep.c                         |  17 +++-
 builtin/submodule--helper.c            |   6 +-
 git-submodule.sh                       |   5 +
 submodule-config.c                     |  31 ++++++-
 t/t7411-submodule-config.sh            |  26 +++++-
 t/t7418-submodule-sparse-gitmodules.sh | 122 +++++++++++++++++++++++++
 t/t7814-grep-recurse-submodules.sh     |  16 ++++
 7 files changed, 216 insertions(+), 7 deletions(-)
 create mode 100755 t/t7418-submodule-sparse-gitmodules.sh

diff --git a/builtin/grep.c b/builtin/grep.c
index d8508ddf79..56e4a11052 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -422,11 +422,23 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
 	struct repository submodule;
 	int hit;
 
-	if (!is_submodule_active(superproject, path))
+	/*
+	 * NEEDSWORK: submodules functions need to be protected because they
+	 * access the object store via config_from_gitmodules(): the latter
+	 * uses get_oid() which, for now, relies on the global the_repository
+	 * object.
+	 */
+	grep_read_lock();
+
+	if (!is_submodule_active(superproject, path)) {
+		grep_read_unlock();
 		return 0;
+	}
 
-	if (repo_submodule_init(&submodule, superproject, path))
+	if (repo_submodule_init(&submodule, superproject, path)) {
+		grep_read_unlock();
 		return 0;
+	}
 
 	repo_read_gitmodules(&submodule);
 
@@ -440,7 +452,6 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
 	 * store is no longer global and instead is a member of the repository
 	 * object.
 	 */
-	grep_read_lock();
 	add_to_alternates_memory(submodule.objects->objectdir);
 	grep_read_unlock();
 
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index b272a78801..05ce666142 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2155,8 +2155,12 @@ static int module_config(int argc, const char **argv, const char *prefix)
 		return print_config_from_gitmodules(the_repository, argv[1]);
 
 	/* Equivalent to ACTION_SET in builtin/config.c */
-	if (argc == 3)
+	if (argc == 3) {
+		if (!is_writing_gitmodules_ok())
+			die(_("please make sure that the .gitmodules file is in the working tree"));
+
 		return config_set_in_gitmodules_file_gently(argv[1], argv[2]);
+	}
 
 	usage_with_options(git_submodule_helper_usage, module_config_options);
 }
diff --git a/git-submodule.sh b/git-submodule.sh
index 0805fadf47..f5124bbf23 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -159,6 +159,11 @@ cmd_add()
 		shift
 	done
 
+	if ! git submodule--helper config --check-writeable >/dev/null 2>&1
+	then
+		 die "$(eval_gettext "please make sure that the .gitmodules file is in the working tree")"
+	fi
+
 	if test -n "$reference_path"
 	then
 		is_absolute_path "$reference_path" ||
diff --git a/submodule-config.c b/submodule-config.c
index 329c0b44f6..52702c62d9 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "dir.h"
 #include "repository.h"
 #include "config.h"
 #include "submodule-config.h"
@@ -613,8 +614,34 @@ static void submodule_cache_check_init(struct repository *repo)
 static void config_from_gitmodules(config_fn_t fn, struct repository *repo, void *data)
 {
 	if (repo->worktree) {
-		char *file = repo_worktree_path(repo, GITMODULES_FILE);
-		git_config_from_file(fn, file, data);
+		struct git_config_source config_source = { 0 };
+		const struct config_options opts = { 0 };
+		struct object_id oid;
+		char *file;
+
+		file = repo_worktree_path(repo, GITMODULES_FILE);
+		if (file_exists(file)) {
+			config_source.file = file;
+		} else if (repo->submodule_prefix) {
+			/*
+			 * When get_oid and config_with_options, used below,
+			 * become able to work on a specific repository, this
+			 * warning branch can be removed.
+			 */
+			warning("nested submodules without %s in the working tree are not supported yet",
+				GITMODULES_FILE);
+			goto out;
+		} else if (get_oid(GITMODULES_INDEX, &oid) >= 0) {
+			config_source.blob = GITMODULES_INDEX;
+		} else if (get_oid(GITMODULES_HEAD, &oid) >= 0) {
+			config_source.blob = GITMODULES_HEAD;
+		} else {
+			goto out;
+		}
+
+		config_with_options(fn, data, &config_source, &opts);
+
+out:
 		free(file);
 	}
 }
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index 45953f9300..2cfabb18bc 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -134,7 +134,7 @@ test_expect_success 'error in history in fetchrecursesubmodule lets continue' '
 	)
 '
 
-test_expect_success 'reading submodules config with "submodule--helper config"' '
+test_expect_success 'reading submodules config from the working tree with "submodule--helper config"' '
 	(cd super &&
 		echo "../submodule" >expect &&
 		git submodule--helper config submodule.submodule.url >actual &&
@@ -192,4 +192,28 @@ test_expect_success 'non-writeable .gitmodules when it is in the current branch
 	)
 '
 
+test_expect_success 'reading submodules config from the index when .gitmodules is not in the working tree' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
+	(cd super &&
+		git submodule--helper config submodule.submodule.url "staged_url" &&
+		git add .gitmodules &&
+		rm -f .gitmodules &&
+		echo "staged_url" >expect &&
+		git submodule--helper config submodule.submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'reading submodules config from the current branch when .gitmodules is not in the index' '
+	ORIG=$(git -C super rev-parse HEAD) &&
+	test_when_finished "git -C super reset --hard $ORIG" &&
+	(cd super &&
+		git rm .gitmodules &&
+		echo "../submodule" >expect &&
+		git submodule--helper config submodule.submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
 test_done
diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
new file mode 100755
index 0000000000..21a86b89c6
--- /dev/null
+++ b/t/t7418-submodule-sparse-gitmodules.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+#
+# Copyright (C) 2018  Antonio Ospite <ao2@ao2.it>
+#
+
+test_description='Test reading/writing .gitmodules when not in the working tree
+
+This test verifies that, when .gitmodules is in the current branch but is not
+in the working tree reading from it still works but writing to it does not.
+
+The test setup uses a sparse checkout, however the same scenario can be set up
+also by committing .gitmodules and then just removing it from the filesystem.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'sparse checkout setup which hides .gitmodules' '
+	git init upstream &&
+	git init submodule &&
+	(cd submodule &&
+		echo file >file &&
+		git add file &&
+		test_tick &&
+		git commit -m "Add file"
+	) &&
+	(cd upstream &&
+		git submodule add ../submodule &&
+		test_tick &&
+		git commit -m "Add submodule"
+	) &&
+	git clone upstream super &&
+	(cd super &&
+		cat >.git/info/sparse-checkout <<-\EOF &&
+		/*
+		!/.gitmodules
+		EOF
+		git config core.sparsecheckout true &&
+		git read-tree -m -u HEAD &&
+		test_path_is_missing .gitmodules
+	)
+'
+
+test_expect_success 'reading gitmodules config file when it is not checked out' '
+	echo "../submodule" >expect &&
+	git -C super submodule--helper config submodule.submodule.url >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'not writing gitmodules config file when it is not checked out' '
+	test_must_fail git -C super submodule--helper config submodule.submodule.url newurl &&
+	test_path_is_missing super/.gitmodules
+'
+
+test_expect_success 'initialising submodule when the gitmodules config is not checked out' '
+	test_must_fail git -C super config submodule.submodule.url &&
+	git -C super submodule init &&
+	git -C super config submodule.submodule.url >actual &&
+	echo "$PWD/submodule" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'updating submodule when the gitmodules config is not checked out' '
+	test_path_is_missing super/submodule/file &&
+	git -C super submodule update &&
+	test_cmp submodule/file super/submodule/file
+'
+
+ORIG_SUBMODULE=$(git -C submodule rev-parse HEAD)
+ORIG_UPSTREAM=$(git -C upstream rev-parse HEAD)
+ORIG_SUPER=$(git -C super rev-parse HEAD)
+
+test_expect_success 're-updating submodule when the gitmodules config is not checked out' '
+	test_when_finished "git -C submodule reset --hard $ORIG_SUBMODULE;
+			    git -C upstream reset --hard $ORIG_UPSTREAM;
+			    git -C super reset --hard $ORIG_SUPER;
+			    git -C upstream submodule update --remote;
+			    git -C super pull;
+			    git -C super submodule update --remote" &&
+	(cd submodule &&
+		echo file2 >file2 &&
+		git add file2 &&
+		test_tick &&
+		git commit -m "Add file2 to submodule"
+	) &&
+	(cd upstream &&
+		git submodule update --remote &&
+		git add submodule &&
+		test_tick &&
+		git commit -m "Update submodule"
+	) &&
+	git -C super pull &&
+	# The --for-status options reads the gitmodules config
+	git -C super submodule summary --for-status >actual &&
+	rev1=$(git -C submodule rev-parse --short HEAD) &&
+	rev2=$(git -C submodule rev-parse --short HEAD^) &&
+	cat >expect <<-EOF &&
+	* submodule ${rev1}...${rev2} (1):
+	  < Add file2 to submodule
+
+	EOF
+	test_cmp expect actual &&
+	# Test that the update actually succeeds
+	test_path_is_missing super/submodule/file2 &&
+	git -C super submodule update &&
+	test_cmp submodule/file2 super/submodule/file2 &&
+	git -C super status --short >output &&
+	test_must_be_empty output
+'
+
+test_expect_success 'not adding submodules when the gitmodules config is not checked out' '
+	git clone submodule new_submodule &&
+	test_must_fail git -C super submodule add ../new_submodule &&
+	test_path_is_missing .gitmodules
+'
+
+# This test checks that the previous "git submodule add" did not leave the
+# repository in a spurious state when it failed.
+test_expect_success 'init submodule still works even after the previous add failed' '
+	git -C super submodule init
+'
+
+test_done
diff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh
index 7184113b9b..fa475d52fa 100755
--- a/t/t7814-grep-recurse-submodules.sh
+++ b/t/t7814-grep-recurse-submodules.sh
@@ -380,4 +380,20 @@ test_expect_success 'grep --recurse-submodules should pass the pattern type alon
 	fi
 '
 
+# Recursing down into nested submodules which do not have .gitmodules in their
+# working tree does not work yet. This is because config_from_gitmodules()
+# uses get_oid() and the latter is still not able to get objects from an
+# arbitrary repository (the nested submodule, in this case).
+test_expect_failure 'grep --recurse-submodules with submodules without .gitmodules in the working tree' '
+	test_when_finished "git -C submodule checkout .gitmodules" &&
+	rm submodule/.gitmodules &&
+	git grep --recurse-submodules -e "(.|.)[\d]" >actual &&
+	cat >expect <<-\EOF &&
+	a:(1|2)d(3|4)
+	submodule/a:(1|2)d(3|4)
+	submodule/sub/a:(1|2)d(3|4)
+	EOF
+	test_cmp expect actual
+'
+
 test_done
-- 
2.19.1


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

* [PATCH v7 10/10] t/helper: add test-submodule-nested-repo-config
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (8 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree Antonio Ospite
@ 2018-10-25 16:18 ` Antonio Ospite
  2018-10-25 18:49 ` [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Stefan Beller
  10 siblings, 0 replies; 17+ messages in thread
From: Antonio Ospite @ 2018-10-25 16:18 UTC (permalink / raw)
  To: gitster
  Cc: git, Jonathan Nieder, Stefan Beller, Jeff King, SZEDER Gábor,
	Antonio Ospite

Add a test tool to exercise config_from_gitmodules(), in particular for
the case of nested submodules.

Add also a test to document that reading the submoudles config of nested
submodules does not work yet when the .gitmodules file is not in the
working tree but it still in the index.

This is because the git API does not always make it possible access the
object store  of an arbitrary repository (see get_oid() usage in
config_from_gitmodules()).

When this git limitation gets fixed the aforementioned use case will be
supported too.

Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
 Makefile                                     |  1 +
 t/helper/test-submodule-nested-repo-config.c | 30 +++++++++++++++++
 t/helper/test-tool.c                         |  1 +
 t/helper/test-tool.h                         |  1 +
 t/t7411-submodule-config.sh                  | 34 ++++++++++++++++++++
 5 files changed, 67 insertions(+)
 create mode 100644 t/helper/test-submodule-nested-repo-config.c

diff --git a/Makefile b/Makefile
index d18ab0fe78..d8f4dfdb3e 100644
--- a/Makefile
+++ b/Makefile
@@ -741,6 +741,7 @@ TEST_BUILTINS_OBJS += test-sigchain.o
 TEST_BUILTINS_OBJS += test-strcmp-offset.o
 TEST_BUILTINS_OBJS += test-string-list.o
 TEST_BUILTINS_OBJS += test-submodule-config.o
+TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
 TEST_BUILTINS_OBJS += test-subprocess.o
 TEST_BUILTINS_OBJS += test-urlmatch-normalization.o
 TEST_BUILTINS_OBJS += test-wildmatch.o
diff --git a/t/helper/test-submodule-nested-repo-config.c b/t/helper/test-submodule-nested-repo-config.c
new file mode 100644
index 0000000000..a31e2a9bea
--- /dev/null
+++ b/t/helper/test-submodule-nested-repo-config.c
@@ -0,0 +1,30 @@
+#include "test-tool.h"
+#include "submodule-config.h"
+
+static void die_usage(int argc, const char **argv, const char *msg)
+{
+	fprintf(stderr, "%s\n", msg);
+	fprintf(stderr, "Usage: %s <submodulepath> <config name>\n", argv[0]);
+	exit(1);
+}
+
+int cmd__submodule_nested_repo_config(int argc, const char **argv)
+{
+	struct repository submodule;
+
+	if (argc < 3)
+		die_usage(argc, argv, "Wrong number of arguments.");
+
+	setup_git_directory();
+
+	if (repo_submodule_init(&submodule, the_repository, argv[1])) {
+		die_usage(argc, argv, "Submodule not found.");
+	}
+
+	/* Read the config of _child_ submodules. */
+	print_config_from_gitmodules(&submodule, argv[2]);
+
+	submodule_free(the_repository);
+
+	return 0;
+}
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 6b5836dc1b..ca5c5ede6c 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -46,6 +46,7 @@ static struct test_cmd cmds[] = {
 	{ "strcmp-offset", cmd__strcmp_offset },
 	{ "string-list", cmd__string_list },
 	{ "submodule-config", cmd__submodule_config },
+	{ "submodule-nested-repo-config", cmd__submodule_nested_repo_config },
 	{ "subprocess", cmd__subprocess },
 	{ "urlmatch-normalization", cmd__urlmatch_normalization },
 	{ "wildmatch", cmd__wildmatch },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index e4890566da..500e3684e1 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -42,6 +42,7 @@ int cmd__sigchain(int argc, const char **argv);
 int cmd__strcmp_offset(int argc, const char **argv);
 int cmd__string_list(int argc, const char **argv);
 int cmd__submodule_config(int argc, const char **argv);
+int cmd__submodule_nested_repo_config(int argc, const char **argv);
 int cmd__subprocess(int argc, const char **argv);
 int cmd__urlmatch_normalization(int argc, const char **argv);
 int cmd__wildmatch(int argc, const char **argv);
diff --git a/t/t7411-submodule-config.sh b/t/t7411-submodule-config.sh
index 2cfabb18bc..89690b7adb 100755
--- a/t/t7411-submodule-config.sh
+++ b/t/t7411-submodule-config.sh
@@ -216,4 +216,38 @@ test_expect_success 'reading submodules config from the current branch when .git
 	)
 '
 
+test_expect_success 'reading nested submodules config' '
+	(cd super &&
+		git init submodule/nested_submodule &&
+		echo "a" >submodule/nested_submodule/a &&
+		git -C submodule/nested_submodule add a &&
+		git -C submodule/nested_submodule commit -m "add a" &&
+		git -C submodule submodule add ./nested_submodule &&
+		git -C submodule add nested_submodule &&
+		git -C submodule commit -m "added nested_submodule" &&
+		git add submodule &&
+		git commit -m "updated submodule" &&
+		echo "./nested_submodule" >expect &&
+		test-tool submodule-nested-repo-config \
+			submodule submodule.nested_submodule.url >actual &&
+		test_cmp expect actual
+	)
+'
+
+# When this test eventually passes, before turning it into
+# test_expect_success, remember to replace the test_i18ngrep below with
+# a "test_must_be_empty warning" to be sure that the warning is actually
+# removed from the code.
+test_expect_failure 'reading nested submodules config when .gitmodules is not in the working tree' '
+	test_when_finished "git -C super/submodule checkout .gitmodules" &&
+	(cd super &&
+		echo "./nested_submodule" >expect &&
+		rm submodule/.gitmodules &&
+		test-tool submodule-nested-repo-config \
+			submodule submodule.nested_submodule.url >actual 2>warning &&
+		test_i18ngrep "nested submodules without %s in the working tree are not supported yet" warning &&
+		test_cmp expect actual
+	)
+'
+
 test_done
-- 
2.19.1


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

* Re: [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out
  2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
                   ` (9 preceding siblings ...)
  2018-10-25 16:18 ` [PATCH v7 10/10] t/helper: add test-submodule-nested-repo-config Antonio Ospite
@ 2018-10-25 18:49 ` Stefan Beller
  2018-10-26  1:59   ` Junio C Hamano
  10 siblings, 1 reply; 17+ messages in thread
From: Stefan Beller @ 2018-10-25 18:49 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: Junio C Hamano, git, Jonathan Nieder, Jeff King,
	SZEDER Gábor

> In this series I am addressing the comments by Stefan Beller about the
> tests in patch 9.
>
> If the new tests look OK, I'd say we try moving the series to "next" and
> see what happens?

Sounds good to me.

Thanks,
Stefan

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

* Re: [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out
  2018-10-25 18:49 ` [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Stefan Beller
@ 2018-10-26  1:59   ` Junio C Hamano
  2018-10-26 18:43     ` Stefan Beller
  0 siblings, 1 reply; 17+ messages in thread
From: Junio C Hamano @ 2018-10-26  1:59 UTC (permalink / raw)
  To: Stefan Beller
  Cc: Antonio Ospite, git, Jonathan Nieder, Jeff King,
	SZEDER Gábor

Stefan Beller <sbeller@google.com> writes:

>> In this series I am addressing the comments by Stefan Beller about the
>> tests in patch 9.
>>
>> If the new tests look OK, I'd say we try moving the series to "next" and
>> see what happens?
>
> Sounds good to me.

Which means (1) the plan sounds OK but I didn't look at these new
tests or (2) the new tests look OK and I am happy to see this go to
'next'?

tbdiff tells me that 9/10 is the only patch different from the
previous round, and I vaguely recall that the other patches looked
OK to me (even though I admit I only skimmed them quickly).

Thanks.

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

* Re: [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out
  2018-10-26  1:59   ` Junio C Hamano
@ 2018-10-26 18:43     ` Stefan Beller
  0 siblings, 0 replies; 17+ messages in thread
From: Stefan Beller @ 2018-10-26 18:43 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Antonio Ospite, git, Jonathan Nieder, Jeff King,
	SZEDER Gábor

On Thu, Oct 25, 2018 at 6:59 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Stefan Beller <sbeller@google.com> writes:
>
> >> In this series I am addressing the comments by Stefan Beller about the
> >> tests in patch 9.
> >>
> >> If the new tests look OK, I'd say we try moving the series to "next" and
> >> see what happens?
> >
> > Sounds good to me.
>
> Which means (1) the plan sounds OK but I didn't look at these new
> tests or (2) the new tests look OK and I am happy to see this go to
> 'next'?

I looked at the tests and found it a pleasant read, so I think the plan of
merging it to next and seeing what will happen is a good one.

Stefan

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

* Re: [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree
  2018-10-25 16:18 ` [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree Antonio Ospite
@ 2018-10-30  9:57   ` Johannes Schindelin
  2018-10-30 11:16     ` Antonio Ospite
  0 siblings, 1 reply; 17+ messages in thread
From: Johannes Schindelin @ 2018-10-30  9:57 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: gitster, git, Jonathan Nieder, Stefan Beller, Jeff King,
	SZEDER Gábor

Hi Antonio,

On Thu, 25 Oct 2018, Antonio Ospite wrote:

> diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
> new file mode 100755
> index 0000000000..21a86b89c6
> --- /dev/null
> +++ b/t/t7418-submodule-sparse-gitmodules.sh
> @@ -0,0 +1,122 @@
> +#!/bin/sh
> +#
> +# Copyright (C) 2018  Antonio Ospite <ao2@ao2.it>
> +#
> +
> +test_description='Test reading/writing .gitmodules when not in the working tree
> +
> +This test verifies that, when .gitmodules is in the current branch but is not
> +in the working tree reading from it still works but writing to it does not.
> +
> +The test setup uses a sparse checkout, however the same scenario can be set up
> +also by committing .gitmodules and then just removing it from the filesystem.
> +'
> +
> +. ./test-lib.sh
> +
> +test_expect_success 'sparse checkout setup which hides .gitmodules' '
> +	git init upstream &&
> +	git init submodule &&
> +	(cd submodule &&
> +		echo file >file &&
> +		git add file &&
> +		test_tick &&
> +		git commit -m "Add file"
> +	) &&
> +	(cd upstream &&
> +		git submodule add ../submodule &&
> +		test_tick &&
> +		git commit -m "Add submodule"
> +	) &&
> +	git clone upstream super &&
> +	(cd super &&
> +		cat >.git/info/sparse-checkout <<-\EOF &&
> +		/*
> +		!/.gitmodules
> +		EOF
> +		git config core.sparsecheckout true &&
> +		git read-tree -m -u HEAD &&
> +		test_path_is_missing .gitmodules
> +	)
> +'
> +
> +test_expect_success 'reading gitmodules config file when it is not checked out' '
> +	echo "../submodule" >expect &&
> +	git -C super submodule--helper config submodule.submodule.url >actual &&
> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'not writing gitmodules config file when it is not checked out' '
> +	test_must_fail git -C super submodule--helper config submodule.submodule.url newurl &&
> +	test_path_is_missing super/.gitmodules
> +'
> +
> +test_expect_success 'initialising submodule when the gitmodules config is not checked out' '
> +	test_must_fail git -C super config submodule.submodule.url &&
> +	git -C super submodule init &&
> +	git -C super config submodule.submodule.url >actual &&
> +	echo "$PWD/submodule" >expect &&

Would you mind squashing this fixup in?

-- snip --
diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
index 21a86b89c6cb..3f7f27188313 100755
--- a/t/t7418-submodule-sparse-gitmodules.sh
+++ b/t/t7418-submodule-sparse-gitmodules.sh
@@ -55,7 +55,7 @@ test_expect_success 'initialising submodule when the gitmodules config is not ch
 	test_must_fail git -C super config submodule.submodule.url &&
 	git -C super submodule init &&
 	git -C super config submodule.submodule.url >actual &&
-	echo "$PWD/submodule" >expect &&
+	echo "$(pwd)/submodule" >expect &&
 	test_cmp expect actual
 '
 
-- snap --

On Windows, `$PWD` and `$(pwd)` are *not* synonymous. The former
reflects the "Unix path" which is understood by the Bash script (and
only by the Bash script, *not* by `git.exe`!) while the latter refers to
the actual Windows path.

Without this fix, your new test case will fail on Windows all the time,
see e.g.
https://git-for-windows.visualstudio.com/git/_build/results?buildId=22913&view=logs

Thanks,
Johannes


> +	test_cmp expect actual
> +'
> +
> +test_expect_success 'updating submodule when the gitmodules config is not checked out' '
> +	test_path_is_missing super/submodule/file &&
> +	git -C super submodule update &&
> +	test_cmp submodule/file super/submodule/file
> +'
> +
> +ORIG_SUBMODULE=$(git -C submodule rev-parse HEAD)
> +ORIG_UPSTREAM=$(git -C upstream rev-parse HEAD)
> +ORIG_SUPER=$(git -C super rev-parse HEAD)
> +
> +test_expect_success 're-updating submodule when the gitmodules config is not checked out' '
> +	test_when_finished "git -C submodule reset --hard $ORIG_SUBMODULE;
> +			    git -C upstream reset --hard $ORIG_UPSTREAM;
> +			    git -C super reset --hard $ORIG_SUPER;
> +			    git -C upstream submodule update --remote;
> +			    git -C super pull;
> +			    git -C super submodule update --remote" &&
> +	(cd submodule &&
> +		echo file2 >file2 &&
> +		git add file2 &&
> +		test_tick &&
> +		git commit -m "Add file2 to submodule"
> +	) &&
> +	(cd upstream &&
> +		git submodule update --remote &&
> +		git add submodule &&
> +		test_tick &&
> +		git commit -m "Update submodule"
> +	) &&
> +	git -C super pull &&
> +	# The --for-status options reads the gitmodules config
> +	git -C super submodule summary --for-status >actual &&
> +	rev1=$(git -C submodule rev-parse --short HEAD) &&
> +	rev2=$(git -C submodule rev-parse --short HEAD^) &&
> +	cat >expect <<-EOF &&
> +	* submodule ${rev1}...${rev2} (1):
> +	  < Add file2 to submodule
> +
> +	EOF
> +	test_cmp expect actual &&
> +	# Test that the update actually succeeds
> +	test_path_is_missing super/submodule/file2 &&
> +	git -C super submodule update &&
> +	test_cmp submodule/file2 super/submodule/file2 &&
> +	git -C super status --short >output &&
> +	test_must_be_empty output
> +'
> +
> +test_expect_success 'not adding submodules when the gitmodules config is not checked out' '
> +	git clone submodule new_submodule &&
> +	test_must_fail git -C super submodule add ../new_submodule &&
> +	test_path_is_missing .gitmodules
> +'
> +
> +# This test checks that the previous "git submodule add" did not leave the
> +# repository in a spurious state when it failed.
> +test_expect_success 'init submodule still works even after the previous add failed' '
> +	git -C super submodule init
> +'
> +
> +test_done

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

* Re: [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree
  2018-10-30  9:57   ` Johannes Schindelin
@ 2018-10-30 11:16     ` Antonio Ospite
  2018-10-31  6:01       ` Junio C Hamano
  0 siblings, 1 reply; 17+ messages in thread
From: Antonio Ospite @ 2018-10-30 11:16 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: gitster, git, Jonathan Nieder, Stefan Beller, Jeff King,
	SZEDER Gábor

On Tue, 30 Oct 2018 10:57:09 +0100 (STD)
Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

> Hi Antonio,
>

Hi Johannes,

> On Thu, 25 Oct 2018, Antonio Ospite wrote:
> 
> > diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
> > new file mode 100755
[...]
> > +	echo "$PWD/submodule" >expect &&
> 
> Would you mind squashing this fixup in?
> 
> -- snip --
> diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
> index 21a86b89c6cb..3f7f27188313 100755
> --- a/t/t7418-submodule-sparse-gitmodules.sh
> +++ b/t/t7418-submodule-sparse-gitmodules.sh
> @@ -55,7 +55,7 @@ test_expect_success 'initialising submodule when the gitmodules config is not ch
>  	test_must_fail git -C super config submodule.submodule.url &&
>  	git -C super submodule init &&
>  	git -C super config submodule.submodule.url >actual &&
> -	echo "$PWD/submodule" >expect &&
> +	echo "$(pwd)/submodule" >expect &&
>  	test_cmp expect actual
>  '
>  
> -- snap --
> 
> On Windows, `$PWD` and `$(pwd)` are *not* synonymous. The former
> reflects the "Unix path" which is understood by the Bash script (and
> only by the Bash script, *not* by `git.exe`!) while the latter refers to
> the actual Windows path.
>

I see, this is also mentioned in t/README, I had overlooked that part.
Thank you for reporting.

> Without this fix, your new test case will fail on Windows all the time,
> see e.g.
> https://git-for-windows.visualstudio.com/git/_build/results?buildId=22913&view=logs
> 

Junio, what is the plan for 'ao/submodule-wo-gitmodules-checked-out'?
I see it's not in next yet; do you want me to resend the whole series
with this fixup in or would it be less overhead for you to apply it
directly to patch 9/10 from v7 of the series?

Thank you,
   Antonio

P.S. I was wondering if it is worth having patchset versions mentioned
somewhere in pu/, maybe in merge commits if not in branch names?
Or at least in whats-cooking.txt next to the date.

-- 
Antonio Ospite
https://ao2.it
https://twitter.com/ao2it

A: Because it messes up the order in which people normally read text.
   See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?

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

* Re: [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree
  2018-10-30 11:16     ` Antonio Ospite
@ 2018-10-31  6:01       ` Junio C Hamano
  0 siblings, 0 replies; 17+ messages in thread
From: Junio C Hamano @ 2018-10-31  6:01 UTC (permalink / raw)
  To: Antonio Ospite
  Cc: Johannes Schindelin, git, Jonathan Nieder, Stefan Beller,
	Jeff King, SZEDER Gábor

Antonio Ospite <ao2@ao2.it> writes:

> I see, this is also mentioned in t/README, I had overlooked that part.
> Thank you for reporting.
>
>> Without this fix, your new test case will fail on Windows all the time,
>> see e.g.
>> https://git-for-windows.visualstudio.com/git/_build/results?buildId=22913&view=logs
>> 
>
> Junio, what is the plan for 'ao/submodule-wo-gitmodules-checked-out'?
>

I did not and do not have a specific plan ;-) 

If the only remaining issue in the previous round of the topic were
what you said in <20181010205645.e1529eff9099805029b1d6ef@ao2.it>,
which you addressed in this round, and given that Stefan (who is
likely to be the person who would need to work with you if there is
any issues later found in this topic) seemed to be happy with it in
<CAGZ79katS+PHWWD_0EqSmoEFazE0vAbMsg8G+iowNfbDmMkyMg@mail.gmail.com>,
I'd say with Dscho's bug fixed, it should be ready for 'next'.

> I see it's not in next yet; do you want me to resend the whole series
> with this fixup in or would it be less overhead for you to apply it
> directly to patch 9/10 from v7 of the series?

In either way, this involves rebuilding ao/* topic and then redoing
sb/submodule-recursive-fetch-gets-the-tip topic on top, before I can
do the 'pu' with them, so I cannot promise it will happen today, but
let's see.  I think I have enough material to do the fix-up locally
without any additional thing sent from you.

Thanks.


> P.S. I was wondering if it is worth having patchset versions mentioned
> somewhere in pu/, maybe in merge commits if not in branch names?

No, not in branch names.

The tip date published in the "What's cooking" report is taken from
the committer date but we may want to use the author date instead,
which may help (and encourage people to be careful _before_ sending
things out, to avoid doing many rerolls in a day).

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

end of thread, other threads:[~2018-10-31  6:01 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-10-25 16:18 [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 01/10] submodule: add a print_config_from_gitmodules() helper Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 02/10] submodule: factor out a config_set_in_gitmodules_file_gently function Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 03/10] t7411: merge tests 5 and 6 Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 04/10] t7411: be nicer to future tests and really clean things up Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 05/10] submodule--helper: add a new 'config' subcommand Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 06/10] submodule: use the 'submodule--helper config' command Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 07/10] t7506: clean up .gitmodules properly before setting up new scenario Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 08/10] submodule: add a helper to check if it is safe to write to .gitmodules Antonio Ospite
2018-10-25 16:18 ` [PATCH v7 09/10] submodule: support reading .gitmodules when it's not in the working tree Antonio Ospite
2018-10-30  9:57   ` Johannes Schindelin
2018-10-30 11:16     ` Antonio Ospite
2018-10-31  6:01       ` Junio C Hamano
2018-10-25 16:18 ` [PATCH v7 10/10] t/helper: add test-submodule-nested-repo-config Antonio Ospite
2018-10-25 18:49 ` [PATCH v7 00/10] Make submodules work if .gitmodules is not checked out Stefan Beller
2018-10-26  1:59   ` Junio C Hamano
2018-10-26 18:43     ` Stefan Beller

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