diff options
author | 2016-09-19 09:42:40 +0000 | |
---|---|---|
committer | 2016-09-19 13:02:15 +0000 | |
commit | 2f4d17a2fa632b05fcbeb8db5d6eb46af8ec341c (patch) | |
tree | 61966bda77c8e8e5b039adddaa9c1336251584fb /src/main/java/com | |
parent | 96d396badb3a0d8caab35aa4bb181cf88700ab79 (diff) |
Also copy directories as output for sandbox.
--
MOS_MIGRATED_REVID=133564429
Diffstat (limited to 'src/main/java/com')
3 files changed, 84 insertions, 7 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/HardlinkedExecRoot.java b/src/main/java/com/google/devtools/build/lib/sandbox/HardlinkedExecRoot.java index 0ce8c76bce..7ddb401bfd 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/HardlinkedExecRoot.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/HardlinkedExecRoot.java @@ -124,7 +124,6 @@ public class HardlinkedExecRoot implements SandboxExecRoot { } } - // TODO(yueg): import unix.FilesystemUtils and use FilesystemUtils.createHardLink() instead private void createHardLink(Path target, Path source) throws IOException { java.nio.file.Path targetNio = java.nio.file.Paths.get(target.toString()); java.nio.file.Path sourceNio = java.nio.file.Paths.get(source.toString()); @@ -153,9 +152,17 @@ public class HardlinkedExecRoot implements SandboxExecRoot { public void copyOutputs(Path execRoot, Collection<PathFragment> outputs) throws IOException { for (PathFragment output : outputs) { Path source = sandboxExecRoot.getRelative(output); + Path target = execRoot.getRelative(output); if (source.isFile() || source.isSymbolicLink()) { - Path target = execRoot.getRelative(output); Files.move(source.getPathFile(), target.getPathFile()); + } else if (source.isDirectory()) { + try { + source.renameTo(target); + } catch (IOException e) { + // Failed to move directory directly, thus move it recursively. + target.createDirectory(); + FileSystemUtils.moveTreesBelow(source, target); + } } } } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedExecRoot.java b/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedExecRoot.java index de0f31f46e..9efe7fcb45 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedExecRoot.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedExecRoot.java @@ -100,15 +100,19 @@ final class SymlinkedExecRoot implements SandboxExecRoot { /** Moves all {@code outputs} to {@code execRoot}. */ @Override public void copyOutputs(Path execRoot, Collection<PathFragment> outputs) throws IOException { - Set<Path> createdDirs = new HashSet<>(); for (PathFragment output : outputs) { Path source = sandboxExecRoot.getRelative(output); + Path target = execRoot.getRelative(output); if (source.isFile() || source.isSymbolicLink()) { - FileSystemUtils.createDirectoryAndParentsWithCache( - createdDirs, execRoot.getRelative(output.getParentDirectory())); - - Path target = execRoot.getRelative(output); Files.move(source.getPathFile(), target.getPathFile()); + } else if (source.isDirectory()) { + try { + source.renameTo(target); + } catch (IOException e) { + // Failed to move directory directly, thus move it recursively. + target.createDirectory(); + FileSystemUtils.moveTreesBelow(source, target); + } } } } 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 ee1af6cc97..c8d1f3c2c4 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 @@ -444,6 +444,41 @@ public class FileSystemUtils { } /** + * Moves the file from location "from" to location "to", while overwriting a + * potentially existing "to". File's last modified time, executable and + * writable bits are also preserved. + * + * <p>If no error occurs, the method returns normally. If a parent directory does + * not exist, a FileNotFoundException is thrown. An IOException is thrown when + * other erroneous situations occur. (e.g. read errors) + */ + @ThreadSafe // but not atomic + public static void moveFile(Path from, Path to) throws IOException { + long mtime = from.getLastModifiedTime(); + boolean writable = from.isWritable(); + boolean executable = from.isExecutable(); + + // We don't try-catch here for better performance. + to.delete(); + try { + from.renameTo(to); + } catch (IOException e) { + asByteSource(from).copyTo(asByteSink(to)); + if (!from.delete()) { + if (!to.delete()) { + throw new IOException("Unable to delete " + to); + } + throw new IOException("Unable to delete " + from); + } + } + to.setLastModifiedTime(mtime); // Preserve mtime. + if (!writable) { + to.setWritable(false); // Make file read-only if original was read-only. + } + to.setExecutable(executable); // Copy executable bit. + } + + /** * Copies a tool binary from one path to another, returning the target path. * The directory of the target path must already exist. The target copy's time * is set to match, as well as its read-only and executable flags. The @@ -569,6 +604,37 @@ public class FileSystemUtils { } /** + * Moves all dir trees under a given 'from' dir to location 'to', while overwriting + * all files in the potentially existing 'to'. Doesn't resolve symbolic links. + * + * <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. + * + * <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 moveTreesBelow(Path from , Path to) 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.isDirectory(Symlinks.NOFOLLOW)) { + Path subDir = to.getChild(entry.getBaseName()); + subDir.createDirectory(); + moveTreesBelow(entry, subDir); + } else { + Path newEntry = to.getChild(entry.getBaseName()); + moveFile(entry, newEntry); + } + } + } + + /** * Attempts to create a directory with the name of the given path, creating * ancestors as necessary. * |