diff options
author | juliexxia <juliexxia@google.com> | 2018-01-12 18:05:46 -0800 |
---|---|---|
committer | Copybara-Service <copybara-piper@google.com> | 2018-01-12 18:07:55 -0800 |
commit | 07c4e3648e3b7a521b6706ffc5cbcdeca1ebf4e1 (patch) | |
tree | 1c7f4fdec231146e25ef4efc71f91a7da344adc5 | |
parent | b178e89e9ec079ecde901e4fca113c88e8aad317 (diff) |
Introduce the blaze cquery command as the new ui for configurable query.
before: blaze build --nobuild //foo --experimental_post_build_query="deps(//foo)"
after: blaze cquery "deps(//foo)"
pros of ui change:
- more concise
- assumes query expression targets == targets to be built (but allows for flexibility through --top_level_targets flag)
- separate from build command
- cquery command recognizes query options, build options, and its own unique set of options
cons of ui change:
- adds another command to blaze
- recognizes options that don't actually work yet -> requires more option validation
RELNOTES: None
PiperOrigin-RevId: 181816980
11 files changed, 364 insertions, 113 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD index 5f5ff0a255..a350bb06a7 100644 --- a/src/main/java/com/google/devtools/build/lib/BUILD +++ b/src/main/java/com/google/devtools/build/lib/BUILD @@ -1109,6 +1109,7 @@ java_library( "//src/main/java/com/google/devtools/build/lib/profiler/memory:allocationtracker", "//src/main/java/com/google/devtools/build/lib/query2", "//src/main/java/com/google/devtools/build/lib/query2:abstract-blaze-query-env", + "//src/main/java/com/google/devtools/build/lib/query2:common-query-options", "//src/main/java/com/google/devtools/build/lib/query2:query-engine", "//src/main/java/com/google/devtools/build/lib/query2:query-output", "//src/main/java/com/google/devtools/build/lib/shell", diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java index 35328c1908..6d400c6699 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java @@ -28,6 +28,7 @@ import com.google.devtools.build.lib.exec.ExecutionOptions; import com.google.devtools.build.lib.packages.SkylarkSemanticsOptions; import com.google.devtools.build.lib.pkgcache.LoadingOptions; import com.google.devtools.build.lib.pkgcache.PackageCacheOptions; +import com.google.devtools.build.lib.query2.engine.QueryExpression; import com.google.devtools.build.lib.runtime.BlazeCommandEventHandler; import com.google.devtools.build.lib.runtime.KeepGoingOption; import com.google.devtools.build.lib.runtime.LoadingPhaseThreadsOption; @@ -40,6 +41,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutionException; +import javax.annotation.Nullable; /** * A BuildRequest represents a single invocation of the build tool by a user. @@ -69,6 +71,8 @@ public class BuildRequest implements OptionsClassProvider { private boolean runningInEmacs; private boolean runTests; + private QueryExpression queryExpression = null; + private static final ImmutableList<Class<? extends OptionsBase>> MANDATORY_OPTIONS = ImmutableList.of( BuildRequestOptions.class, @@ -167,6 +171,22 @@ public class BuildRequest implements OptionsClassProvider { return outErr; } + /** + * If this BuildRequest was created as part of a cquery, return the query expression, if not this + * will return null. TODO(juliexxia): find a better way to get this information through to + * BuildTool without polluting BuildRequest (like put into constructor of BuildTool or refactor to + * have a cquery specific BuildTool). + */ + @Nullable + public QueryExpression getQueryExpression() { + return queryExpression; + } + + /** Set this BuildRequest's query expression. */ + public void setQueryExpression(QueryExpression expr) { + this.queryExpression = expr; + } + @Override @SuppressWarnings("unchecked") public <T extends OptionsBase> T getOptions(Class<T> clazz) { diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java index 57f0936a51..a92fbb3dc7 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java @@ -202,22 +202,6 @@ public class BuildRequestOptions extends OptionsBase { public boolean dumpToStdout; @Option( - name = "experimental_post_build_query", - defaultValue = "null", - documentationCategory = OptionDocumentationCategory.LOGGING, - effectTags = {OptionEffectTag.UNKNOWN} - ) - public String queryExpression; - - @Option( - name = "experimental_query_options", - defaultValue = "null", - documentationCategory = OptionDocumentationCategory.LOGGING, - effectTags = {OptionEffectTag.UNKNOWN} - ) - public String queryOptions; - - @Option( name = "analyze", defaultValue = "true", documentationCategory = OptionDocumentationCategory.UNDOCUMENTED, diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java index 4a7165058a..5adcbc8cc5 100644 --- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java +++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java @@ -62,9 +62,11 @@ import com.google.devtools.build.lib.pkgcache.LoadingPhaseRunner; import com.google.devtools.build.lib.pkgcache.LoadingResult; import com.google.devtools.build.lib.profiler.ProfilePhase; import com.google.devtools.build.lib.profiler.Profiler; +import com.google.devtools.build.lib.query2.CommonQueryOptions; import com.google.devtools.build.lib.query2.ConfiguredTargetQueryEnvironment; import com.google.devtools.build.lib.query2.engine.QueryEvalResult; import com.google.devtools.build.lib.query2.engine.QueryException; +import com.google.devtools.build.lib.query2.engine.QueryExpression; import com.google.devtools.build.lib.query2.engine.TargetLiteral; import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback; import com.google.devtools.build.lib.runtime.BlazeRuntime; @@ -77,7 +79,6 @@ import com.google.devtools.build.skyframe.WalkableGraph; import com.google.devtools.common.options.OptionsParsingException; import java.io.IOException; import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -237,7 +238,7 @@ public final class BuildTool { // not reproducible at the level of a single command. Either tolerate, or wipe the analysis // graph beforehand if this option is specified, or add another option to wipe if desired // (SkyframeExecutor#handleConfiguredTargetChange should be sufficient). - if (request.getBuildOptions().queryExpression != null) { + if (request.getQueryExpression() != null) { if (!env.getSkyframeExecutor().tracksStateForIncrementality()) { throw new ConfiguredTargetQueryCommandLineException( "Configured query is not allowed if incrementality state is not being kept"); @@ -415,7 +416,7 @@ public final class BuildTool { List<TargetAndConfiguration> topLevelTargetsWithConfigs) throws InterruptedException, QueryException, IOException { - String queryExpr = request.getBuildOptions().queryExpression; + QueryExpression expr = request.getQueryExpression(); // Currently, CTQE assumes that all top level targets take on the same default config and we // don't have the ability to map multiple configs to multiple top level targets. @@ -426,7 +427,7 @@ public final class BuildTool { for (TargetAndConfiguration targAndConfig : topLevelTargetsWithConfigs) { if (!targAndConfig.getConfiguration().equals(sampleConfig)) { throw new QueryException( - new TargetLiteral(queryExpr), + new TargetLiteral(expr.toString()), String.format( "Top level targets %s and %s have different configurations (top level " + "targets with different configurations is not supported)", @@ -436,7 +437,6 @@ public final class BuildTool { WalkableGraph walkableGraph = SkyframeExecutorWrappingWalkableGraph.of(env.getSkyframeExecutor()); - String queryOptions = request.getBuildOptions().queryOptions; ConfiguredTargetQueryEnvironment configuredTargetQueryEnvironment = new ConfiguredTargetQueryEnvironment( request.getKeepGoing(), @@ -447,26 +447,25 @@ public final class BuildTool { env.newTargetPatternEvaluator().getOffset(), env.getPackageManager().getPackagePath(), () -> walkableGraph, - queryOptions == null - ? new HashSet<>() - : ConfiguredTargetQueryEnvironment.parseOptions(queryOptions).toSettings()); - QueryEvalResult result = configuredTargetQueryEnvironment.evaluateQuery( - queryExpr, - new ThreadSafeOutputFormatterCallback<ConfiguredTarget>() { - @Override - public void processOutput(Iterable<ConfiguredTarget> partialResult) - throws IOException, InterruptedException { - for (ConfiguredTarget configuredTarget : partialResult) { - env.getReporter() - .getOutErr() - .printOutLn( - configuredTarget.getLabel() - + " (" - + configuredTarget.getConfiguration() - + ")"); - } - } - }); + request.getOptions(CommonQueryOptions.class).toSettings()); + QueryEvalResult result = + configuredTargetQueryEnvironment.evaluateQuery( + expr, + new ThreadSafeOutputFormatterCallback<ConfiguredTarget>() { + @Override + public void processOutput(Iterable<ConfiguredTarget> partialResult) + throws IOException, InterruptedException { + for (ConfiguredTarget configuredTarget : partialResult) { + env.getReporter() + .getOutErr() + .printOutLn( + configuredTarget.getLabel() + + " (" + + configuredTarget.getConfiguration() + + ")"); + } + } + }); if (result.isEmpty()) { env.getReporter().handle(Event.info("Empty query results")); } diff --git a/src/main/java/com/google/devtools/build/lib/query2/BUILD b/src/main/java/com/google/devtools/build/lib/query2/BUILD index 8f143033ba..8a0d01f136 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/BUILD +++ b/src/main/java/com/google/devtools/build/lib/query2/BUILD @@ -43,6 +43,7 @@ java_library( srcs = glob(["output/*.java"]), deps = [ ":abstract-blaze-query-env", + ":common-query-options", ":fake-load-target", ":query-engine", "//src/main/java/com/google/devtools/build/lib:events", @@ -74,6 +75,17 @@ java_library( ) java_library( + name = "common-query-options", + srcs = [ + "CommonQueryOptions.java", + ], + deps = [ + ":query-engine", + "//src/main/java/com/google/devtools/common/options", + ], +) + +java_library( name = "fake-load-target", srcs = [ "FakeLoadTarget.java", diff --git a/src/main/java/com/google/devtools/build/lib/query2/CommonQueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/CommonQueryOptions.java new file mode 100644 index 0000000000..7417b697ba --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/query2/CommonQueryOptions.java @@ -0,0 +1,90 @@ +// 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.query2; + +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting; +import com.google.devtools.common.options.Converters; +import com.google.devtools.common.options.Option; +import com.google.devtools.common.options.OptionDocumentationCategory; +import com.google.devtools.common.options.OptionEffectTag; +import com.google.devtools.common.options.OptionsBase; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +/** Options shared between blaze query and blaze cquery. */ +public class CommonQueryOptions extends OptionsBase { + @Option( + name = "universe_scope", + defaultValue = "", + documentationCategory = OptionDocumentationCategory.QUERY, + converter = Converters.CommaSeparatedOptionListConverter.class, + effectTags = {OptionEffectTag.LOADING_AND_ANALYSIS}, + help = + "A comma-separated set of target patterns (additive and subtractive). The query may " + + "be performed in the universe defined by the transitive closure of the specified " + + "targets. This option is used for the query and cquery commands. \n" + + "For cquery, the input to this option is the targets all answers are built under and " + + "so this option may affect configurations and transitions. If this option is not " + + "specified, the top-level targets are assumed to be the targets parsed from the " + + "query expression. Note: For cquery, not specifying this option may cause the build " + + "to break if targets parsed from the query expression are not buildable with " + + "top-level options." + ) + public List<String> universeScope; + + @Option( + name = "host_deps", + defaultValue = "true", + documentationCategory = OptionDocumentationCategory.QUERY, + effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS}, + help = + "Query: If disabled, dependencies on 'host configuration' targets will not be included in " + + "the dependency graph over which the query operates. A 'host configuration' " + + "dependency edge, such as the one from any 'proto_library' rule to the Protocol " + + "Compiler, usually points to a tool executed during the build (on the host machine) " + + "rather than a part of the same 'target' program. \n" + + "Cquery: If disabled, filters out all configured targets which cross a host " + + "transition from the top-level target that discovered this configured target. That " + + "means if the top-level target is in the target configuration, only configured " + + "targets also in the target configuration will be returned. If the top-level target " + + "is in the host configuration, only host configured targets will be returned." + ) + public boolean includeHostDeps; + + @Option( + name = "implicit_deps", + defaultValue = "true", + category = "query", + documentationCategory = OptionDocumentationCategory.QUERY, + effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS}, + help = + "If enabled, implicit dependencies will be included in the dependency graph over " + + "which the query operates. An implicit dependency is one that is not explicitly " + + "specified in the BUILD file but added by blaze." + ) + public boolean includeImplicitDeps; + + /** Return the current options as a set of QueryEnvironment settings. */ + public Set<Setting> toSettings() { + Set<Setting> settings = EnumSet.noneOf(Setting.class); + if (!includeHostDeps) { + settings.add(Setting.NO_HOST_DEPS); + } + if (!includeImplicitDeps) { + settings.add(Setting.NO_IMPLICIT_DEPS); + } + return settings; + } +} diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/QueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/output/QueryOptions.java index 328c8e71b8..70dca68c98 100644 --- a/src/main/java/com/google/devtools/build/lib/query2/output/QueryOptions.java +++ b/src/main/java/com/google/devtools/build/lib/query2/output/QueryOptions.java @@ -13,21 +13,16 @@ // limitations under the License. package com.google.devtools.build.lib.query2.output; +import com.google.devtools.build.lib.query2.CommonQueryOptions; import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting; -import com.google.devtools.common.options.Converters; import com.google.devtools.common.options.EnumConverter; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.OptionDocumentationCategory; import com.google.devtools.common.options.OptionEffectTag; -import com.google.devtools.common.options.OptionsBase; -import java.util.EnumSet; -import java.util.List; import java.util.Set; -/** - * Command-line options for the Blaze query language, revision 2. - */ -public class QueryOptions extends OptionsBase { +/** Command-line options for the Blaze query language, revision 2. */ +public class QueryOptions extends CommonQueryOptions { /** An enum converter for {@code AspectResolver.Mode} . Should be used internally only. */ public static class AspectResolutionModeConverter extends EnumConverter<AspectResolver.Mode> { public AspectResolutionModeConverter() { @@ -131,37 +126,6 @@ public class QueryOptions extends OptionsBase { public OrderOutput orderOutput; @Option( - name = "host_deps", - defaultValue = "true", - category = "query", - documentationCategory = OptionDocumentationCategory.QUERY, - effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS}, - help = - "If enabled, dependencies on 'host configuration' targets will be included in the " - + "dependency graph over which the query operates. A 'host configuration' dependency " - + "edge, such as the one from any 'proto_library' rule to the Protocol Compiler, " - + "usually points to a tool executed during the build (on the host machine) rather " - + "than a part of the same 'target' program. Queries whose purpose is to discover " - + "the set of things needed during a build will typically enable this option; queries " - + "aimed at revealing the structure of a single program will typically disable this " - + "option." - ) - public boolean includeHostDeps; - - @Option( - name = "implicit_deps", - defaultValue = "true", - category = "query", - documentationCategory = OptionDocumentationCategory.QUERY, - effectTags = {OptionEffectTag.BUILD_FILE_SEMANTICS}, - help = - "If enabled, implicit dependencies will be included in the dependency graph over " - + "which the query operates. An implicit dependency is one that is not explicitly " - + "specified in the BUILD file but added by blaze." - ) - public boolean includeImplicitDeps; - - @Option( name = "graph:node_limit", defaultValue = "512", category = "query", @@ -236,20 +200,6 @@ public class QueryOptions extends OptionsBase { public boolean strictTestSuite; @Option( - name = "universe_scope", - converter = Converters.CommaSeparatedOptionListConverter.class, - defaultValue = "", - category = "query", - documentationCategory = OptionDocumentationCategory.QUERY, - effectTags = {OptionEffectTag.CHANGES_INPUTS}, - help = - "A comma-separated set of target patterns (additive and subtractive). The query may " - + "be performed in the universe defined by the transitive closure of the specified " - + "targets." - ) - public List<String> universeScope; - - @Option( name = "relative_locations", defaultValue = "false", category = "query", @@ -318,17 +268,12 @@ public class QueryOptions extends OptionsBase { public boolean protoFlattenSelects; /** Return the current options as a set of QueryEnvironment settings. */ + @Override public Set<Setting> toSettings() { - Set<Setting> settings = EnumSet.noneOf(Setting.class); + Set<Setting> settings = super.toSettings(); if (strictTestSuite) { settings.add(Setting.TESTS_EXPRESSION_STRICT); } - if (!includeHostDeps) { - settings.add(Setting.NO_HOST_DEPS); - } - if (!includeImplicitDeps) { - settings.add(Setting.NO_IMPLICIT_DEPS); - } return settings; } } diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BuiltinCommandModule.java b/src/main/java/com/google/devtools/build/lib/runtime/BuiltinCommandModule.java index e8a9c394c9..499f54fdb8 100644 --- a/src/main/java/com/google/devtools/build/lib/runtime/BuiltinCommandModule.java +++ b/src/main/java/com/google/devtools/build/lib/runtime/BuiltinCommandModule.java @@ -17,6 +17,7 @@ import com.google.devtools.build.lib.runtime.commands.BuildCommand; import com.google.devtools.build.lib.runtime.commands.CanonicalizeCommand; import com.google.devtools.build.lib.runtime.commands.CleanCommand; import com.google.devtools.build.lib.runtime.commands.CoverageCommand; +import com.google.devtools.build.lib.runtime.commands.CqueryCommand; import com.google.devtools.build.lib.runtime.commands.DumpCommand; import com.google.devtools.build.lib.runtime.commands.HelpCommand; import com.google.devtools.build.lib.runtime.commands.InfoCommand; @@ -50,7 +51,8 @@ public final class BuiltinCommandModule extends BlazeModule { new RunCommand(), new ShutdownCommand(), new TestCommand(), - new VersionCommand()); + new VersionCommand(), + new CqueryCommand()); // Only enable the "license" command when this binary has an embedded LICENSE file. if (LicenseCommand.isSupported()) { builder.addCommands(new LicenseCommand()); diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/CqueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/CqueryCommand.java new file mode 100644 index 0000000000..9c1ba0abb5 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/CqueryCommand.java @@ -0,0 +1,110 @@ +// 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.runtime.commands; + +import com.google.common.base.Joiner; +import com.google.common.collect.ImmutableList; +import com.google.devtools.build.lib.buildtool.BuildRequest; +import com.google.devtools.build.lib.buildtool.BuildTool; +import com.google.devtools.build.lib.events.Event; +import com.google.devtools.build.lib.query2.CommonQueryOptions; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment; +import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction; +import com.google.devtools.build.lib.query2.engine.QueryException; +import com.google.devtools.build.lib.query2.engine.QueryExpression; +import com.google.devtools.build.lib.query2.engine.QueryParser; +import com.google.devtools.build.lib.runtime.BlazeCommand; +import com.google.devtools.build.lib.runtime.BlazeRuntime; +import com.google.devtools.build.lib.runtime.Command; +import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.util.ExitCode; +import com.google.devtools.common.options.OptionPriority.PriorityCategory; +import com.google.devtools.common.options.OptionsParser; +import com.google.devtools.common.options.OptionsParsingException; +import com.google.devtools.common.options.OptionsProvider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** Handles the 'cquery' command on the Blaze command line. */ +@Command( + name = "cquery", + builds = true, + inherits = {BuildCommand.class}, + options = {CommonQueryOptions.class}, + usesConfigurationOptions = true, + shortDescription = "Loads, analyzes, and queries the specified targets w/ configurations.", + allowResidue = true, + completion = "label", + help = "resource:cquery.txt" +) +public final class CqueryCommand implements BlazeCommand { + + @Override + public void editOptions(OptionsParser optionsParser) { + try { + optionsParser.parse( + PriorityCategory.COMPUTED_DEFAULT, + "Options required by cquery", + ImmutableList.of("--nobuild")); + } catch (OptionsParsingException e) { + throw new IllegalStateException("Cquery's known options failed to parse", e); + } + } + + @Override + public ExitCode exec(CommandEnvironment env, OptionsProvider options) { + if (options.getResidue().isEmpty()) { + env.getReporter() + .handle( + Event.error( + "Missing query expression. Use the 'help cquery' command for syntax and help.")); + return ExitCode.COMMAND_LINE_ERROR; + } + String query = Joiner.on(' ').join(options.getResidue()); + HashMap<String, QueryFunction> functions = new HashMap<>(); + for (QueryFunction queryFunction : QueryEnvironment.DEFAULT_QUERY_FUNCTIONS) { + functions.put(queryFunction.getName(), queryFunction); + } + QueryExpression expr; + try { + expr = QueryParser.parse(query, functions); + } catch (QueryException e) { + env.getReporter() + .handle(Event.error("Error while parsing '" + query + "': " + e.getMessage())); + return ExitCode.COMMAND_LINE_ERROR; + } + + List<String> topLevelTargets = options.getOptions(CommonQueryOptions.class).universeScope; + Set<String> targetPatternSet = new LinkedHashSet<>(); + if (topLevelTargets.isEmpty()) { + expr.collectTargetPatterns(targetPatternSet); + topLevelTargets = new ArrayList<>(targetPatternSet); + } + BlazeRuntime runtime = env.getRuntime(); + BuildRequest request = + BuildRequest.create( + getClass().getAnnotation(Command.class).name(), + options, + runtime.getStartupOptionsProvider(), + topLevelTargets, + env.getReporter().getOutErr(), + env.getCommandId(), + env.getCommandStartTime()); + request.setQueryExpression(expr); + return new BuildTool(env).processRequest(request, null).getExitCondition(); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/cquery.txt b/src/main/java/com/google/devtools/build/lib/runtime/commands/cquery.txt new file mode 100644 index 0000000000..e631bca01b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/cquery.txt @@ -0,0 +1,8 @@ + +Usage: %{product} %{command} <options> <targets> + +Queries the specified targets, taking options into account. Unlike query, +cquery works on the post analysis phase configured target graph. It understands +and takes into account configurations and configuration transitions. + +%{options} diff --git a/src/test/shell/integration/configured_query_test.sh b/src/test/shell/integration/configured_query_test.sh index 240beaac76..6a45a89b0f 100755 --- a/src/test/shell/integration/configured_query_test.sh +++ b/src/test/shell/integration/configured_query_test.sh @@ -14,7 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# configured_query_test.sh: integration tests for bazel configured query +# configured_query_test.sh: integration tests for bazel configured query. +# This tests the command line ui of configured query while +# ConfiguredTargetQueryTest tests its internal functionality. # Load the test setup defined in the parent directory CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -26,22 +28,48 @@ add_to_bazelrc "build --package_path=%workspace%" #### TESTS ############################################################# function test_basic_query() { - rm -rf maple - mkdir -p maple - cat > maple/BUILD <<EOF + rm -rf maple + mkdir -p maple + cat > maple/BUILD <<EOF sh_library(name='maple', deps=[':japanese']) sh_library(name='japanese') EOF - bazel build --nobuild //maple \ - --experimental_post_build_query='deps(//maple)' > output 2>"$TEST_log" \ - || fail "Expected success" - cat output >> "$TEST_log" + bazel cquery 'deps(//maple)' > output 2>"$TEST_log" || fail "Expected success" assert_contains "//maple:maple" output assert_contains "//maple:japanese" output } +function test_respects_selects() { + rm -rf ash + mkdir -p ash + cat > ash/BUILD <<EOF +sh_library( + name = "ash", + deps = select({ + ":excelsior": [":foo"], + ":americana": [":bar"], + }), +) +sh_library(name = "foo") +sh_library(name = "bar") +config_setting( + name = "excelsior", + values = {"define": "species=excelsior"}, +) +config_setting( + name = "americana", + values = {"define": "species=americana"}, +) +EOF + + bazel cquery 'deps(//ash)' --define species=excelsior > output \ + 2>"$TEST_log" || fail "Excepted success" + assert_contains "//ash:foo" output + assert_not_contains "//ash:bar" output +} + function test_empty_results_printed() { rm -rf redwood mkdir -p redwood @@ -51,15 +79,67 @@ sh_library(name='sequoia') sh_library(name='sequoiadendron') EOF - bazel build --nobuild //redwood \ - --experimental_post_build_query='somepath(//redwood:sequoia,//redwood:sequoiadendron)' \ + bazel cquery 'somepath(//redwood:sequoia,//redwood:sequoiadendron)' \ > output 2>"$TEST_log" || fail "Expected success" expect_log "INFO: Empty query results" - expect_not_log "//redwood:sequoiadendreon" + assert_not_contains "//redwood:sequoiadendreon" output +} + +function test_universe_scope_specified() { + write_java_library_build + + # The java_library rule has a host transition on its plugins attribute. + bazel cquery //pine:dep+//pine:plugin --universe_scope=//pine:my_java \ + > output 2>"$TEST_log" || fail "Excepted success" + # Find the lines of output for //pine:plugin and //pine:dep. + PINE_HOST=$(grep "//pine:plugin" output) + PINE_TARGET=$(grep "//pine:dep" output) + # Trim to just configurations. + HOST_CONFIG=${PINE_HOST/"//pine:plugin"} + TARGET_CONFIG=${PINE_TARGET/"//pine:dep"} + # Ensure they are are not equal. + assert_not_equals $HOST_CONFIG $TARGET_CONFIG } +# This test ensures the known buggy behavior described at b/71905538 i.e. nodes +# lingering from previous builds. +# TODO(juliexxia): Remove this test once b/71905538 is fixed. +function test_ghost_nodes_bug() { + write_java_library_build + + # Create host-configured //pine:plugin node in this cquery + bazel cquery "deps(//pine:my_java)" || fail "Excepted success" + # This cquery should return target configured //pine:plugin but returns + # the host-configured target generated above. + bazel cquery //pine:dep+//pine:plugin \ + > output 2>"$TEST_log" || fail "Excepted success" + + # Find the lines of output for //pine:plugin and //pine:dep. + PLUGIN=$(grep "//pine:plugin" output) + DEP=$(grep "//pine:dep" output) + # Trim to just configurations. + PLUGIN_CONFIG=${PLUGIN/"//pine:plugin"} + DEP_CONFIG=${DEP/"//pine:dep"} + # Ensure they are are not equal (the buggy behavior). + assert_not_equals $PLUGIN_CONFIG $DEP_CONFIG +} + +function write_java_library_build() { + rm -rf pine + mkdir -p pine + cat > pine/BUILD <<EOF +java_library( + name = "my_java", + srcs = ['foo.java'], + deps = [":dep"], + plugins = [":plugin"] +) +java_library(name = "dep") +java_plugin(name = "plugin") +EOF +} function tear_down() { bazel shutdown |