aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build
diff options
context:
space:
mode:
authorGravatar ulfjack <ulfjack@google.com>2018-06-15 01:40:02 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-06-15 01:41:16 -0700
commit68aa410229cb36ceedc910c803a0aff2db6d027f (patch)
tree3fa7f6805066a96966e9fa4191774a4b1c06d2cf /src/main/java/com/google/devtools/build
parent522f76ae5e50ae9848b6f407acbcce62bb808016 (diff)
Add a mechanism for build event protocol events to upload files
This should be a no-op, mostly replacing PathConverter with BuildEventArtifactUploader, since none of the implementations perform any upload yet. PiperOrigin-RevId: 200685325
Diffstat (limited to 'src/main/java/com/google/devtools/build')
-rw-r--r--src/main/java/com/google/devtools/build/lib/actions/ActionExecutedEvent.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/TargetCompleteEvent.java13
-rw-r--r--src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java39
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceProtoUtil.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceTransport.java59
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java23
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploader.java38
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploaderMap.java59
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java11
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildToolLogs.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/PathConverter.java64
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java46
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java105
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java91
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/JsonFormatFileTransport.java46
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransport.java43
-rw-r--r--src/main/java/com/google/devtools/build/lib/exec/TestAttempt.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java18
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java14
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/NamedArtifactGroup.java15
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/ServerBuilder.java37
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/TestSummary.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/KnownConfigurations.java2
26 files changed, 557 insertions, 237 deletions
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 52ec1096fc..a4fa28be5e 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
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.actions;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
import com.google.devtools.build.lib.buildeventstream.BuildEventId;
@@ -117,6 +118,21 @@ public class ActionExecutedEvent implements BuildEventWithConfiguration, Progres
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ ImmutableSet.Builder<Path> artifacts = ImmutableSet.builder();
+ if (stdout != null) {
+ artifacts.add(stdout);
+ }
+ if (stderr != null) {
+ artifacts.add(stderr);
+ }
+ if (exception == null) {
+ artifacts.add(action.getPrimaryOutput().getPath());
+ }
+ return artifacts.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
PathConverter pathConverter = converters.pathConverter();
BuildEventStreamProtos.ActionExecuted.Builder actionBuilder =
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 7473de21b6..adb71f4f9d 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
@@ -278,6 +278,19 @@ public final class TargetCompleteEvent
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
+ for (ArtifactsInOutputGroup group : outputs) {
+ if (group.areImportant()) {
+ for (Artifact artifact : group.getArtifacts()) {
+ builder.add(artifact.getPath());
+ }
+ }
+ }
+ return builder.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
BuildEventStreamProtos.TargetComplete.Builder builder =
BuildEventStreamProtos.TargetComplete.newBuilder();
diff --git a/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java b/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java
index 28682aef5d..21b6588b1d 100644
--- a/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java
@@ -113,12 +113,15 @@ public final class GoogleAuthUtils {
}
/**
- * Create a new {@link Credentials} object.
+ * Create a new {@link Credentials} object, or {@code null} if no options are provided.
*
* @throws IOException in case the credentials can't be constructed.
*/
- public static Credentials newCredentials(AuthAndTLSOptions options) throws IOException {
- if (options.googleCredentials != null) {
+ @Nullable
+ public static Credentials newCredentials(@Nullable AuthAndTLSOptions options) throws IOException {
+ if (options == null) {
+ return null;
+ } else if (options.googleCredentials != null) {
// Credentials from file
try (InputStream authFile = new FileInputStream(options.googleCredentials)) {
return newCredentials(authFile, options.googleAuthScopes);
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java
index 80c5599620..115808a66a 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java
@@ -20,14 +20,16 @@ import static com.google.devtools.build.lib.buildeventservice.BuildEventServiceT
import static java.lang.String.format;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions;
import com.google.devtools.build.lib.buildeventservice.client.BuildEventServiceClient;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploaderMap;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
import com.google.devtools.build.lib.buildeventstream.transports.BuildEventStreamOptions;
import com.google.devtools.build.lib.buildeventstream.transports.BuildEventTransportFactory;
import com.google.devtools.build.lib.clock.Clock;
@@ -72,8 +74,7 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
}
@Override
- public void beforeCommand(CommandEnvironment commandEnvironment)
- throws AbruptExitException {
+ public void beforeCommand(CommandEnvironment commandEnvironment) {
// Reset to null in case afterCommand was not called.
this.outErr = null;
if (!whitelistedCommands().contains(commandEnvironment.getCommandName())) {
@@ -87,7 +88,7 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
commandEnvironment.getReporter(),
commandEnvironment.getBlazeModuleEnvironment(),
commandEnvironment.getRuntime().getClock(),
- commandEnvironment.getRuntime().getPathToUriConverter(),
+ commandEnvironment.getRuntime().getBuildEventArtifactUploaders(),
commandEnvironment.getReporter(),
commandEnvironment.getBuildRequestId().toString(),
commandEnvironment.getCommandId().toString(),
@@ -129,9 +130,7 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
this.outErr = null;
}
- /**
- * Returns {@code null} if no stream could be created.
- */
+ /** Returns {@code null} if no stream could be created. */
@Nullable
@VisibleForTesting
BuildEventStreamer tryCreateStreamer(
@@ -140,11 +139,13 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
EventHandler commandLineReporter,
ModuleEnvironment moduleEnvironment,
Clock clock,
- PathConverter pathConverter,
+ BuildEventArtifactUploaderMap artifactUploaders,
Reporter reporter,
String buildRequestId,
String invocationId,
String commandName) {
+ Preconditions.checkNotNull(artifactUploaders);
+
try {
T besOptions =
checkNotNull(
@@ -172,18 +173,20 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
moduleEnvironment,
clock,
protocolOptions,
- pathConverter,
+ artifactUploaders,
commandLineReporter,
startupOptionsProvider);
} catch (Exception e) {
commandLineReporter.handle(Event.error(format(UPLOAD_FAILED_MESSAGE, e.getMessage())));
- moduleEnvironment.exit(new AbruptExitException(
- "Failed while creating BuildEventTransport", ExitCode.PUBLISH_ERROR));
+ moduleEnvironment.exit(
+ new AbruptExitException(
+ "Failed while creating BuildEventTransport", ExitCode.PUBLISH_ERROR));
return null;
}
ImmutableSet<BuildEventTransport> bepTransports =
- BuildEventTransportFactory.createFromOptions(bepOptions, protocolOptions, pathConverter);
+ BuildEventTransportFactory.createFromOptions(
+ bepOptions, protocolOptions, artifactUploaders, moduleEnvironment::exit);
ImmutableSet.Builder<BuildEventTransport> transportsBuilder =
ImmutableSet.<BuildEventTransport>builder().addAll(bepTransports);
@@ -213,7 +216,7 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
ModuleEnvironment moduleEnvironment,
Clock clock,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter,
+ BuildEventArtifactUploaderMap artifactUploaders,
EventHandler commandLineReporter,
OptionsProvider startupOptionsProvider)
throws IOException, OptionsParsingException {
@@ -242,9 +245,13 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
besOptions.besBackend, buildRequestId, invocationId)));
}
+ BuildEventServiceClient client = createBesClient(besOptions, authTlsOptions);
+ BuildEventArtifactUploader artifactUploader =
+ artifactUploaders.select(protocolOptions.buildEventUploadStrategy);
+
BuildEventTransport besTransport =
new BuildEventServiceTransport(
- createBesClient(besOptions, authTlsOptions),
+ client,
besOptions.besTimeout,
besOptions.besLifecycleEvents,
buildRequestId,
@@ -253,11 +260,11 @@ public abstract class BuildEventServiceModule<T extends BuildEventServiceOptions
moduleEnvironment,
clock,
protocolOptions,
- pathConverter,
commandLineReporter,
besOptions.projectId,
keywords(besOptions, startupOptionsProvider),
- besResultsUrl);
+ besResultsUrl,
+ artifactUploader);
logger.fine("BuildEventServiceTransport was created successfully");
return besTransport;
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceProtoUtil.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceProtoUtil.java
index 217fcbd419..dc6172cd08 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceProtoUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceProtoUtil.java
@@ -107,6 +107,11 @@ public final class BuildEventServiceProtoUtil {
return streamSequenceNumber.getAndIncrement();
}
+ /** Creates a PublishBuildToolEventStreamRequest from a packed bazel event. */
+ public PublishBuildToolEventStreamRequest bazelEvent(Any packedEvent, int sequenceNumber) {
+ return bazelEvent(sequenceNumber, packedEvent);
+ }
+
@VisibleForTesting
public PublishBuildToolEventStreamRequest bazelEvent(int sequenceNumber, Any packedEvent) {
return publishBuildToolEventStreamRequest(
@@ -114,7 +119,6 @@ public final class BuildEventServiceProtoUtil {
com.google.devtools.build.v1.BuildEvent.newBuilder().setBazelEvent(packedEvent));
}
- @VisibleForTesting
public PublishBuildToolEventStreamRequest streamFinished(int sequenceNumber) {
return publishBuildToolEventStreamRequest(
sequenceNumber,
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceTransport.java
index 37355cc6f6..acf5686671 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceTransport.java
@@ -27,6 +27,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.SettableFuture;
@@ -34,6 +35,7 @@ import com.google.devtools.build.lib.buildeventservice.client.BuildEventServiceC
import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
import com.google.devtools.build.lib.buildeventstream.BuildCompletingEvent;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
@@ -48,12 +50,14 @@ import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.JavaSleeper;
import com.google.devtools.build.lib.util.Sleeper;
+import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.v1.BuildStatus.Result;
import com.google.devtools.build.v1.PublishBuildToolEventStreamRequest;
import com.google.devtools.build.v1.PublishBuildToolEventStreamResponse;
import com.google.devtools.build.v1.PublishLifecycleEventRequest;
import com.google.protobuf.Any;
import io.grpc.Status;
+import java.io.IOException;
import java.time.Duration;
import java.util.Deque;
import java.util.Set;
@@ -95,7 +99,7 @@ public class BuildEventServiceTransport implements BuildEventTransport {
private final ModuleEnvironment moduleEnvironment;
private final EventHandler commandLineReporter;
private final BuildEventProtocolOptions protocolOptions;
- private final PathConverter pathConverter;
+ private final BuildEventArtifactUploader artifactUploader;
private final Sleeper sleeper;
/** Contains all pendingAck events that might be retried in case of failures. */
private ConcurrentLinkedDeque<InternalOrderedBuildEvent> pendingAck;
@@ -131,11 +135,11 @@ public class BuildEventServiceTransport implements BuildEventTransport {
ModuleEnvironment moduleEnvironment,
Clock clock,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter,
EventHandler commandLineReporter,
@Nullable String projectId,
Set<String> keywords,
- @Nullable String besResultsUrl) {
+ @Nullable String besResultsUrl,
+ BuildEventArtifactUploader artifactUploader) {
this(
besClient,
uploadTimeout,
@@ -146,12 +150,12 @@ public class BuildEventServiceTransport implements BuildEventTransport {
moduleEnvironment,
clock,
protocolOptions,
- pathConverter,
commandLineReporter,
projectId,
keywords,
- new JavaSleeper(),
- besResultsUrl);
+ besResultsUrl,
+ artifactUploader,
+ new JavaSleeper());
}
@VisibleForTesting
@@ -165,12 +169,12 @@ public class BuildEventServiceTransport implements BuildEventTransport {
ModuleEnvironment moduleEnvironment,
Clock clock,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter,
EventHandler commandLineReporter,
@Nullable String projectId,
Set<String> keywords,
- Sleeper sleeper,
- @Nullable String besResultsUrl) {
+ @Nullable String besResultsUrl,
+ BuildEventArtifactUploader artifactUploader,
+ Sleeper sleeper) {
this.besClient = besClient;
this.besProtoUtil =
new BuildEventServiceProtoUtil(
@@ -187,9 +191,9 @@ public class BuildEventServiceTransport implements BuildEventTransport {
// TODO(buchgr): Fix it.
this.uploaderExecutorService = listeningDecorator(Executors.newFixedThreadPool(2));
this.protocolOptions = protocolOptions;
- this.pathConverter = pathConverter;
this.invocationResult = UNKNOWN_STATUS;
this.uploadTimeout = uploadTimeout;
+ this.artifactUploader = artifactUploader;
this.sleeper = sleeper;
this.besResultsUrl = besResultsUrl;
}
@@ -480,6 +484,27 @@ public class BuildEventServiceTransport implements BuildEventTransport {
do {
orderedBuildEvent = pendingSend.pollFirst(STREAMING_RPC_POLL_IN_SECS, TimeUnit.SECONDS);
if (orderedBuildEvent != null) {
+ final PathConverter pathConverter;
+ try {
+ pathConverter = artifactUploader.upload(orderedBuildEvent.referencedLocalFiles());
+ } catch (IOException e) {
+ logger.log(
+ Level.WARNING,
+ String.format(
+ "Aborting publishBuildToolEventStream RPC because of a failure to "
+ + "upload referenced artifacts: %s",
+ e.getMessage()),
+ e);
+ besClient.abortStream(Status.INTERNAL.augmentDescription(e.getMessage()));
+ throw e;
+ } catch (InterruptedException e) {
+ // By convention the interrupted flag should have been cleared,
+ // but just to be sure clear it.
+ Thread.interrupted();
+ String additionalDetails = "Uploading referenced artifacts";
+ besClient.abortStream(Status.CANCELLED.augmentDescription(additionalDetails));
+ throw e;
+ }
pendingAck.add(orderedBuildEvent);
besClient.sendOverStream(orderedBuildEvent.serialize(pathConverter));
}
@@ -621,6 +646,8 @@ public class BuildEventServiceTransport implements BuildEventTransport {
int getSequenceNumber();
+ Set<Path> referencedLocalFiles();
+
PublishBuildToolEventStreamRequest serialize(PathConverter pathConverter);
}
@@ -647,6 +674,11 @@ public class BuildEventServiceTransport implements BuildEventTransport {
}
@Override
+ public Set<Path> referencedLocalFiles() {
+ return event.referencedLocalFiles();
+ }
+
+ @Override
public PublishBuildToolEventStreamRequest serialize(PathConverter pathConverter) {
BuildEventStreamProtos.BuildEvent eventProto =
event.asStreamProto(
@@ -666,7 +698,7 @@ public class BuildEventServiceTransport implements BuildEventTransport {
return protocolOptions;
}
});
- return besProtoUtil.bazelEvent(sequenceNumber, Any.pack(eventProto));
+ return besProtoUtil.bazelEvent(Any.pack(eventProto), sequenceNumber);
}
}
@@ -688,6 +720,11 @@ public class BuildEventServiceTransport implements BuildEventTransport {
}
@Override
+ public Set<Path> referencedLocalFiles() {
+ return ImmutableSet.of();
+ }
+
+ @Override
public PublishBuildToolEventStreamRequest serialize(PathConverter pathConverter) {
return besProtoUtil.streamFinished(sequenceNumber);
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java
index de4cfb8c88..6d6900687c 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEvent.java
@@ -14,7 +14,10 @@
package com.google.devtools.build.lib.buildeventstream;
+import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.vfs.Path;
+import java.util.Set;
/**
* Interface for objects that can be posted on the public event stream.
@@ -23,11 +26,29 @@ import com.google.devtools.build.lib.events.ExtendedEventHandler;
* pass-through of events, as well as proper chaining of events.
*/
public interface BuildEvent extends ChainableEvent, ExtendedEventHandler.Postable {
+
+ /**
+ * Returns a list of files that are referenced in the protobuf representation returned by {@link
+ * #asStreamProto(BuildEventContext)}.
+ *
+ * <p>This method is different from {@code EventReportingArtifacts#reportedArtifacts()} in that it
+ * only returns files directly referenced in the protobuf returned by {@link
+ * #asStreamProto(BuildEventContext)}.
+ *
+ * <p>Note the consistency requirement - you must not attempt to pass Path objects to the
+ * {@link PathConverter} unless you have returned the Path object here.
+ */
+ // TODO(ulfjack): Consider moving the upload call to the BuildEventContext and returning a map
+ // from Path to URI, rather than a callback.
+ default Set<Path> referencedLocalFiles() {
+ return ImmutableSet.of();
+ }
+
/**
* Provide a binary representation of the event.
*
* <p>Provide a presentation of the event according to the specified binary format, as appropriate
* protocol buffer.
*/
- BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters);
+ BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext context);
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploader.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploader.java
new file mode 100644
index 0000000000..7b7ffb15ab
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploader.java
@@ -0,0 +1,38 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.buildeventstream;
+
+import com.google.devtools.build.lib.buildeventstream.PathConverter.FileUriPathConverter;
+import com.google.devtools.build.lib.vfs.Path;
+import java.io.IOException;
+import java.util.Set;
+
+/** Uploads artifacts referenced by the Build Event Protocol (BEP). */
+public interface BuildEventArtifactUploader {
+ public static final BuildEventArtifactUploader LOCAL_FILES_UPLOADER =
+ new BuildEventArtifactUploader() {
+ @Override
+ public PathConverter upload(Set<Path> files) {
+ return new FileUriPathConverter();
+ }
+ };
+
+ /**
+ * Uploads a set of files referenced by the protobuf representation of a {@link BuildEvent}.
+ *
+ * <p>Returns a {@link PathConverter} that must provide a name for each uploaded file as it should
+ * appear in the BEP.
+ */
+ PathConverter upload(Set<Path> files) throws IOException, InterruptedException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploaderMap.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploaderMap.java
new file mode 100644
index 0000000000..8987def882
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventArtifactUploaderMap.java
@@ -0,0 +1,59 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.buildeventstream;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+/** Selects between multiple available upload strategies. */
+@ThreadSafe
+public class BuildEventArtifactUploaderMap {
+ private final ImmutableMap<String, BuildEventArtifactUploader> uploaders;
+
+ private BuildEventArtifactUploaderMap(
+ ImmutableMap<String, BuildEventArtifactUploader> uploaders) {
+ this.uploaders = uploaders;
+ }
+
+ public BuildEventArtifactUploader select(@Nullable String name) {
+ if (name == null) {
+ // TODO(b/110235226): We currently choose the strategy with alphabetically first strategy,
+ // which happens to be backwards-compatible; we need to set
+ // experimental_build_event_upload_strategy to appropriate default values instead, and then
+ // make it an error to pass null.
+ return uploaders.values().iterator().next();
+ }
+ return uploaders.getOrDefault(name, BuildEventArtifactUploader.LOCAL_FILES_UPLOADER);
+ }
+
+ /** Builder class for {@link BuildEventArtifactUploaderMap}. */
+ public static class Builder {
+ private final SortedMap<String, BuildEventArtifactUploader> uploaders = new TreeMap<>();
+
+ public Builder() {
+ }
+
+ public Builder add(String name, BuildEventArtifactUploader uploader) {
+ uploaders.put(name, uploader);
+ return this;
+ }
+
+ public BuildEventArtifactUploaderMap build() {
+ return new BuildEventArtifactUploaderMap(ImmutableMap.copyOf(uploaders));
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java
index e22d1669ef..4f31f75eaa 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java
@@ -28,7 +28,16 @@ public class BuildEventProtocolOptions extends OptionsBase {
documentationCategory = OptionDocumentationCategory.LOGGING,
effectTags = {OptionEffectTag.AFFECTS_OUTPUTS},
help = "Use this to suppress generation of the legacy important_outputs field in the "
- + "TargetComplete event"
+ + "TargetComplete event."
)
public boolean legacyImportantOutputs;
+
+ @Option(
+ name = "experimental_build_event_upload_strategy",
+ defaultValue = "null",
+ documentationCategory = OptionDocumentationCategory.LOGGING,
+ effectTags = {OptionEffectTag.AFFECTS_OUTPUTS},
+ help = "Selects how to upload artifacts referenced in the build event protocol."
+ )
+ public String buildEventUploadStrategy;
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java
index 9b930b9ecd..9d61c1c4e3 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventTransport.java
@@ -26,7 +26,6 @@ import javax.annotation.concurrent.ThreadSafe;
*/
@ThreadSafe
public interface BuildEventTransport {
-
/**
* The name of this transport as can be displayed to a user.
*/
@@ -39,16 +38,14 @@ public interface BuildEventTransport {
* <p>In case the transport is in error, this method still needs to be able to accept build
* events. It may choose to ignore them, though.
*
- * <p>This method should not throw any exceptions.
- *
* @param event the event to sendBuildEvent.
*/
void sendBuildEvent(BuildEvent event, ArtifactGroupNamer namer);
/**
- * Initiates a close. Callers may listen to the returned future to be notified when the close
- * is complete i.e. wait for all build events to be sent. The future does not contain any
- * information about possible transport errors.
+ * Initiates a close. Callers may listen to the returned future to be notified when the close is
+ * complete i.e. wait for all build events to be sent. The future may contain any information
+ * about possible transport errors.
*
* <p>This method might be called multiple times without any effect after the first call.
*
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 fe68043eb0..c4eee48b28 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
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.buildeventstream;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.vfs.Path;
import com.google.protobuf.ByteString;
@@ -41,6 +42,15 @@ public class BuildToolLogs implements BuildEventWithOrderConstraint {
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ ImmutableSet.Builder<Path> artifacts = ImmutableSet.builder();
+ for (Pair<String, Path> logFile : logFiles) {
+ artifacts.add(logFile.getSecond());
+ }
+ return artifacts.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
BuildEventStreamProtos.BuildToolLogs.Builder toolLogs =
BuildEventStreamProtos.BuildToolLogs.newBuilder();
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 e230d36953..a1aaf31d40 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
@@ -13,15 +13,75 @@
// limitations under the License.
package com.google.devtools.build.lib.buildeventstream;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import com.google.devtools.build.lib.vfs.Path;
+import java.net.URI;
+import java.net.URISyntaxException;
/**
* 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()));
+ }
+ };
+
+ /** A {@link PathConverter} that returns a path formatted as a URI with a {@code file} scheme. */
+ // TODO(ulfjack): Make this a static final field.
+ final class FileUriPathConverter implements PathConverter {
+ @Override
+ public String apply(Path path) {
+ Preconditions.checkNotNull(path);
+ return pathToUriString(path.getPathString());
+ }
+
+ /**
+ * Returns the path encoded as an {@link URI}.
+ *
+ * <p>This concrete implementation returns URIs with "file" as the scheme. For Example: - On
+ * Unix the path "/tmp/foo bar.txt" will be encoded as "file:///tmp/foo%20bar.txt". - On Windows
+ * the path "C:\Temp\Foo Bar.txt" will be encoded as "file:///C:/Temp/Foo%20Bar.txt"
+ *
+ * <p>Implementors extending this class for special filesystems will likely need to override
+ * this method.
+ */
+ @VisibleForTesting
+ static String pathToUriString(String path) {
+ if (!path.startsWith("/")) {
+ // On Windows URI's need to start with a '/'. i.e. C:\Foo\Bar would be file:///C:/Foo/Bar
+ path = "/" + path;
+ }
+ try {
+ return new URI(
+ "file",
+ // Needs to be "" instead of null, so that toString() will append "//" after the
+ // scheme.
+ // We need this for backwards compatibility reasons as some consumers of the BEP are
+ // broken.
+ "",
+ path,
+ null,
+ null)
+ .toString();
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
/**
- * Return the URI corresponding to the given path, if the path can be converted to a URI by this
- * path converter; return {@link null} otherwise.
+ * Return the URI corresponding to the given path.
+ *
+ * <p>This method must not return {@code null}.
*/
String apply(Path path);
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
index 7d8fe5709a..117d18cf19 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
@@ -10,7 +10,9 @@ java_library(
name = "transports",
srcs = glob(["*.java"]),
deps = [
+ "//src/main/java/com/google/devtools/build/lib:exitcode-external",
"//src/main/java/com/google/devtools/build/lib:io",
+ "//src/main/java/com/google/devtools/build/lib:util",
"//src/main/java/com/google/devtools/build/lib/buildeventstream",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
"//src/main/java/com/google/devtools/build/lib/vfs",
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java
index 71e4fd878a..2f1d15c25a 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BinaryFormatFileTransport.java
@@ -14,30 +14,28 @@
package com.google.devtools.build.lib.buildeventstream.transports;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
-import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.util.AbruptExitException;
import java.io.IOException;
+import java.util.function.Consumer;
/**
* A simple {@link BuildEventTransport} that writes a varint delimited binary representation of
* {@link BuildEvent} protocol buffers to a file.
*/
public final class BinaryFormatFileTransport extends FileTransport {
- private final BuildEventProtocolOptions options;
- private final PathConverter pathConverter;
-
BinaryFormatFileTransport(
- String path, BuildEventProtocolOptions options, PathConverter pathConverter)
- throws IOException {
- super(path);
- this.options = options;
- this.pathConverter = pathConverter;
+ String path,
+ BuildEventProtocolOptions options,
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
+ super(path, options, uploader, exitFunc);
}
@Override
@@ -47,24 +45,10 @@ public final class BinaryFormatFileTransport extends FileTransport {
@Override
public synchronized void sendBuildEvent(BuildEvent event, final ArtifactGroupNamer namer) {
- checkNotNull(event);
- BuildEventContext converters =
- new BuildEventContext() {
- @Override
- public PathConverter pathConverter() {
- return pathConverter;
- }
-
- @Override
- public ArtifactGroupNamer artifactGroupNamer() {
- return namer;
- }
-
- @Override
- public BuildEventProtocolOptions getOptions() {
- return options;
- }
- };
- write(event.asStreamProto(converters));
+ BuildEventStreamProtos.BuildEvent protoEvent = asStreamProto(event, namer);
+ if (protoEvent == null) {
+ return;
+ }
+ write(protoEvent);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java
index 0cc84b0f74..eef7583451 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BuildEventTransportFactory.java
@@ -17,13 +17,13 @@ package com.google.devtools.build.lib.buildeventstream.transports;
import static com.google.common.base.Strings.isNullOrEmpty;
import com.google.common.collect.ImmutableSet;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploaderMap;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
-import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.util.AbruptExitException;
import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
+import java.util.function.Consumer;
/** Factory used to create a Set of BuildEventTransports from BuildEventStreamOptions. */
public enum BuildEventTransportFactory {
@@ -37,11 +37,16 @@ public enum BuildEventTransportFactory {
protected BuildEventTransport create(
BuildEventStreamOptions options,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter) throws IOException {
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
return new TextFormatFileTransport(
- options.getBuildEventTextFile(),
- protocolOptions,
- options.getBuildEventTextFilePathConversion() ? pathConverter : new NullPathConverter());
+ options.getBuildEventTextFile(), protocolOptions, uploader, exitFunc);
+ }
+
+ @Override
+ protected boolean usePathConverter(BuildEventStreamOptions options) {
+ return options.getBuildEventTextFilePathConversion();
}
},
@@ -55,13 +60,16 @@ public enum BuildEventTransportFactory {
protected BuildEventTransport create(
BuildEventStreamOptions options,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter) throws IOException {
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
return new BinaryFormatFileTransport(
- options.getBuildEventBinaryFile(),
- protocolOptions,
- options.getBuildEventBinaryFilePathConversion()
- ? pathConverter
- : new NullPathConverter());
+ options.getBuildEventBinaryFile(), protocolOptions, uploader, exitFunc);
+ }
+
+ @Override
+ protected boolean usePathConverter(BuildEventStreamOptions options) {
+ return options.getBuildEventBinaryFilePathConversion();
}
},
@@ -75,11 +83,16 @@ public enum BuildEventTransportFactory {
protected BuildEventTransport create(
BuildEventStreamOptions options,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter) throws IOException {
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
return new JsonFormatFileTransport(
- options.getBuildEventJsonFile(),
- protocolOptions,
- options.getBuildEventJsonFilePathConversion() ? pathConverter : new NullPathConverter());
+ options.getBuildEventJsonFile(), protocolOptions, uploader, exitFunc);
+ }
+
+ @Override
+ protected boolean usePathConverter(BuildEventStreamOptions options) {
+ return options.getBuildEventJsonFilePathConversion();
}
};
@@ -94,13 +107,17 @@ public enum BuildEventTransportFactory {
public static ImmutableSet<BuildEventTransport> createFromOptions(
BuildEventStreamOptions options,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter)
- throws IOException {
+ BuildEventArtifactUploaderMap artifactUploaders,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
ImmutableSet.Builder<BuildEventTransport> buildEventTransportsBuilder = ImmutableSet.builder();
for (BuildEventTransportFactory transportFactory : BuildEventTransportFactory.values()) {
if (transportFactory.enabled(options)) {
+ BuildEventArtifactUploader uploader = transportFactory.usePathConverter(options)
+ ? artifactUploaders.select(protocolOptions.buildEventUploadStrategy)
+ : BuildEventArtifactUploader.LOCAL_FILES_UPLOADER;
buildEventTransportsBuilder.add(
- transportFactory.create(options, protocolOptions, pathConverter));
+ transportFactory.create(options, protocolOptions, uploader, exitFunc));
}
}
return buildEventTransportsBuilder.build();
@@ -113,47 +130,9 @@ public enum BuildEventTransportFactory {
protected abstract BuildEventTransport create(
BuildEventStreamOptions options,
BuildEventProtocolOptions protocolOptions,
- PathConverter pathConverter)
- throws IOException;
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException;
- private static class NullPathConverter implements PathConverter {
- @Override
- public String apply(Path path) {
- return pathToUriString(path.getPathString());
- }
- }
-
- /**
- * Returns the path encoded as an {@link URI}.
- *
- * <p>This concrete implementation returns URIs with "file" as the scheme. For Example: - On Unix
- * the path "/tmp/foo bar.txt" will be encoded as "file:///tmp/foo%20bar.txt". - On Windows the
- * path "C:\Temp\Foo Bar.txt" will be encoded as "file:///C:/Temp/Foo%20Bar.txt"
- *
- * <p>Implementors extending this class for special filesystems will likely need to override this
- * method.
- *
- * @throws URISyntaxException if the URI cannot be constructed.
- */
- static String pathToUriString(String path) {
- if (!path.startsWith("/")) {
- // On Windows URI's need to start with a '/'. i.e. C:\Foo\Bar would be file:///C:/Foo/Bar
- path = "/" + path;
- }
- try {
- return new URI(
- "file",
- // Needs to be "" instead of null, so that toString() will append "//" after the
- // scheme.
- // We need this for backwards compatibility reasons as some consumers of the BEP are
- // broken.
- "",
- path,
- null,
- null)
- .toString();
- } catch (URISyntaxException e) {
- throw new IllegalStateException(e);
- }
- }
+ protected abstract boolean usePathConverter(BuildEventStreamOptions options);
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java
index a2d1164bb2..540a7e84cd 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/FileTransport.java
@@ -14,16 +14,32 @@
package com.google.devtools.build.lib.buildeventstream.transports;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Throwables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
+import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
+import com.google.devtools.build.lib.buildeventstream.BuildEvent;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
+import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
+import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
+import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.io.AsynchronousFileOutputStream;
+import com.google.devtools.build.lib.vfs.Path;
import com.google.protobuf.Message;
import java.io.IOException;
+import java.util.Set;
+import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.annotation.Nullable;
/**
* Non-blocking file transport.
@@ -35,10 +51,23 @@ import java.util.logging.Logger;
abstract class FileTransport implements BuildEventTransport {
private static final Logger logger = Logger.getLogger(FileTransport.class.getName());
+ private final BuildEventProtocolOptions options;
+ private final BuildEventArtifactUploader uploader;
+ private final Consumer<AbruptExitException> exitFunc;
+ private boolean errored;
+
@VisibleForTesting
final AsynchronousFileOutputStream out;
- FileTransport(String path) throws IOException {
+ FileTransport(
+ String path,
+ BuildEventProtocolOptions options,
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
+ this.uploader = uploader;
+ this.options = options;
+ this.exitFunc = exitFunc;
out = new AsynchronousFileOutputStream(path);
}
@@ -60,7 +89,6 @@ abstract class FileTransport implements BuildEventTransport {
}
}
-
@Override
public synchronized ListenableFuture<Void> close() {
return Futures.catching(
@@ -77,4 +105,63 @@ abstract class FileTransport implements BuildEventTransport {
public void closeNow() {
out.closeNow();
}
+
+ /**
+ * Converts the given event into a proto object; this may trigger uploading of referenced files as
+ * a side effect. May return {@code null} if there was an interrupt. This method is not
+ * thread-safe.
+ */
+ @Nullable
+ protected BuildEventStreamProtos.BuildEvent asStreamProto(
+ BuildEvent event, ArtifactGroupNamer namer) {
+ checkNotNull(event);
+ PathConverter pathConverter = uploadReferencedFiles(event.referencedLocalFiles());
+ if (pathConverter == null) {
+ return null;
+ }
+
+ BuildEventContext context =
+ new BuildEventContext() {
+ @Override
+ public PathConverter pathConverter() {
+ return pathConverter;
+ }
+
+ @Override
+ public ArtifactGroupNamer artifactGroupNamer() {
+ return namer;
+ }
+
+ @Override
+ public BuildEventProtocolOptions getOptions() {
+ return options;
+ }
+ };
+ return event.asStreamProto(context);
+ }
+
+ /**
+ * Returns a {@link PathConverter} for the uploaded files, or {@code null} when the uploaded
+ * failed.
+ */
+ private @Nullable PathConverter uploadReferencedFiles(Set<Path> artifacts) {
+ checkNotNull(artifacts);
+
+ if (errored) {
+ return null;
+ }
+ try {
+ return uploader.upload(artifacts);
+ } catch (IOException e) {
+ errored = true;
+ exitFunc.accept(
+ new AbruptExitException(
+ Throwables.getStackTraceAsString(e), ExitCode.PUBLISH_ERROR, e));
+ } catch (InterruptedException e) {
+ errored = true;
+ exitFunc.accept(new AbruptExitException(ExitCode.INTERRUPTED, e));
+ Thread.currentThread().interrupt();
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/JsonFormatFileTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/JsonFormatFileTransport.java
index 3d51c4f632..33b296143e 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/JsonFormatFileTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/JsonFormatFileTransport.java
@@ -16,28 +16,28 @@ package com.google.devtools.build.lib.buildeventstream.transports;
import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
-import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import java.io.IOException;
+import java.util.function.Consumer;
/**
* A simple {@link BuildEventTransport} that writes the JSON representation of the protocol-buffer
* representation of the events to a file.
*/
public final class JsonFormatFileTransport extends FileTransport {
- private final BuildEventProtocolOptions options;
- private final PathConverter pathConverter;
-
JsonFormatFileTransport(
- String path, BuildEventProtocolOptions options, PathConverter pathConverter)
- throws IOException {
- super(path);
- this.options = options;
- this.pathConverter = pathConverter;
+ String path,
+ BuildEventProtocolOptions options,
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
+ super(path, options, uploader, exitFunc);
}
@Override
@@ -47,30 +47,14 @@ public final class JsonFormatFileTransport extends FileTransport {
@Override
public synchronized void sendBuildEvent(BuildEvent event, final ArtifactGroupNamer namer) {
- BuildEventContext converters =
- new BuildEventContext() {
- @Override
- public PathConverter pathConverter() {
- return pathConverter;
- }
-
- @Override
- public ArtifactGroupNamer artifactGroupNamer() {
- return namer;
- }
-
- @Override
- public BuildEventProtocolOptions getOptions() {
- return options;
- }
- };
+ BuildEventStreamProtos.BuildEvent protoEvent = asStreamProto(event, namer);
+ if (protoEvent == null) {
+ return;
+ }
String protoJsonRepresentation;
try {
protoJsonRepresentation =
- JsonFormat.printer()
- .omittingInsignificantWhitespace()
- .print(event.asStreamProto(converters))
- + "\n";
+ JsonFormat.printer().omittingInsignificantWhitespace().print(protoEvent) + "\n";
} catch (InvalidProtocolBufferException e) {
// We don't expect any unknown Any fields in our protocol buffer. Nevertheless, handle
// the exception gracefully and, at least, return valid JSON with an id field.
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransport.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransport.java
index 2735712bfb..af1364f3bf 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransport.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/TextFormatFileTransport.java
@@ -16,12 +16,14 @@ package com.google.devtools.build.lib.buildeventstream.transports;
import com.google.devtools.build.lib.buildeventstream.ArtifactGroupNamer;
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
-import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.BuildEventTransport;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.util.AbruptExitException;
import com.google.protobuf.TextFormat;
import java.io.IOException;
+import java.util.function.Consumer;
/**
* A simple {@link BuildEventTransport} that writes the text representation of the protocol-buffer
@@ -30,15 +32,13 @@ import java.io.IOException;
* <p>This class is used for debugging.
*/
public final class TextFormatFileTransport extends FileTransport {
- private final BuildEventProtocolOptions options;
- private final PathConverter pathConverter;
-
TextFormatFileTransport(
- String path, BuildEventProtocolOptions options, PathConverter pathConverter)
- throws IOException {
- super(path);
- this.options = options;
- this.pathConverter = pathConverter;
+ String path,
+ BuildEventProtocolOptions options,
+ BuildEventArtifactUploader uploader,
+ Consumer<AbruptExitException> exitFunc)
+ throws IOException {
+ super(path, options, uploader, exitFunc);
}
@Override
@@ -48,24 +48,11 @@ public final class TextFormatFileTransport extends FileTransport {
@Override
public synchronized void sendBuildEvent(BuildEvent event, final ArtifactGroupNamer namer) {
- BuildEventContext converters =
- new BuildEventContext() {
- @Override
- public PathConverter pathConverter() {
- return pathConverter;
- }
-
- @Override
- public ArtifactGroupNamer artifactGroupNamer() {
- return namer;
- }
-
- @Override
- public BuildEventProtocolOptions getOptions() {
- return options;
- }
- };
- String protoTextRepresentation = TextFormat.printToString(event.asStreamProto(converters));
+ BuildEventStreamProtos.BuildEvent protoEvent = asStreamProto(event, namer);
+ if (protoEvent == null) {
+ return;
+ }
+ String protoTextRepresentation = TextFormat.printToString(protoEvent);
write("event {\n" + protoTextRepresentation + "}\n\n");
}
}
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 deec19e3f3..5d2c94a540 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
@@ -17,6 +17,7 @@ package com.google.devtools.build.lib.exec;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.test.TestRunnerAction;
import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
@@ -188,6 +189,15 @@ public class TestAttempt implements BuildEventWithOrderConstraint {
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ ImmutableSet.Builder<Path> artifacts = ImmutableSet.builder();
+ for (Pair<String, Path> file : files) {
+ artifacts.add(file.getSecond());
+ }
+ return artifacts.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
return GenericBuildEvent.protoChaining(this).setTestResult(asTestResult(converters)).build();
}
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
index 9201c94858..d5b0db5965 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
@@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions;
import com.google.devtools.build.lib.authandtls.GoogleAuthUtils;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
import com.google.devtools.build.lib.buildeventstream.PathConverter;
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.events.Event;
@@ -42,6 +43,7 @@ import com.google.devtools.remoteexecution.v1test.Digest;
import io.grpc.Channel;
import io.grpc.ClientInterceptors;
import java.io.IOException;
+import java.util.Set;
import java.util.concurrent.Executors;
import java.util.logging.Logger;
@@ -60,11 +62,12 @@ public final class RemoteModule extends BlazeModule {
// the PathConverter.
RemoteOptions options;
DigestUtil digestUtil;
+ PathConverter fallbackConverter = new FileUriPathConverter();
@Override
public String apply(Path path) {
if (options == null || digestUtil == null || !remoteEnabled(options)) {
- return null;
+ return fallbackConverter.apply(path);
}
String server = options.remoteCache;
String remoteInstanceName = options.remoteInstanceName;
@@ -84,7 +87,7 @@ public final class RemoteModule extends BlazeModule {
digest.getSizeBytes());
} catch (IOException e) {
// TODO(ulfjack): Don't fail silently!
- return null;
+ return fallbackConverter.apply(path);
}
}
}
@@ -95,9 +98,14 @@ public final class RemoteModule extends BlazeModule {
private RemoteActionContextProvider actionContextProvider;
@Override
- public void serverInit(OptionsProvider startupOptions, ServerBuilder builder)
- throws AbruptExitException {
- builder.addPathToUriConverter(converter);
+ public void serverInit(OptionsProvider startupOptions, ServerBuilder builder) {
+ builder.addBuildEventArtifactUploader(new BuildEventArtifactUploader() {
+ @Override
+ public PathConverter upload(Set<Path> files) {
+ // TODO(ulfjack): Actually hook up upload here.
+ return converter;
+ }
+ }, "remote");
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index d4591a46b2..44e9f61e39 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -31,7 +31,7 @@ import com.google.devtools.build.lib.analysis.ServerDirectories;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
import com.google.devtools.build.lib.analysis.test.CoverageReportActionFactory;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploaderMap;
import com.google.devtools.build.lib.clock.BlazeClock;
import com.google.devtools.build.lib.clock.Clock;
import com.google.devtools.build.lib.events.Event;
@@ -153,7 +153,7 @@ public final class BlazeRuntime {
private final String defaultsPackageContent;
private final SubscriberExceptionHandler eventBusExceptionHandler;
private final String productName;
- private final PathConverter pathToUriConverter;
+ private final BuildEventArtifactUploaderMap buildEventArtifactUploaders;
private final ActionKeyContext actionKeyContext;
// Workspace state (currently exactly one workspace per server)
@@ -178,7 +178,7 @@ public final class BlazeRuntime {
InvocationPolicy moduleInvocationPolicy,
Iterable<BlazeCommand> commands,
String productName,
- PathConverter pathToUriConverter) {
+ BuildEventArtifactUploaderMap buildEventArtifactUploaders) {
// Server state
this.fileSystem = fileSystem;
this.blazeModules = blazeModules;
@@ -205,7 +205,7 @@ public final class BlazeRuntime {
CommandNameCache.CommandNameCacheInstance.INSTANCE.setCommandNameCache(
new CommandNameCacheImpl(getCommandMap()));
this.productName = productName;
- this.pathToUriConverter = pathToUriConverter;
+ this.buildEventArtifactUploaders = buildEventArtifactUploaders;
}
public BlazeWorkspace initWorkspace(BlazeDirectories directories, BinTools binTools)
@@ -1261,8 +1261,8 @@ public final class BlazeRuntime {
return productName;
}
- public PathConverter getPathToUriConverter() {
- return pathToUriConverter;
+ public BuildEventArtifactUploaderMap getBuildEventArtifactUploaders() {
+ return buildEventArtifactUploaders;
}
/**
@@ -1369,7 +1369,7 @@ public final class BlazeRuntime {
serverBuilder.getInvocationPolicy(),
serverBuilder.getCommands(),
productName,
- serverBuilder.getPathToUriConverter());
+ serverBuilder.getBuildEventArtifactUploaderMap());
}
public Builder setProductName(String productName) {
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 b990c15c7b..431b4276ad 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
@@ -25,6 +25,7 @@ import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
import com.google.devtools.build.lib.buildeventstream.PathConverter;
import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
+import com.google.devtools.build.lib.vfs.Path;
import java.util.Collection;
/**
@@ -52,6 +53,19 @@ class NamedArtifactGroup implements BuildEvent {
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ // This has to be consistent with the code below.
+ ImmutableSet.Builder<Path> artifacts = ImmutableSet.builder();
+ for (Artifact artifact : view.directs()) {
+ if (artifact.isMiddlemanArtifact()) {
+ continue;
+ }
+ artifacts.add(artifact.getPath());
+ }
+ return artifacts.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
PathConverter pathConverter = converters.pathConverter();
ArtifactGroupNamer namer = converters.artifactGroupNamer();
@@ -59,6 +73,7 @@ class NamedArtifactGroup implements BuildEvent {
BuildEventStreamProtos.NamedSetOfFiles.Builder builder =
BuildEventStreamProtos.NamedSetOfFiles.newBuilder();
for (Artifact artifact : view.directs()) {
+ // We never want to report middleman artifacts. They are for internal use only.
if (artifact.isMiddlemanArtifact()) {
continue;
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/ServerBuilder.java b/src/main/java/com/google/devtools/build/lib/runtime/ServerBuilder.java
index b8dc2eb7ef..73bb27e67a 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/ServerBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/ServerBuilder.java
@@ -18,7 +18,8 @@ import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.devtools.build.lib.buildeventstream.PathConverter;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
+import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploaderMap;
import com.google.devtools.build.lib.packages.AttributeContainer;
import com.google.devtools.build.lib.packages.PackageFactory;
import com.google.devtools.build.lib.packages.RuleClass;
@@ -28,7 +29,6 @@ import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunctio
import com.google.devtools.build.lib.query2.output.OutputFormatter;
import com.google.devtools.build.lib.runtime.commands.InfoItem;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
-import com.google.devtools.build.lib.vfs.Path;
/**
* Builder class to create a {@link BlazeRuntime} instance. This class is part of the module API,
@@ -45,8 +45,8 @@ public final class ServerBuilder {
ImmutableList.builder();
private final ImmutableList.Builder<PackageFactory.EnvironmentExtension> environmentExtensions =
ImmutableList.builder();
- private final ImmutableList.Builder<PathConverter> pathToUriConverters
- = ImmutableList.builder();
+ private final BuildEventArtifactUploaderMap.Builder buildEventArtifactUploaders =
+ new BuildEventArtifactUploaderMap.Builder();
@VisibleForTesting
public ServerBuilder() {}
@@ -87,25 +87,8 @@ public final class ServerBuilder {
return commands.build();
}
- /**
- * Return the derived total converter from Paths to URIs. It returns the answer of the first
- * registered converter that can convert the given path, if any. If no registered converter can
- * convert the given path, the "file" URI scheme is used.
- */
- public PathConverter getPathToUriConverter() {
- final ImmutableList<PathConverter> converters = this.pathToUriConverters.build();
- return new PathConverter(){
- @Override
- public String apply(Path path) {
- for (PathConverter converter : converters) {
- String value = converter.apply(path);
- if (value != null) {
- return value;
- }
- }
- return "file://" + path.getPathString();
- }
- };
+ public BuildEventArtifactUploaderMap getBuildEventArtifactUploaderMap() {
+ return buildEventArtifactUploaders.build();
}
/**
@@ -195,11 +178,9 @@ public final class ServerBuilder {
return this;
}
- /**
- * Register a new {@link PathConverter}. Contervers are tried in the order they are registered.
- */
- public ServerBuilder addPathToUriConverter(PathConverter converter) {
- this.pathToUriConverters.add(converter);
+ public ServerBuilder addBuildEventArtifactUploader(
+ BuildEventArtifactUploader uploader, String name) {
+ buildEventArtifactUploaders.add(name, uploader);
return this;
}
}
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 97c66cb8e6..4c8d46825f 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
@@ -18,6 +18,7 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;
import com.google.devtools.build.lib.analysis.AliasProvider;
@@ -490,6 +491,14 @@ public class TestSummary implements Comparable<TestSummary>, BuildEventWithOrder
}
@Override
+ public ImmutableSet<Path> referencedLocalFiles() {
+ ImmutableSet.Builder<Path> artifacts = ImmutableSet.builder();
+ artifacts.addAll(getFailedLogs());
+ artifacts.addAll(getPassedLogs());
+ return artifacts.build();
+ }
+
+ @Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext converters) {
PathConverter pathConverter = converters.pathConverter();
BuildEventStreamProtos.TestSummary.Builder summaryBuilder =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/KnownConfigurations.java b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/KnownConfigurations.java
index 59626a73a6..32da894774 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/KnownConfigurations.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/actiongraph/KnownConfigurations.java
@@ -28,7 +28,7 @@ public class KnownConfigurations extends BaseCache<BuildEvent, AnalysisProtos.Co
@Override
AnalysisProtos.Configuration createProto(BuildEvent config, String id) {
BuildEventStreamProtos.Configuration configProto =
- config.asStreamProto(/*converters=*/ null).getConfiguration();
+ config.asStreamProto(/*context=*/ null).getConfiguration();
return AnalysisProtos.Configuration.newBuilder()
.setMnemonic(configProto.getMnemonic())
.setPlatformName(configProto.getPlatformName())