summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java43
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java232
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java69
-rw-r--r--org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java10
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java94
9 files changed, 437 insertions, 17 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
index d14d11b62d..dee2accf24 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleAddTest.java
@@ -47,6 +47,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.io.File;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
@@ -58,6 +59,7 @@ import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectId;
@@ -169,4 +171,45 @@ public class SubmoduleAddTest extends RepositoryTestCase {
e.getMessage());
}
}
+
+ @Test
+ public void addSubmoduleWithRelativeUri() throws Exception {
+ Git git = new Git(db);
+ writeTrashFile("file.txt", "content");
+ git.add().addFilepattern("file.txt").call();
+ RevCommit commit = git.commit().setMessage("create file").call();
+
+ SubmoduleAddCommand command = new SubmoduleAddCommand(db);
+ String path = "sub";
+ String uri = "./.git";
+ command.setPath(path);
+ command.setURI(uri);
+ Repository repo = command.call();
+ assertNotNull(repo);
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(path, generator.getPath());
+ assertEquals(commit, generator.getObjectId());
+ assertEquals(uri, generator.getModulesUrl());
+ assertEquals(path, generator.getModulesPath());
+ String fullUri = db.getDirectory().getAbsolutePath();
+ if (File.separatorChar == '\\')
+ fullUri = fullUri.replace('\\', '/');
+ assertEquals(fullUri, generator.getConfigUrl());
+ assertNotNull(generator.getRepository());
+ assertEquals(
+ fullUri,
+ generator
+ .getRepository()
+ .getConfig()
+ .getString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME,
+ ConfigConstants.CONFIG_KEY_URL));
+ assertEquals(commit, repo.resolve(Constants.HEAD));
+
+ Status status = Git.wrap(db).status().call();
+ assertTrue(status.getAdded().contains(Constants.DOT_GIT_MODULES));
+ assertTrue(status.getAdded().contains(path));
+ }
} \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
index 727368f34a..f0a0750c5c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleInitTest.java
@@ -46,12 +46,14 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.eclipse.jgit.api.SubmoduleInitCommand;
+import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
@@ -81,19 +83,7 @@ public class SubmoduleInitTest extends RepositoryTestCase {
@Test
public void repositoryWithUninitializedModule() throws IOException,
ConfigInvalidException {
- final ObjectId id = ObjectId
- .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
- final String path = "sub";
- DirCache cache = db.lockDirCache();
- DirCacheEditor editor = cache.editor();
- editor.add(new PathEdit(path) {
-
- public void apply(DirCacheEntry ent) {
- ent.setFileMode(FileMode.GITLINK);
- ent.setObjectId(id);
- }
- });
- editor.commit();
+ final String path = addSubmoduleToIndex();
SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
assertTrue(generator.next());
@@ -123,4 +113,220 @@ public class SubmoduleInitTest extends RepositoryTestCase {
assertEquals(url, generator.getConfigUrl());
assertEquals(update, generator.getConfigUpdate());
}
+
+ @Test
+ public void resolveSameLevelRelativeUrl() throws Exception {
+ final String path = addSubmoduleToIndex();
+
+ String base = "git://server/repo.git";
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ base);
+ config.save();
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertNull(generator.getConfigUpdate());
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String url = "./sub.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, url);
+ String update = "rebase";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_UPDATE, update);
+ modulesConfig.save();
+
+ SubmoduleInitCommand command = new SubmoduleInitCommand(db);
+ Collection<String> modules = command.call();
+ assertNotNull(modules);
+ assertEquals(1, modules.size());
+ assertEquals(path, modules.iterator().next());
+
+ generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals("git://server/repo.git/sub.git", generator.getConfigUrl());
+ assertEquals(update, generator.getConfigUpdate());
+ }
+
+ @Test
+ public void resolveOneLevelHigherRelativeUrl() throws IOException,
+ ConfigInvalidException {
+ final String path = addSubmoduleToIndex();
+
+ String base = "git://server/repo.git";
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ base);
+ config.save();
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertNull(generator.getConfigUpdate());
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String url = "../sub.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, url);
+ String update = "rebase";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_UPDATE, update);
+ modulesConfig.save();
+
+ SubmoduleInitCommand command = new SubmoduleInitCommand(db);
+ Collection<String> modules = command.call();
+ assertNotNull(modules);
+ assertEquals(1, modules.size());
+ assertEquals(path, modules.iterator().next());
+
+ generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals("git://server/sub.git", generator.getConfigUrl());
+ assertEquals(update, generator.getConfigUpdate());
+ }
+
+ @Test
+ public void resolveTwoLevelHigherRelativeUrl() throws IOException,
+ ConfigInvalidException {
+ final String path = addSubmoduleToIndex();
+
+ String base = "git://server/repo.git";
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ base);
+ config.save();
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertNull(generator.getConfigUpdate());
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String url = "../../server2/sub.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, url);
+ String update = "rebase";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_UPDATE, update);
+ modulesConfig.save();
+
+ SubmoduleInitCommand command = new SubmoduleInitCommand(db);
+ Collection<String> modules = command.call();
+ assertNotNull(modules);
+ assertEquals(1, modules.size());
+ assertEquals(path, modules.iterator().next());
+
+ generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals("git://server2/sub.git", generator.getConfigUrl());
+ assertEquals(update, generator.getConfigUpdate());
+ }
+
+ @Test
+ public void resolveWorkingDirectoryRelativeUrl() throws IOException,
+ ConfigInvalidException {
+ final String path = addSubmoduleToIndex();
+
+ String base = db.getWorkTree().getAbsolutePath();
+ if (File.separatorChar == '\\')
+ base = base.replace('\\', '/');
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ null);
+ config.save();
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertNull(generator.getConfigUpdate());
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String url = "./sub.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, url);
+ String update = "rebase";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_UPDATE, update);
+ modulesConfig.save();
+
+ SubmoduleInitCommand command = new SubmoduleInitCommand(db);
+ Collection<String> modules = command.call();
+ assertNotNull(modules);
+ assertEquals(1, modules.size());
+ assertEquals(path, modules.iterator().next());
+
+ generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals(base + "/sub.git", generator.getConfigUrl());
+ assertEquals(update, generator.getConfigUpdate());
+ }
+
+ @Test
+ public void resolveInvalidParentUrl() throws IOException,
+ ConfigInvalidException {
+ final String path = addSubmoduleToIndex();
+
+ String base = "no_slash";
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ base);
+ config.save();
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertNull(generator.getConfigUpdate());
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String url = "../sub.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, url);
+ modulesConfig.save();
+
+ try {
+ new SubmoduleInitCommand(db).call();
+ fail("Exception not thrown");
+ } catch (JGitInternalException e) {
+ assertTrue(e.getCause() instanceof IOException);
+ }
+ }
+
+ private String addSubmoduleToIndex() throws IOException {
+ final ObjectId id = ObjectId
+ .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
+
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
+ return path;
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
index f61aad2f38..4df9077ba0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleSyncTest.java
@@ -137,4 +137,73 @@ public class SubmoduleSyncTest extends RepositoryTestCase {
ConfigConstants.CONFIG_REMOTE_SECTION,
Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL));
}
+
+ @Test
+ public void repositoryWithRelativeUriSubmodule() throws Exception {
+ writeTrashFile("file.txt", "content");
+ Git git = Git.wrap(db);
+ git.add().addFilepattern("file.txt").call();
+ git.commit().setMessage("create file").call();
+
+ final ObjectId id = ObjectId
+ .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234");
+ final String path = "sub";
+ DirCache cache = db.lockDirCache();
+ DirCacheEditor editor = cache.editor();
+ editor.add(new PathEdit(path) {
+
+ public void apply(DirCacheEntry ent) {
+ ent.setFileMode(FileMode.GITLINK);
+ ent.setObjectId(id);
+ }
+ });
+ editor.commit();
+
+ String base = "git://server/repo.git";
+ FileBasedConfig config = db.getConfig();
+ config.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL,
+ base);
+ config.save();
+
+ FileBasedConfig modulesConfig = new FileBasedConfig(new File(
+ db.getWorkTree(), Constants.DOT_GIT_MODULES), db.getFS());
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_PATH, path);
+ String current = "git://server/repo.git";
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, current);
+ modulesConfig.save();
+
+ Repository subRepo = Git.cloneRepository()
+ .setURI(db.getDirectory().toURI().toString())
+ .setDirectory(new File(db.getWorkTree(), path)).call()
+ .getRepository();
+ assertNotNull(subRepo);
+
+ SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertNull(generator.getConfigUrl());
+ assertEquals(current, generator.getModulesUrl());
+
+ modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
+ ConfigConstants.CONFIG_KEY_URL, "../sub.git");
+ modulesConfig.save();
+
+ SubmoduleSyncCommand command = new SubmoduleSyncCommand(db);
+ Map<String, String> synced = command.call();
+ assertNotNull(synced);
+ assertEquals(1, synced.size());
+ Entry<String, String> module = synced.entrySet().iterator().next();
+ assertEquals(path, module.getKey());
+ assertEquals("git://server/sub.git", module.getValue());
+
+ generator = SubmoduleWalk.forIndex(db);
+ assertTrue(generator.next());
+ assertEquals("git://server/sub.git", generator.getConfigUrl());
+ StoredConfig submoduleConfig = generator.getRepository().getConfig();
+ assertEquals("git://server/sub.git", submoduleConfig.getString(
+ ConfigConstants.CONFIG_REMOTE_SECTION,
+ Constants.DEFAULT_REMOTE_NAME, ConfigConstants.CONFIG_KEY_URL));
+ }
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
index a80e6bcae5..5b22801342 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties
@@ -423,6 +423,7 @@ staleRevFlagsOn=Stale RevFlags on {0}
startingReadStageWithoutWrittenRequestDataPendingIsNotSupported=Starting read stage without written request data pending is not supported
statelessRPCRequiresOptionToBeEnabled=stateless RPC requires {0} to be enabled
submoduleExists=Submodule ''{0}'' already exists in the index
+submoduleParentRemoteUrlInvalid=Cannot remove segment from remote url ''{0}''
submodulesNotSupported=Submodules are not supported
symlinkCannotBeWrittenAsTheLinkTarget=Symlink "{0}" cannot be written as the link target cannot be read from within Java.
systemConfigFileInvalid=Systen wide config file {0} is invalid {1}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
index f4de487558..dbc3bcae62 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java
@@ -484,6 +484,7 @@ public class JGitText extends TranslationBundle {
/***/ public String statelessRPCRequiresOptionToBeEnabled;
/***/ public String submoduleExists;
/***/ public String submodulesNotSupported;
+ /***/ public String submoduleParentRemoteUrlInvalid;
/***/ public String symlinkCannotBeWrittenAsTheLinkTarget;
/***/ public String systemConfigFileInvalid;
/***/ public String tagNameInvalid;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
index ac81ccb457..e1b293c43d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -148,12 +148,18 @@ public class SubmoduleAddCommand extends
throw new JGitInternalException(e.getMessage(), e);
}
+ final String resolvedUri;
+ try {
+ resolvedUri = SubmoduleWalk.getSubmoduleRemoteUrl(repo, uri);
+ } catch (IOException e) {
+ throw new JGitInternalException(e.getMessage(), e);
+ }
// Clone submodule repository
File moduleDirectory = SubmoduleWalk.getSubmoduleDirectory(repo, path);
CloneCommand clone = Git.cloneRepository();
configure(clone);
clone.setDirectory(moduleDirectory);
- clone.setURI(uri);
+ clone.setURI(resolvedUri);
if (monitor != null)
clone.setProgressMonitor(monitor);
Repository subRepo = clone.call().getRepository();
@@ -161,7 +167,7 @@ public class SubmoduleAddCommand extends
// Save submodule URL to parent repository's config
StoredConfig config = repo.getConfig();
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, path,
- ConfigConstants.CONFIG_KEY_URL, uri);
+ ConfigConstants.CONFIG_KEY_URL, resolvedUri);
try {
config.save();
} catch (IOException e) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
index ad8f02e47f..fef13704ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleInitCommand.java
@@ -106,7 +106,7 @@ public class SubmoduleInitCommand extends GitCommand<Collection<String>> {
String path = generator.getPath();
// Copy 'url' and 'update' fields from .gitmodules to config
// file
- String url = generator.getModulesUrl();
+ String url = generator.getRemoteUrl();
String update = generator.getModulesUpdate();
if (url != null)
config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
index 43647a0c69..fd8ddc941d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -116,7 +116,7 @@ public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> {
Map<String, String> synced = new HashMap<String, String>();
StoredConfig config = repo.getConfig();
while (generator.next()) {
- String remoteUrl = generator.getModulesUrl();
+ String remoteUrl = generator.getRemoteUrl();
if (remoteUrl == null)
continue;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index ebe994826e..78896f8a54 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -44,7 +44,9 @@ package org.eclipse.jgit.submodule;
import java.io.File;
import java.io.IOException;
+import java.text.MessageFormat;
+import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.CorruptObjectException;
@@ -176,6 +178,83 @@ public class SubmoduleWalk {
return new File(getSubmoduleDirectory(parent, path), Constants.DOT_GIT);
}
+ /**
+ * Resolve submodule repository URL.
+ * <p>
+ * This handles relative URLs that are typically specified in the
+ * '.gitmodules' file by resolving them against the remote URL of the parent
+ * repository.
+ * <p>
+ * Relative URLs will be resolved against the parent repository's working
+ * directory if the parent repository has no configured remote URL.
+ *
+ * @param parent
+ * parent repository
+ * @param url
+ * absolute or relative URL of the submodule repository
+ * @return resolved URL
+ * @throws IOException
+ */
+ public static String getSubmoduleRemoteUrl(final Repository parent,
+ final String url) throws IOException {
+ if (!url.startsWith("./") && !url.startsWith("../"))
+ return url;
+
+ String remoteName = null;
+ // Look up remote URL associated wit HEAD ref
+ Ref ref = parent.getRef(Constants.HEAD);
+ if (ref != null) {
+ if (ref.isSymbolic())
+ ref = ref.getLeaf();
+ remoteName = parent.getConfig().getString(
+ ConfigConstants.CONFIG_BRANCH_SECTION,
+ Repository.shortenRefName(ref.getName()),
+ ConfigConstants.CONFIG_KEY_REMOTE);
+ }
+
+ // Fall back to 'origin' if current HEAD ref has no remote URL
+ if (remoteName == null)
+ remoteName = Constants.DEFAULT_REMOTE_NAME;
+
+ String remoteUrl = parent.getConfig().getString(
+ ConfigConstants.CONFIG_REMOTE_SECTION, remoteName,
+ ConfigConstants.CONFIG_KEY_URL);
+
+ // Fall back to parent repository's working directory if no remote URL
+ if (remoteUrl == null) {
+ remoteUrl = parent.getWorkTree().getAbsolutePath();
+ // Normalize slashes to '/'
+ if ('\\' == File.separatorChar)
+ remoteUrl = remoteUrl.replace('\\', '/');
+ }
+
+ // Remove trailing '/'
+ if (remoteUrl.charAt(remoteUrl.length() - 1) == '/')
+ remoteUrl = remoteUrl.substring(0, remoteUrl.length() - 1);
+
+ char separator = '/';
+ String submoduleUrl = url;
+ while (submoduleUrl.length() > 0) {
+ if (submoduleUrl.startsWith("./"))
+ submoduleUrl = submoduleUrl.substring(2);
+ else if (submoduleUrl.startsWith("../")) {
+ int lastSeparator = remoteUrl.lastIndexOf('/');
+ if (lastSeparator < 1) {
+ lastSeparator = remoteUrl.lastIndexOf(':');
+ separator = ':';
+ }
+ if (lastSeparator < 1)
+ throw new IOException(MessageFormat.format(
+ JGitText.get().submoduleParentRemoteUrlInvalid,
+ remoteUrl));
+ remoteUrl = remoteUrl.substring(0, lastSeparator);
+ submoduleUrl = submoduleUrl.substring(3);
+ } else
+ break;
+ }
+ return remoteUrl + separator + submoduleUrl;
+ }
+
private final Repository repository;
private final TreeWalk walk;
@@ -432,4 +511,19 @@ public class SubmoduleWalk {
Ref head = subRepo.getRef(Constants.HEAD);
return head != null ? head.getLeaf().getName() : null;
}
+
+ /**
+ * Get the resolved remote URL for the current submodule.
+ * <p>
+ * This method resolves the value of {@link #getModulesUrl()} to an absolute
+ * URL
+ *
+ * @return resolved remote URL
+ * @throws IOException
+ * @throws ConfigInvalidException
+ */
+ public String getRemoteUrl() throws IOException, ConfigInvalidException {
+ String url = getModulesUrl();
+ return url != null ? getSubmoduleRemoteUrl(repository, url) : null;
+ }
}