diff options
author | 2018-03-23 14:51:43 -0700 | |
---|---|---|
committer | 2018-03-23 14:52:55 -0700 | |
commit | 64d4c652f9db83b0a5ae62f319cc442a2cb79400 (patch) | |
tree | ff6bf942c2810b1cd0b6a4774dfef19b121ea743 /src/main/java/com/google | |
parent | 6dae259c43c0688a149865bd69bee177f633e10c (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')
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); |