aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar ccalvarin <ccalvarin@google.com>2017-10-10 05:29:56 +0200
committerGravatar Marcel Hlopko <hlopko@google.com>2017-10-10 11:24:42 +0200
commitceb1013c1ca0238188e2714442fcfb2efb16bc6a (patch)
tree2cdd1a3a21e716a7653c8be61d39d8b2396c7bb0 /src/main/java/com/google/devtools
parent43edc92ac185ee2f1b8d0db31943ec1655b43434 (diff)
Report the structured Bazel command line via the BEP.
This is part of the effort outlined in https://bazel.build/designs/2017/07/13/improved-command-line-reporting.html. The refactoring of the options parser is not yet complete, so we still do not have complete & correct information about the canonical command line. Where the information is blatantly incorrect, a best approximation was made, with comments and tests documenting the deficiencies. Change the names of the initial CommandLine fields in the BEP to be explicitly identified as unstructured. RELNOTES: None. PiperOrigin-RevId: 171625377
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD2
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java21
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto20
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/buildevent/BuildStartingEvent.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/CommandLineEvent.java369
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/GotOptionsEvent.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/OriginalUnstructuredCommandLineEvent.java (renamed from src/main/java/com/google/devtools/build/lib/runtime/OriginalCommandLineEvent.java)9
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionValueDescription.java7
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsProvider.java6
-rw-r--r--src/main/java/com/google/devtools/common/options/ParsedOptionDescription.java2
12 files changed, 443 insertions, 25 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index c2848dbf3e..9dfb06ba1e 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -1007,10 +1007,12 @@ java_library(
"//src/main/protobuf:action_cache_java_proto",
"//src/main/protobuf:bazel_flags_java_proto",
"//src/main/protobuf:build_java_proto",
+ "//src/main/protobuf:command_line_java_proto",
"//src/main/protobuf:command_server_java_grpc",
"//src/main/protobuf:command_server_java_proto",
"//src/main/protobuf:extra_actions_base_java_proto",
"//src/main/protobuf:invocation_policy_java_proto",
+ "//src/main/protobuf:option_filters_java_proto",
"//src/main/protobuf:test_status_java_proto",
"//third_party:guava",
"//third_party:jsr305",
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java
index 1e73efc3db..2479b59b3d 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/BuildEventId.java
@@ -88,11 +88,24 @@ public final class BuildEventId implements Serializable {
BuildEventStreamProtos.BuildEventId.newBuilder().setStarted(startedId).build());
}
- public static BuildEventId commandlineId() {
- BuildEventStreamProtos.BuildEventId.CommandLineId commandLineId =
- BuildEventStreamProtos.BuildEventId.CommandLineId.getDefaultInstance();
+ public static BuildEventId unstructuredCommandlineId() {
+ BuildEventStreamProtos.BuildEventId.UnstructuredCommandLineId commandLineId =
+ BuildEventStreamProtos.BuildEventId.UnstructuredCommandLineId.getDefaultInstance();
return new BuildEventId(
- BuildEventStreamProtos.BuildEventId.newBuilder().setCommandLine(commandLineId).build());
+ BuildEventStreamProtos.BuildEventId.newBuilder()
+ .setUnstructuredCommandLine(commandLineId)
+ .build());
+ }
+
+ public static BuildEventId structuredCommandlineId(String commandLineLabel) {
+ BuildEventStreamProtos.BuildEventId.StructuredCommandLineId commandLineId =
+ BuildEventStreamProtos.BuildEventId.StructuredCommandLineId.newBuilder()
+ .setCommandLineLabel(commandLineLabel)
+ .build();
+ return new BuildEventId(
+ BuildEventStreamProtos.BuildEventId.newBuilder()
+ .setStructuredCommandLine(commandLineId)
+ .build());
}
public static BuildEventId optionsParsedId() {
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD
index c1c65b2696..a4bd2ed85a 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/BUILD
@@ -22,6 +22,7 @@ proto_library(
name = "build_event_stream_proto",
srcs = ["build_event_stream.proto"],
deps = [
+ "//src/main/protobuf:command_line_proto",
"//src/main/protobuf:invocation_policy_proto",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
index 472f104ecc..bbe9963ab9 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/proto/build_event_stream.proto
@@ -20,6 +20,7 @@ option java_package = "com.google.devtools.build.lib.buildeventstream";
option java_outer_classname = "BuildEventStreamProtos";
import "src/main/protobuf/invocation_policy.proto";
+import "src/main/protobuf/command_line.proto";
// Identifier for a build event. It is deliberately structured to also provide
// information about which build target etc the event is related to.
@@ -53,7 +54,16 @@ message BuildEventId {
// Identifier on an event indicating the original commandline received by
// the bazel server.
- message CommandLineId {
+ message UnstructuredCommandLineId {
+ }
+
+ // Identifier on an event describing the commandline received by Bazel.
+ message StructuredCommandLineId {
+ // A title for this command line value, as there may be multiple.
+ // For example, a single invocation may wish to report both the literal and
+ // canonical command lines, and this label would be used to differentiate
+ // between both versions.
+ string command_line_label = 1;
}
// Identifier of an event indicating the workspace status.
@@ -159,7 +169,8 @@ message BuildEventId {
UnknownBuildEventId unknown = 1;
ProgressId progress = 2;
BuildStartedId started = 3;
- CommandLineId command_line = 11;
+ UnstructuredCommandLineId unstructured_command_line = 11;
+ StructuredCommandLineId structured_command_line = 18;
WorkspaceStatusId workspace_status = 14;
OptionsParsedId options_parsed = 12;
FetchId fetch = 17;
@@ -260,7 +271,7 @@ message BuildStarted {
// like name and relevant entries of rc-files and client environment variables.
// However, it does contain enough information to reproduce the build
// invocation.
-message CommandLine {
+message UnstructuredCommandLine {
repeated string args = 1;
}
@@ -531,7 +542,8 @@ message BuildEvent {
Progress progress = 3;
Aborted aborted = 4;
BuildStarted started = 5;
- CommandLine command_line = 12;
+ UnstructuredCommandLine unstructured_command_line = 12;
+ command_line.CommandLine structured_command_line = 22;
OptionsParsed options_parsed = 13;
WorkspaceStatus workspace_status = 16;
Fetch fetch = 21;
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/BuildStartingEvent.java b/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/BuildStartingEvent.java
index e84df587de..df601bb1ca 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/BuildStartingEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/buildevent/BuildStartingEvent.java
@@ -82,7 +82,7 @@ public final class BuildStartingEvent implements BuildEvent {
public Collection<BuildEventId> getChildrenEvents() {
return ImmutableList.of(
ProgressEvent.INITIAL_PROGRESS_UPDATE,
- BuildEventId.commandlineId(),
+ BuildEventId.unstructuredCommandlineId(),
BuildEventId.optionsParsedId(),
BuildEventId.workspaceStatusId(),
BuildEventId.targetPatternExpanded(request.getTargets()),
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
index 5bd9ad9f54..12d87af3ce 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeCommandDispatcher.java
@@ -231,9 +231,14 @@ public class BlazeCommandDispatcher {
parseOptionsForCommand(rcfileNotes, commandAnnotation, optionsParser, optionsMap, null, null);
if (commandAnnotation.builds()) {
+ // splits project files from targets in the traditional sense
ProjectFileSupport.handleProjectFiles(
- eventHandler, runtime.getProjectFileProvider(), workspaceDirectory, workingDirectory,
- optionsParser, commandAnnotation.name());
+ eventHandler,
+ runtime.getProjectFileProvider(),
+ workspaceDirectory,
+ workingDirectory,
+ optionsParser,
+ commandAnnotation.name());
}
// Fix-point iteration until all configs are loaded.
@@ -276,7 +281,8 @@ public class BlazeCommandDispatcher {
long firstContactTime,
Optional<List<Pair<String, String>>> startupOptionsTaggedWithBazelRc)
throws ShutdownBlazeServerException, InterruptedException {
- OriginalCommandLineEvent originalCommandLine = new OriginalCommandLineEvent(args);
+ OriginalUnstructuredCommandLineEvent originalCommandLine =
+ new OriginalUnstructuredCommandLineEvent(args);
Preconditions.checkNotNull(clientDescription);
if (args.isEmpty()) { // Default to help command if no arguments specified.
args = HELP_COMMAND;
@@ -370,7 +376,7 @@ public class BlazeCommandDispatcher {
}
private int execExclusively(
- OriginalCommandLineEvent originalCommandLine,
+ OriginalUnstructuredCommandLineEvent unstructuredServerCommandLineEvent,
InvocationPolicy invocationPolicy,
List<String> args,
OutErr outErr,
@@ -395,7 +401,11 @@ public class BlazeCommandDispatcher {
eventHandler, workspace, command, commandAnnotation, commandName, invocationPolicy, args,
optionsResult, rcfileNotes);
OptionsProvider options = optionsResult.get();
-
+ CommandLineEvent originalCommandLineEvent =
+ new CommandLineEvent.OriginalCommandLineEvent(
+ runtime, commandName, options, startupOptionsTaggedWithBazelRc);
+ CommandLineEvent canonicalCommandLineEvent =
+ new CommandLineEvent.CanonicalCommandLineEvent(runtime, commandName, options);
// The initCommand call also records the start time for the timestamp granularity monitor.
CommandEnvironment env = workspace.initCommand(commandAnnotation, options);
// Record the command's starting time for use by the commands themselves.
@@ -591,7 +601,11 @@ public class BlazeCommandDispatcher {
return e.getExitCode().getNumericExitCode();
}
- env.getEventBus().post(originalCommandLine);
+ // Log the command line now that the modules have all had a change to register their listeners
+ // to the event bus.
+ env.getEventBus().post(unstructuredServerCommandLineEvent);
+ env.getEventBus().post(originalCommandLineEvent);
+ env.getEventBus().post(canonicalCommandLineEvent);
for (BlazeModule module : runtime.getBlazeModules()) {
env.getSkyframeExecutor().injectExtraPrecomputedValues(module.getPrecomputedValues());
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandLineEvent.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandLineEvent.java
new file mode 100644
index 0000000000..232aa45123
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandLineEvent.java
@@ -0,0 +1,369 @@
+// Copyright 2017 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.runtime;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.buildeventstream.BuildEventConverters;
+import com.google.devtools.build.lib.buildeventstream.BuildEventId;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos;
+import com.google.devtools.build.lib.buildeventstream.BuildEventWithOrderConstraint;
+import com.google.devtools.build.lib.buildeventstream.GenericBuildEvent;
+import com.google.devtools.build.lib.runtime.proto.CommandLineOuterClass.ChunkList;
+import com.google.devtools.build.lib.runtime.proto.CommandLineOuterClass.CommandLine;
+import com.google.devtools.build.lib.runtime.proto.CommandLineOuterClass.CommandLineSection;
+import com.google.devtools.build.lib.runtime.proto.CommandLineOuterClass.Option;
+import com.google.devtools.build.lib.runtime.proto.CommandLineOuterClass.OptionList;
+import com.google.devtools.build.lib.util.Pair;
+import com.google.devtools.common.options.OptionDefinition;
+import com.google.devtools.common.options.OptionEffectTag;
+import com.google.devtools.common.options.OptionMetadataTag;
+import com.google.devtools.common.options.OptionPriority;
+import com.google.devtools.common.options.OptionsParser;
+import com.google.devtools.common.options.OptionsParsingException;
+import com.google.devtools.common.options.OptionsProvider;
+import com.google.devtools.common.options.ParsedOptionDescription;
+import com.google.devtools.common.options.proto.OptionFilters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+/** A build event reporting the command line by which Bazel was invoked. */
+public abstract class CommandLineEvent implements BuildEventWithOrderConstraint {
+ protected final String productName;
+ protected final OptionsProvider activeStartupOptions;
+ protected final String commandName;
+ protected final OptionsProvider commandOptions;
+
+ CommandLineEvent(
+ String productName,
+ OptionsProvider activeStartupOptions,
+ String commandName,
+ OptionsProvider commandOptions) {
+ this.productName = productName;
+ this.activeStartupOptions = activeStartupOptions;
+ this.commandName = commandName;
+ this.commandOptions = commandOptions;
+ }
+
+ @Override
+ public Collection<BuildEventId> getChildrenEvents() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public Collection<BuildEventId> postedAfter() {
+ return ImmutableList.of(BuildEventId.buildStartedId());
+ }
+
+ CommandLineSection getExecutableSection() {
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("executable")
+ .setChunkList(ChunkList.newBuilder().addChunk(productName))
+ .build();
+ }
+
+ CommandLineSection getCommandSection() {
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("command")
+ .setChunkList(ChunkList.newBuilder().addChunk(commandName))
+ .build();
+ }
+
+ /**
+ * Convert an array of tags to the equivalent proto-generated enum values.
+ *
+ * <p>The proto type is duplicate in order to not burden the OptionsParser with the proto
+ * dependency. A test guarantees that the two enum types are kept in sync with matching indices.
+ */
+ static List<OptionFilters.OptionEffectTag> getProtoEffectTags(OptionEffectTag[] tagArray) {
+ ArrayList<OptionFilters.OptionEffectTag> effectTags = new ArrayList<>(tagArray.length);
+ for (OptionEffectTag tag : tagArray) {
+ effectTags.add(OptionFilters.OptionEffectTag.forNumber(tag.getValue()));
+ }
+ return effectTags;
+ }
+
+ /**
+ * Convert an array of tags to the equivalent proto-generated enum values.
+ *
+ * <p>The proto type is duplicate in order to not burden the OptionsParser with the proto
+ * dependency. A test guarantees that the two enum types are kept in sync with matching indices.
+ */
+ static List<OptionFilters.OptionMetadataTag> getProtoMetadataTags(OptionMetadataTag[] tagArray) {
+ ArrayList<OptionFilters.OptionMetadataTag> metadataTags = new ArrayList<>(tagArray.length);
+ for (OptionMetadataTag tag : tagArray) {
+ metadataTags.add(OptionFilters.OptionMetadataTag.forNumber(tag.getValue()));
+ }
+ return metadataTags;
+ }
+
+ List<Option> getOptionListFromParsedOptionDescriptions(
+ List<ParsedOptionDescription> parsedOptionDescriptions) {
+ List<Option> options = new ArrayList<>();
+ for (ParsedOptionDescription parsedOption : parsedOptionDescriptions) {
+ options.add(
+ createOption(
+ parsedOption.getOptionDefinition(),
+ parsedOption.getCommandLineForm(),
+ parsedOption.getUnconvertedValue()));
+ }
+ return options;
+ }
+
+ private Option createOption(
+ OptionDefinition optionDefinition, String combinedForm, @Nullable String value) {
+ Option.Builder option = Option.newBuilder();
+ option.setCombinedForm(combinedForm);
+ option.setOptionName(optionDefinition.getOptionName());
+ if (value != null) {
+ option.setOptionValue(value);
+ }
+ option.addAllEffectTags(getProtoEffectTags(optionDefinition.getOptionEffectTags()));
+ option.addAllMetadataTags(getProtoMetadataTags(optionDefinition.getOptionMetadataTags()));
+ return option.build();
+ }
+
+ /**
+ * Returns the startup option section of the command line for the startup options as the server
+ * received them at its startup. Since not all client options get passed to the server as startup
+ * options, this might not represent the actual list of startup options as the user provided them.
+ */
+ CommandLineSection getActiveStartupOptions() {
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("startup options")
+ .setOptionList(
+ OptionList.newBuilder()
+ .addAllOption(
+ getOptionListFromParsedOptionDescriptions(
+ activeStartupOptions.asCompleteListOfParsedOptions())))
+ .build();
+ }
+
+ /**
+ * Returns the final part of the command line, containing whatever was left after obtaining the
+ * command and its options.
+ */
+ CommandLineSection getResidual() {
+ // Potential further split: how the residual, if any is accepted, gets interpreted depends on
+ // the command. For example, for build commands, we might want to consider separating out
+ // project files, as in runtime.commands.ProjectFileSupport. To properly report this, we would
+ // need to let the command customize how the residual is listed. This catch-all could serve
+ // as a default in this case.
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("residual")
+ .setChunkList(ChunkList.newBuilder().addAllChunk(commandOptions.getResidue()))
+ .build();
+ }
+
+ /** This reports a reassembled version of the command line as Bazel received it. */
+ public static class OriginalCommandLineEvent extends CommandLineEvent {
+ private static final String LABEL = "original";
+ private final Optional<List<Pair<String, String>>> originalStartupOptions;
+
+ public OriginalCommandLineEvent(
+ BlazeRuntime runtime,
+ String commandName,
+ OptionsProvider commandOptions,
+ Optional<List<Pair<String, String>>> originalStartupOptions) {
+ this(
+ runtime.getProductName(),
+ runtime.getStartupOptionsProvider(),
+ commandName,
+ commandOptions,
+ originalStartupOptions);
+ }
+
+ @VisibleForTesting
+ OriginalCommandLineEvent(
+ String productName,
+ OptionsProvider activeStartupOptions,
+ String commandName,
+ OptionsProvider commandOptions,
+ Optional<List<Pair<String, String>>> originalStartupOptions) {
+ super(productName, activeStartupOptions, commandName, commandOptions);
+ this.originalStartupOptions = originalStartupOptions;
+ }
+
+ @Override
+ public BuildEventId getEventId() {
+ return BuildEventId.structuredCommandlineId(LABEL);
+ }
+
+ /**
+ * Returns the literal command line options as received. These are not the final parsed values,
+ * but are passed as is from the client, so we do not have the full OptionDefinition
+ * information. In this form, only set the "combinedForm" field.
+ */
+ private CommandLineSection getStartupOptionSection() {
+ if (originalStartupOptions.isPresent()) {
+ List<Option> options = new ArrayList<>();
+ for (Pair<String, String> sourceToOptionPair : originalStartupOptions.get()) {
+ // Only add the options that were added by the command line.
+ // TODO(b/19881919) decide the format that option source information should take and then
+ // add all options, tagged with the source, instead of filtering out the rc options.
+ if (sourceToOptionPair.first != null && sourceToOptionPair.first.isEmpty()) {
+ options.add(
+ Option.newBuilder().setCombinedForm(sourceToOptionPair.getSecond()).build());
+ }
+ }
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("startup options")
+ .setOptionList(OptionList.newBuilder().addAllOption(options))
+ .build();
+ } else {
+ // If we were not provided with the startup options, fallback to reporting the active ones
+ // stored by the Bazel Runtime.
+ return getActiveStartupOptions();
+ }
+ }
+
+ private CommandLineSection getExplicitCommandOptions() {
+ List<ParsedOptionDescription> explicitOptions =
+ commandOptions
+ .asListOfExplicitOptions()
+ .stream()
+ .filter(
+ parsedOptionDescription ->
+ parsedOptionDescription.getPriority() == OptionPriority.COMMAND_LINE)
+ .collect(Collectors.toList());
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("command options")
+ .setOptionList(
+ OptionList.newBuilder()
+ .addAllOption(getOptionListFromParsedOptionDescriptions(explicitOptions)))
+ .build();
+ }
+
+ @Override
+ public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventConverters converters) {
+ return GenericBuildEvent.protoChaining(this)
+ .setStructuredCommandLine(
+ CommandLine.newBuilder()
+ .setCommandLineLabel(LABEL)
+ .addSections(getExecutableSection())
+ .addSections(getStartupOptionSection())
+ .addSections(getCommandSection())
+ .addSections(getExplicitCommandOptions())
+ .addSections(getResidual())
+ .build())
+ .build();
+ }
+ }
+
+ /** This reports the canonical form of the command line. */
+ public static class CanonicalCommandLineEvent extends CommandLineEvent {
+ private static final String LABEL = "canonical";
+
+ public CanonicalCommandLineEvent(
+ BlazeRuntime runtime, String commandName, OptionsProvider commandOptions) {
+ this(
+ runtime.getProductName(),
+ runtime.getStartupOptionsProvider(),
+ commandName,
+ commandOptions);
+ }
+
+ @VisibleForTesting
+ CanonicalCommandLineEvent(
+ String productName,
+ OptionsProvider activeStartupOptions,
+ String commandName,
+ OptionsProvider commandOptions) {
+ super(productName, activeStartupOptions, commandName, commandOptions);
+ }
+
+ @Override
+ public BuildEventId getEventId() {
+ return BuildEventId.structuredCommandlineId(LABEL);
+ }
+
+ /**
+ * Returns the effective startup options.
+ *
+ * <p>Since in this command line the command options include invocation policy's and blazercs'
+ * contents expanded fully, the list of startup options should prevent reapplication of these
+ * contents.
+ *
+ * <p>The options parser does not understand the effect of these flags, since the relationship
+ * between these startup options and the command options is not held within the options parser,
+ * so instead, we add a small hack. Remove any explicit mentions of these flags, and explicitly
+ * add the options that prevent Blaze from looking for the default rc files.
+ */
+ private CommandLineSection getCanonicalStartupOptions() {
+ List<Option> unfilteredOptions = getActiveStartupOptions().getOptionList().getOptionList();
+ // Create the fake ones to prevent reapplication of the original rc file contents.
+ OptionsParser fakeOptions = OptionsParser.newOptionsParser(BlazeServerStartupOptions.class);
+ try {
+ fakeOptions.parse("--nomaster_blazerc", "--blazerc=/dev/null");
+ } catch (OptionsParsingException e) {
+ // Unless someone changes the definition of these flags, this is impossible.
+ throw new IllegalStateException(e);
+ }
+
+ // Remove any instances of the applied, and add the new blocking ones.
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("startup options")
+ .setOptionList(
+ OptionList.newBuilder()
+ .addAllOption(
+ unfilteredOptions
+ .stream()
+ .filter(
+ option -> {
+ String optionName = option.getOptionName();
+ return !optionName.equals("blazerc")
+ && !optionName.equals("master_blazerc")
+ && !optionName.equals("invocation_policy");
+ })
+ .collect(Collectors.toList()))
+ .addAllOption(
+ getOptionListFromParsedOptionDescriptions(
+ fakeOptions.asCompleteListOfParsedOptions())))
+ .build();
+ }
+
+ /** Returns the canonical command options, overridden and default values are not listed. */
+ // TODO(b/19881919) this should use OptionValueDescription's tracking of relevant option
+ // instances, but as this is not yet possible, list the full options list.
+ private CommandLineSection getCanonicalCommandOptions() {
+ return CommandLineSection.newBuilder()
+ .setSectionLabel("command options")
+ .setOptionList(
+ OptionList.newBuilder()
+ .addAllOption(
+ getOptionListFromParsedOptionDescriptions(
+ commandOptions.asCompleteListOfParsedOptions())))
+ .build();
+ }
+
+ @Override
+ public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventConverters converters) {
+ return GenericBuildEvent.protoChaining(this)
+ .setStructuredCommandLine(
+ CommandLine.newBuilder()
+ .setCommandLineLabel(LABEL)
+ .addSections(getExecutableSection())
+ .addSections(getCanonicalStartupOptions())
+ .addSections(getCommandSection())
+ .addSections(getCanonicalCommandOptions())
+ .addSections(getResidual())
+ .build())
+ .build();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/GotOptionsEvent.java b/src/main/java/com/google/devtools/build/lib/runtime/GotOptionsEvent.java
index cf7c363872..2193761000 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/GotOptionsEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/GotOptionsEvent.java
@@ -105,6 +105,7 @@ public class GotOptionsEvent implements BuildEventWithOrderConstraint {
@Override
public Collection<BuildEventId> postedAfter() {
- return ImmutableList.of(BuildEventId.buildStartedId(), BuildEventId.commandlineId());
+ return ImmutableList.of(
+ BuildEventId.buildStartedId(), BuildEventId.unstructuredCommandlineId());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/OriginalCommandLineEvent.java b/src/main/java/com/google/devtools/build/lib/runtime/OriginalUnstructuredCommandLineEvent.java
index e6b02ba101..291f1e6f4a 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/OriginalCommandLineEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/OriginalUnstructuredCommandLineEvent.java
@@ -24,17 +24,17 @@ import java.util.Collection;
import java.util.List;
/** A build event reporting the original commandline by which bazel was invoked. */
-public class OriginalCommandLineEvent implements BuildEventWithOrderConstraint {
+public class OriginalUnstructuredCommandLineEvent implements BuildEventWithOrderConstraint {
private final ImmutableList<String> args;
- public OriginalCommandLineEvent(List<String> args) {
+ public OriginalUnstructuredCommandLineEvent(List<String> args) {
this.args = ImmutableList.copyOf(args);
}
@Override
public BuildEventId getEventId() {
- return BuildEventId.commandlineId();
+ return BuildEventId.unstructuredCommandlineId();
}
@Override
@@ -50,7 +50,8 @@ public class OriginalCommandLineEvent implements BuildEventWithOrderConstraint {
@Override
public BuildEventStreamProtos.BuildEvent asStreamProto(BuildEventConverters converters) {
return GenericBuildEvent.protoChaining(this)
- .setCommandLine(BuildEventStreamProtos.CommandLine.newBuilder().addAllArgs(args).build())
+ .setUnstructuredCommandLine(
+ BuildEventStreamProtos.UnstructuredCommandLine.newBuilder().addAllArgs(args).build())
.build();
}
}
diff --git a/src/main/java/com/google/devtools/common/options/OptionValueDescription.java b/src/main/java/com/google/devtools/common/options/OptionValueDescription.java
index 0d81d49a84..aa808e2141 100644
--- a/src/main/java/com/google/devtools/common/options/OptionValueDescription.java
+++ b/src/main/java/com/google/devtools/common/options/OptionValueDescription.java
@@ -208,8 +208,11 @@ public abstract class OptionValueDescription {
// The new value does not override the old value, as it has lower priority.
warnings.add(
String.format(
- "The lower priority option '%s' does not override the previous value '%s'",
- parsedOption.getCommandLineForm(), effectiveOptionInstance.getCommandLineForm()));
+ "The lower priority option '%s' (source %s) does not override the previous value "
+ + "'%s'",
+ parsedOption.getCommandLineForm(),
+ parsedOption.getSource(),
+ effectiveOptionInstance.getCommandLineForm()));
}
}
diff --git a/src/main/java/com/google/devtools/common/options/OptionsProvider.java b/src/main/java/com/google/devtools/common/options/OptionsProvider.java
index 1c7737fbda..5fd8ac00c1 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsProvider.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsProvider.java
@@ -39,8 +39,10 @@ public interface OptionsProvider extends OptionsClassProvider {
* specified. If an option was specified multiple times, it is included in the result multiple
* times. Does not include the residue.
*
- * <p>The returned list can be filtered if undocumented, hidden or implicit options should not be
- * displayed.
+ * <p>The returned list includes undocumented, hidden or implicit options, and should be filtered
+ * as needed. Since it includes all options parsed, it will also include both an expansion option
+ * and the options it expanded to, and so blindly using this list for a new invocation will cause
+ * double-application of these options.
*/
List<ParsedOptionDescription> asCompleteListOfParsedOptions();
diff --git a/src/main/java/com/google/devtools/common/options/ParsedOptionDescription.java b/src/main/java/com/google/devtools/common/options/ParsedOptionDescription.java
index 1f43172fb2..d5582635e3 100644
--- a/src/main/java/com/google/devtools/common/options/ParsedOptionDescription.java
+++ b/src/main/java/com/google/devtools/common/options/ParsedOptionDescription.java
@@ -115,7 +115,7 @@ public final class ParsedOptionDescription {
return unconvertedValue;
}
- OptionPriority getPriority() {
+ public OptionPriority getPriority() {
return origin.getPriority();
}