From 2f79cf9900288991e51b8da408511ead05f4d085 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Wed, 8 Feb 2012 23:10:28 +0100 Subject: [PATCH] Support gitdir references in working tree .git file A '.git' file in a repository's working tree root is now parsed as a ref to a folder located elsewhere. This supports submodules having their repository location outside of the parent repository's working directory such as in the parent repository's '.git/modules' directory. This adds support to BaseRepositoryBuilder for repositories created with the '--separate-git-dir' option specified to 'git init'. Change-Id: I73c538f6d845bdbc0c4e2bce5a77f900cf36e1a9 Signed-off-by: Matthias Sohn --- .../jgit/submodule/SubmoduleWalkTest.java | 103 +++++++++++++++++- .../org/eclipse/jgit/JGitText.properties | 1 + .../src/org/eclipse/jgit/JGitText.java | 1 + .../jgit/lib/BaseRepositoryBuilder.java | 50 ++++++++- .../eclipse/jgit/submodule/SubmoduleWalk.java | 53 ++++----- .../jgit/treewalk/FileTreeIterator.java | 2 +- .../jgit/treewalk/WorkingTreeIterator.java | 14 +-- 7 files changed, 173 insertions(+), 51 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java index c4bf33b8b..89843fc24 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/submodule/SubmoduleWalkTest.java @@ -44,10 +44,12 @@ package org.eclipse.jgit.submodule; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import org.eclipse.jgit.dircache.DirCache; @@ -58,7 +60,9 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryTestCase; +import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.treewalk.filter.PathFilter; import org.junit.Test; @@ -97,8 +101,6 @@ public class SubmoduleWalkTest extends RepositoryTestCase { assertEquals(path, gen.getPath()); assertEquals(id, gen.getObjectId()); assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertEquals(new File(db.getWorkTree(), path + File.separatorChar - + Constants.DOT_GIT), gen.getGitDirectory()); assertNull(gen.getConfigUpdate()); assertNull(gen.getConfigUrl()); assertNull(gen.getModulesPath()); @@ -108,6 +110,101 @@ public class SubmoduleWalkTest extends RepositoryTestCase { assertFalse(gen.next()); } + @Test + public void repositoryWithRootLevelSubmoduleAbsoluteRef() + throws IOException, ConfigInvalidException { + final ObjectId id = ObjectId + .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); + final String path = "sub"; + File dotGit = new File(db.getWorkTree(), path + File.separatorChar + + Constants.DOT_GIT); + if (!dotGit.getParentFile().exists()) + dotGit.getParentFile().mkdirs(); + + File modulesGitDir = new File(db.getDirectory(), "modules" + + File.separatorChar + path); + new FileWriter(dotGit).append( + "gitdir: " + modulesGitDir.getAbsolutePath()).close(); + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + builder.setWorkTree(new File(db.getWorkTree(), path)); + builder.build().create(); + + 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(); + + SubmoduleWalk gen = SubmoduleWalk.forIndex(db); + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + Repository subRepo = gen.getRepository(); + assertNotNull(subRepo); + assertEquals(modulesGitDir, subRepo.getDirectory()); + assertEquals(new File(db.getWorkTree(), path), subRepo.getWorkTree()); + assertFalse(gen.next()); + } + + @Test + public void repositoryWithRootLevelSubmoduleRelativeRef() + throws IOException, ConfigInvalidException { + final ObjectId id = ObjectId + .fromString("abcd1234abcd1234abcd1234abcd1234abcd1234"); + final String path = "sub"; + File dotGit = new File(db.getWorkTree(), path + File.separatorChar + + Constants.DOT_GIT); + if (!dotGit.getParentFile().exists()) + dotGit.getParentFile().mkdirs(); + + File modulesGitDir = new File(db.getDirectory(), "modules" + + File.separatorChar + path); + new FileWriter(dotGit).append( + "gitdir: " + "../" + Constants.DOT_GIT + "/modules/" + path) + .close(); + FileRepositoryBuilder builder = new FileRepositoryBuilder(); + builder.setWorkTree(new File(db.getWorkTree(), path)); + builder.build().create(); + + 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(); + + SubmoduleWalk gen = SubmoduleWalk.forIndex(db); + assertTrue(gen.next()); + assertEquals(path, gen.getPath()); + assertEquals(id, gen.getObjectId()); + assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); + assertNull(gen.getConfigUpdate()); + assertNull(gen.getConfigUrl()); + assertNull(gen.getModulesPath()); + assertNull(gen.getModulesUpdate()); + assertNull(gen.getModulesUrl()); + Repository subRepo = gen.getRepository(); + assertNotNull(subRepo); + assertEquals(modulesGitDir, subRepo.getDirectory()); + assertEquals(new File(db.getWorkTree(), path), subRepo.getWorkTree()); + assertFalse(gen.next()); + } + @Test public void repositoryWithNestedSubmodule() throws IOException, ConfigInvalidException { @@ -130,8 +227,6 @@ public class SubmoduleWalkTest extends RepositoryTestCase { assertEquals(path, gen.getPath()); assertEquals(id, gen.getObjectId()); assertEquals(new File(db.getWorkTree(), path), gen.getDirectory()); - assertEquals(new File(db.getWorkTree(), path + File.separatorChar - + Constants.DOT_GIT), gen.getGitDirectory()); assertNull(gen.getConfigUpdate()); assertNull(gen.getConfigUrl()); assertNull(gen.getModulesPath()); diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties index 5b2280134..8a5e02310 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/JGitText.properties @@ -234,6 +234,7 @@ invalidChannel=Invalid channel {0} invalidCharacterInBase64Data=Invalid character in Base64 data. invalidCommitParentNumber=Invalid commit parent number invalidEncryption=Invalid encryption +invalidGitdirRef = Invalid .git reference in file ''{0}'' invalidGitType=invalid git type: {0} invalidId=Invalid id {0} invalidIdLength=Invalid id length {0}; should be {1} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java index dbc3bcae6..bcd14c6a4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/JGitText.java @@ -294,6 +294,7 @@ public class JGitText extends TranslationBundle { /***/ public String invalidCharacterInBase64Data; /***/ public String invalidCommitParentNumber; /***/ public String invalidEncryption; + /***/ public String invalidGitdirRef; /***/ public String invalidGitType; /***/ public String invalidId; /***/ public String invalidIdLength; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java index 22a2ae505..7db0b9f87 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java @@ -69,6 +69,8 @@ import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.storage.file.FileRepository; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.SystemReader; /** @@ -85,6 +87,19 @@ import org.eclipse.jgit.util.SystemReader; * @see FileRepositoryBuilder */ public class BaseRepositoryBuilder { + private static boolean isSymRef(byte[] ref) { + if (ref.length < 9) + return false; + return /**/ref[0] == 'g' // + && ref[1] == 'i' // + && ref[2] == 't' // + && ref[3] == 'd' // + && ref[4] == 'i' // + && ref[5] == 'r' // + && ref[6] == ':' // + && ref[7] == ' '; + } + private FS fs; private File gitDir; @@ -546,10 +561,37 @@ public class BaseRepositoryBuilder