diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java index 82a0ce84a..cc062dbe8 100644 --- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java +++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java @@ -52,6 +52,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryCache.FileKey; +import org.eclipse.jgit.util.FS; /** Default resolver serving from a single root path in local filesystem. */ public class FileResolver implements RepositoryResolver { @@ -82,7 +83,7 @@ public Repository open(final HttpServletRequest req, final Repository db; try { final File gitdir = new File(basePath, repositoryName); - db = RepositoryCache.open(FileKey.lenient(gitdir), true); + db = RepositoryCache.open(FileKey.lenient(gitdir, FS.DETECTED), true); } catch (IOException e) { throw new RepositoryNotFoundException(repositoryName, e); } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index b4f0b7e90..c502fb634 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -53,6 +53,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileBasedConfig; +import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; public class MockSystemReader extends SystemReader { @@ -102,7 +103,7 @@ public String getProperty(String key) { } @Override - public FileBasedConfig openUserConfig() { + public FileBasedConfig openUserConfig(FS fs) { return userGitConfig; } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java index 0bc9ee112..2043ac209 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java @@ -64,6 +64,7 @@ import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.util.FS; /** * Custom argument handler {@link AbstractTreeIterator} from string values. @@ -95,7 +96,7 @@ public int parseArguments(final Parameters params) throws CmdLineException { final String name = params.getParameter(0); if (new File(name).isDirectory()) { - setter.addValue(new FileTreeIterator(new File(name))); + setter.addValue(new FileTreeIterator(new File(name), FS.DETECTED)); return 1; } diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0007_GitIndexTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0007_GitIndexTest.java index 21dcdffbf..dd3b51efc 100644 --- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0007_GitIndexTest.java +++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0007_GitIndexTest.java @@ -337,7 +337,7 @@ public void testCheckout() throws Exception { } public void test030_executeBit_coreModeTrue() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception { - if (!FS.INSTANCE.supportsExecute()) { + if (!FS.DETECTED.supportsExecute()) { System.err.println("Test ignored since platform FS does not support the execute permission"); return; } @@ -392,7 +392,7 @@ public void test030_executeBit_coreModeTrue() throws IllegalArgumentException, I } public void test031_executeBit_coreModeFalse() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception { - if (!FS.INSTANCE.supportsExecute()) { + if (!FS.DETECTED.supportsExecute()) { System.err.println("Test ignored since platform FS does not support the execute permission"); return; } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java index f05889308..cab3cba37 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java @@ -54,13 +54,13 @@ public void testNonBareFileKey() { File gitdir = db.getDirectory(); File parent = gitdir.getParentFile(); File other = new File(parent, "notagit"); - assertEquals(gitdir, FileKey.exact(gitdir).getFile()); - assertEquals(parent, FileKey.exact(parent).getFile()); - assertEquals(other, FileKey.exact(other).getFile()); + assertEquals(gitdir, FileKey.exact(gitdir, db.getFS()).getFile()); + assertEquals(parent, FileKey.exact(parent, db.getFS()).getFile()); + assertEquals(other, FileKey.exact(other, db.getFS()).getFile()); - assertEquals(gitdir, FileKey.lenient(gitdir).getFile()); - assertEquals(gitdir, FileKey.lenient(parent).getFile()); - assertEquals(other, FileKey.lenient(other).getFile()); + assertEquals(gitdir, FileKey.lenient(gitdir, db.getFS()).getFile()); + assertEquals(gitdir, FileKey.lenient(parent, db.getFS()).getFile()); + assertEquals(other, FileKey.lenient(other, db.getFS()).getFile()); } public void testBareFileKey() throws IOException { @@ -71,21 +71,21 @@ public void testBareFileKey() throws IOException { assertTrue(name.endsWith(".git")); name = name.substring(0, name.length() - 4); - assertEquals(gitdir, FileKey.exact(gitdir).getFile()); + assertEquals(gitdir, FileKey.exact(gitdir, db.getFS()).getFile()); - assertEquals(gitdir, FileKey.lenient(gitdir).getFile()); - assertEquals(gitdir, FileKey.lenient(new File(parent, name)).getFile()); + assertEquals(gitdir, FileKey.lenient(gitdir, db.getFS()).getFile()); + assertEquals(gitdir, FileKey.lenient(new File(parent, name), db.getFS()).getFile()); } public void testFileKeyOpenExisting() throws IOException { Repository r; - r = new FileKey(db.getDirectory()).open(true); + r = new FileKey(db.getDirectory(), db.getFS()).open(true); assertNotNull(r); assertEquals(db.getDirectory(), r.getDirectory()); r.close(); - r = new FileKey(db.getDirectory()).open(false); + r = new FileKey(db.getDirectory(), db.getFS()).open(false); assertNotNull(r); assertEquals(db.getDirectory(), r.getDirectory()); r.close(); @@ -99,13 +99,13 @@ public void testFileKeyOpenNew() throws IOException { assertFalse(gitdir.exists()); try { - new FileKey(gitdir).open(true); + new FileKey(gitdir, db.getFS()).open(true); fail("incorrectly opened a non existant repository"); } catch (RepositoryNotFoundException e) { assertEquals("repository not found: " + gitdir, e.getMessage()); } - final Repository o = new FileKey(gitdir).open(false); + final Repository o = new FileKey(gitdir, db.getFS()).open(false); assertNotNull(o); assertEquals(gitdir, o.getDirectory()); assertFalse(gitdir.exists()); @@ -114,18 +114,18 @@ public void testFileKeyOpenNew() throws IOException { public void testCacheRegisterOpen() throws Exception { final File dir = db.getDirectory(); RepositoryCache.register(db); - assertSame(db, RepositoryCache.open(FileKey.exact(dir))); + assertSame(db, RepositoryCache.open(FileKey.exact(dir, db.getFS()))); assertEquals(".git", dir.getName()); final File parent = dir.getParentFile(); - assertSame(db, RepositoryCache.open(FileKey.lenient(parent))); + assertSame(db, RepositoryCache.open(FileKey.lenient(parent, db.getFS()))); } public void testCacheOpen() throws Exception { - final FileKey loc = FileKey.exact(db.getDirectory()); + final FileKey loc = FileKey.exact(db.getDirectory(), db.getFS()); final Repository d2 = RepositoryCache.open(loc); assertNotSame(db, d2); - assertSame(d2, RepositoryCache.open(FileKey.exact(loc.getFile()))); + assertSame(d2, RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS()))); d2.close(); d2.close(); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java index 41c4971a0..6f8076f09 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java @@ -54,6 +54,7 @@ import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.junit.MockSystemReader; +import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.SystemReader; /** @@ -116,7 +117,7 @@ public void test007_readUserConfig() { final MockSystemReader mockSystemReader = new MockSystemReader(); SystemReader.setInstance(mockSystemReader); final String hostname = mockSystemReader.getHostname(); - final Config userGitConfig = mockSystemReader.openUserConfig(); + final Config userGitConfig = mockSystemReader.openUserConfig(FS.DETECTED); final Config localConfig = new Config(userGitConfig); mockSystemReader.clearProperties(); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java index 081290310..eb08e495b 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java @@ -77,7 +77,7 @@ public void setUp() throws Exception { public void testEmptyIfRootIsFile() throws Exception { final File r = new File(trash, paths[0]); assertTrue(r.isFile()); - final FileTreeIterator fti = new FileTreeIterator(r); + final FileTreeIterator fti = new FileTreeIterator(r, db.getFS()); assertTrue(fti.first()); assertTrue(fti.eof()); } @@ -85,7 +85,7 @@ public void testEmptyIfRootIsFile() throws Exception { public void testEmptyIfRootDoesNotExist() throws Exception { final File r = new File(trash, "not-existing-file"); assertFalse(r.exists()); - final FileTreeIterator fti = new FileTreeIterator(r); + final FileTreeIterator fti = new FileTreeIterator(r, db.getFS()); assertTrue(fti.first()); assertTrue(fti.eof()); } @@ -96,13 +96,13 @@ public void testEmptyIfRootIsEmpty() throws Exception { r.mkdir(); assertTrue(r.isDirectory()); - final FileTreeIterator fti = new FileTreeIterator(r); + final FileTreeIterator fti = new FileTreeIterator(r, db.getFS()); assertTrue(fti.first()); assertTrue(fti.eof()); } public void testSimpleIterate() throws Exception { - final FileTreeIterator top = new FileTreeIterator(trash); + final FileTreeIterator top = new FileTreeIterator(trash, db.getFS()); assertTrue(top.first()); assertFalse(top.eof()); @@ -149,7 +149,7 @@ public void testSimpleIterate() throws Exception { } public void testComputeFileObjectId() throws Exception { - final FileTreeIterator top = new FileTreeIterator(trash); + final FileTreeIterator top = new FileTreeIterator(trash, db.getFS()); final MessageDigest md = Constants.newMessageDigest(); md.update(Constants.encodeASCII(Constants.TYPE_BLOB)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitIndex.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitIndex.java index 0203d5d44..d5cab0e4c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitIndex.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/GitIndex.java @@ -71,7 +71,6 @@ import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.NotSupportedException; -import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.RawParseUtils; /** @@ -328,16 +327,16 @@ private void checkWriteOk() throws IOException { } } - static boolean File_canExecute( File f){ - return FS.INSTANCE.canExecute(f); + private boolean File_canExecute(File f){ + return db.getFS().canExecute(f); } - static boolean File_setExecute(File f, boolean value) { - return FS.INSTANCE.setExecute(f, value); + private boolean File_setExecute(File f, boolean value) { + return db.getFS().setExecute(f, value); } - static boolean File_hasExecute() { - return FS.INSTANCE.supportsExecute(); + private boolean File_hasExecute() { + return db.getFS().supportsExecute(); } static byte[] makeKey(File wd, File f) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java index 06700ebe1..9a5bcdb68 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java @@ -88,6 +88,8 @@ public class ObjectDirectory extends ObjectDatabase { private final File[] alternateObjectDir; + private final FS fs; + /** * Initialize a reference to an on-disk object directory. * @@ -95,14 +97,18 @@ public class ObjectDirectory extends ObjectDatabase { * the location of the objects directory. * @param alternateObjectDir * a list of alternate object directories + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. */ - public ObjectDirectory(final File dir, File[] alternateObjectDir) { + public ObjectDirectory(final File dir, File[] alternateObjectDir, FS fs) { objects = dir; this.alternateObjectDir = alternateObjectDir; infoDirectory = new File(objects, "info"); packDirectory = new File(objects, "pack"); alternatesFile = new File(infoDirectory, "alternates"); packList = new AtomicReference(NO_PACKS); + this.fs = fs; } /** @@ -485,17 +491,17 @@ private static BufferedReader open(final File f) private ObjectDatabase openAlternate(final String location) throws IOException { - final File objdir = FS.resolve(objects, location); + final File objdir = fs.resolve(objects, location); return openAlternate(objdir); } private ObjectDatabase openAlternate(File objdir) throws IOException { final File parent = objdir.getParentFile(); - if (FileKey.isGitRepository(parent)) { - final Repository db = RepositoryCache.open(FileKey.exact(parent)); + if (FileKey.isGitRepository(parent, fs)) { + final Repository db = RepositoryCache.open(FileKey.exact(parent, fs)); return new AlternateRepositoryDatabase(db); } - return new ObjectDirectory(objdir, null); + return new ObjectDirectory(objdir, null, fs); } private static final class PackList { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDirectory.java index 5ba186955..302b63b48 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDirectory.java @@ -151,12 +151,13 @@ public class RefDirectory extends RefDatabase { private final AtomicInteger lastNotifiedModCnt = new AtomicInteger(); RefDirectory(final Repository db) { + final FS fs = db.getFS(); parent = db; gitDir = db.getDirectory(); - refsDir = FS.resolve(gitDir, R_REFS); - logsDir = FS.resolve(gitDir, LOGS); - logsRefsDir = FS.resolve(gitDir, LOGS + '/' + R_REFS); - packedRefsFile = FS.resolve(gitDir, PACKED_REFS); + refsDir = fs.resolve(gitDir, R_REFS); + logsDir = fs.resolve(gitDir, LOGS); + logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS); + packedRefsFile = fs.resolve(gitDir, PACKED_REFS); looseRefs.set(RefList. emptyList()); packedRefs.set(PackedRefList.NO_PACKED_REFS); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 233cecf31..98362af98 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -102,6 +102,8 @@ public class Repository { private final File gitDir; + private final FS fs; + private final FileBasedConfig userConfig; private final RepositoryConfig config; @@ -185,6 +187,41 @@ public Repository(final File d, final File workTree) throws IOException { */ public Repository(final File d, final File workTree, final File objectDir, final File[] alternateObjectDir, final File indexFile) throws IOException { + this(d, workTree, objectDir, alternateObjectDir, indexFile, FS.DETECTED); + } + + /** + * Construct a representation of a Git repository using the given parameters + * possibly overriding default conventions. + * + * @param d + * GIT_DIR (the location of the repository metadata). May be null + * for default value in which case it depends on GIT_WORK_TREE. + * @param workTree + * GIT_WORK_TREE (the root of the checkout). May be null for + * default value if GIT_DIR is + * @param objectDir + * GIT_OBJECT_DIRECTORY (where objects and are stored). May be + * null for default value. Relative names ares resolved against + * GIT_WORK_TREE + * @param alternateObjectDir + * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read + * from). May be null for default value. Relative names ares + * resolved against GIT_WORK_TREE + * @param indexFile + * GIT_INDEX_FILE (the location of the index file). May be null + * for default value. Relative names ares resolved against + * GIT_WORK_TREE. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. + * @throws IOException + * the repository appears to already exist but cannot be + * accessed. + */ + public Repository(final File d, final File workTree, final File objectDir, + final File[] alternateObjectDir, final File indexFile, + FS fs) throws IOException { if (workTree != null) { workDir = workTree; @@ -199,8 +236,10 @@ public Repository(final File d, final File workTree, final File objectDir, throw new IllegalArgumentException(JGitText.get().eitherGIT_DIRorGIT_WORK_TREEmustBePassed); } - userConfig = SystemReader.getInstance().openUserConfig(); - config = new RepositoryConfig(userConfig, FS.resolve(gitDir, "config")); + this.fs = fs; + + userConfig = SystemReader.getInstance().openUserConfig(fs); + config = new RepositoryConfig(userConfig, fs.resolve(gitDir, "config")); loadUserConfig(); loadConfig(); @@ -208,7 +247,7 @@ public Repository(final File d, final File workTree, final File objectDir, if (workDir == null) { String workTreeConfig = getConfig().getString("core", null, "worktree"); if (workTreeConfig != null) { - workDir = FS.resolve(d, workTreeConfig); + workDir = fs.resolve(d, workTreeConfig); } else { workDir = gitDir.getParentFile(); } @@ -216,11 +255,11 @@ public Repository(final File d, final File workTree, final File objectDir, refs = new RefDirectory(this); if (objectDir != null) - objectDatabase = new ObjectDirectory(FS.resolve(objectDir, ""), - alternateObjectDir); + objectDatabase = new ObjectDirectory(fs.resolve(objectDir, ""), + alternateObjectDir, fs); else - objectDatabase = new ObjectDirectory(FS.resolve(gitDir, "objects"), - alternateObjectDir); + objectDatabase = new ObjectDirectory(fs.resolve(gitDir, "objects"), + alternateObjectDir, fs); if (indexFile != null) this.indexFile = indexFile; @@ -351,6 +390,13 @@ public RepositoryConfig getConfig() { return config; } + /** + * @return the used file system abstraction + */ + public FS getFS() { + return fs; + } + /** * Construct a filename where the loose object having a specified SHA-1 * should be stored. If the object is stored in a shared repository the path diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java index b086968c6..0b0260a4c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java @@ -120,7 +120,7 @@ public static Repository open(final Key location, final boolean mustExist) * repository to register. */ public static void register(final Repository db) { - cache.registerRepository(FileKey.exact(db.getDirectory()), db); + cache.registerRepository(FileKey.exact(db.getDirectory(), db.getFS()), db); } /** @@ -133,7 +133,7 @@ public static void register(final Repository db) { * repository to unregister. */ public static void close(final Repository db) { - cache.unregisterRepository(FileKey.exact(db.getDirectory())); + cache.unregisterRepository(FileKey.exact(db.getDirectory(), db.getFS())); } /** Unregister all repositories from the cache. */ @@ -248,11 +248,14 @@ public static class FileKey implements Key { * * @param directory * location where the repository database is. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return a key for the given directory. - * @see #lenient(File) + * @see #lenient(File, FS) */ - public static FileKey exact(final File directory) { - return new FileKey(directory); + public static FileKey exact(final File directory, FS fs) { + return new FileKey(directory, fs); } /** @@ -268,22 +271,30 @@ public static FileKey exact(final File directory) { * * @param directory * location where the repository database might be. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return a key for the given directory. - * @see #exact(File) + * @see #exact(File, FS) */ - public static FileKey lenient(final File directory) { - final File gitdir = resolve(directory); - return new FileKey(gitdir != null ? gitdir : directory); + public static FileKey lenient(final File directory, FS fs) { + final File gitdir = resolve(directory, fs); + return new FileKey(gitdir != null ? gitdir : directory, fs); } private final File path; + private final FS fs; /** * @param directory * exact location of the repository. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. */ - protected FileKey(final File directory) { + protected FileKey(final File directory, FS fs) { path = canonical(directory); + this.fs = fs; } private static File canonical(final File path) { @@ -300,7 +311,7 @@ public final File getFile() { } public Repository open(final boolean mustExist) throws IOException { - if (mustExist && !isGitRepository(path)) + if (mustExist && !isGitRepository(path, fs)) throw new RepositoryNotFoundException(path); return new Repository(path); } @@ -328,13 +339,16 @@ public String toString() { * * @param dir * the location of the directory to examine. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return true if the directory "looks like" a Git repository; false if * it doesn't look enough like a Git directory to really be a * Git directory. */ - public static boolean isGitRepository(final File dir) { - return FS.resolve(dir, "objects").exists() - && FS.resolve(dir, "refs").exists() + public static boolean isGitRepository(final File dir, FS fs) { + return fs.resolve(dir, "objects").exists() + && fs.resolve(dir, "refs").exists() && isValidHead(new File(dir, Constants.HEAD)); } @@ -371,18 +385,21 @@ private static String readFirstLine(final File head) { * * @param directory * location to guess from. Several permutations are tried. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return the actual directory location if a better match is found; * null if there is no suitable match. */ - public static File resolve(final File directory) { - if (isGitRepository(directory)) + public static File resolve(final File directory, FS fs) { + if (isGitRepository(directory, fs)) return directory; - if (isGitRepository(new File(directory, Constants.DOT_GIT))) + if (isGitRepository(new File(directory, Constants.DOT_GIT), fs)) return new File(directory, Constants.DOT_GIT); final String name = directory.getName(); final File parent = directory.getParentFile(); - if (isGitRepository(new File(parent, name + Constants.DOT_GIT_EXT))) + if (isGitRepository(new File(parent, name + Constants.DOT_GIT_EXT), fs)) return new File(parent, name + Constants.DOT_GIT_EXT); return null; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java index 39c7ae8f0..aa2e2521c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java @@ -63,6 +63,7 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryCache; import org.eclipse.jgit.lib.RepositoryCache.FileKey; +import org.eclipse.jgit.util.FS; /** Basic daemon for the anonymous git:// transport protocol. */ public class Daemon { @@ -368,7 +369,7 @@ Repository openRepository(String name) { } for (final File baseDir : exportBase) { - final File gitdir = FileKey.resolve(new File(baseDir, name)); + final File gitdir = FileKey.resolve(new File(baseDir, name), FS.DETECTED); if (gitdir != null && canExport(gitdir)) return openRepository(gitdir); } @@ -377,7 +378,7 @@ Repository openRepository(String name) { private static Repository openRepository(final File gitdir) { try { - return RepositoryCache.open(FileKey.exact(gitdir)); + return RepositoryCache.open(FileKey.exact(gitdir, FS.DETECTED)); } catch (IOException err) { // null signals it "wasn't found", which is all that is suitable // for the remote client to know. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java index e7a307f80..20f3174b2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java @@ -82,10 +82,13 @@ public class OpenSshConfig { * requests are cached and are automatically updated if the user modifies * the configuration file since the last time it was cached. * + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return a caching reader of the user's configuration file. */ - public static OpenSshConfig get() { - File home = FS.userHome(); + public static OpenSshConfig get(FS fs) { + File home = fs.userHome(); if (home == null) home = new File(".").getAbsoluteFile(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java index c30d32d9f..daa6f4ca2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java @@ -83,15 +83,18 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory { @Override public synchronized Session getSession(String user, String pass, - String host, int port) throws JSchException { - final OpenSshConfig.Host hc = getConfig().lookup(host); + String host, int port, FS fs) throws JSchException { + if (config == null) + config = OpenSshConfig.get(fs); + + final OpenSshConfig.Host hc = config.lookup(host); host = hc.getHostName(); if (port <= 0) port = hc.getPort(); if (user == null) user = hc.getUser(); - final Session session = createSession(hc, user, host, port); + final Session session = createSession(hc, user, host, port, fs); if (pass != null) session.setPassword(pass); final String strictHostKeyCheckingPolicy = hc @@ -117,14 +120,17 @@ public synchronized Session getSession(String user, String pass, * server name to connect to. * @param port * port number of the SSH daemon (typically 22). + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return new session instance, but otherwise unconfigured. * @throws JSchException * the session could not be created. */ protected Session createSession(final OpenSshConfig.Host hc, - final String user, final String host, final int port) + final String user, final String host, final int port, FS fs) throws JSchException { - return getJSch(hc).getSession(user, host, port); + return getJSch(hc, fs).getSession(user, host, port); } /** @@ -143,58 +149,54 @@ protected Session createSession(final OpenSshConfig.Host hc, * * @param hc * host configuration + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return the JSch instance to use. * @throws JSchException * the user configuration could not be created. */ - protected JSch getJSch(final OpenSshConfig.Host hc) throws JSchException { - final JSch def = getDefaultJSch(); + protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException { + if (defaultJSch == null) { + defaultJSch = createDefaultJSch(fs); + for (Object name : defaultJSch.getIdentityNames()) { + byIdentityFile.put((String) name, defaultJSch); + } + } + final File identityFile = hc.getIdentityFile(); if (identityFile == null) { - return def; + return defaultJSch; } final String identityKey = identityFile.getAbsolutePath(); JSch jsch = byIdentityFile.get(identityKey); if (jsch == null) { jsch = new JSch(); - jsch.setHostKeyRepository(def.getHostKeyRepository()); + jsch.setHostKeyRepository(defaultJSch.getHostKeyRepository()); jsch.addIdentity(identityKey); byIdentityFile.put(identityKey, jsch); } return jsch; } - private JSch getDefaultJSch() throws JSchException { - if (defaultJSch == null) { - defaultJSch = createDefaultJSch(); - for (Object name : defaultJSch.getIdentityNames()) { - byIdentityFile.put((String) name, defaultJSch); - } - } - return defaultJSch; - } - /** + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return the new default JSch implementation. * @throws JSchException * known host keys cannot be loaded. */ - protected JSch createDefaultJSch() throws JSchException { + protected JSch createDefaultJSch(FS fs) throws JSchException { final JSch jsch = new JSch(); - knownHosts(jsch); - identities(jsch); + knownHosts(jsch, fs); + identities(jsch, fs); return jsch; } - private OpenSshConfig getConfig() { - if (config == null) - config = OpenSshConfig.get(); - return config; - } - - private static void knownHosts(final JSch sch) throws JSchException { - final File home = FS.userHome(); + private static void knownHosts(final JSch sch, FS fs) throws JSchException { + final File home = fs.userHome(); if (home == null) return; final File known_hosts = new File(new File(home, ".ssh"), "known_hosts"); @@ -212,8 +214,8 @@ private static void knownHosts(final JSch sch) throws JSchException { } } - private static void identities(final JSch sch) { - final File home = FS.userHome(); + private static void identities(final JSch sch, FS fs) { + final File home = fs.userHome(); if (home == null) return; final File sshdir = new File(home, ".ssh"); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java index 810b04ce4..d10010fcf 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java @@ -44,6 +44,8 @@ package org.eclipse.jgit.transport; +import org.eclipse.jgit.util.FS; + import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; @@ -109,19 +111,22 @@ public static void setInstance(final SshSessionFactory newFactory) { * @param port * port number the server is listening for connections on. May be <= * 0 to indicate the IANA registered port of 22 should be used. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return a session that can contact the remote host. * @throws JSchException * the session could not be created. */ public abstract Session getSession(String user, String pass, String host, - int port) throws JSchException; + int port, FS fs) throws JSchException; /** * Close (or recycle) a session to a host. * * @param session * a session previously obtained from this factory's - * {@link #getSession(String,String, String, int)} method.s + * {@link #getSession(String,String, String, int, FS)} method.s */ public void releaseSession(final Session session) { if (session.isConnected()) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java index d25a7b618..f642ac1ea 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java @@ -128,7 +128,7 @@ protected void initSession() throws TransportException { final String host = uri.getHost(); final int port = uri.getPort(); try { - sock = sch.getSession(user, pass, host, port); + sock = sch.getSession(user, pass, host, port, local.getFS()); if (!sock.isConnected()) sock.connect(tms); } catch (JSchException je) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java index 2fe3cb932..e1988a6c8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java @@ -66,6 +66,7 @@ import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.TransferConfig; +import org.eclipse.jgit.util.FS; /** * Connects two Git repositories together and copies objects between them. @@ -323,9 +324,11 @@ private static boolean doesNotExist(final RemoteConfig cfg) { * * @param remote * location of the remote repository. + * @param fs + * type of filesystem the local repository is stored on. * @return true if the protocol is supported. */ - public static boolean canHandleProtocol(final URIish remote) { + public static boolean canHandleProtocol(final URIish remote, final FS fs) { if (TransportGitSsh.canHandle(remote)) return true; @@ -341,10 +344,10 @@ else if (TransportGitAnon.canHandle(remote)) else if (TransportAmazonS3.canHandle(remote)) return true; - else if (TransportBundleFile.canHandle(remote)) + else if (TransportBundleFile.canHandle(remote, fs)) return true; - else if (TransportLocal.canHandle(remote)) + else if (TransportLocal.canHandle(remote, fs)) return true; return false; @@ -378,10 +381,10 @@ else if (TransportGitAnon.canHandle(remote)) else if (TransportAmazonS3.canHandle(remote)) return new TransportAmazonS3(local, remote); - else if (TransportBundleFile.canHandle(remote)) + else if (TransportBundleFile.canHandle(remote, local.getFS())) return new TransportBundleFile(local, remote); - else if (TransportLocal.canHandle(remote)) + else if (TransportLocal.canHandle(remote, local.getFS())) return new TransportLocal(local, remote); throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, remote)); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java index bcf6e873f..56a5c9796 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java @@ -69,7 +69,6 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.SymbolicRef; import org.eclipse.jgit.lib.Ref.Storage; -import org.eclipse.jgit.util.FS; /** * Transport over the non-Git aware Amazon S3 protocol. @@ -130,7 +129,7 @@ static boolean canHandle(final URIish uri) { Properties props = null; File propsFile = new File(local.getDirectory(), uri.getUser()); if (!propsFile.isFile()) - propsFile = new File(FS.userHome(), uri.getUser()); + propsFile = new File(local.getFS().userHome(), uri.getUser()); if (propsFile.isFile()) { try { props = AmazonS3.properties(propsFile); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java index 0245818fe..c47833f21 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java @@ -58,13 +58,13 @@ import org.eclipse.jgit.util.FS; class TransportBundleFile extends Transport implements TransportBundle { - static boolean canHandle(final URIish uri) { + static boolean canHandle(final URIish uri, FS fs) { if (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null || uri.getPass() != null || uri.getPath() == null) return false; if ("file".equals(uri.getScheme()) || uri.getScheme() == null) { - final File f = FS.resolve(new File("."), uri.getPath()); + final File f = fs.resolve(new File("."), uri.getPath()); return f.isFile() || f.getName().endsWith(".bundle"); } @@ -75,7 +75,7 @@ static boolean canHandle(final URIish uri) { TransportBundleFile(final Repository local, final URIish uri) { super(local, uri); - bundle = FS.resolve(new File("."), uri.getPath()).getAbsoluteFile(); + bundle = local.getFS().resolve(new File("."), uri.getPath()).getAbsoluteFile(); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java index cf4dbd539..08fd8901d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java @@ -91,13 +91,13 @@ class TransportLocal extends Transport implements PackTransport { private static final String PWD = "."; - static boolean canHandle(final URIish uri) { + static boolean canHandle(final URIish uri, FS fs) { if (uri.getHost() != null || uri.getPort() > 0 || uri.getUser() != null || uri.getPass() != null || uri.getPath() == null) return false; if ("file".equals(uri.getScheme()) || uri.getScheme() == null) - return FS.resolve(new File(PWD), uri.getPath()).isDirectory(); + return fs.resolve(new File(PWD), uri.getPath()).isDirectory(); return false; } @@ -106,7 +106,7 @@ static boolean canHandle(final URIish uri) { TransportLocal(final Repository local, final URIish uri) { super(local, uri); - File d = FS.resolve(new File(PWD), uri.getPath()).getAbsoluteFile(); + File d = local.getFS().resolve(new File(PWD), uri.getPath()).getAbsoluteFile(); if (new File(d, Constants.DOT_GIT).isDirectory()) d = new File(d, Constants.DOT_GIT); remoteGitDir = d; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java index 19db39a8f..8dfab8aa5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java @@ -65,6 +65,7 @@ */ public class FileTreeIterator extends WorkingTreeIterator { private final File directory; + private final FS fs; /** * Create a new iterator to traverse the given directory and its children. @@ -72,9 +73,13 @@ public class FileTreeIterator extends WorkingTreeIterator { * @param root * the starting directory. This directory should correspond to * the root of the repository. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. */ - public FileTreeIterator(final File root) { + public FileTreeIterator(final File root, FS fs) { directory = root; + this.fs = fs; init(entries()); } @@ -83,20 +88,24 @@ public FileTreeIterator(final File root) { * * @param p * the parent iterator we were created from. + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @param root * the subdirectory. This should be a directory contained within * the parent directory. */ - protected FileTreeIterator(final FileTreeIterator p, final File root) { + protected FileTreeIterator(final FileTreeIterator p, final File root, FS fs) { super(p); directory = root; + this.fs = fs; init(entries()); } @Override public AbstractTreeIterator createSubtreeIterator(final Repository repo) throws IncorrectObjectTypeException, IOException { - return new FileTreeIterator(this, ((FileEntry) current()).file); + return new FileTreeIterator(this, ((FileEntry) current()).file, fs); } private Entry[] entries() { @@ -105,7 +114,7 @@ private Entry[] entries() { return EOF; final Entry[] r = new Entry[all.length]; for (int i = 0; i < r.length; i++) - r[i] = new FileEntry(all[i]); + r[i] = new FileEntry(all[i], fs); return r; } @@ -121,7 +130,7 @@ static public class FileEntry extends Entry { private long lastModified; - FileEntry(final File f) { + FileEntry(final File f, FS fs) { file = f; if (f.isDirectory()) { @@ -129,7 +138,7 @@ static public class FileEntry extends Entry { mode = FileMode.GITLINK; else mode = FileMode.TREE; - } else if (FS.INSTANCE.canExecute(file)) + } else if (fs.canExecute(file)) mode = FileMode.EXECUTABLE_FILE; else mode = FileMode.REGULAR_FILE; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java index c4f4242f9..b8d433762 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -49,19 +49,28 @@ /** Abstraction to support various file system operations not in Java. */ public abstract class FS { - /** The implementation selected for this operating system and JRE. */ - public static final FS INSTANCE; + /** The auto-detected implementation selected for this operating system and JRE. */ + public static final FS DETECTED; static { if (FS_Win32.detect()) { if (FS_Win32_Cygwin.detect()) - INSTANCE = new FS_Win32_Cygwin(); + DETECTED = new FS_Win32_Cygwin(); else - INSTANCE = new FS_Win32(); + DETECTED = new FS_Win32(); } else if (FS_POSIX_Java6.detect()) - INSTANCE = new FS_POSIX_Java6(); + DETECTED = new FS_POSIX_Java6(); else - INSTANCE = new FS_POSIX_Java5(); + DETECTED = new FS_POSIX_Java5(); + } + + private final File userHome; + + /** + * Constructs a file system abstraction. + */ + protected FS() { + this.userHome = userHomeImpl(); } /** @@ -117,29 +126,7 @@ public abstract class FS { * @return the translated path. new File(dir,name) if this * platform does not require path name translation. */ - public static File resolve(final File dir, final String name) { - return INSTANCE.resolveImpl(dir, name); - } - - /** - * Resolve this file to its actual path name that the JRE can use. - *

- * This method can be relatively expensive. Computing a translation may - * require forking an external process per path name translated. Callers - * should try to minimize the number of translations necessary by caching - * the results. - *

- * Not all platforms and JREs require path name translation. Currently only - * Cygwin on Win32 require translation for Cygwin based paths. - * - * @param dir - * directory relative to which the path name is. - * @param name - * path name to translate. - * @return the translated path. new File(dir,name) if this - * platform does not require path name translation. - */ - protected File resolveImpl(final File dir, final String name) { + public File resolve(final File dir, final String name) { final File abspn = new File(name); if (abspn.isAbsolute()) return abspn; @@ -157,12 +144,8 @@ protected File resolveImpl(final File dir, final String name) { * * @return the user's home directory; null if the user does not have one. */ - public static File userHome() { - return USER_HOME.home; - } - - private static class USER_HOME { - static final File home = INSTANCE.userHomeImpl(); + public File userHome() { + return userHome; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index f72708486..39f2c03a0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java @@ -72,7 +72,7 @@ public String run() { return false; } - protected File resolveImpl(final File dir, final String pn) { + public File resolve(final File dir, final String pn) { try { final Process p; @@ -103,7 +103,7 @@ protected File resolveImpl(final File dir, final String pn) { // Fall through and use the default return. // } - return super.resolveImpl(dir, pn); + return super.resolve(dir, pn); } @Override @@ -116,6 +116,6 @@ public String run() { }); if (home == null || home.length() == 0) return super.userHomeImpl(); - return resolveImpl(new File("."), home); + return resolve(new File("."), home); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java index 771e77058..9d7feb08f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -72,8 +72,8 @@ public String getProperty(String key) { return System.getProperty(key); } - public FileBasedConfig openUserConfig() { - final File home = FS.userHome(); + public FileBasedConfig openUserConfig(FS fs) { + final File home = fs.userHome(); return new FileBasedConfig(new File(home, ".gitconfig")); } @@ -136,9 +136,12 @@ public static void setInstance(SystemReader newReader) { public abstract String getProperty(String key); /** + * @param fs + * the file system abstraction which will be necessary to + * perform certain file system operations. * @return the git configuration found in the user home */ - public abstract FileBasedConfig openUserConfig(); + public abstract FileBasedConfig openUserConfig(FS fs); /** * @return the current system time