Interpret submodule URLs that start with './' or '../' as relative to either the configured remote for the HEAD branch, or 'origin', or the parent repository working directory if no remote URL is configured Bug: 368536 Change-Id: Id4985824023b75cd45cd64a4dd9d421166391e10tags/v1.3.0.201202121842-rc4
@@ -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)); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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)); | |||
} | |||
} |
@@ -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} |
@@ -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; |
@@ -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) { |
@@ -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, |
@@ -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; | |||
@@ -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; | |||
} | |||
} |