Remove Event's BUILD dependencies on filesystem things
This winds up pulling in all sorts of dependencies (filesystem, profiler) for
what's otherwise a low-level library.
Also, this makes it much more clear that the whole withOutErr thing exists
purely for ferrying action output around the system. Having events be
semi-silently backed by files has been a source of several issues in the past,
hopefully this rephrasing / indirection discourages future uses.
I feel like the code in this area is still somewhat awkward - I tried to look
past that for the most part and stay focused on cutting dependencies.
PiperOrigin-RevId: 393846789
diff --git a/src/main/java/com/google/devtools/build/lib/events/BUILD b/src/main/java/com/google/devtools/build/lib/events/BUILD
index cfb4d2d..913884e 100644
--- a/src/main/java/com/google/devtools/build/lib/events/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/events/BUILD
@@ -12,9 +12,7 @@
name = "events",
srcs = glob(["*.java"]),
deps = [
- "//src/main/java/com/google/devtools/build/lib/util/io",
"//src/main/java/com/google/devtools/build/lib/util/io:out-err",
- "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//src/main/java/net/starlark/java/eval",
"//src/main/java/net/starlark/java/syntax",
"//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/lib/events/Event.java b/src/main/java/com/google/devtools/build/lib/events/Event.java
index bbd8c52..a74c70b 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Event.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Event.java
@@ -19,8 +19,6 @@
import static java.util.Comparator.comparing;
import com.google.common.collect.ImmutableClassToInstanceMap;
-import com.google.devtools.build.lib.util.io.FileOutErr;
-import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
import java.io.Serializable;
import java.util.Arrays;
@@ -173,9 +171,12 @@
return withProperty(String.class, tag);
}
- /** Like {@link #withProperty(Class, Object)}, with {@code type.equals(FileOutErr.class)}. */
- public Event withStdoutStderr(FileOutErr outErr) {
- return withProperty(FileOutErr.class, outErr);
+ /**
+ * Returns a new event with the provided {@link ProcessOutput} property. See {@link #withProperty}
+ * for more specifics.
+ */
+ public Event withProcessOutput(ProcessOutput processOutput) {
+ return withProperty(ProcessOutput.class, processOutput);
}
/**
@@ -189,61 +190,29 @@
return getProperty(String.class);
}
- /** Indicates if a {@link FileOutErr} property is associated with this event. */
- public boolean hasStdoutStderr() {
- return getProperty(FileOutErr.class) != null;
- }
-
- /**
- * Gets the path to the stdout associated with this event (which the caller must not access), or
- * null if there is no such path.
- */
@Nullable
- public PathFragment getStdOutPathFragment() {
- FileOutErr outErr = getProperty(FileOutErr.class);
- return outErr == null ? null : outErr.getOutputPathFragment();
- }
-
- /** Gets the size of the stdout associated with this event without reading it. */
- public long getStdOutSize() throws IOException {
- FileOutErr outErr = getProperty(FileOutErr.class);
- return outErr == null ? 0 : outErr.outSize();
+ public ProcessOutput getProcessOutput() {
+ return getProperty(ProcessOutput.class);
}
/** Returns the stdout bytes associated with this event if any, and {@code null} otherwise. */
@Nullable
public byte[] getStdOut() {
- FileOutErr outErr = getProperty(FileOutErr.class);
- if (outErr == null) {
+ ProcessOutput processOutput = getProperty(ProcessOutput.class);
+ if (processOutput == null) {
return null;
}
- return outErr.outAsBytes();
- }
-
- /**
- * Gets the path to the stderr associated with this event (which the caller must not access), or
- * null if there is no such path.
- */
- @Nullable
- public PathFragment getStdErrPathFragment() {
- FileOutErr outErr = getProperty(FileOutErr.class);
- return outErr == null ? null : outErr.getErrorPathFragment();
- }
-
- /** Gets the size of the stderr associated with this event without reading it. */
- public long getStdErrSize() throws IOException {
- FileOutErr outErr = getProperty(FileOutErr.class);
- return outErr == null ? 0 : outErr.errSize();
+ return processOutput.getStdOut();
}
/** Returns the stderr bytes associated with this event if any, and {@code null} otherwise. */
@Nullable
public byte[] getStdErr() {
- FileOutErr outErr = getProperty(FileOutErr.class);
- if (outErr == null) {
+ ProcessOutput processOutput = getProperty(ProcessOutput.class);
+ if (processOutput == null) {
return null;
}
- return outErr.errAsBytes();
+ return processOutput.getStdErr();
}
/**
@@ -463,4 +432,34 @@
public static StarlarkThread.PrintHandler makeDebugPrintHandler(EventHandler h) {
return (thread, msg) -> h.handle(Event.debug(thread.getCallerLocation(), msg));
}
+
+ /**
+ * Process output associated with an event. The contents is just-about-certainly on disk, so
+ * special care should be taken when accessing it.
+ *
+ * <p>Note that this indirection exists partially for documentation sake, but also to keep the
+ * event library lightweight and broadly usable by avoiding bringing in all of the dependencies
+ * that come with dealing with process output (specifically the filesystem library).
+ */
+ public interface ProcessOutput {
+ /**
+ * Returns the string representation of the path containing the process's stdout for
+ * logging/debugging purposes.
+ */
+ String getStdOutPath();
+
+ long getStdOutSize() throws IOException;
+
+ byte[] getStdOut();
+
+ /**
+ * Returns the string representation of the path containing the process's stderr for
+ * logging/debugging purposes.
+ */
+ String getStdErrPath();
+
+ long getStdErrSize() throws IOException;
+
+ byte[] getStdErr();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
index 1c56e04..ae84347 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/UiEventHandler.java
@@ -41,6 +41,7 @@
import com.google.devtools.build.lib.buildtool.buildevent.TestFilteringCompleteEvent;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.Event.ProcessOutput;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.ExtendedEventHandler.FetchProgress;
@@ -385,7 +386,7 @@
@Nullable
private byte[] getContentIfSmallEnough(
- String name, long size, Supplier<byte[]> getContent, Supplier<PathFragment> getPath) {
+ String name, long size, Supplier<byte[]> getContent, Supplier<String> getPath) {
if (size == 0) {
// Avoid any possible I/O when we know it'll be empty anyway.
return null;
@@ -412,13 +413,20 @@
// much memory.
byte[] stdout = null;
byte[] stderr = null;
- if (event.hasStdoutStderr()) {
+ ProcessOutput processOutput = event.getProcessOutput();
+ if (processOutput != null) {
stdout =
getContentIfSmallEnough(
- "stdout", event.getStdOutSize(), event::getStdOut, event::getStdOutPathFragment);
+ "stdout",
+ processOutput.getStdOutSize(),
+ processOutput::getStdOut,
+ processOutput::getStdOutPath);
stderr =
getContentIfSmallEnough(
- "stderr", event.getStdErrSize(), event::getStdErr, event::getStdErrPathFragment);
+ "stderr",
+ processOutput.getStdErrSize(),
+ processOutput::getStdErr,
+ processOutput::getStdErrPath);
}
if (debugAllEvents) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
index 57e85e1..5076621 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
@@ -1645,7 +1645,7 @@
}
if (outErrBuffer != null && outErrBuffer.hasRecordedOutput()) {
// Bind the output to the prefix event.
- eventHandler.handle(prefixEvent.withStdoutStderr(outErrBuffer));
+ eventHandler.handle(prefixEvent.withProcessOutput(new ActionOutputEventData(outErrBuffer)));
} else {
eventHandler.handle(prefixEvent);
}
@@ -1736,4 +1736,43 @@
return input != null ? input : perBuildFileCache.getInput(execPath);
}
}
+
+ /** Adapts a {@link FileOutErr} to an {@link Event.ProcessOutput}. */
+ private static class ActionOutputEventData implements Event.ProcessOutput {
+ private final FileOutErr fileOutErr;
+
+ private ActionOutputEventData(FileOutErr fileOutErr) {
+ this.fileOutErr = fileOutErr;
+ }
+
+ @Override
+ public String getStdOutPath() {
+ return fileOutErr.getOutputPathFragment().getPathString();
+ }
+
+ @Override
+ public long getStdOutSize() throws IOException {
+ return fileOutErr.outSize();
+ }
+
+ @Override
+ public byte[] getStdOut() {
+ return fileOutErr.outAsBytes();
+ }
+
+ @Override
+ public String getStdErrPath() {
+ return fileOutErr.getErrorPathFragment().getPathString();
+ }
+
+ @Override
+ public long getStdErrSize() throws IOException {
+ return fileOutErr.errSize();
+ }
+
+ @Override
+ public byte[] getStdErr() {
+ return fileOutErr.errAsBytes();
+ }
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/events/EventTest.java b/src/test/java/com/google/devtools/build/lib/events/EventTest.java
index 4da3d9c..9ac7645 100644
--- a/src/test/java/com/google/devtools/build/lib/events/EventTest.java
+++ b/src/test/java/com/google/devtools/build/lib/events/EventTest.java
@@ -21,7 +21,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.testing.EqualsTester;
-import com.google.devtools.build.lib.testutil.TestFileOutErr;
+import com.google.devtools.build.lib.events.Event.ProcessOutput;
import net.starlark.java.eval.Mutability;
import net.starlark.java.eval.StarlarkSemantics;
import net.starlark.java.eval.StarlarkThread;
@@ -180,29 +180,59 @@
}
@Test
- public void stdoutStderr() throws Exception {
+ public void testWithProcessOutput() throws Exception {
+ String stdoutPath = "/stdout";
+ byte[] stdout = "some stdout output".getBytes(UTF_8);
+ String stderrPath = "/stderr";
+ byte[] stderr = "some stderr error".getBytes(UTF_8);
+
+ ProcessOutput testProcessOutput =
+ new ProcessOutput() {
+ @Override
+ public String getStdOutPath() {
+ return stdoutPath;
+ }
+
+ @Override
+ public long getStdOutSize() {
+ return stdout.length;
+ }
+
+ @Override
+ public byte[] getStdOut() {
+ return stdout;
+ }
+
+ @Override
+ public String getStdErrPath() {
+ return stderrPath;
+ }
+
+ @Override
+ public long getStdErrSize() {
+ return stderr.length;
+ }
+
+ @Override
+ public byte[] getStdErr() {
+ return stderr;
+ }
+ };
+
Event event = Event.of(EventKind.WARNING, "myMessage");
- TestFileOutErr testFileOutErr = new TestFileOutErr();
- String stdoutText = "some stdout output";
- String stderrText = "some stderr error";
- testFileOutErr.printOut(stdoutText);
- testFileOutErr.printErr(stderrText);
- Event eventWithStdoutStderr = event.withStdoutStderr(testFileOutErr);
+ Event eventWithProcessOutput = event.withProcessOutput(testProcessOutput);
- assertThat(event.hasStdoutStderr()).isFalse();
- assertThat(eventWithStdoutStderr.hasStdoutStderr()).isTrue();
+ assertThat(eventWithProcessOutput).isNotEqualTo(event);
+ assertThat(event.getProcessOutput()).isNull();
+ assertThat(eventWithProcessOutput.getProcessOutput()).isNotNull();
- byte[] stdoutBytes = stdoutText.getBytes(UTF_8);
- int stdoutLength = stdoutBytes.length;
- assertThat(eventWithStdoutStderr.getStdOut()).isEqualTo(stdoutBytes);
- assertThat(eventWithStdoutStderr.getStdOutSize()).isEqualTo(stdoutLength);
- assertThat(eventWithStdoutStderr.getStdOut()).isEqualTo(stdoutBytes);
+ assertThat(eventWithProcessOutput.getStdOut()).isEqualTo(stdout);
+ assertThat(eventWithProcessOutput.getProcessOutput().getStdOut()).isEqualTo(stdout);
+ assertThat(eventWithProcessOutput.getProcessOutput().getStdOutSize()).isEqualTo(stdout.length);
- byte[] stderrBytes = stderrText.getBytes(UTF_8);
- int stderrLength = stderrBytes.length;
- assertThat(eventWithStdoutStderr.getStdErr()).isEqualTo(stderrBytes);
- assertThat(eventWithStdoutStderr.getStdErrSize()).isEqualTo(stderrLength);
- assertThat(eventWithStdoutStderr.getStdErr()).isEqualTo(stderrBytes);
+ assertThat(eventWithProcessOutput.getStdErr()).isEqualTo(stderr);
+ assertThat(eventWithProcessOutput.getProcessOutput().getStdErr()).isEqualTo(stderr);
+ assertThat(eventWithProcessOutput.getProcessOutput().getStdErrSize()).isEqualTo(stderr.length);
}
@Test