diff options
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java | 41 | ||||
-rw-r--r-- | src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java | 21 |
2 files changed, 54 insertions, 8 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java index bb4904283c..604f1c3dae 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java @@ -24,6 +24,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Streams; import com.google.common.hash.Hashing; import com.google.common.io.BaseEncoding; +import com.google.common.io.ByteStreams; import com.google.devtools.build.lib.actions.ActionInput; import com.google.devtools.build.lib.actions.ActionInputMap; import com.google.devtools.build.lib.actions.Artifact; @@ -421,6 +422,16 @@ final class ActionFileSystem extends AbstractFileSystemWithCustomStat @Override protected InputStream getInputStream(Path path) throws IOException { FileArtifactValue metadata = getMetadataChecked(asExecPath(path)); + InputStream inputStream = getInputStreamFromMetadata(metadata, path); + if (inputStream != null) { + return inputStream; + } + return getSourcePath(path.asFragment()).getInputStream(); + } + + @Nullable + private InputStream getInputStreamFromMetadata(FileArtifactValue metadata, Path path) + throws IOException { if (metadata instanceof InlineFileArtifactValue) { return ((InlineFileArtifactValue) metadata).getInputStream(); } @@ -430,13 +441,12 @@ final class ActionFileSystem extends AbstractFileSystemWithCustomStat if (metadata instanceof RemoteFileArtifactValue) { throw new IOException("ActionFileSystem cannot read remote file: " + path); } - return getSourcePath(path.asFragment()).getInputStream(); + return null; } @Override protected OutputStream getOutputStream(Path path, boolean append) { - Preconditions.checkArgument(!append, "ActionFileSystem doesn't support append."); - return outputs.getUnchecked(asExecPath(path)).getOutputStream(); + return outputs.getUnchecked(asExecPath(path)).getOutputStream(append, path); } @Override @@ -634,23 +644,38 @@ final class ActionFileSystem extends AbstractFileSystemWithCustomStat } /** Callers are expected to close the returned stream. */ - public ByteArrayOutputStream getOutputStream() { - Preconditions.checkState(metadata == null, "getOutputStream called twice for: %s", artifact); - return new ByteArrayOutputStream() { + public ByteArrayOutputStream getOutputStream(boolean append, Path path) { + ByteArrayOutputStream baos = new ByteArrayOutputStream() { @Override public void close() throws IOException { - flush(); + flushInternal(true); super.close(); } @Override public void flush() throws IOException { + flushInternal(false); + } + + private void flushInternal(boolean notify) throws IOException { super.flush(); byte[] data = toByteArray(); set(new InlineFileArtifactValue(data, Hashing.md5().hashBytes(data).asBytes()), - /*notifyConsumer=*/ true); + /*notifyConsumer=*/ notify); } }; + + if (append && metadata != null) { + try (InputStream in = getInputStreamFromMetadata(metadata, path)) { + if (in == null) { + throw new IOException("Unable to read file " + path + " with metadata " + metadata); + } + ByteStreams.copy(in, baos); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + return baos; } } } diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java index d7b5e78127..ee90fe69d0 100644 --- a/src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java +++ b/src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java @@ -23,6 +23,7 @@ import com.google.devtools.build.lib.vfs.Path; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; import java.io.OutputStream; +import java.io.PrintStream; import java.nio.charset.StandardCharsets; import org.junit.Before; import org.junit.Test; @@ -64,6 +65,26 @@ public class ActionFileSystemTest { } @Test + public void testAppendLocalFile() throws Exception { + String testData = "abc"; + + Path file = outputPath.getRelative("foo/bar"); + FileSystemUtils.writeContentAsLatin1(file, testData); + assertThat(new String(FileSystemUtils.readContentAsLatin1(file))).isEqualTo(testData); + + try (OutputStream out = file.getOutputStream(true)) { + PrintStream printStream = new PrintStream(out); + printStream.append("defg"); + printStream.flush(); + } + assertThat(new String(FileSystemUtils.readContentAsLatin1(file))).isEqualTo("abcdefg"); + + // Now make sure we can still overwrite the file in non-append mode. + FileSystemUtils.writeContentAsLatin1(file, "cheesy"); + assertThat(new String(FileSystemUtils.readContentAsLatin1(file))).isEqualTo("cheesy"); + } + + @Test public void testFlushedButNotClosedFileWrite() throws Exception { String testData = "abc19"; |