Omit parts of BEP events (like stdout, stderr) when the associated artifact uploader cannot upload a particular file.

RELNOTES: None
PiperOrigin-RevId: 204167372
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutedEvent.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutedEvent.java
index 372c559..f903503 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutedEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutedEvent.java
@@ -144,18 +144,18 @@
       actionBuilder.setExitCode(exception.getExitCode().getNumericExitCode());
     }
     if (stdout != null) {
-      actionBuilder.setStdout(
-          BuildEventStreamProtos.File.newBuilder()
-          .setName("stdout")
-          .setUri(pathConverter.apply(stdout))
-          .build());
+      String uri = pathConverter.apply(stdout);
+      if (uri != null) {
+        actionBuilder.setStdout(
+            BuildEventStreamProtos.File.newBuilder().setName("stdout").setUri(uri).build());
+      }
     }
     if (stderr != null) {
-      actionBuilder.setStderr(
-          BuildEventStreamProtos.File.newBuilder()
-          .setName("stderr")
-          .setUri(pathConverter.apply(stderr))
-          .build());
+      String uri = pathConverter.apply(stderr);
+      if (uri != null) {
+        actionBuilder.setStderr(
+            BuildEventStreamProtos.File.newBuilder().setName("stderr").setUri(uri).build());
+      }
     }
     if (action.getOwner() != null && action.getOwner().getLabel() != null) {
       actionBuilder.setLabel(action.getOwner().getLabel().toString());
@@ -168,10 +168,11 @@
       actionBuilder.setConfiguration(configuration.getEventId().asStreamProto().getConfiguration());
     }
     if (exception == null) {
-      actionBuilder.setPrimaryOutput(
-          BuildEventStreamProtos.File.newBuilder()
-              .setUri(pathConverter.apply(action.getPrimaryOutput().getPath()))
-              .build());
+      String uri = pathConverter.apply(action.getPrimaryOutput().getPath());
+      if (uri != null) {
+        actionBuilder.setPrimaryOutput(
+            BuildEventStreamProtos.File.newBuilder().setUri(uri).build());
+      }
     }
     try {
       if (action instanceof CommandAction) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
index 4ae435e..767eac0 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java
@@ -274,7 +274,9 @@
     for (Artifact artifact : artifacts) {
       String name = artifactNameFunction.apply(artifact);
       String uri = converters.pathConverter().apply(artifact.getPath());
-      builder.addImportantOutput(File.newBuilder().setName(name).setUri(uri).build());
+      if (uri != null) {
+        builder.addImportantOutput(File.newBuilder().setName(name).setUri(uri).build());
+      }
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildToolLogs.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildToolLogs.java
index 8ac55d6..eb5358b 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildToolLogs.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildToolLogs.java
@@ -62,11 +62,14 @@
               .build());
     }
     for (Pair<String, Path> logFile : logFiles) {
-      toolLogs.addLog(
-          BuildEventStreamProtos.File.newBuilder()
-              .setName(logFile.getFirst())
-              .setUri(converters.pathConverter().apply(logFile.getSecond()))
-              .build());
+      String uri = converters.pathConverter().apply(logFile.getSecond());
+      if (uri != null) {
+        toolLogs.addLog(
+            BuildEventStreamProtos.File.newBuilder()
+                .setName(logFile.getFirst())
+                .setUri(uri)
+                .build());
+      }
     }
     return GenericBuildEvent.protoChaining(this).setBuildToolLogs(toolLogs.build()).build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/PathConverter.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/PathConverter.java
index a1aaf31..b09073f 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/PathConverter.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/PathConverter.java
@@ -18,22 +18,21 @@
 import com.google.devtools.build.lib.vfs.Path;
 import java.net.URI;
 import java.net.URISyntaxException;
+import javax.annotation.Nullable;
 
 /**
  * Interface for conversion of paths to URIs.
  */
 public interface PathConverter {
   /** An implementation that throws on every call to {@link #apply(Path)}. */
-  public static final PathConverter NO_CONVERSION = new PathConverter() {
-    @Override
-    public String apply(Path path) {
-      throw new IllegalStateException(
-          String.format(
-              "Can't convert '%s', as it has not been"
-                  + "declared as a referenced artifact of a build event",
-              path.getPathString()));
-    }
-  };
+  PathConverter NO_CONVERSION =
+      path -> {
+        throw new IllegalStateException(
+            String.format(
+                "Can't convert '%s', as it has not been"
+                    + "declared as a referenced artifact of a build event",
+                path.getPathString()));
+      };
 
   /** A {@link PathConverter} that returns a path formatted as a URI with a {@code file} scheme. */
   // TODO(ulfjack): Make this a static final field.
@@ -81,7 +80,12 @@
   /**
    * Return the URI corresponding to the given path.
    *
-   * <p>This method must not return {@code null}.
+   * <p>This method may return null, in which case the associated {@link BuildEventArtifactUploader}
+   * was permanently unable to upload the file. The file should be omitted from the BEP stream.
+   *
+   * <p>This method may throw {@link IllegalStateException} if it is passed a path that
+   * wasn't declared in {@link BuildEvent#referencedLocalFiles()}.
    */
+  @Nullable
   String apply(Path path);
 }
diff --git a/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java b/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
index ea90ce7..ce731a1 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java
@@ -219,11 +219,11 @@
     builder.setTestAttemptDurationMillis(durationMillis);
     builder.addAllWarning(testWarnings);
     for (Pair<String, Path> file : files) {
-      builder.addTestActionOutput(
-          BuildEventStreamProtos.File.newBuilder()
-              .setName(file.getFirst())
-              .setUri(pathConverter.apply(file.getSecond()))
-              .build());
+      String uri = pathConverter.apply(file.getSecond());
+      if (uri != null) {
+        builder.addTestActionOutput(
+            BuildEventStreamProtos.File.newBuilder().setName(file.getFirst()).setUri(uri).build());
+      }
     }
     return builder.build();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/NamedArtifactGroup.java b/src/main/java/com/google/devtools/build/lib/runtime/NamedArtifactGroup.java
index 0160345..8624658 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/NamedArtifactGroup.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/NamedArtifactGroup.java
@@ -83,7 +83,9 @@
       }
       String name = artifact.getRootRelativePathString();
       String uri = pathConverter.apply(artifact.getPath());
-      builder.addFiles(BuildEventStreamProtos.File.newBuilder().setName(name).setUri(uri));
+      if (uri != null) {
+        builder.addFiles(BuildEventStreamProtos.File.newBuilder().setName(name).setUri(uri));
+      }
     }
     for (NestedSetView<Artifact> child : view.transitives()) {
       builder.addFileSets(namer.apply(child.identifier()));
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/TestSummary.java b/src/main/java/com/google/devtools/build/lib/runtime/TestSummary.java
index 098e17a..7b5a804 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/TestSummary.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/TestSummary.java
@@ -511,12 +511,16 @@
             .setTotalNumCached(getNumCached())
             .setTotalRunCount(totalRuns());
     for (Path path : getFailedLogs()) {
-      summaryBuilder.addFailed(
-          BuildEventStreamProtos.File.newBuilder().setUri(pathConverter.apply(path)).build());
+      String uri = pathConverter.apply(path);
+      if (uri != null) {
+        summaryBuilder.addFailed(BuildEventStreamProtos.File.newBuilder().setUri(uri).build());
+      }
     }
     for (Path path : getPassedLogs()) {
-      summaryBuilder.addPassed(
-          BuildEventStreamProtos.File.newBuilder().setUri(pathConverter.apply(path)).build());
+      String uri = pathConverter.apply(path);
+      if (uri != null) {
+        summaryBuilder.addPassed(BuildEventStreamProtos.File.newBuilder().setUri(uri).build());
+      }
     }
     return GenericBuildEvent.protoChaining(this).setTestSummary(summaryBuilder.build()).build();
   }