aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/FileSystemUtils.java31
-rw-r--r--src/test/java/com/google/devtools/build/lib/vfs/FileSystemUtilsTest.java52
-rw-r--r--src/tools/benchmark/java/com/google/devtools/build/benchmark/BazelBuildCase.java5
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);
}