Commit b2ab887e1137207edb286812a3237b351ab39506

Jameson Miller 2014-10-20T18:07:32

submodule init should resolve relative url paths Submodule init should handle relative paths in .gitmodules files and resolve these urls when updating the git config file.

diff --git a/src/submodule.c b/src/submodule.c
index 8dca0ae..d2af144 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -381,10 +381,6 @@ int git_submodule_add_setup(
 		return GIT_EEXISTS;
 	}
 
-	/* resolve parameters */
-	if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
-		goto cleanup;
-
 	/* validate and normalize path */
 
 	if (git__prefixcmp(path, git_repository_workdir(repo)) == 0)
@@ -409,7 +405,7 @@ int git_submodule_add_setup(
 		goto cleanup;
 
 	if ((error = submodule_config_key_trunc_puts(&name, "url")) < 0 ||
-		(error = git_config_file_set_string(mods, name.ptr, real_url.ptr)) < 0)
+		(error = git_config_file_set_string(mods, name.ptr, url)) < 0)
 		goto cleanup;
 
 	git_buf_clear(&name);
@@ -425,7 +421,12 @@ int git_submodule_add_setup(
 	 */
 	if (!(git_path_exists(name.ptr) &&
 		git_path_contains(&name, DOT_GIT))) {
-		if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
+
+		/* resolve the actual URL to use */
+		if ((error = git_submodule_resolve_url(&real_url, repo, url)) < 0)
+			goto cleanup;
+
+		 if ((error = submodule_repo_init(&subrepo, repo, path, real_url.ptr, use_gitlink)) < 0)
 			goto cleanup;
 	}
 
@@ -466,13 +467,24 @@ int git_submodule_repo_init(
 {
 	int error;
 	git_repository *sub_repo = NULL;
+	const char *configured_url;
+	git_config *cfg = NULL;
+	git_buf buf = GIT_BUF_INIT;
 
 	assert(out && sm);
 
-	error = submodule_repo_init(&sub_repo, sm->repo, sm->path, sm->url, use_gitlink);
+	/* get the configured remote url of the submodule */
+	if ((error = git_buf_printf(&buf, "submodule.%s.url", sm->name)) < 0 ||
+		(error = git_repository_config(&cfg, sm->repo)) < 0 ||
+		(error = git_config_get_string(&configured_url, cfg, buf.ptr)) < 0 ||
+		(error = submodule_repo_init(&sub_repo, sm->repo, sm->path, configured_url, use_gitlink)) < 0)
+		goto done;
 
 	*out = sub_repo;
 
+done:
+	git_config_free(cfg);
+	git_buf_free(&buf);
 	return error;
 }
 
@@ -827,7 +839,7 @@ int git_submodule_init(git_submodule *sm, int overwrite)
 {
 	int error;
 	const char *val;
-	git_buf key = GIT_BUF_INIT;
+	git_buf key = GIT_BUF_INIT, effective_submodule_url = GIT_BUF_INIT;
 	git_config *cfg = NULL;
 
 	if (!sm->url) {
@@ -841,9 +853,10 @@ int git_submodule_init(git_submodule *sm, int overwrite)
 
 	/* write "submodule.NAME.url" */
 
-	if ((error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
+	if ((git_submodule_resolve_url(&effective_submodule_url, sm->repo, sm->url)) < 0 ||
+		(error = git_buf_printf(&key, "submodule.%s.url", sm->name)) < 0 ||
 		(error = git_config__update_entry(
-			cfg, key.ptr, sm->url, overwrite != 0, false)) < 0)
+			cfg, key.ptr, effective_submodule_url.ptr, overwrite != 0, false)) < 0)
 		goto cleanup;
 
 	/* write "submodule.NAME.update" if not default */
@@ -861,6 +874,7 @@ int git_submodule_init(git_submodule *sm, int overwrite)
 cleanup:
 	git_config_free(cfg);
 	git_buf_free(&key);
+	git_buf_free(&effective_submodule_url);
 
 	return error;
 }
diff --git a/tests/resources/submodule_simple/.gitmodules b/tests/resources/submodule_simple/.gitmodules
new file mode 100644
index 0000000..03150b4
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "testrepo"]
+	path = testrepo
+	url = ../testrepo.git
diff --git a/tests/resources/submodule_simple/.gitted/HEAD b/tests/resources/submodule_simple/.gitted/HEAD
new file mode 100644
index 0000000..cb089cd
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/tests/resources/submodule_simple/.gitted/config b/tests/resources/submodule_simple/.gitted/config
new file mode 100644
index 0000000..78387c5
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/config
@@ -0,0 +1,8 @@
+[core]
+	repositoryformatversion = 0
+	filemode = false
+	bare = false
+	logallrefupdates = true
+	symlinks = false
+	ignorecase = true
+	hideDotFiles = dotGitOnly
diff --git a/tests/resources/submodule_simple/.gitted/description b/tests/resources/submodule_simple/.gitted/description
new file mode 100644
index 0000000..498b267
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/resources/submodule_simple/.gitted/index b/tests/resources/submodule_simple/.gitted/index
new file mode 100644
index 0000000..6e22d7f
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/index differ
diff --git a/tests/resources/submodule_simple/.gitted/objects/22/9cea838964f435d4fc2c11561ddb7447003609 b/tests/resources/submodule_simple/.gitted/objects/22/9cea838964f435d4fc2c11561ddb7447003609
new file mode 100644
index 0000000..9f0800d
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/objects/22/9cea838964f435d4fc2c11561ddb7447003609 differ
diff --git a/tests/resources/submodule_simple/.gitted/objects/5b/19f7523fbf55c96153ff5a94875583f1115a36 b/tests/resources/submodule_simple/.gitted/objects/5b/19f7523fbf55c96153ff5a94875583f1115a36
new file mode 100644
index 0000000..d0681ac
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/objects/5b/19f7523fbf55c96153ff5a94875583f1115a36 differ
diff --git a/tests/resources/submodule_simple/.gitted/objects/a8/575e6aaececba78823993e4f11abbc6172aabd b/tests/resources/submodule_simple/.gitted/objects/a8/575e6aaececba78823993e4f11abbc6172aabd
new file mode 100644
index 0000000..b8961b0
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/objects/a8/575e6aaececba78823993e4f11abbc6172aabd differ
diff --git a/tests/resources/submodule_simple/.gitted/objects/b4/f28943fad380f4ee3a9c6b95259b28204cc25a b/tests/resources/submodule_simple/.gitted/objects/b4/f28943fad380f4ee3a9c6b95259b28204cc25a
new file mode 100644
index 0000000..653238c
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/objects/b4/f28943fad380f4ee3a9c6b95259b28204cc25a differ
diff --git a/tests/resources/submodule_simple/.gitted/objects/d6/9ff504a3ba631f2fdb35bff93cc8cb8e85f4f8 b/tests/resources/submodule_simple/.gitted/objects/d6/9ff504a3ba631f2fdb35bff93cc8cb8e85f4f8
new file mode 100644
index 0000000..dabf65b
Binary files /dev/null and b/tests/resources/submodule_simple/.gitted/objects/d6/9ff504a3ba631f2fdb35bff93cc8cb8e85f4f8 differ
diff --git a/tests/resources/submodule_simple/.gitted/packed-refs b/tests/resources/submodule_simple/.gitted/packed-refs
new file mode 100644
index 0000000..0400126
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/packed-refs
@@ -0,0 +1,3 @@
+# pack-refs with: peeled fully-peeled 
+229cea838964f435d4fc2c11561ddb7447003609 refs/remotes/origin/alternate_1
+a8575e6aaececba78823993e4f11abbc6172aabd refs/remotes/origin/master
diff --git a/tests/resources/submodule_simple/.gitted/refs/heads/alternate_1 b/tests/resources/submodule_simple/.gitted/refs/heads/alternate_1
new file mode 100644
index 0000000..6f51966
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/refs/heads/alternate_1
@@ -0,0 +1 @@
+229cea838964f435d4fc2c11561ddb7447003609
diff --git a/tests/resources/submodule_simple/.gitted/refs/heads/master b/tests/resources/submodule_simple/.gitted/refs/heads/master
new file mode 100644
index 0000000..f01cfb2
--- /dev/null
+++ b/tests/resources/submodule_simple/.gitted/refs/heads/master
@@ -0,0 +1 @@
+a8575e6aaececba78823993e4f11abbc6172aabd
diff --git a/tests/submodule/init.c b/tests/submodule/init.c
new file mode 100644
index 0000000..c03bf46
--- /dev/null
+++ b/tests/submodule/init.c
@@ -0,0 +1,73 @@
+#include "clar_libgit2.h"
+#include "posix.h"
+#include "path.h"
+#include "submodule_helpers.h"
+#include "fileops.h"
+
+static git_repository *g_repo = NULL;
+
+void test_submodule_init__cleanup(void)
+{
+	cl_git_sandbox_cleanup();
+}
+
+void test_submodule_init__absolute_url(void)
+{
+	git_submodule *sm;
+	git_config *cfg;
+	git_buf absolute_url = GIT_BUF_INIT;
+	const char *config_url;
+
+	g_repo = setup_fixture_submodule_simple();
+
+	cl_assert(git_path_dirname_r(&absolute_url, git_repository_workdir(g_repo)) > 0);
+	cl_git_pass(git_buf_joinpath(&absolute_url, absolute_url.ptr, "testrepo.git"));
+
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
+
+	/* write the absolute url to the .gitmodules file*/
+	cl_git_pass(git_submodule_set_url(sm, absolute_url.ptr));
+
+	/* verify that the .gitmodules is set with an absolute path*/
+	cl_assert_equal_s(absolute_url.ptr, git_submodule_url(sm));
+
+	/* init and verify that absolute path is written to .git/config */
+	cl_git_pass(git_submodule_init(sm, false));
+
+	cl_git_pass(git_repository_config(&cfg, g_repo));
+
+	git_config_get_string(&config_url, cfg, "submodule.testrepo.url");
+	cl_assert_equal_s(absolute_url.ptr, config_url);
+
+	git_buf_free(&absolute_url);
+	git_config_free(cfg);
+}
+
+void test_submodule_init__relative_url(void)
+{
+	git_submodule *sm;
+	git_config *cfg;
+	git_buf absolute_url = GIT_BUF_INIT;
+	const char *config_url;
+
+	g_repo = setup_fixture_submodule_simple();
+
+	cl_assert(git_path_dirname_r(&absolute_url, git_repository_workdir(g_repo)) > 0);
+	cl_git_pass(git_buf_joinpath(&absolute_url, absolute_url.ptr, "testrepo.git"));
+
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "testrepo"));
+
+	/* verify that the .gitmodules is set with an absolute path*/
+	cl_assert_equal_s("../testrepo.git", git_submodule_url(sm));
+
+	/* init and verify that absolute path is written to .git/config */
+	cl_git_pass(git_submodule_init(sm, false));
+
+	cl_git_pass(git_repository_config(&cfg, g_repo));
+
+	git_config_get_string(&config_url, cfg, "submodule.testrepo.url");
+	cl_assert_equal_s(absolute_url.ptr, config_url);
+
+	git_buf_free(&absolute_url);
+	git_config_free(cfg);
+}
diff --git a/tests/submodule/repository_init.c b/tests/submodule/repository_init.c
index e9733a6..bf1968d 100644
--- a/tests/submodule/repository_init.c
+++ b/tests/submodule/repository_init.c
@@ -17,6 +17,7 @@ void test_submodule_repository_init__basic(void)
 	g_repo = setup_fixture_submod2();
 
 	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
+	cl_git_pass(git_submodule_init(sm, 0));
 	cl_git_pass(git_submodule_repo_init(&repo, sm, 1));
 
 	/* Verify worktree */
diff --git a/tests/submodule/submodule_helpers.c b/tests/submodule/submodule_helpers.c
index c6d04b4..19bb04f 100644
--- a/tests/submodule/submodule_helpers.c
+++ b/tests/submodule/submodule_helpers.c
@@ -126,6 +126,20 @@ git_repository *setup_fixture_submod2(void)
 	return repo;
 }
 
+git_repository *setup_fixture_submodule_simple(void)
+{
+	git_repository *repo = cl_git_sandbox_init("submodule_simple");
+
+	cl_fixture_sandbox("testrepo.git");
+	p_mkdir("submodule_simple/testrepo", 0777);
+
+	cl_set_cleanup(cleanup_fixture_submodules, "testrepo.git");
+
+	cl_git_pass(git_repository_reinit_filesystem(repo, 1));
+
+	return repo;
+}
+
 void assert__submodule_exists(
 	git_repository *repo, const char *name,
 	const char *msg, const char *file, int line)
diff --git a/tests/submodule/submodule_helpers.h b/tests/submodule/submodule_helpers.h
index 4b2620b..1493f24 100644
--- a/tests/submodule/submodule_helpers.h
+++ b/tests/submodule/submodule_helpers.h
@@ -3,6 +3,7 @@ extern void rewrite_gitmodules(const char *workdir);
 /* these will automatically set a cleanup callback */
 extern git_repository *setup_fixture_submodules(void);
 extern git_repository *setup_fixture_submod2(void);
+extern git_repository *setup_fixture_submodule_simple(void);
 
 extern unsigned int get_submodule_status(git_repository *, const char *);