diff options
Diffstat (limited to 'org.eclipse.jgit/src')
8 files changed, 347 insertions, 32 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index bd211e7e91..29bec97ee7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -242,6 +242,7 @@ public class JGitText extends TranslationBundle { /***/ public String errorListing; /***/ public String errorOccurredDuringUnpackingOnTheRemoteEnd; /***/ public String errorReadingInfoRefs; + /***/ public String errorSymlinksNotSupported; /***/ public String exceptionCaughtDuringExecutionOfAddCommand; /***/ public String exceptionCaughtDuringExecutionOfCherryPickCommand; /***/ public String exceptionCaughtDuringExecutionOfCommitCommand; 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 ae6197838c..1b68801ae0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -53,11 +53,51 @@ import java.security.PrivilegedAction; import java.util.Arrays; import java.util.concurrent.atomic.AtomicBoolean; +import org.eclipse.jgit.errors.SymlinksNotSupportedException; +import org.eclipse.jgit.internal.JGitText; + /** Abstraction to support various file system operations not in Java. */ public abstract class FS { + /** + * This class creates FS instances. It will be overridden by a Java7 variant + * if such can be detected in {@link #detect(Boolean)}. + * + * @since 3.0 + */ + public static class FSFactory { + /** + * Constructor + */ + protected FSFactory() { + // empty + } + + /** + * Detect the file system + * + * @param cygwinUsed + * @return FS instance + */ + public FS detect(Boolean cygwinUsed) { + if (SystemReader.getInstance().isWindows()) { + if (cygwinUsed == null) + cygwinUsed = Boolean.valueOf(FS_Win32_Cygwin.isCygwin()); + if (cygwinUsed.booleanValue()) + return new FS_Win32_Cygwin(); + else + return new FS_Win32(); + } else if (FS_POSIX_Java6.hasExecute()) + return new FS_POSIX_Java6(); + else + return new FS_POSIX_Java5(); + } + } + /** The auto-detected implementation selected for this operating system and JRE. */ public static final FS DETECTED = detect(); + private static FSFactory factory; + /** * Auto-detect the appropriate file system abstraction. * @@ -89,17 +129,25 @@ public abstract class FS { * @return detected file system abstraction */ public static FS detect(Boolean cygwinUsed) { - if (SystemReader.getInstance().isWindows()) { - if (cygwinUsed == null) - cygwinUsed = Boolean.valueOf(FS_Win32_Cygwin.isCygwin()); - if (cygwinUsed.booleanValue()) - return new FS_Win32_Cygwin(); - else - return new FS_Win32(); - } else if (FS_POSIX_Java6.hasExecute()) - return new FS_POSIX_Java6(); - else - return new FS_POSIX_Java5(); + if (factory == null) { + try { + Class<?> activatorClass = Class + .forName("org.eclipse.jgit.util.Java7FSFactory"); //$NON-NLS-1$ + // found Java7 + factory = (FSFactory) activatorClass.newInstance(); + } catch (ClassNotFoundException e) { + // Java7 module not found + factory = new FS.FSFactory(); + // Silently ignore failure to find Java7 FS factory + } catch (UnsupportedClassVersionError e) { + // Java7 module not accessible + factory = new FS.FSFactory(); + } catch (Exception e) { + factory = new FS.FSFactory(); + throw new Error(e); + } + } + return factory.detect(cygwinUsed); } private volatile Holder<File> userHome; @@ -136,6 +184,17 @@ public abstract class FS { public abstract boolean supportsExecute(); /** + * Does this operating system and JRE supports symbolic links. The + * capability to handle symbolic links is detected at runtime. + * + * @return true if symbolic links may be used + * @since 3.0 + */ + public boolean supportsSymlinks() { + return false; + } + + /** * Is this file system case sensitive * * @return true if this implementation is case sensitive @@ -147,6 +206,10 @@ public abstract class FS { * <p> * Not all platforms and JREs support executable flags on files. If the * feature is unsupported this method will always return false. + * <p> + * <em>If the platform supports symbolic links and <code>f</code> is a symbolic link + * this method returns false, rather than the state of the executable flags + * on the target file.</em> * * @param f * abstract path to test. @@ -170,6 +233,46 @@ public abstract class FS { public abstract boolean setExecute(File f, boolean canExec); /** + * Get the last modified time of a file system object. If the OS/JRE support + * symbolic links, the modification time of the link is returned, rather + * than that of the link target. + * + * @param f + * @return last modified time of f + * @throws IOException + * @since 3.0 + */ + public long lastModified(File f) throws IOException { + return f.lastModified(); + } + + /** + * Set the last modified time of a file system object. If the OS/JRE support + * symbolic links, the link is modified, not the target, + * + * @param f + * @param time + * @throws IOException + * @since 3.0 + */ + public void setLastModified(File f, long time) throws IOException { + f.setLastModified(time); + } + + /** + * Get the length of a file or link, If the OS/JRE supports symbolic links + * it's the length of the link, else the length of the target. + * + * @param path + * @return length of a file + * @throws IOException + * @since 3.0 + */ + public long length(File path) throws IOException { + return path.length(); + } + + /** * Resolve this file to its actual path name that the JRE can use. * <p> * This method can be relatively expensive. Computing a translation may @@ -260,8 +363,9 @@ public abstract class FS { * @param lookFor * Files to search for in the given path * @return the first match found, or null + * @since 3.0 **/ - static File searchPath(final String path, final String... lookFor) { + protected static File searchPath(final String path, final String... lookFor) { if (path == null) return null; @@ -398,6 +502,103 @@ public abstract class FS { } /** + * Check if a file is a symbolic link and read it + * + * @param path + * @return target of link or null + * @throws IOException + * @since 3.0 + */ + public String readSymLink(File path) throws IOException { + throw new SymlinksNotSupportedException( + JGitText.get().errorSymlinksNotSupported); + } + + /** + * @param path + * @return true if the path is a symbolic link (and we support these) + * @throws IOException + * @since 3.0 + */ + public boolean isSymLink(File path) throws IOException { + return false; + } + + /** + * Tests if the path exists, in case of a symbolic link, true even if the + * target does not exist + * + * @param path + * @return true if path exists + * @since 3.0 + */ + public boolean exists(File path) { + return path.exists(); + } + + /** + * Check if path is a directory. If the OS/JRE supports symbolic links and + * path is a symbolic link to a directory, this method returns false. + * + * @param path + * @return true if file is a directory, + * @since 3.0 + */ + public boolean isDirectory(File path) { + return path.isDirectory(); + } + + /** + * Examine if path represents a regular file. If the OS/JRE supports + * symbolic links the test returns false if path represents a symbolic link. + * + * @param path + * @return true if path represents a regular file + * @since 3.0 + */ + public boolean isFile(File path) { + return path.isFile(); + } + + /** + * @param path + * @return true if path is hidden, either starts with . on unix or has the + * hidden attribute in windows + * @throws IOException + * @since 3.0 + */ + public boolean isHidden(File path) throws IOException { + return path.isHidden(); + } + + /** + * Set the hidden attribute for file whose name starts with a period. + * + * @param path + * @param hidden + * @throws IOException + * @since 3.0 + */ + public void setHidden(File path, boolean hidden) throws IOException { + if (!path.getName().startsWith(".")) //$NON-NLS-1$ + throw new IllegalArgumentException( + "Hiding only allowed for names that start with a period"); + } + + /** + * Create a symbolic link + * + * @param path + * @param target + * @throws IOException + * @since 3.0 + */ + public void createSymLink(File path, String target) throws IOException { + throw new SymlinksNotSupportedException( + JGitText.get().errorSymlinksNotSupported); + } + + /** * Initialize a ProcesssBuilder to run a command using the system shell. * * @param cmd diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java index b6b5595902..b7de056ee4 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java @@ -43,12 +43,19 @@ package org.eclipse.jgit.util; import java.io.File; +import java.io.IOException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -abstract class FS_POSIX extends FS { + +/** + * Base FS for POSIX based systems + * + * @since 3.0 + */ +public abstract class FS_POSIX extends FS { @Override protected File discoverGitPrefix() { String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$ @@ -75,11 +82,20 @@ abstract class FS_POSIX extends FS { return null; } - FS_POSIX() { + /** + * Default constructor + */ + protected FS_POSIX() { super(); } - FS_POSIX(FS src) { + /** + * Constructor + * + * @param src + * FS to copy some settings from + */ + protected FS_POSIX(FS src) { super(src); } @@ -89,6 +105,11 @@ abstract class FS_POSIX extends FS { } @Override + public void setHidden(File path, boolean hidden) throws IOException { + // Do nothing + } + + @Override public ProcessBuilder runInShell(String cmd, String[] args) { List<String> argv = new ArrayList<String>(4 + args.length); argv.add("sh"); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java5.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java5.java index c79bbe69bd..46ea2aa3fe 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java5.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java5.java @@ -45,12 +45,27 @@ package org.eclipse.jgit.util; import java.io.File; -class FS_POSIX_Java5 extends FS_POSIX { - FS_POSIX_Java5() { + +/** + * FS implementaton for Java5 + * + * @since 3.0 + */ +public class FS_POSIX_Java5 extends FS_POSIX { + /** + * Constructor + */ + public FS_POSIX_Java5() { super(); } - FS_POSIX_Java5(FS src) { + /** + * Constructor + * + * @param src + * instance whose attributes to copy + */ + public FS_POSIX_Java5(FS src) { super(src); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java6.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java6.java index 05025479b5..47a7a68e4d 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java6.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX_Java6.java @@ -49,7 +49,13 @@ import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -class FS_POSIX_Java6 extends FS_POSIX { + +/** + * FS implementation for POSIX systems using Java6 + * + * @since 3.0 + */ +public class FS_POSIX_Java6 extends FS_POSIX { private static final Method canExecute; private static final Method setExecute; @@ -59,7 +65,11 @@ class FS_POSIX_Java6 extends FS_POSIX { setExecute = needMethod(File.class, "setExecutable", Boolean.TYPE); //$NON-NLS-1$ } - static boolean hasExecute() { + /** + * @return true if Java has the ability to set and get the executable flag + * on files + */ + public static boolean hasExecute() { return canExecute != null && setExecute != null; } @@ -74,11 +84,20 @@ class FS_POSIX_Java6 extends FS_POSIX { } } - FS_POSIX_Java6() { + /** + * Constructor + */ + public FS_POSIX_Java6() { super(); } - FS_POSIX_Java6(FS src) { + /** + * Constructor + * + * @param src + * instance whose attributes to copy + */ + public FS_POSIX_Java6(FS src) { super(src); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java index 73f9161ca3..5822dcfae1 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java @@ -50,12 +50,27 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -class FS_Win32 extends FS { - FS_Win32() { + +/** + * FS implementation for Windows + * + * @since 3.0 + */ +public class FS_Win32 extends FS { + /** + * Constructor + */ + public FS_Win32() { super(); } - FS_Win32(FS src) { + /** + * Constructor + * + * @param src + * instance whose attributes to copy + */ + protected FS_Win32(FS src) { super(src); } 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 af2d5a9a72..81f2001125 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 @@ -50,10 +50,19 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -class FS_Win32_Cygwin extends FS_Win32 { + +/** + * FS implementation for Cygwin on Windows + * + * @since 3.0 + */ +public class FS_Win32_Cygwin extends FS_Win32 { private static String cygpath; - static boolean isCygwin() { + /** + * @return true if cygwin is found + */ + public static boolean isCygwin() { final String path = AccessController .doPrivileged(new PrivilegedAction<String>() { public String run() { @@ -68,11 +77,20 @@ class FS_Win32_Cygwin extends FS_Win32 { return cygpath != null; } - FS_Win32_Cygwin() { + /** + * Constructor + */ + public FS_Win32_Cygwin() { super(); } - FS_Win32_Cygwin(FS src) { + /** + * Constructor + * + * @param src + * instance whose attributes to copy + */ + protected FS_Win32_Cygwin(FS src) { super(src); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java index c4fdd6fff9..834cc85f49 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java @@ -126,10 +126,11 @@ public class FileUtils { * exception is not thrown when IGNORE_ERRORS is set. */ public static void delete(final File f, int options) throws IOException { - if ((options & SKIP_MISSING) != 0 && !f.exists()) + FS fs = FS.DETECTED; + if ((options & SKIP_MISSING) != 0 && !fs.exists(f)) return; - if ((options & RECURSIVE) != 0 && f.isDirectory()) { + if ((options & RECURSIVE) != 0 && fs.isDirectory(f)) { final File[] items = f.listFiles(); if (items != null) { List<File> files = new ArrayList<File>(); @@ -164,7 +165,7 @@ public class FileUtils { } if (delete && !f.delete()) { - if ((options & RETRY) != 0 && f.exists()) { + if ((options & RETRY) != 0 && fs.exists(f)) { for (int i = 1; i < 10; i++) { try { Thread.sleep(100); @@ -337,4 +338,28 @@ public class FileUtils { throw new IOException(MessageFormat.format( JGitText.get().createNewFileFailed, f)); } + + /** + * Create a symbolic link + * + * @param path + * @param target + * @throws IOException + * @since 3.0 + */ + public static void createSymLink(File path, String target) + throws IOException { + FS.DETECTED.createSymLink(path, target); + } + + /** + * @param path + * @return the target of the symbolic link, or null if it is not a symbolic + * link + * @throws IOException + * @since 3.0 + */ + public static String readSymLink(File path) throws IOException { + return FS.DETECTED.readSymLink(path); + } } |