aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google
diff options
context:
space:
mode:
authorGravatar juliexxia <juliexxia@google.com>2018-03-23 14:51:43 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-03-23 14:52:55 -0700
commit64d4c652f9db83b0a5ae62f319cc442a2cb79400 (patch)
treeff6bf942c2810b1cd0b6a4774dfef19b121ea743 /src/main/java/com/google
parent6dae259c43c0688a149865bd69bee177f633e10c (diff)
Create a new output formatter for cquery which output transition information in either a FULL or LITE version. Trigger new output with the new --transitions cquery flag in the new CqueryOptions class.
PiperOrigin-RevId: 190278664
Diffstat (limited to 'src/main/java/com/google')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java75
-rw-r--r--src/main/java/com/google/devtools/build/lib/buildtool/CqueryBuildTool.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetAccessor.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/TransitionsOutputFormatterCallback.java301
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/engine/QueryParser.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/query2/output/CqueryOptions.java49
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/CqueryCommand.java6
10 files changed, 443 insertions, 33 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index 54e7468ad5..56e54a37a9 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -1390,7 +1390,7 @@ public class BuildConfiguration {
globalMakeEnvBuilder.put("GENDIR", getGenfilesDirectory().getExecPath().getPathString());
globalMakeEnv = globalMakeEnvBuilder.build();
- checksum = Fingerprint.md5Digest(buildOptions.computeCacheKey());
+ checksum = computeChecksum(buildOptions);
hashCode = computeHashCode();
ImmutableSet.Builder<String> reservedActionMnemonics = ImmutableSet.builder();
@@ -1401,6 +1401,10 @@ public class BuildConfiguration {
this.buildEventSupplier = Suppliers.memoize(this::createBuildEvent);
}
+ public static String computeChecksum(BuildOptions buildOptions) {
+ return Fingerprint.md5Digest(buildOptions.computeCacheKey());
+ }
+
/**
* Returns a copy of this configuration only including the given fragments (which the current
* configuration is assumed to have).
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
index c4ce4e5ea3..d84db4ce32 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java
@@ -21,12 +21,14 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.util.Fingerprint;
+import com.google.devtools.build.lib.util.OrderedSetMultimap;
import com.google.devtools.common.options.InvocationPolicyEnforcer;
import com.google.devtools.common.options.OptionDefinition;
import com.google.devtools.common.options.OptionsBase;
@@ -34,11 +36,13 @@ import com.google.devtools.common.options.OptionsClassProvider;
import com.google.devtools.common.options.OptionsParser;
import com.google.devtools.common.options.OptionsParsingException;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -344,16 +348,32 @@ public final class BuildOptions implements Cloneable, Serializable {
}
}
- /** Returns the difference between two BuildOptions in a {@link BuildOptions.OptionsDiff}. */
- public static OptionsDiff diff(BuildOptions first, BuildOptions second) {
+ /** Returns the difference between two BuildOptions in a new {@link BuildOptions.OptionsDiff}. */
+ public static OptionsDiff diff(@Nullable BuildOptions first, @Nullable BuildOptions second) {
+ return diff(new OptionsDiff(), first, second);
+ }
+
+ /**
+ * Returns the difference between two BuildOptions in a pre-existing {@link
+ * BuildOptions.OptionsDiff}.
+ *
+ * <p>In a single pass through this method, the method can only compare a single "first" {@link
+ * BuildOptions} and single "second" BuildOptions; but an OptionsDiff instance can store the diff
+ * between a single "first" BuildOptions and multiple "second" BuildOptions. Being able to
+ * maintain a single OptionsDiff over multiple calls to diff is useful for, for example,
+ * aggregating the difference between a single BuildOptions and the results of applying a {@link
+ * com.google.devtools.build.lib.analysis.config.transitions.SplitTransition}) to it.
+ */
+ public static OptionsDiff diff(
+ OptionsDiff diff, @Nullable BuildOptions first, @Nullable BuildOptions second) {
if (first == null || second == null) {
throw new IllegalArgumentException("Cannot diff null BuildOptions");
}
- OptionsDiff diff = new OptionsDiff();
if (first.equals(second)) {
return diff;
}
- // Check if either class has been trimmed of an options class that exists in the other.
+ // Check and report if either class has been trimmed of an options class that exists in the
+ // other.
ImmutableSet<Class<? extends FragmentOptions>> firstOptionClasses =
first.getOptions()
.stream()
@@ -405,7 +425,17 @@ public final class BuildOptions implements Cloneable, Serializable {
Collection<OptionDefinition> fields = diff.differingOptions.get(clazz);
HashMap<String, Object> valueMap = new HashMap<>(fields.size());
for (OptionDefinition optionDefinition : fields) {
- Object secondValue = diff.second.get(optionDefinition);
+ Object secondValue;
+ try {
+ secondValue = Iterables.getOnlyElement(diff.second.get(optionDefinition));
+ } catch (IllegalArgumentException e) {
+ // TODO(janakr): Currently this exception should never be thrown since diff is never
+ // constructed using the diff method that takes in a preexisting OptionsDiff. If this
+ // changes, add a test verifying this error catching works properly.
+ throw new IllegalStateException(
+ "OptionsDiffForReconstruction can only handle a single first BuildOptions and a "
+ + "single second BuildOptions and has encountered multiple second BuildOptions");
+ }
valueMap.put(optionDefinition.getField().getName(), secondValue);
}
differingOptions.put(clazz, valueMap);
@@ -419,14 +449,20 @@ public final class BuildOptions implements Cloneable, Serializable {
}
/**
- * A diff class for BuildOptions. Fields are meant to be populated and returned by
- * {@link BuildOptions#diff}
+ * A diff class for BuildOptions. Fields are meant to be populated and returned by {@link
+ * BuildOptions#diff}
*/
public static class OptionsDiff{
private final Multimap<Class<? extends FragmentOptions>, OptionDefinition> differingOptions =
ArrayListMultimap.create();
- private final Map<OptionDefinition, Object> first = new HashMap<>();
- private final Map<OptionDefinition, Object> second = new HashMap<>();
+ // The keyset for the {@link first} and {@link second} maps are identical and indicate which
+ // specific options differ between the first and second built options.
+ private final Map<OptionDefinition, Object> first = new LinkedHashMap<>();
+ // Since this class can be used to track the result of transitions, {@link second} is a multimap
+ // to be able to handle [@link SplitTransition}s.
+ private final Multimap<OptionDefinition, Object> second = OrderedSetMultimap.create();
+ // List of "extra" fragments for each BuildOption aka fragments that were trimmed off one
+ // BuildOption but not the other.
private final Set<Class<? extends FragmentOptions>> extraFirstFragments = new HashSet<>();
private final Set<FragmentOptions> extraSecondFragments = new HashSet<>();
@@ -452,7 +488,7 @@ public final class BuildOptions implements Cloneable, Serializable {
return first;
}
- public Map<OptionDefinition, Object> getSecond() {
+ public Multimap<OptionDefinition, Object> getSecond() {
return second;
}
@@ -480,17 +516,20 @@ public final class BuildOptions implements Cloneable, Serializable {
public String prettyPrint() {
StringBuilder toReturn = new StringBuilder();
- for (Map.Entry<OptionDefinition, Object> firstOption : first.entrySet()) {
- toReturn
- .append(firstOption.getKey().getOptionName())
- .append(":")
- .append(firstOption.getValue())
- .append(" -> ")
- .append(second.get(firstOption.getKey()))
- .append(System.lineSeparator());
+ for (String diff : getPrettyPrintList()) {
+ toReturn.append(diff).append(System.lineSeparator());
}
return toReturn.toString();
}
+
+ public List<String> getPrettyPrintList() {
+ List<String> toReturn = new ArrayList<>();
+ first.forEach(
+ (option, value) ->
+ toReturn.add(
+ option.getOptionName() + ":" + value + " -> " + second.get(option)));
+ return toReturn;
+ }
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/CqueryBuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/CqueryBuildTool.java
index 3bcdb3e9d0..8bf7a0b112 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/CqueryBuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/CqueryBuildTool.java
@@ -21,14 +21,16 @@ import com.google.devtools.build.lib.analysis.ViewCreationFailedException;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.query2.CommonQueryOptions;
import com.google.devtools.build.lib.query2.ConfiguredTargetQueryEnvironment;
+import com.google.devtools.build.lib.query2.TransitionsOutputFormatterCallback;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
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.query2.output.CqueryOptions;
+import com.google.devtools.build.lib.query2.output.CqueryOptions.Transitions;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.skyframe.SkyframeExecutorWrappingWalkableGraph;
import com.google.devtools.build.skyframe.WalkableGraph;
@@ -109,7 +111,6 @@ public class CqueryBuildTool extends BuildTool {
}
}
}
-
WalkableGraph walkableGraph =
SkyframeExecutorWrappingWalkableGraph.of(env.getSkyframeExecutor());
ImmutableList<QueryFunction> extraFunctions =
@@ -117,6 +118,7 @@ public class CqueryBuildTool extends BuildTool {
.addAll(ConfiguredTargetQueryEnvironment.CQUERY_FUNCTIONS)
.addAll(env.getRuntime().getQueryFunctions())
.build();
+ CqueryOptions cqueryOptions = request.getOptions(CqueryOptions.class);
ConfiguredTargetQueryEnvironment configuredTargetQueryEnvironment =
new ConfiguredTargetQueryEnvironment(
request.getKeepGoing(),
@@ -127,11 +129,17 @@ public class CqueryBuildTool extends BuildTool {
env.newTargetPatternEvaluator().getOffset(),
env.getPackageManager().getPackagePath(),
() -> walkableGraph,
- request.getOptions(CommonQueryOptions.class).toSettings());
- QueryEvalResult result =
- configuredTargetQueryEnvironment.evaluateQuery(
- queryExpression,
- new ThreadSafeOutputFormatterCallback<ConfiguredTarget>() {
+ cqueryOptions.toSettings());
+ CqueryOptions.Transitions transitions = cqueryOptions.transitions;
+ ThreadSafeOutputFormatterCallback<ConfiguredTarget> callback =
+ !transitions.equals(Transitions.NONE)
+ ? new TransitionsOutputFormatterCallback(
+ configuredTargetQueryEnvironment.getAccessor(),
+ transitions,
+ env.getReporter().getOutErr().getOutputStream(),
+ env.getSkyframeExecutor(),
+ hostConfiguration)
+ : new ThreadSafeOutputFormatterCallback<ConfiguredTarget>() {
@Override
public void processOutput(Iterable<ConfiguredTarget> partialResult)
throws IOException, InterruptedException {
@@ -147,7 +155,11 @@ public class CqueryBuildTool extends BuildTool {
env.getReporter().getOutErr().printOutLn(output.toString());
}
}
- });
+ };
+ QueryEvalResult result =
+ configuredTargetQueryEnvironment.evaluateQuery(
+ queryExpression,
+ callback);
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 8a0d01f136..2bf456c22a 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/BUILD
@@ -26,6 +26,7 @@ java_library(
"//src/main/java/com/google/devtools/build/lib:util",
"//src/main/java/com/google/devtools/build/lib/actions",
"//src/main/java/com/google/devtools/build/lib/collect/compacthashset",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/graph",
"//src/main/java/com/google/devtools/build/lib/profiler",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetAccessor.java b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetAccessor.java
index cfba199f77..eabd2c6c78 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetAccessor.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetAccessor.java
@@ -106,7 +106,7 @@ class ConfiguredTargetAccessor implements TargetAccessor<ConfiguredTarget> {
throw new UnsupportedOperationException();
}
- private Target getTargetFromConfiguredTarget(ConfiguredTarget configuredTarget) {
+ public Target getTargetFromConfiguredTarget(ConfiguredTarget configuredTarget) {
Target target = null;
try {
target =
diff --git a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java
index 776a84e28e..547d7d107b 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/ConfiguredTargetQueryEnvironment.java
@@ -148,6 +148,7 @@ public class ConfiguredTargetQueryEnvironment
this.parserPrefix = parserPrefix;
this.pkgPath = pkgPath;
this.walkableGraphSupplier = walkableGraphSupplier;
+ this.accessor = new ConfiguredTargetAccessor(walkableGraphSupplier.get());
}
private void beforeEvaluateQuery() throws InterruptedException, QueryException {
@@ -160,7 +161,6 @@ public class ConfiguredTargetQueryEnvironment
eventHandler,
FilteringPolicies.NO_FILTER,
MultisetSemaphore.unbounded());
- accessor = new ConfiguredTargetAccessor(walkableGraphSupplier.get());
checkSettings(settings);
}
@@ -175,6 +175,10 @@ public class ConfiguredTargetQueryEnvironment
return ImmutableList.of(new ConfigFunction());
}
+ public BuildConfiguration getHostConfiguration() {
+ return hostConfiguration;
+ }
+
/**
* This method has to exist because {@link AliasConfiguredTarget#getLabel()} returns
* the label of the "actual" target instead of the alias target. Grr.
diff --git a/src/main/java/com/google/devtools/build/lib/query2/TransitionsOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/TransitionsOutputFormatterCallback.java
new file mode 100644
index 0000000000..cd48b94264
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/TransitionsOutputFormatterCallback.java
@@ -0,0 +1,301 @@
+// 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.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.devtools.build.lib.analysis.AspectCollection;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.Dependency;
+import com.google.devtools.build.lib.analysis.DependencyResolver;
+import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
+import com.google.devtools.build.lib.analysis.PlatformSemantics;
+import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptions.OptionsDiff;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
+import com.google.devtools.build.lib.analysis.config.FragmentClassSet;
+import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
+import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
+import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
+import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.events.NullEventHandler;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.RuleTransitionFactory;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
+import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback;
+import com.google.devtools.build.lib.query2.output.CqueryOptions;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.util.OrderedSetMultimap;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Output formatter that prints {@link ConfigurationTransition} information for rule configured
+ * targets in the results of a cquery call.
+ */
+public class TransitionsOutputFormatterCallback
+ extends ThreadSafeOutputFormatterCallback<ConfiguredTarget> {
+
+ private final ConfiguredTargetAccessor accessor;
+ private final SkyframeExecutor skyframeExecutor;
+ private final BuildConfiguration hostConfiguration;
+ private final CqueryOptions.Transitions transitions;
+ private final HashMap<Label, Target> partialResultMap;
+
+ private PrintStream printStream = null;
+ private final List<String> result = new ArrayList<>();
+
+ /**
+ * @param accessor provider of query result configured targets.
+ * @param transitions a value of {@link CqueryOptions.Transitions} enum that signals how verbose
+ * the transition information should be.
+ * @param out output stream. This is nullable for testing purposes since tests directly access
+ * result.
+ */
+ public TransitionsOutputFormatterCallback(
+ TargetAccessor<ConfiguredTarget> accessor,
+ CqueryOptions.Transitions transitions,
+ OutputStream out,
+ SkyframeExecutor skyframeExecutor,
+ BuildConfiguration hostConfiguration) {
+ this.accessor = (ConfiguredTargetAccessor) accessor;
+ this.skyframeExecutor = skyframeExecutor;
+ this.hostConfiguration = hostConfiguration;
+ Preconditions.checkArgument(
+ !transitions.equals(CqueryOptions.Transitions.NONE),
+ "This formatter callback should never be constructed if "
+ + "CqueryOptions.Transitions == NONE.");
+ this.transitions = transitions;
+ if (out != null) {
+ this.printStream = new PrintStream(out);
+ }
+ this.partialResultMap = Maps.newHashMap();
+ }
+
+ @Override
+ public void processOutput(Iterable<ConfiguredTarget> partialResult)
+ throws IOException, InterruptedException {
+ partialResult.forEach(
+ ct -> partialResultMap.put(ct.getLabel(), accessor.getTargetFromConfiguredTarget(ct)));
+ for (ConfiguredTarget configuredTarget : partialResult) {
+ Target target = partialResultMap.get(configuredTarget.getLabel());
+ BuildConfiguration config = configuredTarget.getConfiguration();
+ addResult(
+ getRuleClassTransition(configuredTarget, target)
+ + configuredTarget.getLabel()
+ + " ("
+ + (config != null && config.isHostConfiguration() ? "HOST" : config)
+ + ")");
+ if (!(configuredTarget instanceof RuleConfiguredTarget)) {
+ continue;
+ }
+ OrderedSetMultimap<Attribute, Dependency> deps;
+ ImmutableMap<Label, ConfigMatchingProvider> configConditions =
+ ((RuleConfiguredTarget) configuredTarget).getConfigConditions();
+ BuildOptions fromOptions = config.getOptions();
+ try {
+ // Note: Being able to pull the $toolchain attr unconditionally from the mapper relies on
+ // the fact that {@link PlatformSemantics.TOOLCHAIN_ATTRS} exists in every rule.
+ // Also, we don't actually use fromOptions in our implementation of DependencyResolver but
+ // passing to avoid passing a null and since we have the information anyway.
+ deps =
+ new FormatterDependencyResolver(configuredTarget, NullEventHandler.INSTANCE)
+ .dependentNodeMap(
+ new TargetAndConfiguration(target, config),
+ hostConfiguration,
+ /*aspect=*/ null,
+ configConditions,
+ ImmutableSet.copyOf(
+ ConfiguredAttributeMapper.of(target.getAssociatedRule(), configConditions)
+ .get(PlatformSemantics.TOOLCHAINS_ATTR, BuildType.LABEL_LIST)),
+ fromOptions);
+ } catch (EvalException | InvalidConfigurationException | InconsistentAspectOrderException e) {
+ throw new InterruptedException(e.getMessage());
+ }
+ for (Map.Entry<Attribute, Dependency> attributeAndDep : deps.entries()) {
+ if (attributeAndDep.getValue().hasExplicitConfiguration()
+ || attributeAndDep.getValue().getTransition() instanceof NoTransition) {
+ continue;
+ }
+ List<BuildOptions> toOptions;
+ Dependency dep = attributeAndDep.getValue();
+ ConfigurationTransition transition = dep.getTransition();
+ if (transition instanceof SplitTransition) {
+ toOptions = ((SplitTransition) transition).split(fromOptions);
+ } else if (transition instanceof PatchTransition) {
+ toOptions = Collections.singletonList(((PatchTransition) transition).apply(fromOptions));
+ } else {
+ throw new IllegalStateException(
+ "If this error is thrown, cquery needs to be updated to take into account non-Patch"
+ + " and non-Split Transitions");
+ }
+ String hostConfigurationChecksum = hostConfiguration.checksum();
+ addResult(
+ " "
+ .concat(attributeAndDep.getKey().getName())
+ .concat("#")
+ .concat(dep.getLabel().toString())
+ .concat("#")
+ .concat(dep.getTransition().getName())
+ .concat(" ( -> ")
+ .concat(
+ toOptions
+ .stream()
+ .map(options -> {
+ String checksum = BuildConfiguration.computeChecksum(options);
+ return checksum.equals(hostConfigurationChecksum) ? "HOST" : checksum;
+ })
+ .collect(Collectors.joining(", ")))
+ .concat(")"));
+ if (transitions == CqueryOptions.Transitions.LITE) {
+ continue;
+ }
+ OptionsDiff diff = new OptionsDiff();
+ for (BuildOptions options : toOptions) {
+ diff = BuildOptions.diff(diff, fromOptions, options);
+ }
+ diff.getPrettyPrintList().forEach(singleDiff -> addResult(" " + singleDiff));
+ }
+ }
+ }
+
+ private String getRuleClassTransition(ConfiguredTarget ct, Target target) {
+ String output = "";
+ if (ct instanceof RuleConfiguredTarget) {
+ RuleTransitionFactory factory =
+ target.getAssociatedRule().getRuleClassObject().getTransitionFactory();
+ if (factory != null) {
+ output =
+ factory
+ .buildTransitionFor(target.getAssociatedRule())
+ .getClass()
+ .getSimpleName()
+ .concat(" -> ");
+ }
+ }
+ return output;
+ }
+
+ private void addResult(String string) {
+ result.add(string);
+ }
+
+ @VisibleForTesting
+ public List<String> getResult() {
+ return result;
+ }
+
+ @Override
+ public void close(boolean failFast) throws InterruptedException, IOException {
+ if (!failFast && printStream != null) {
+ result.forEach(printStream::println);
+ }
+ }
+
+ private class FormatterDependencyResolver extends DependencyResolver {
+
+ private ConfiguredTarget ct;
+ private final ExtendedEventHandler eventHandler;
+
+ private FormatterDependencyResolver(ConfiguredTarget ct, ExtendedEventHandler eventHandler) {
+ this.ct = ct;
+ this.eventHandler = eventHandler;
+ }
+
+ protected FormatterDependencyResolver setCt(ConfiguredTarget ct) {
+ this.ct = ct;
+ return this;
+ }
+
+ @Override
+ protected void invalidVisibilityReferenceHook(TargetAndConfiguration node, Label label) {
+ eventHandler.handle(
+ Event.error(
+ TargetUtils.getLocationMaybe(node.getTarget()),
+ String.format(
+ "Label '%s' in visibility attribute does not refer to a package group", label)));
+ }
+
+ @Override
+ protected void invalidPackageGroupReferenceHook(TargetAndConfiguration node, Label label) {
+ eventHandler.handle(
+ Event.error(
+ TargetUtils.getLocationMaybe(node.getTarget()),
+ String.format("label '%s' does not refer to a package group", label)));
+ }
+
+ @Override
+ protected void missingEdgeHook(Target from, Label to, NoSuchThingException e) {
+ eventHandler.handle(
+ Event.error(
+ "missing dependency from " + from.getLabel() + " to " + to + ": " + e.getMessage()));
+ }
+
+ @Override
+ protected Target getTarget(Target from, Label label, NestedSetBuilder<Label> rootCauses)
+ throws InterruptedException {
+ return partialResultMap.get(label);
+ }
+
+ @Override
+ protected List<BuildConfiguration> getConfigurations(
+ FragmentClassSet fragments,
+ Iterable<BuildOptions> buildOptions,
+ BuildOptions defaultOptions) {
+ Preconditions.checkArgument(
+ ct.getConfiguration().fragmentClasses().equals(fragments),
+ "Mismatch: %s %s",
+ ct,
+ fragments);
+ Dependency asDep =
+ Dependency.withTransitionAndAspects(
+ ct.getLabel(), NoTransition.INSTANCE, AspectCollection.EMPTY);
+ ImmutableList.Builder<BuildConfiguration> builder = ImmutableList.builder();
+ for (BuildOptions options : buildOptions) {
+ builder.add(
+ Iterables.getOnlyElement(
+ skyframeExecutor
+ .getConfigurations(eventHandler, options, ImmutableList.<Dependency>of(asDep))
+ .values()));
+ }
+ return builder.build();
+ }
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryParser.java b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryParser.java
index 8d35aedcfa..64dd0e6d95 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/engine/QueryParser.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/engine/QueryParser.java
@@ -55,7 +55,7 @@ public final class QueryParser {
/**
* Scan and parse the specified query expression.
*/
- static QueryExpression parse(String query, QueryEnvironment<?> env) throws QueryException {
+ public static QueryExpression parse(String query, QueryEnvironment<?> env) throws QueryException {
HashMap<String, QueryFunction> functions = new HashMap<>();
for (QueryFunction queryFunction : env.getFunctions()) {
functions.put(queryFunction.getName(), queryFunction);
diff --git a/src/main/java/com/google/devtools/build/lib/query2/output/CqueryOptions.java b/src/main/java/com/google/devtools/build/lib/query2/output/CqueryOptions.java
new file mode 100644
index 0000000000..9d9cb0d099
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/query2/output/CqueryOptions.java
@@ -0,0 +1,49 @@
+// 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.output;
+
+import com.google.devtools.build.lib.query2.CommonQueryOptions;
+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;
+
+/** Options class for cquery specific query options. */
+public class CqueryOptions extends CommonQueryOptions {
+
+ /** Converter for {@link CqueryOptions.Transitions} enum. */
+ public static class TransitionsConverter extends EnumConverter<Transitions> {
+ public TransitionsConverter() {
+ super(Transitions.class, "transition verbosity");
+ }
+ }
+
+ /** How much information to output about transitions. */
+ public enum Transitions {
+ FULL, /** includes everything in LITE plus transition's effect on options. */
+ LITE, /** includes which attribute the transition is applied on and class name of transition */
+ NONE /** default value, no transition information */
+ }
+
+ @Option(
+ name = "transitions",
+ converter = TransitionsConverter.class,
+ defaultValue = "none",
+ documentationCategory = OptionDocumentationCategory.QUERY,
+ effectTags = {OptionEffectTag.AFFECTS_OUTPUTS},
+ help = "The format in which cquery will print transition information."
+ )
+ public Transitions transitions;
+
+}
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
index 6a80e0849e..acd9f0d9d1 100644
--- 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
@@ -18,12 +18,12 @@ import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.buildtool.CqueryBuildTool;
import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.query2.CommonQueryOptions;
import com.google.devtools.build.lib.query2.ConfiguredTargetQueryEnvironment;
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.query2.output.CqueryOptions;
import com.google.devtools.build.lib.runtime.BlazeCommand;
import com.google.devtools.build.lib.runtime.BlazeCommandResult;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
@@ -45,7 +45,7 @@ import java.util.Set;
name = "cquery",
builds = true,
inherits = {BuildCommand.class},
- options = {CommonQueryOptions.class},
+ options = {CqueryOptions.class},
usesConfigurationOptions = true,
shortDescription = "Loads, analyzes, and queries the specified targets w/ configurations.",
allowResidue = true,
@@ -92,7 +92,7 @@ public final class CqueryCommand implements BlazeCommand {
return BlazeCommandResult.exitCode(ExitCode.COMMAND_LINE_ERROR);
}
- List<String> topLevelTargets = options.getOptions(CommonQueryOptions.class).universeScope;
+ List<String> topLevelTargets = options.getOptions(CqueryOptions.class).universeScope;
Set<String> targetPatternSet = new LinkedHashSet<>();
if (topLevelTargets.isEmpty()) {
expr.collectTargetPatterns(targetPatternSet);