diff options
author | janakr <janakr@google.com> | 2017-10-11 22:12:39 +0200 |
---|---|---|
committer | Marcel Hlopko <hlopko@google.com> | 2017-10-12 10:16:37 +0200 |
commit | 3ce58ce65663b89a1209d9d9767752a11445edfe (patch) | |
tree | 756929e2067815cf88321424efdcd4a39b76d1a8 | |
parent | 0e1e28d610eeb416bc87492277d19bc2b215d67d (diff) |
Add follow-symlinks parameter to FileSystemUtils#copyTreesBelow, so that all the tool setup we do in tests doesn't necessarily have to be copied if we copy a workspace over.
PiperOrigin-RevId: 171864170
3 files changed, 66 insertions, 22 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java index 698b671d04..69a56fa6d9 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java @@ -574,32 +574,35 @@ public class FileSystemUtils { } /** - * Copies all dir trees under a given 'from' dir to location 'to', while overwriting - * all files in the potentially existing 'to'. Resolves symbolic links. + * Copies all dir trees under a given 'from' dir to location 'to', while overwriting all files in + * the potentially existing 'to'. Resolves symbolic links if {@code followSymlinks == + * Symlinks#FOLLOW}. Otherwise copies symlinks as-is. * * <p>The source and the destination must be non-overlapping, otherwise an - * IllegalArgumentException will be thrown. This method cannot be used to copy - * a dir tree to a sub tree of itself. + * IllegalArgumentException will be thrown. This method cannot be used to copy a dir tree to a sub + * tree of itself. * - * <p>If no error occurs, the method returns normally. If the given 'from' does - * not exist, a FileNotFoundException is thrown. An IOException is thrown when - * other erroneous situations occur. (e.g. read errors) + * <p>If no error occurs, the method returns normally. If the given 'from' does not exist, a + * FileNotFoundException is thrown. An IOException is thrown when other erroneous situations + * occur. (e.g. read errors) */ @ThreadSafe - public static void copyTreesBelow(Path from , Path to) throws IOException { + public static void copyTreesBelow(Path from, Path to, Symlinks followSymlinks) + throws IOException { if (to.startsWith(from)) { throw new IllegalArgumentException(to + " is a subdirectory of " + from); } Collection<Path> entries = from.getDirectoryEntries(); for (Path entry : entries) { - if (entry.isFile()) { - Path newEntry = to.getChild(entry.getBaseName()); - copyFile(entry, newEntry); + Path toPath = to.getChild(entry.getBaseName()); + if (!followSymlinks.toBoolean() && entry.isSymbolicLink()) { + FileSystemUtils.ensureSymbolicLink(toPath, entry.readSymbolicLink()); + } else if (entry.isFile()) { + copyFile(entry, toPath); } else { - Path subDir = to.getChild(entry.getBaseName()); - subDir.createDirectory(); - copyTreesBelow(entry, subDir); + toPath.createDirectory(); + copyTreesBelow(entry, toPath, followSymlinks); } } } diff --git a/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java index f6898ad070..e3da74c178 100644 --- a/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java +++ b/src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java @@ -112,7 +112,7 @@ public class FileSystemUtilsTest { FileSystemUtils.createEmptyFile(file5); } - private void checkTestDirectoryTreesBelow(Path toPath) throws IOException { + private Path checkTestDirectoryTreesBelowExceptSymlinks(Path toPath) throws IOException { Path copiedFile1 = toPath.getChild("file-1"); assertThat(copiedFile1.exists()).isTrue(); assertThat(copiedFile1.isFile()).isTrue(); @@ -134,7 +134,11 @@ public class FileSystemUtilsTest { Path copiedInnerDir = copiedADir.getChild("inner-dir"); assertThat(copiedInnerDir.exists()).isTrue(); assertThat(copiedInnerDir.isDirectory()).isTrue(); + return copiedInnerDir; + } + private void checkTestDirectoryTreesBelow(Path toPath) throws IOException { + Path copiedInnerDir = checkTestDirectoryTreesBelowExceptSymlinks(toPath); Path copiedLink1 = copiedInnerDir.getChild("link-1"); assertThat(copiedLink1.exists()).isTrue(); assertThat(copiedLink1.isSymbolicLink()).isFalse(); @@ -454,7 +458,7 @@ public class FileSystemUtilsTest { Path toPath = fileSystem.getPath("/copy-here"); toPath.createDirectory(); - FileSystemUtils.copyTreesBelow(topDir, toPath); + FileSystemUtils.copyTreesBelow(topDir, toPath, Symlinks.FOLLOW); checkTestDirectoryTreesBelow(toPath); } @@ -465,7 +469,7 @@ public class FileSystemUtilsTest { toPath.createDirectory(); toPath.getChild("file-2"); - FileSystemUtils.copyTreesBelow(topDir, toPath); + FileSystemUtils.copyTreesBelow(topDir, toPath, Symlinks.FOLLOW); checkTestDirectoryTreesBelow(toPath); } @@ -473,7 +477,7 @@ public class FileSystemUtilsTest { public void testCopyTreesBelowToSubtree() throws IOException { createTestDirectoryTree(); try { - FileSystemUtils.copyTreesBelow(topDir, aDir); + FileSystemUtils.copyTreesBelow(topDir, aDir, Symlinks.FOLLOW); fail("Should not be able to copy a directory to a subdir"); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessage("/top-dir/a-dir is a subdirectory of /top-dir"); @@ -484,7 +488,7 @@ public class FileSystemUtilsTest { public void testCopyFileAsDirectoryTree() throws IOException { createTestDirectoryTree(); try { - FileSystemUtils.copyTreesBelow(file1, aDir); + FileSystemUtils.copyTreesBelow(file1, aDir, Symlinks.FOLLOW); fail("Should not be able to copy a file with copyDirectory method"); } catch (IOException expected) { assertThat(expected).hasMessage("/top-dir/file-1 (Not a directory)"); @@ -498,7 +502,7 @@ public class FileSystemUtilsTest { Path copySubDir = fileSystem.getPath("/my-dir/subdir"); FileSystemUtils.createDirectoryAndParents(copySubDir); try { - FileSystemUtils.copyTreesBelow(copyDir, file4); + FileSystemUtils.copyTreesBelow(copyDir, file4, Symlinks.FOLLOW); fail("Should not be able to copy a directory to a file"); } catch (IOException expected) { assertThat(expected).hasMessage("/file-4 (Not a directory)"); @@ -511,7 +515,7 @@ public class FileSystemUtilsTest { try { Path unexistingDir = fileSystem.getPath("/unexisting-dir"); - FileSystemUtils.copyTreesBelow(unexistingDir, aDir); + FileSystemUtils.copyTreesBelow(unexistingDir, aDir, Symlinks.FOLLOW); fail("Should not be able to copy from an unexisting path"); } catch (FileNotFoundException expected) { assertThat(expected).hasMessage("/unexisting-dir (No such file or directory)"); @@ -519,6 +523,40 @@ public class FileSystemUtilsTest { } @Test + public void testCopyTreesBelowNoFollowSymlinks() throws IOException { + createTestDirectoryTree(); + PathFragment relative1 = file1.relativeTo(topDir); + topDir.getRelative("relative-link").createSymbolicLink(relative1); + PathFragment relativeInner = PathFragment.create("..").getRelative(relative1); + bDir.getRelative("relative-inner-link").createSymbolicLink(relativeInner); + PathFragment rootDirectory = PathFragment.create("/"); + topDir.getRelative("absolute-link").createSymbolicLink(rootDirectory); + Path toPath = fileSystem.getPath("/copy-here"); + toPath.createDirectory(); + + FileSystemUtils.copyTreesBelow(topDir, toPath, Symlinks.NOFOLLOW); + Path copiedInnerDir = checkTestDirectoryTreesBelowExceptSymlinks(toPath); + Path copiedLink1 = copiedInnerDir.getChild("link-1"); + assertThat(copiedLink1.exists()).isTrue(); + assertThat(copiedLink1.isSymbolicLink()).isTrue(); + assertThat(copiedLink1.readSymbolicLink()).isEqualTo(file4.asFragment()); + + Path copiedDirLink = copiedInnerDir.getChild("dir-link"); + assertThat(copiedDirLink.exists()).isTrue(); + assertThat(copiedDirLink.isDirectory()).isTrue(); + assertThat(copiedDirLink.readSymbolicLink()).isEqualTo(bDir.asFragment()); + + assertThat(toPath.getRelative("relative-link").readSymbolicLink()).isEqualTo(relative1); + assertThat( + toPath + .getRelative(bDir.relativeTo(topDir)) + .getRelative("relative-inner-link") + .readSymbolicLink()) + .isEqualTo(relativeInner); + assertThat(toPath.getRelative("absolute-link").readSymbolicLink()).isEqualTo(rootDirectory); + } + + @Test public void testTraverseTree() throws IOException { createTestDirectoryTree(); diff --git a/src/tools/benchmark/java/com/google/devtools/build/benchmark/BazelBuildCase.java b/src/tools/benchmark/java/com/google/devtools/build/benchmark/BazelBuildCase.java index f3a75f01e0..8b59c079af 100644 --- a/src/tools/benchmark/java/com/google/devtools/build/benchmark/BazelBuildCase.java +++ b/src/tools/benchmark/java/com/google/devtools/build/benchmark/BazelBuildCase.java @@ -24,6 +24,7 @@ import com.google.devtools.build.lib.shell.CommandException; import com.google.devtools.build.lib.vfs.FileSystem; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.JavaIoFileSystem; +import com.google.devtools.build.lib.vfs.Symlinks; import java.io.IOException; import java.nio.file.Path; @@ -112,7 +113,9 @@ final class BazelBuildCase implements BuildCase { // Copy try { FileSystemUtils.copyTreesBelow( - fileSystem.getPath(copyDir.toString()), fileSystem.getPath(generatedCodePath.toString())); + fileSystem.getPath(copyDir.toString()), + fileSystem.getPath(generatedCodePath.toString()), + Symlinks.FOLLOW); } catch (IOException e) { throw new IOException("Failed to copy generated code", e); } |