diff --git a/src/main/java/org/codehaus/plexus/util/FileUtils.java b/src/main/java/org/codehaus/plexus/util/FileUtils.java index 7cd1ddcf..df03be02 100644 --- a/src/main/java/org/codehaus/plexus/util/FileUtils.java +++ b/src/main/java/org/codehaus/plexus/util/FileUtils.java @@ -1058,6 +1058,38 @@ private static void doCopyFileUsingNewIO( File source, File destination ) NioFiles.copy( source, destination ); } + /** + * Link file from destination to source. The directories up to destination will be created if they + * don't already exist. destination will be overwritten if it already exists. + * + * @param source An existing non-directory File to link to. + * @param destination A non-directory File becoming the link (possibly overwriting). + * @throws IOException if source does not exist, destination cannot be created, or an + * IO error occurs during linking. + * @throws java.io.FileNotFoundException if destination is a directory (use + * {@link #copyFileToDirectory}). + */ + public static void linkFile( final File source, final File destination ) + throws IOException + { + // check source exists + if ( !source.exists() ) + { + final String message = "File " + source + " does not exist"; + throw new IOException( message ); + } + + // check source != destination, see PLXUTILS-10 + if ( source.getCanonicalPath().equals( destination.getCanonicalPath() ) ) + { + // if they are equal, we can exit the method without doing any work + return; + } + mkdirsFor( destination ); + + NioFiles.createSymbolicLink( destination, source ); + } + /** * Copy file from source to destination only if source timestamp is later than the destination timestamp. The * directories up to destination will be created if they don't already exist. destination diff --git a/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java b/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java index f29dd418..4f7724f6 100644 --- a/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java +++ b/src/test/java/org/codehaus/plexus/util/FileUtilsTest.java @@ -34,6 +34,7 @@ import java.io.Reader; import java.io.Writer; import java.net.URL; +import java.nio.file.Files; import java.util.Properties; import org.junit.Before; @@ -428,6 +429,50 @@ public void testCopyFile3() assertTrue( "Check Full copy", destination.length() == testFile2Size ); } + // linkFile + @Test + public void testLinkFile1() + throws Exception + { + final File destination = new File( getTestDirectory(), "link1.txt" ); + FileUtils.linkFile( testFile1, destination ); + assertTrue( "Check Exist", destination.exists() ); + assertTrue( "Check File length", destination.length() == testFile1Size ); + assertTrue( "Check is link", Files.isSymbolicLink(destination.toPath())); + } + + @Test + public void testLinkFile2() + throws Exception + { + final File destination = new File( getTestDirectory(), "link2.txt" ); + FileUtils.linkFile( testFile1, destination ); + assertTrue( "Check Exist", destination.exists() ); + assertTrue( "Check File length", destination.length() == testFile2Size ); + assertTrue( "Check is link", Files.isSymbolicLink(destination.toPath())); + } + + /** + * ensure we create directory tree for destination + * + * @throws Exception + */ + @Test + public void testLinkFile3() + throws Exception + { + File destDirectory = new File( getTestDirectory(), "foo/bar/testlink" ); + if ( destDirectory.exists() ) + { + destDirectory.delete(); + } + final File destination = new File( destDirectory, "link2.txt" ); + FileUtils.linkFile( testFile1, destination ); + assertTrue( "Check Exist", destination.exists() ); + assertTrue( "Check File length", destination.length() == testFile2Size ); + assertTrue( "Check is link", Files.isSymbolicLink(destination.toPath())); + } + // copyFileIfModified @Test