aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ActionFileSystem.java41
-rw-r--r--src/test/java/com/google/devtools/build/lib/skyframe/ActionFileSystemTest.java21
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";