Skip to content

Commit 9a047de

Browse files
Googlercopybara-github
authored andcommitted
Announce an ExecRequest event for run commands on the BEP.
Also introduce `--experimental_bep_exec_request_include_residue` to optionally include the residue of the run command in said `ExecRequest`. Currently the client on `bazel run` commands uses the `ExecRequest` returned via the grpc stream from the server to run the built executable. With this change, the BEP is an alternative location to observe the `ExecRequest`. `bazel run` commands now delegate to `RunBuildCompleteEvent` for `BuildCompleteEvent` information - this allows the `ExecRequestEvent` to be sent before `BuildCompleteEvent`. PiperOrigin-RevId: 553159588 Change-Id: I166a75ddefdbe6101a4d0bd76b6cd4b29aa2bcc0
1 parent 3da12c8 commit 9a047de

File tree

8 files changed

+305
-37
lines changed

8 files changed

+305
-37
lines changed

src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventIdUtil.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ public static ConfigurationId configurationIdMessage(String checksum) {
122122
return ConfigurationId.newBuilder().setId(checksum).build();
123123
}
124124

125+
public static BuildEventId execRequestId() {
126+
return BuildEventId.newBuilder()
127+
.setExecRequest(BuildEventId.ExecRequestId.getDefaultInstance())
128+
.build();
129+
}
130+
125131
public static BuildEventId nullConfigurationId() {
126132
return NULL_CONFIGURATION_ID;
127133
}

src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventProtocolOptions.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,12 @@ public class BuildEventProtocolOptions extends OptionsBase {
9595
effectTags = {OptionEffectTag.UNKNOWN},
9696
help = "Whether to publish TargetSummary events.")
9797
public boolean publishTargetSummary;
98+
99+
@Option(
100+
name = "experimental_bep_exec_request_include_residue",
101+
defaultValue = "false",
102+
documentationCategory = OptionDocumentationCategory.LOGGING,
103+
effectTags = {OptionEffectTag.AFFECTS_OUTPUTS},
104+
help = "Whether to include the residue in ExecRequest events.")
105+
public boolean includeResidueInExecRequest;
98106
}

src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ message BuildEventId {
230230
// Identifier of an event signalling that the coverage actions are finished.
231231
message CoverageActionsFinishedId {}
232232

233+
// Identifier of an event providing the ExecRequest of a run command.
234+
message ExecRequestId {}
235+
233236
oneof id {
234237
UnknownBuildEventId unknown = 1;
235238
ProgressId progress = 2;
@@ -258,6 +261,7 @@ message BuildEventId {
258261
BuildMetadataId build_metadata = 24;
259262
ConvenienceSymlinksIdentifiedId convenience_symlinks_identified = 25;
260263
CoverageActionsFinishedId coverage_actions_finished = 27;
264+
ExecRequestId exec_request = 28;
261265
}
262266
}
263267

@@ -1205,6 +1209,21 @@ message ConvenienceSymlink {
12051209
string target = 3;
12061210
}
12071211

1212+
// Event that contains the ExecRequest of a run command announced only after a
1213+
// successful build and before trying to execute the requested command-line.
1214+
message ExecRequestConstructed {
1215+
bytes working_directory = 1;
1216+
repeated bytes argv = 2;
1217+
repeated EnvironmentVariable environment_variable = 3;
1218+
repeated bytes environment_variable_to_clear = 4;
1219+
}
1220+
1221+
// An environment variable provided by a run command after a successful build.
1222+
message EnvironmentVariable {
1223+
bytes name = 1;
1224+
bytes value = 2;
1225+
}
1226+
12081227
// Message describing a build event. Events will have an identifier that
12091228
// is unique within a given build invocation; they also announce follow-up
12101229
// events as children. More details, which are specific to the kind of event
@@ -1239,5 +1258,6 @@ message BuildEvent {
12391258
WorkspaceConfig workspace_info = 25;
12401259
BuildMetadata build_metadata = 26;
12411260
ConvenienceSymlinksIdentified convenience_symlinks_identified = 27;
1261+
ExecRequestConstructed exec_request = 29;
12421262
}
12431263
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2023 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package com.google.devtools.build.lib.buildtool.buildevent;
15+
16+
import com.google.common.collect.ImmutableList;
17+
import com.google.devtools.build.lib.buildeventstream.BuildEvent;
18+
import com.google.devtools.build.lib.buildeventstream.BuildEventContext;
19+
import com.google.devtools.build.lib.buildeventstream.BuildEventIdUtil;
20+
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
21+
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
22+
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.EnvironmentVariable;
23+
import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
24+
import com.google.devtools.build.lib.server.CommandProtos;
25+
import com.google.devtools.build.lib.server.CommandProtos.ExecRequest;
26+
import com.google.protobuf.ByteString;
27+
import java.util.Collection;
28+
29+
/**
30+
* Event triggered after building of the run command has completed and the {@link ExecRequest} has
31+
* been constructed.
32+
*/
33+
public class ExecRequestEvent implements BuildEvent {
34+
35+
private final ExecRequest execRequest;
36+
private final boolean includeResidue;
37+
38+
public ExecRequestEvent(ExecRequest execRequest, boolean includeResidue) {
39+
this.execRequest = execRequest;
40+
this.includeResidue = includeResidue;
41+
}
42+
43+
@Override
44+
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventContext context) {
45+
BuildEventStreamProtos.ExecRequestConstructed.Builder builder =
46+
BuildEventStreamProtos.ExecRequestConstructed.newBuilder();
47+
builder.setWorkingDirectory(execRequest.getWorkingDirectory());
48+
if (includeResidue) {
49+
for (ByteString argv : execRequest.getArgvList()) {
50+
builder.addArgv(argv);
51+
}
52+
}
53+
for (CommandProtos.EnvironmentVariable environmentVariable :
54+
execRequest.getEnvironmentVariableList()) {
55+
builder.addEnvironmentVariable(
56+
EnvironmentVariable.newBuilder()
57+
.setName(environmentVariable.getName())
58+
.setValue(environmentVariable.getValue()));
59+
}
60+
for (ByteString envVarToClear : execRequest.getEnvironmentVariableToClearList()) {
61+
builder.addEnvironmentVariableToClear(envVarToClear);
62+
}
63+
return GenericBuildEvent.protoChaining(this).setExecRequest(builder.build()).build();
64+
}
65+
66+
@Override
67+
public BuildEventId getEventId() {
68+
return BuildEventIdUtil.execRequestId();
69+
}
70+
71+
@Override
72+
public Collection<BuildEventId> getChildrenEvents() {
73+
return ImmutableList.of();
74+
}
75+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2023 The Bazel Authors. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package com.google.devtools.build.lib.buildtool.buildevent;
15+
16+
import com.google.devtools.build.lib.buildeventstream.BuildCompletingEvent;
17+
import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
18+
import com.google.devtools.build.lib.util.ExitCode;
19+
import java.util.Collection;
20+
21+
/**
22+
* Event triggered during a run command after the requested binary has been built but before it has
23+
* been run.
24+
*
25+
* <p>This event is used by the BEP to construct the {@link
26+
* com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildFinished} event when
27+
* the run command is used.
28+
*/
29+
public class RunBuildCompleteEvent extends BuildCompletingEvent {
30+
31+
public RunBuildCompleteEvent(
32+
ExitCode exitCode, long finishTimeMillis, Collection<BuildEventId> children) {
33+
super(exitCode, finishTimeMillis, children);
34+
}
35+
36+
public RunBuildCompleteEvent(ExitCode exitCode, long finishTimeMillis) {
37+
super(exitCode, finishTimeMillis);
38+
}
39+
}

src/main/java/com/google/devtools/build/lib/runtime/BuildEventStreamer.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ private enum RetentionDecision {
119119
@GuardedBy("this")
120120
private final Set<AbortReason> abortReasons = new LinkedHashSet<>();
121121

122-
// Will be set to true if the build was invoked through "bazel test" or "bazel coverage".
123-
private boolean isTestCommand;
122+
// Will be set to true if the build was invoked through "bazel test", "bazel coverage", or
123+
// "bazel run".
124+
private boolean isCommandToSkipBuildCompleteEvent;
124125

125126
// After #buildComplete is called, contains the set of events that the streamer is expected to
126127
// process. The streamer will fully close after seeing them. This field is null until
@@ -461,9 +462,10 @@ public void buildEvent(BuildEvent event) {
461462

462463
if (event instanceof BuildStartingEvent) {
463464
BuildRequest buildRequest = ((BuildStartingEvent) event).request();
464-
isTestCommand =
465-
"test".equals(buildRequest.getCommandName())
466-
|| "coverage".equals(buildRequest.getCommandName());
465+
isCommandToSkipBuildCompleteEvent =
466+
buildRequest.getCommandName().equals("test")
467+
|| buildRequest.getCommandName().equals("coverage")
468+
|| buildRequest.getCommandName().equals("run");
467469
}
468470

469471
if (event instanceof BuildEventWithConfiguration) {
@@ -721,9 +723,9 @@ private RetentionDecision routeBuildEvent(BuildEvent event) {
721723
return RetentionDecision.DISCARD;
722724
}
723725

724-
if (isTestCommand && event instanceof BuildCompleteEvent) {
725-
// In case of "bazel test" ignore the BuildCompleteEvent, as it will be followed by a
726-
// TestingCompleteEvent that contains the correct exit code.
726+
if (isCommandToSkipBuildCompleteEvent && event instanceof BuildCompleteEvent) {
727+
// In case of "bazel test" or "bazel run" ignore the BuildCompleteEvent, as it will be
728+
// followed by a TestingCompleteEvent that contains the correct exit code.
727729
return isCrash((BuildCompleteEvent) event)
728730
? RetentionDecision.POST
729731
: RetentionDecision.DISCARD;

0 commit comments

Comments
 (0)