Automated rollback of commit 607d0f7335f95aa0ee236ba3c18ce2a232370cdb.
*** Reason for rollback ***
It changes the output format of --output=jsonproto to ndjson (i.e. which prints out ConfiguredTarget(s) and Configuration(s) separated by a newline) instead of being wrapped by a CqueryResult. Caught by https://github.com/bazelbuild/rules_go/issues/3597.
*** Original change description ***
Add new output format for cquery `--output=streamed_proto`.
* The current state of the output formats of cquery has a few forms now:
- (UNCHANGED) `cquery --output=proto|jsonproto|textproto --proto:include_configurations`: A single CqueryResult of the specified `--output` format.
- (NEW) `cquery --output=streamed_proto --proto:include_configurations`: Multiple length-delimited `CqueryResult` protos each containing a single `ConfiguredTarget` or `Configuration`.
- (UNCHANGED) `cquery --out...
***
PiperOrigin-RevId: 543767534
Change-Id: Ib63ed4b5bc2b8e4823a4f935c1f7a32a22a80bcc
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
index b0eb759..a799e04 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryEnvironment.java
@@ -53,7 +53,6 @@
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.WalkableGraph;
-import com.google.protobuf.CodedOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
@@ -78,12 +77,6 @@
/** Cquery specific functions. */
public static final ImmutableList<QueryFunction> CQUERY_FUNCTIONS = getCqueryFunctions();
- /**
- * Pseudo-arbitrarily chosen buffer size for output. Chosen to be large enough to fit a handful of
- * messages without needing to flush to the underlying output, which may not be buffered.
- */
- private static final int OUTPUT_BUFFER_SIZE = 16384;
-
private CqueryOptions cqueryOptions;
private final TopLevelArtifactContext topLevelArtifactContext;
@@ -231,7 +224,6 @@
eventHandler,
cqueryOptions,
out,
- CodedOutputStream.newInstance(out, OUTPUT_BUFFER_SIZE),
skyframeExecutor,
accessor,
aspectResolver,
@@ -241,17 +233,6 @@
eventHandler,
cqueryOptions,
out,
- CodedOutputStream.newInstance(out, OUTPUT_BUFFER_SIZE),
- skyframeExecutor,
- accessor,
- aspectResolver,
- OutputType.DELIMITED_BINARY,
- ruleClassProvider),
- new ProtoOutputFormatterCallback(
- eventHandler,
- cqueryOptions,
- out,
- CodedOutputStream.newInstance(out, OUTPUT_BUFFER_SIZE),
skyframeExecutor,
accessor,
aspectResolver,
@@ -261,7 +242,6 @@
eventHandler,
cqueryOptions,
out,
- CodedOutputStream.newInstance(out, OUTPUT_BUFFER_SIZE),
skyframeExecutor,
accessor,
aspectResolver,
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryOptions.java
index 7876039..0d85d0d 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/CqueryOptions.java
@@ -45,9 +45,8 @@
effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
help =
"The format in which the cquery results should be printed. Allowed values for cquery "
- + "are: label, label_kind, textproto, transitions, proto, streamed_proto, jsonproto. "
- + "If you select 'transitions', you also have to specify the "
- + "--transitions=(lite|full) option.")
+ + "are: label, label_kind, textproto, transitions, proto, jsonproto. If you select "
+ + "'transitions', you also have to specify the --transitions=(lite|full) option.")
public String outputFormat;
@Option(
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
index 4fe5f64..c22c7ba 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallback.java
@@ -15,7 +15,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
-import com.google.common.base.Preconditions;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -23,7 +23,6 @@
import com.google.devtools.build.lib.actions.BuildConfigurationEvent;
import com.google.devtools.build.lib.analysis.AnalysisProtosV2;
import com.google.devtools.build.lib.analysis.AnalysisProtosV2.Configuration;
-import com.google.devtools.build.lib.analysis.AnalysisProtosV2.CqueryResult;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
@@ -40,13 +39,11 @@
import com.google.devtools.build.lib.query2.cquery.CqueryTransitionResolver.EvaluateException;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
import com.google.devtools.build.lib.query2.proto.proto2api.Build;
-import com.google.devtools.build.lib.query2.proto.proto2api.Build.QueryResult;
import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver;
import com.google.devtools.build.lib.query2.query.output.ProtoOutputFormatter;
import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
-import com.google.protobuf.CodedOutputStream;
import com.google.protobuf.Message;
import com.google.protobuf.TextFormat;
import com.google.protobuf.util.JsonFormat;
@@ -63,7 +60,6 @@
/** Defines the types of proto output this class can handle. */
public enum OutputType {
BINARY("proto"),
- DELIMITED_BINARY("streamed_proto"),
TEXT("textproto"),
JSON("jsonproto");
@@ -106,7 +102,6 @@
}
}
- private final CodedOutputStream codedOut;
private final OutputType outputType;
private final AspectResolver resolver;
private final SkyframeExecutor skyframeExecutor;
@@ -114,6 +109,8 @@
private final JsonFormat.Printer jsonPrinter = JsonFormat.printer();
private final RuleClassProvider ruleClassProvider;
+ private AnalysisProtosV2.CqueryResult.Builder protoResult;
+
private final Map<Label, Target> partialResultMap;
private ConfiguredTarget currentTarget;
@@ -121,14 +118,12 @@
ExtendedEventHandler eventHandler,
CqueryOptions options,
OutputStream out,
- CodedOutputStream codedOut,
SkyframeExecutor skyframeExecutor,
TargetAccessor<ConfiguredTarget> accessor,
AspectResolver resolver,
OutputType outputType,
RuleClassProvider ruleClassProvider) {
super(eventHandler, options, out, skyframeExecutor, accessor, /*uniquifyResults=*/ false);
- this.codedOut = codedOut;
this.outputType = outputType;
this.skyframeExecutor = skyframeExecutor;
this.resolver = resolver;
@@ -137,40 +132,31 @@
}
@Override
+ public void start() {
+ protoResult = AnalysisProtosV2.CqueryResult.newBuilder();
+ }
+
+ @Override
public void close(boolean failFast) throws IOException {
- if (failFast || printStream == null) {
- return;
- }
- if (options.protoIncludeConfigurations) {
- for (Configuration configuration : configurationCache.getConfigurations()) {
- if (outputType == OutputType.DELIMITED_BINARY) {
- // For streamed protos, we wrap each Configuration in its own CqueryResult that will be
- // written length delimited to the stream.
- writeData(
- AnalysisProtosV2.CqueryResult.newBuilder().addConfigurations(configuration).build());
- } else {
- writeData(configuration, CqueryResult.CONFIGURATIONS_FIELD_NUMBER);
- }
+ if (!failFast && printStream != null) {
+ if (options.protoIncludeConfigurations) {
+ writeData(getProtoResult());
+ } else {
+ // Documentation promises that setting this flag to false means we convert directly
+ // to the build.proto format. This is hard to test in integration testing due to the way
+ // proto output is turned readable (codex). So change the following code with caution.
+ Build.QueryResult.Builder queryResult = Build.QueryResult.newBuilder();
+ protoResult.getResultsList().forEach(ct -> queryResult.addTarget(ct.getTarget()));
+ writeData(queryResult.build());
}
+ printStream.flush();
}
- codedOut.flush();
- outputStream.flush();
- printStream.flush();
}
private void writeData(Message message) throws IOException {
- writeData(message, 0);
- }
-
- private void writeData(Message message, int fieldNumber) throws IOException {
switch (outputType) {
case BINARY:
- Preconditions.checkState(
- fieldNumber != 0, "Cannot have fieldNumber of 0 when outputType is BINARY");
- codedOut.writeMessage(fieldNumber, message);
- break;
- case DELIMITED_BINARY:
- message.writeDelimitedTo(outputStream);
+ message.writeTo(outputStream);
break;
case TEXT:
TextFormat.printer().print(message, printStream);
@@ -189,9 +175,14 @@
return outputType.formatName();
}
+ @VisibleForTesting
+ public AnalysisProtosV2.CqueryResult getProtoResult() {
+ protoResult.addAllConfigurations(configurationCache.getConfigurations());
+ return protoResult.build();
+ }
+
@Override
- public void processOutput(Iterable<ConfiguredTarget> partialResult)
- throws InterruptedException, IOException {
+ public void processOutput(Iterable<ConfiguredTarget> partialResult) throws InterruptedException {
partialResult.forEach(
kct -> partialResultMap.put(kct.getOriginalLabel(), accessor.getTarget(kct)));
@@ -248,7 +239,6 @@
throw new InterruptedException(e.getMessage());
}
}
-
builder.setTarget(targetBuilder);
if (options.protoIncludeConfigurations) {
@@ -269,33 +259,7 @@
}
}
- // There are a few cases that affect the shape of the output:
- // 1. --output=proto|textproto|jsonproto --proto:include_configurations =>
- // Writes a single CqueryResult containing all the ConfiguredTarget(s) and
- // Configuration(s) in the specified output format.
- // 2. --output=streamed_proto --proto:include_configurations =>
- // Writes multiple length delimited CqueryResult protos, each containing a single
- // ConfiguredTarget or Configuration.
- // 3. --output=proto|textproto|jsonproto --noproto:include_configurations =>
- // Writes a single QueryResult containing all the corresponding Target(s) in the
- // specified output format.
- // 4.--output=streamed_proto --noproto:include_configurations =>
- // Writes multiple length delimited Target protos.
- if (options.protoIncludeConfigurations) {
- if (outputType == OutputType.DELIMITED_BINARY) {
- // Case 2.
- writeData(AnalysisProtosV2.CqueryResult.newBuilder().addResults(builder).build());
- } else {
- // Case 1.
- writeData(builder.build(), CqueryResult.RESULTS_FIELD_NUMBER);
- }
- } else {
- // Case 3 & 4.
- // Documentation promises that setting this flag to false means we convert directly
- // to the build.proto format. This is hard to test in integration testing due to the way
- // proto output is turned readable (codex). So change the following code with caution.
- writeData(builder.build().getTarget(), QueryResult.TARGET_FIELD_NUMBER);
- }
+ protoResult.addResults(builder.build());
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
index 54e9b61..095797e 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
@@ -137,14 +137,12 @@
"//src/main/java/com/google/devtools/build/lib/query2/engine",
"//src/main/java/com/google/devtools/build/lib/query2/query/aspectresolvers",
"//src/main/java/com/google/devtools/build/lib/util:filetype",
- "//src/main/java/com/google/devtools/build/lib/util:pair",
"//src/main/protobuf:analysis_v2_java_proto",
"//src/main/protobuf:build_java_proto",
"//src/test/java/com/google/devtools/build/lib/analysis/util",
"//third_party:guava",
"//third_party:junit4",
"//third_party:truth",
- "//third_party/protobuf:protobuf_java",
],
)
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
index 6f11ee3..5819474 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/ProtoOutputFormatterCallbackTest.java
@@ -18,7 +18,6 @@
import static com.google.devtools.build.lib.packages.Attribute.attr;
import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.eventbus.EventBus;
import com.google.devtools.build.lib.analysis.AnalysisProtosV2;
@@ -41,13 +40,6 @@
import com.google.devtools.build.lib.query2.proto.proto2api.Build.ConfiguredRuleInput;
import com.google.devtools.build.lib.query2.query.aspectresolvers.AspectResolver.Mode;
import com.google.devtools.build.lib.util.FileTypeSet;
-import com.google.devtools.build.lib.util.Pair;
-import com.google.protobuf.CodedInputStream;
-import com.google.protobuf.CodedOutputStream;
-import com.google.protobuf.ExtensionRegistry;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -325,103 +317,31 @@
.containsAtLeast("//test:my_alias_rule", "//test:config1", "//test:target1");
}
- @Test
- public void testStreamedProtoAndProtoOutputsAreEquivalent() throws Exception {
- MockRule depsRule =
- () ->
- MockRule.define(
- "my_rule",
- (builder, env) ->
- builder.add(attr("deps", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE)));
- ConfiguredRuleClassProvider ruleClassProvider = setRuleClassProviders(depsRule).build();
- helper.useRuleClassProvider(ruleClassProvider);
-
- writeFile(
- "test/BUILD",
- "my_rule(name = 'my_rule',",
- " deps = select({",
- " ':garfield': ['lasagna.java', 'naps.java'],",
- " '//conditions:default': ['mondays.java']",
- " })",
- ")",
- "config_setting(",
- " name = 'garfield',",
- " values = {'foo': 'cat'}",
- ")");
- getHelper().useConfiguration("--foo=cat");
- AnalysisProtosV2.CqueryResult protoOutput = getOutput("//test:my_rule", ruleClassProvider);
- ImmutableList<AnalysisProtosV2.CqueryResult> streamedProtoOutput =
- getStreamedOutput("//test:my_rule", ruleClassProvider);
- AnalysisProtosV2.CqueryResult.Builder combinedStreamedProtoBuilder =
- AnalysisProtosV2.CqueryResult.newBuilder();
- for (AnalysisProtosV2.CqueryResult result : streamedProtoOutput) {
- if (!result.getResultsList().isEmpty()) {
- combinedStreamedProtoBuilder.addAllResults(result.getResultsList());
- }
- if (!result.getConfigurationsList().isEmpty()) {
- combinedStreamedProtoBuilder.addAllConfigurations(result.getConfigurationsList());
- }
- }
- assertThat(protoOutput)
- .ignoringRepeatedFieldOrder()
- .isEqualTo(combinedStreamedProtoBuilder.build());
- }
-
private MockRule getSimpleRule() {
return () -> MockRule.define("simple_rule");
}
private AnalysisProtosV2.CqueryResult getOutput(
String queryExpression, RuleClassProvider ruleClassProvider) throws Exception {
- CodedInputStream codedIn =
- getInputStreamsWithData(queryExpression, ruleClassProvider, OutputType.BINARY).getSecond();
- return AnalysisProtosV2.CqueryResult.parser()
- .parseFrom(codedIn, ExtensionRegistry.getEmptyRegistry());
- }
-
- private ImmutableList<AnalysisProtosV2.CqueryResult> getStreamedOutput(
- String queryExpression, RuleClassProvider ruleClassProvider) throws Exception {
- InputStream in =
- getInputStreamsWithData(queryExpression, ruleClassProvider, OutputType.DELIMITED_BINARY)
- .getFirst();
- ImmutableList.Builder<AnalysisProtosV2.CqueryResult> builder = new ImmutableList.Builder<>();
- AnalysisProtosV2.CqueryResult result;
- while ((result =
- AnalysisProtosV2.CqueryResult.parser()
- .parseDelimitedFrom(in, ExtensionRegistry.getEmptyRegistry()))
- != null) {
- builder.add(result);
- }
- return builder.build();
- }
-
- private Pair<InputStream, CodedInputStream> getInputStreamsWithData(
- String queryExpression, RuleClassProvider ruleClassProvider, OutputType outputType)
- throws Exception {
QueryExpression expression = QueryParser.parse(queryExpression, getDefaultFunctions());
Set<String> targetPatternSet = new LinkedHashSet<>();
expression.collectTargetPatterns(targetPatternSet);
helper.setQuerySettings(Setting.NO_IMPLICIT_DEPS);
PostAnalysisQueryEnvironment<ConfiguredTarget> env =
((ConfiguredTargetQueryHelper) helper).getPostAnalysisQueryEnvironment(targetPatternSet);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- CodedOutputStream codedOut = CodedOutputStream.newInstance(out);
+
ProtoOutputFormatterCallback callback =
new ProtoOutputFormatterCallback(
reporter,
options,
- out,
- codedOut,
+ /* out= */ null,
getHelper().getSkyframeExecutor(),
env.getAccessor(),
options.aspectDeps.createResolver(
getHelper().getPackageManager(), NullEventHandler.INSTANCE),
- outputType,
+ OutputType.BINARY,
ruleClassProvider);
env.evaluateQuery(expression, callback);
- codedOut.flush();
- ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
- CodedInputStream codedIn = CodedInputStream.newInstance(in);
- return new Pair<>(in, codedIn);
+ return callback.getProtoResult();
}
}