]> source.dussan.org Git - jgit.git/commitdiff
Repository can be configured with FS 88/588/3
authorMarc Strapetz <marc.strapetz@syntevo.com>
Tue, 20 Apr 2010 19:01:19 +0000 (21:01 +0200)
committerShawn O. Pearce <spearce@spearce.org>
Sat, 5 Jun 2010 02:08:58 +0000 (19:08 -0700)
On Windows, FS_Win32_Cygwin has been used if a Cygwin Git installation
is present in the PATH. Assuming that the user works with the Cygwin
Git installation may result in unnecessary overhead if he actually
does not.

Applications built on top of jgit may have more knowledge on the
actually used Git client (Cygwin or not) and hence should be able to
configure which FS to use accordingly.

Change-Id: Ifc4278078b298781d55cf5421e9647a21fa5db24

25 files changed:
org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/resolver/FileResolver.java
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0007_GitIndexTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/GitIndex.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDirectory.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/Daemon.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/OpenSshConfig.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/SshConfigSessionFactory.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/SshTransport.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportAmazonS3.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportBundleFile.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java
org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java

index 82a0ce84a04faffc6027c90266d3e05fc62cd35b..cc062dbe88e6f1cdaa8e444bc53a9fbcbccca740 100644 (file)
@@ -52,6 +52,7 @@ import org.eclipse.jgit.errors.RepositoryNotFoundException;
 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 class FileResolver implements RepositoryResolver {
                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);
                }
index b4f0b7e90913a6a4ac02f5420cdc2637fb86e2c7..c502fb6344d7d6a47e652eb1c415850b7af9df85 100644 (file)
@@ -53,6 +53,7 @@ import java.util.TimeZone;
 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 class MockSystemReader extends SystemReader {
        }
 
        @Override
-       public FileBasedConfig openUserConfig() {
+       public FileBasedConfig openUserConfig(FS fs) {
                return userGitConfig;
        }
 
index 0bc9ee11220857b8add168c49c5cc0f6f534c15d..2043ac20909fb7536fa654f4d35698029aa2cf75 100644 (file)
@@ -64,6 +64,7 @@ import org.eclipse.jgit.pgm.CLIText;
 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 class AbstractTreeIteratorHandler extends
                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;
                }
 
index 21dcdffbfd2a2412376af471d9c5def7c2152fb9..dd3b51efc7771c08a7e231896e9bdbbfeb784942 100644 (file)
@@ -337,7 +337,7 @@ public class T0007_GitIndexTest extends LocalDiskRepositoryTestCase {
        }
 
        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 class T0007_GitIndexTest extends LocalDiskRepositoryTestCase {
        }
 
        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;
                }
index f05889308d7e6d81599fad91c6e10b80289926ef..cab3cba374db527f8064ed175585fb484c2eb188 100644 (file)
@@ -54,13 +54,13 @@ public class RepositoryCacheTest extends RepositoryTestCase {
                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 class RepositoryCacheTest extends RepositoryTestCase {
                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 class RepositoryCacheTest extends RepositoryTestCase {
                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 class RepositoryCacheTest extends RepositoryTestCase {
        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();
        }
index 41c4971a04e08181ed9fee6106f7d8cc94a69e1f..6f8076f09204215d3129126b3dc4a86b0eeb7693 100644 (file)
@@ -54,6 +54,7 @@ import junit.framework.TestCase;
 
 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 class RepositoryConfigTest extends TestCase {
                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();
 
index 081290310a6a8c41ef905a4e6fde8d69db7ed135..eb08e495b968f842405990be9f9d9fd78889c017 100644 (file)
@@ -77,7 +77,7 @@ public class FileTreeIteratorTest extends RepositoryTestCase {
        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 class FileTreeIteratorTest extends RepositoryTestCase {
        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 class FileTreeIteratorTest extends RepositoryTestCase {
                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 class FileTreeIteratorTest extends RepositoryTestCase {
        }
 
        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));
index 0203d5d44a779d46ba9c193726dd5a974d57dcbb..d5cab0e4c6a6ffbb45a14f7c495d04bba84bebe5 100644 (file)
@@ -71,7 +71,6 @@ import org.eclipse.jgit.JGitText;
 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 @@ public class GitIndex {
                }
        }
 
-       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) {
index 06700ebe1dcf7c4307efc1bd0c93d00e41470601..9a5bcdb68c2181d70825aa15db77df1066eb90d4 100644 (file)
@@ -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 <code>objects</code> 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<PackList>(NO_PACKS);
+               this.fs = fs;
        }
 
        /**
@@ -485,17 +491,17 @@ public class ObjectDirectory extends ObjectDatabase {
 
        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 {
index 5ba186955f0b1ecb4f4d8425e09de9e2d92b421b..302b63b48630ee5991994058c55f4ed2361f16ff 100644 (file)
@@ -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.<LooseRef> emptyList());
                packedRefs.set(PackedRefList.NO_PACKED_REFS);
index 233cecf310eaa4bdbe5ddebd46ed755b41dd62a8..98362af987bb136231c282a52970b74fa0adb58b 100644 (file)
@@ -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 class Repository {
         */
        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 class Repository {
                                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 class Repository {
                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 class Repository {
 
                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 class Repository {
                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
index b086968c6ce2497d0ffb9d1361d68674f8ad1f24..0b0260a4ccea4118833c2a7401fd62333addd5f5 100644 (file)
@@ -120,7 +120,7 @@ public class RepositoryCache {
         *            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 class RepositoryCache {
         *            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 class RepositoryCache {
                 *
                 * @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 class RepositoryCache {
                 *
                 * @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 class RepositoryCache {
                }
 
                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 class RepositoryCache {
                 *
                 * @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 @@ public class RepositoryCache {
                 *
                 * @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;
                }
index 39c7ae8f01e821eef158486434c34428c841fd5b..aa2e2521c2cb152373ee354775ffe1100f78c0ea 100644 (file)
@@ -63,6 +63,7 @@ import org.eclipse.jgit.lib.PersonIdent;
 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 <code>git://</code> transport protocol. */
 public class Daemon {
@@ -368,7 +369,7 @@ public class Daemon {
                }
 
                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 @@ public class Daemon {
 
        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.
index e7a307f80981e2de46a3b23c8fb16c96b2ad759b..20f3174b2ef6ffeae9129f4e0417334b694f9ba0 100644 (file)
@@ -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();
 
index c30d32d9f928d7c376a5e444c2ae7da69f5f20a6..daa6f4ca2f9fb67442295fd31d027b7129ee7876 100644 (file)
@@ -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 abstract class SshConfigSessionFactory extends SshSessionFactory {
         *            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 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory {
         *
         * @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 @@ public abstract class SshConfigSessionFactory extends SshSessionFactory {
                }
        }
 
-       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");
index 810b04ce40f1ff68f9e9dc39f7c74a27d6deee31..d10010fcf6894c45de1b597b3c1f1f0ee85ce99b 100644 (file)
@@ -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 abstract class SshSessionFactory {
         * @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())
index d25a7b6180261809358d457de29868d3dd117647..f642ac1ea841c96fb45304e2c618f2032584513a 100644 (file)
@@ -128,7 +128,7 @@ public abstract class SshTransport extends TcpTransport {
                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) {
index 2fe3cb93265bf890e862b420d17cbb0dd2f14ce5..e1988a6c85fb056259226d63f933c688a6b32e7e 100644 (file)
@@ -66,6 +66,7 @@ import org.eclipse.jgit.lib.ProgressMonitor;
 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 @@ public abstract class Transport {
         *
         * @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 @@ public abstract class Transport {
                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 @@ public abstract class Transport {
                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));
index bcf6e873fea3dc3cd069bf97d02b48b3410a8812..56a5c9796d7c9c04d8a6c01ff13d347f463edc1d 100644 (file)
@@ -69,7 +69,6 @@ import org.eclipse.jgit.lib.Ref;
 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 @@ public class TransportAmazonS3 extends HttpTransport implements WalkTransport {
                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);
index 0245818fe3da18b6e9e3e58b6eb83b84f51840a3..c47833f21cf08715f3011b81c575e8a1ec79f912 100644 (file)
@@ -58,13 +58,13 @@ import org.eclipse.jgit.lib.Repository;
 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 @@ class TransportBundleFile extends Transport implements TransportBundle {
 
        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
index cf4dbd5392de2903cea391c30cb893607d799d87..08fd8901d8d93d6ddac31b47f705b53cb78edf21 100644 (file)
@@ -91,13 +91,13 @@ import org.eclipse.jgit.util.io.StreamCopyThread;
 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 @@ class TransportLocal extends Transport implements PackTransport {
        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;
index 19db39a8fff1879ba3e14a78ef92be9a6bc1b9cb..8dfab8aa5775be84aaf72087593248355993c0ec 100644 (file)
@@ -65,6 +65,7 @@ import org.eclipse.jgit.util.FS;
  */
 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 class FileTreeIterator extends WorkingTreeIterator {
         *
         * @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 @@ public class FileTreeIterator extends WorkingTreeIterator {
                        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 @@ public class FileTreeIterator extends WorkingTreeIterator {
 
                private long lastModified;
 
-               FileEntry(final File f) {
+               FileEntry(final File f, FS fs) {
                        file = f;
 
                        if (f.isDirectory()) {
@@ -129,7 +138,7 @@ public class FileTreeIterator extends WorkingTreeIterator {
                                        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;
index c4f4242f90012821b94a43ae69af883548474c4c..b8d433762eb15bbb14701d83b74881ab782f4dfd 100644 (file)
@@ -49,19 +49,28 @@ import java.security.PrivilegedAction;
 
 /** 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. <code>new File(dir,name)</code> 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.
-        * <p>
-        * 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.
-        * <p>
-        * 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. <code>new File(dir,name)</code> 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 @@ public abstract class FS {
         *
         * @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;
        }
 
        /**
index f727084860497b0b3db3c57c01234d68267546be..39f2c03a0670e14cf4e45ed4a3c3a3a7cabf9fe9 100644 (file)
@@ -72,7 +72,7 @@ class FS_Win32_Cygwin extends FS_Win32 {
                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 @@ class FS_Win32_Cygwin extends FS_Win32 {
                        // Fall through and use the default return.
                        //
                }
-               return super.resolveImpl(dir, pn);
+               return super.resolve(dir, pn);
        }
 
        @Override
@@ -116,6 +116,6 @@ class FS_Win32_Cygwin extends FS_Win32 {
                                });
                if (home == null || home.length() == 0)
                        return super.userHomeImpl();
-               return resolveImpl(new File("."), home);
+               return resolve(new File("."), home);
        }
 }
index 771e77058aa10448c451f53ddab44e50486d8516..9d7feb08f2b1eaac544932bb7cd0f9133f66ac36 100644 (file)
@@ -72,8 +72,8 @@ public abstract class SystemReader {
                        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 abstract class SystemReader {
        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