blob: 1a3749e433456f4a400769dcdf781e6128d13f97 [file] [log] [blame]
twerthfc6c7422018-06-28 10:18:39 -07001// Copyright 2018 The Bazel Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package com.google.devtools.build.lib.query2;
15
juliexxia5281eee2018-10-03 12:24:01 -070016import com.google.common.base.Preconditions;
twerthfc6c7422018-06-28 10:18:39 -070017import com.google.common.collect.ImmutableList;
juliexxia5281eee2018-10-03 12:24:01 -070018import com.google.common.collect.ImmutableMap;
twerthfc6c7422018-06-28 10:18:39 -070019import com.google.common.collect.ImmutableSet;
juliexxia5281eee2018-10-03 12:24:01 -070020import com.google.common.collect.ImmutableSortedSet;
twerthfc6c7422018-06-28 10:18:39 -070021import com.google.common.collect.Iterables;
22import com.google.common.collect.Maps;
23import com.google.common.collect.Sets;
juliexxia5281eee2018-10-03 12:24:01 -070024import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
twerthfc6c7422018-06-28 10:18:39 -070025import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
John Caterb3b3e8b2019-04-03 09:18:42 -070026import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
twerthfc6c7422018-06-28 10:18:39 -070027import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
28import com.google.devtools.build.lib.cmdline.Label;
29import com.google.devtools.build.lib.cmdline.TargetParsingException;
30import com.google.devtools.build.lib.cmdline.TargetPattern;
31import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet;
32import com.google.devtools.build.lib.concurrent.MultisetSemaphore;
33import com.google.devtools.build.lib.events.Event;
34import com.google.devtools.build.lib.events.ExtendedEventHandler;
twerthfc6c7422018-06-28 10:18:39 -070035import com.google.devtools.build.lib.packages.DependencyFilter;
36import com.google.devtools.build.lib.packages.NoSuchTargetException;
37import com.google.devtools.build.lib.packages.Rule;
twerthfc6c7422018-06-28 10:18:39 -070038import com.google.devtools.build.lib.packages.Target;
39import com.google.devtools.build.lib.pkgcache.FilteringPolicies;
40import com.google.devtools.build.lib.pkgcache.PackageManager;
41import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
michajloe7496772019-08-22 16:55:33 -070042import com.google.devtools.build.lib.query2.common.AbstractBlazeQueryEnvironment;
twerthfc6c7422018-06-28 10:18:39 -070043import com.google.devtools.build.lib.query2.engine.KeyExtractor;
44import com.google.devtools.build.lib.query2.engine.MinDepthUniquifier;
45import com.google.devtools.build.lib.query2.engine.QueryEnvironment;
46import com.google.devtools.build.lib.query2.engine.QueryEvalResult;
47import com.google.devtools.build.lib.query2.engine.QueryException;
48import com.google.devtools.build.lib.query2.engine.QueryExpression;
49import com.google.devtools.build.lib.query2.engine.QueryExpressionContext;
50import com.google.devtools.build.lib.query2.engine.QueryUtil.MinDepthUniquifierImpl;
51import com.google.devtools.build.lib.query2.engine.QueryUtil.MutableKeyExtractorBackedMapImpl;
52import com.google.devtools.build.lib.query2.engine.QueryUtil.UniquifierImpl;
53import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback;
54import com.google.devtools.build.lib.query2.engine.Uniquifier;
55import com.google.devtools.build.lib.rules.AliasConfiguredTarget;
lebad52f31d2019-03-25 20:05:31 -070056import com.google.devtools.build.lib.skyframe.BlacklistedPackagePrefixesValue;
twerthfc6c7422018-06-28 10:18:39 -070057import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
58import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue;
59import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider;
60import com.google.devtools.build.lib.skyframe.PackageValue;
61import com.google.devtools.build.lib.skyframe.RecursivePackageProviderBackedTargetPatternResolver;
62import com.google.devtools.build.lib.skyframe.RecursivePkgValueRootPackageExtractor;
63import com.google.devtools.build.lib.skyframe.SkyFunctions;
64import com.google.devtools.build.lib.skyframe.SkyframeExecutor;
65import com.google.devtools.build.lib.skyframe.TargetPatternValue;
66import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey;
lebad52f31d2019-03-25 20:05:31 -070067import com.google.devtools.build.lib.vfs.PathFragment;
twerthfc6c7422018-06-28 10:18:39 -070068import com.google.devtools.build.skyframe.SkyKey;
69import com.google.devtools.build.skyframe.WalkableGraph;
70import java.io.IOException;
nharmatab5852612018-11-05 10:49:11 -080071import java.io.OutputStream;
twerthfc6c7422018-06-28 10:18:39 -070072import java.util.Collection;
73import java.util.Collections;
juliexxia5281eee2018-10-03 12:24:01 -070074import java.util.Comparator;
twerthfc6c7422018-06-28 10:18:39 -070075import java.util.HashMap;
76import java.util.Map;
77import java.util.Set;
78import java.util.function.Function;
79import java.util.function.Supplier;
80import java.util.stream.Collectors;
81import javax.annotation.Nullable;
82
83/**
84 * {@link QueryEnvironment} that runs queries based on results from the analysis phase.
85 *
86 * <p>This environment can theoretically be used for multiple queries, but currently is only ever
87 * used for one over the course of its lifetime. If this ever changed to be used for multiple, the
88 * {@link TargetAccessor} field should be initialized on a per-query basis not a per-environment
89 * basis.
90 *
91 * <p>Aspects are also not supported, but probably should be in some fashion.
92 */
twerth8c11fe92018-07-10 05:59:01 -070093public abstract class PostAnalysisQueryEnvironment<T> extends AbstractBlazeQueryEnvironment<T> {
juliexxia5281eee2018-10-03 12:24:01 -070094 protected final TopLevelConfigurations topLevelConfigurations;
twerthfc6c7422018-06-28 10:18:39 -070095 protected final BuildConfiguration hostConfiguration;
96 private final String parserPrefix;
97 private final PathPackageLocator pkgPath;
98 private final Supplier<WalkableGraph> walkableGraphSupplier;
twerthfc6c7422018-06-28 10:18:39 -070099 protected WalkableGraph graph;
100
101 private static final Function<SkyKey, ConfiguredTargetKey> SKYKEY_TO_CTKEY =
102 skyKey -> (ConfiguredTargetKey) skyKey.argument();
adgarb70e6362019-11-21 16:54:09 -0800103 private static final ImmutableList<TargetPattern> ALL_PATTERNS =
104 ImmutableList.of(TargetPattern.defaultParser().parseConstantUnchecked("//..."));
twerthfc6c7422018-06-28 10:18:39 -0700105
106 protected RecursivePackageProviderBackedTargetPatternResolver resolver;
107
108 public PostAnalysisQueryEnvironment(
109 boolean keepGoing,
110 ExtendedEventHandler eventHandler,
111 Iterable<QueryFunction> extraFunctions,
juliexxia5281eee2018-10-03 12:24:01 -0700112 TopLevelConfigurations topLevelConfigurations,
twerthfc6c7422018-06-28 10:18:39 -0700113 BuildConfiguration hostConfiguration,
114 String parserPrefix,
115 PathPackageLocator pkgPath,
116 Supplier<WalkableGraph> walkableGraphSupplier,
nharmataf4023b92018-11-07 14:33:51 -0800117 Set<Setting> settings) {
twerthfc6c7422018-06-28 10:18:39 -0700118 super(keepGoing, true, Rule.ALL_LABELS, eventHandler, settings, extraFunctions);
juliexxia5281eee2018-10-03 12:24:01 -0700119 this.topLevelConfigurations = topLevelConfigurations;
twerthfc6c7422018-06-28 10:18:39 -0700120 this.hostConfiguration = hostConfiguration;
121 this.parserPrefix = parserPrefix;
122 this.pkgPath = pkgPath;
123 this.walkableGraphSupplier = walkableGraphSupplier;
twerthfc6c7422018-06-28 10:18:39 -0700124 }
125
twerth8c11fe92018-07-10 05:59:01 -0700126 public abstract ImmutableList<NamedThreadSafeOutputFormatterCallback<T>>
127 getDefaultOutputFormatters(
128 TargetAccessor<T> accessor,
nharmatab5852612018-11-05 10:49:11 -0800129 ExtendedEventHandler eventHandler,
130 OutputStream outputStream,
twerth8c11fe92018-07-10 05:59:01 -0700131 SkyframeExecutor skyframeExecutor,
132 BuildConfiguration hostConfiguration,
John Caterb3b3e8b2019-04-03 09:18:42 -0700133 @Nullable TransitionFactory<Rule> trimmingTransitionFactory,
twerth8c11fe92018-07-10 05:59:01 -0700134 PackageManager packageManager);
135
136 public abstract String getOutputFormat();
twerthfc6c7422018-06-28 10:18:39 -0700137
138 protected abstract KeyExtractor<T, ConfiguredTargetKey> getConfiguredTargetKeyExtractor();
139
140 @Override
141 public QueryEvalResult evaluateQuery(
142 QueryExpression expr, ThreadSafeOutputFormatterCallback<T> callback)
143 throws QueryException, InterruptedException, IOException {
144 beforeEvaluateQuery();
145 return super.evaluateQuery(expr, callback);
146 }
147
148 private void beforeEvaluateQuery() throws QueryException {
149 graph = walkableGraphSupplier.get();
150 GraphBackedRecursivePackageProvider graphBackedRecursivePackageProvider =
151 new GraphBackedRecursivePackageProvider(
152 graph, ALL_PATTERNS, pkgPath, new RecursivePkgValueRootPackageExtractor());
153 resolver =
154 new RecursivePackageProviderBackedTargetPatternResolver(
155 graphBackedRecursivePackageProvider,
156 eventHandler,
157 FilteringPolicies.NO_FILTER,
158 MultisetSemaphore.unbounded());
159 checkSettings(settings);
160 }
161
162 // Check to make sure the settings requested are currently supported by this class
163 private void checkSettings(Set<Setting> settings) throws QueryException {
164 if (settings.contains(Setting.NO_NODEP_DEPS)
165 || settings.contains(Setting.TESTS_EXPRESSION_STRICT)) {
166 settings =
167 Sets.difference(
wtrobertsd39a1ec2019-09-05 07:59:12 -0700168 settings, ImmutableSet.of(Setting.ONLY_TARGET_DEPS, Setting.NO_IMPLICIT_DEPS));
twerthfc6c7422018-06-28 10:18:39 -0700169 throw new QueryException(
170 String.format(
171 "The following filter(s) are not currently supported by configured query: %s",
172 settings.toString()));
173 }
174 }
175
176 public BuildConfiguration getHostConfiguration() {
177 return hostConfiguration;
178 }
179
twerthfc6c7422018-06-28 10:18:39 -0700180 // TODO(bazel-team): It's weird that this untemplated function exists. Fix? Or don't implement?
181 @Override
182 public Target getTarget(Label label) throws TargetNotFoundException, InterruptedException {
183 try {
184 return ((PackageValue)
185 walkableGraphSupplier.get().getValue(PackageValue.key(label.getPackageIdentifier())))
186 .getPackage()
187 .getTarget(label.getName());
188 } catch (NoSuchTargetException e) {
189 throw new TargetNotFoundException(e);
190 }
191 }
192
193 @Override
194 public T getOrCreate(T target) {
195 return target;
196 }
197
198 /**
199 * This method has to exist because {@link AliasConfiguredTarget#getLabel()} returns the label of
200 * the "actual" target instead of the alias target. Grr.
201 */
202 public abstract Label getCorrectLabel(T target);
203
204 @Nullable
205 protected abstract T getHostConfiguredTarget(Label label) throws InterruptedException;
206
207 @Nullable
208 protected abstract T getTargetConfiguredTarget(Label label) throws InterruptedException;
209
210 @Nullable
211 protected abstract T getNullConfiguredTarget(Label label) throws InterruptedException;
212
213 @Nullable
gregcea91495f2019-05-07 07:27:39 -0700214 public ConfiguredTargetValue getConfiguredTargetValue(SkyKey key) throws InterruptedException {
twerthfc6c7422018-06-28 10:18:39 -0700215 return (ConfiguredTargetValue) walkableGraphSupplier.get().getValue(key);
216 }
217
gregcea91495f2019-05-07 07:27:39 -0700218 public ImmutableSet<PathFragment> getBlacklistedPackagePrefixesPathFragments()
lebad52f31d2019-03-25 20:05:31 -0700219 throws InterruptedException {
220 return ((BlacklistedPackagePrefixesValue)
221 walkableGraphSupplier.get().getValue(BlacklistedPackagePrefixesValue.key()))
222 .getPatterns();
223 }
224
twerthfc6c7422018-06-28 10:18:39 -0700225 @Nullable
226 protected abstract T getValueFromKey(SkyKey key) throws InterruptedException;
227
cparsonsdac21352019-05-03 11:41:17 -0700228 protected TargetPattern getPattern(String pattern) throws TargetParsingException {
twerthfc6c7422018-06-28 10:18:39 -0700229 TargetPatternKey targetPatternKey =
230 ((TargetPatternKey)
ulfjacke83775d2019-05-14 08:58:46 -0700231 TargetPatternValue.key(pattern, FilteringPolicies.NO_FILTER, parserPrefix).argument());
twerthfc6c7422018-06-28 10:18:39 -0700232 return targetPatternKey.getParsedPattern();
233 }
234
gregcea91495f2019-05-07 07:27:39 -0700235 public ThreadSafeMutableSet<T> getFwdDeps(Iterable<T> targets) throws InterruptedException {
twerthfc6c7422018-06-28 10:18:39 -0700236 Map<SkyKey, T> targetsByKey = Maps.newHashMapWithExpectedSize(Iterables.size(targets));
237 for (T target : targets) {
238 targetsByKey.put(getSkyKey(target), target);
239 }
juliexxia1eb769f2020-02-07 13:17:32 -0800240 Map<SkyKey, ImmutableList<ClassifiedDependency<T>>> directDeps =
241 targetifyValues(targetsByKey, graph.getDirectDeps(targetsByKey.keySet()));
twerthfc6c7422018-06-28 10:18:39 -0700242 if (targetsByKey.size() != directDeps.size()) {
243 Iterable<ConfiguredTargetKey> missingTargets =
juliexxia5281eee2018-10-03 12:24:01 -0700244 Sets.difference(targetsByKey.keySet(), directDeps.keySet()).stream()
twerthfc6c7422018-06-28 10:18:39 -0700245 .map(SKYKEY_TO_CTKEY)
246 .collect(Collectors.toList());
247 eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets));
248 }
249 ThreadSafeMutableSet<T> result = createThreadSafeMutableSet();
juliexxia1eb769f2020-02-07 13:17:32 -0800250 for (Map.Entry<SkyKey, ImmutableList<ClassifiedDependency<T>>> entry : directDeps.entrySet()) {
twerthfc6c7422018-06-28 10:18:39 -0700251 result.addAll(filterFwdDeps(targetsByKey.get(entry.getKey()), entry.getValue()));
252 }
253 return result;
254 }
255
juliexxiaa880c0c2018-08-21 09:35:01 -0700256 @Override
257 public ThreadSafeMutableSet<T> getFwdDeps(Iterable<T> targets, QueryExpressionContext<T> context)
258 throws InterruptedException {
259 return getFwdDeps(targets);
260 }
261
juliexxia1eb769f2020-02-07 13:17:32 -0800262 private ImmutableList<T> filterFwdDeps(
263 T configTarget, ImmutableList<ClassifiedDependency<T>> rawFwdDeps) {
twerthfc6c7422018-06-28 10:18:39 -0700264 if (settings.isEmpty()) {
juliexxia1eb769f2020-02-07 13:17:32 -0800265 return getDependencies(rawFwdDeps);
twerthfc6c7422018-06-28 10:18:39 -0700266 }
267 return getAllowedDeps(configTarget, rawFwdDeps);
268 }
269
270 @Override
271 public Collection<T> getReverseDeps(Iterable<T> targets, QueryExpressionContext<T> context)
272 throws InterruptedException {
273 Map<SkyKey, T> targetsByKey = Maps.newHashMapWithExpectedSize(Iterables.size(targets));
274 for (T target : targets) {
275 targetsByKey.put(getSkyKey(target), target);
276 }
juliexxia1eb769f2020-02-07 13:17:32 -0800277 Map<SkyKey, ImmutableList<ClassifiedDependency<T>>> reverseDepsByKey =
278 targetifyValues(targetsByKey, graph.getReverseDeps(targetsByKey.keySet()));
twerthfc6c7422018-06-28 10:18:39 -0700279 if (targetsByKey.size() != reverseDepsByKey.size()) {
280 Iterable<ConfiguredTargetKey> missingTargets =
juliexxia5281eee2018-10-03 12:24:01 -0700281 Sets.difference(targetsByKey.keySet(), reverseDepsByKey.keySet()).stream()
twerthfc6c7422018-06-28 10:18:39 -0700282 .map(SKYKEY_TO_CTKEY)
283 .collect(Collectors.toList());
284 eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets));
285 }
juliexxia1eb769f2020-02-07 13:17:32 -0800286 Map<T, ImmutableList<ClassifiedDependency<T>>> reverseDepsByCT = new HashMap<>();
287 for (Map.Entry<SkyKey, ImmutableList<ClassifiedDependency<T>>> entry :
288 reverseDepsByKey.entrySet()) {
twerthfc6c7422018-06-28 10:18:39 -0700289 reverseDepsByCT.put(targetsByKey.get(entry.getKey()), entry.getValue());
290 }
291 return reverseDepsByCT.isEmpty() ? Collections.emptyList() : filterReverseDeps(reverseDepsByCT);
292 }
293
juliexxia1eb769f2020-02-07 13:17:32 -0800294 private Collection<T> filterReverseDeps(
295 Map<T, ImmutableList<ClassifiedDependency<T>>> rawReverseDeps) {
twerthfc6c7422018-06-28 10:18:39 -0700296 Set<T> result = CompactHashSet.create();
juliexxia1eb769f2020-02-07 13:17:32 -0800297 for (Map.Entry<T, ImmutableList<ClassifiedDependency<T>>> targetAndRdeps :
298 rawReverseDeps.entrySet()) {
299 ImmutableList.Builder<ClassifiedDependency<T>> ruleDeps = ImmutableList.builder();
300 for (ClassifiedDependency<T> parent : targetAndRdeps.getValue()) {
301 T dependency = parent.dependency;
302 if (parent.dependency instanceof RuleConfiguredTarget
twerthfc6c7422018-06-28 10:18:39 -0700303 && dependencyFilter != DependencyFilter.ALL_DEPS) {
304 ruleDeps.add(parent);
305 } else {
juliexxia1eb769f2020-02-07 13:17:32 -0800306 result.add(dependency);
twerthfc6c7422018-06-28 10:18:39 -0700307 }
308 }
Googler82e55542018-11-05 14:15:26 -0800309 result.addAll(getAllowedDeps(targetAndRdeps.getKey(), ruleDeps.build()));
twerthfc6c7422018-06-28 10:18:39 -0700310 }
311 return result;
312 }
313
314 /**
315 * @param target source target
316 * @param deps next level of deps to filter
317 */
juliexxia1eb769f2020-02-07 13:17:32 -0800318 private ImmutableList<T> getAllowedDeps(T target, Collection<ClassifiedDependency<T>> deps) {
twerthfc6c7422018-06-28 10:18:39 -0700319 // It's possible to query on a target that's configured in the host configuration. In those
wtroberts5a0cf9b2019-09-06 07:55:15 -0700320 // cases if --notool_deps is turned on, we only allow reachable targets that are ALSO in the
twerthfc6c7422018-06-28 10:18:39 -0700321 // host config. This is somewhat counterintuitive and subject to change in the future but seems
322 // like the best option right now.
wtrobertsd39a1ec2019-09-05 07:59:12 -0700323 if (settings.contains(Setting.ONLY_TARGET_DEPS)) {
twerthfc6c7422018-06-28 10:18:39 -0700324 BuildConfiguration currentConfig = getConfiguration(target);
wtrobertsd39a1ec2019-09-05 07:59:12 -0700325 if (currentConfig != null && currentConfig.isToolConfiguration()) {
twerthfc6c7422018-06-28 10:18:39 -0700326 deps =
327 deps.stream()
328 .filter(
329 dep ->
juliexxia1eb769f2020-02-07 13:17:32 -0800330 getConfiguration(dep.dependency) != null
331 && getConfiguration(dep.dependency).isToolConfiguration())
twerthfc6c7422018-06-28 10:18:39 -0700332 .collect(Collectors.toList());
333 } else {
334 deps =
335 deps.stream()
336 .filter(
337 dep ->
gregce41a8dfd2019-09-12 11:43:43 -0700338 // We include source files, which have null configuration, even though
339 // they can also appear on host-configured attributes like genrule#tools.
340 // While this may not be strictly correct, it's better to overapproximate
341 // than underapproximate the results.
juliexxia1eb769f2020-02-07 13:17:32 -0800342 getConfiguration(dep.dependency) == null
343 || !getConfiguration(dep.dependency).isToolConfiguration())
twerthfc6c7422018-06-28 10:18:39 -0700344 .collect(Collectors.toList());
345 }
346 }
twertha1a57a52018-07-18 05:34:13 -0700347 if (settings.contains(Setting.NO_IMPLICIT_DEPS)) {
348 RuleConfiguredTarget ruleConfiguredTarget = getRuleConfiguredTarget(target);
349 if (ruleConfiguredTarget != null) {
juliexxia1eb769f2020-02-07 13:17:32 -0800350 deps = deps.stream().filter(dep -> !dep.implicit).collect(Collectors.toList());
twertha1a57a52018-07-18 05:34:13 -0700351 }
twerthfc6c7422018-06-28 10:18:39 -0700352 }
juliexxia1eb769f2020-02-07 13:17:32 -0800353 return getDependencies(deps);
twerthfc6c7422018-06-28 10:18:39 -0700354 }
355
twertha1a57a52018-07-18 05:34:13 -0700356 protected abstract RuleConfiguredTarget getRuleConfiguredTarget(T target);
357
juliexxia1eb769f2020-02-07 13:17:32 -0800358 /**
359 * Returns targetified dependencies wrapped as {@link ClassifiedDependency} objects which include
360 * information on if the target is an implicit or explicit dependency.
361 *
362 * @param parent Parent target that knows about its attribute-attached implicit deps. If this is
363 * null, that is a signal from the caller that all dependencies should be considered implicit.
364 * @param dependencies dependencies to targetify
365 */
366 private ImmutableList<ClassifiedDependency<T>> targetifyValues(
367 @Nullable T parent, Iterable<SkyKey> dependencies) throws InterruptedException {
368 Collection<ConfiguredTargetKey> implicitDeps = null;
369 if (parent != null) {
370 RuleConfiguredTarget ruleConfiguredTarget = getRuleConfiguredTarget(parent);
371 if (ruleConfiguredTarget != null) {
372 implicitDeps = ruleConfiguredTarget.getImplicitDeps();
John Catere39e5c92019-04-23 10:28:02 -0700373 }
374 }
juliexxia1eb769f2020-02-07 13:17:32 -0800375
376 ImmutableList.Builder<ClassifiedDependency<T>> values = ImmutableList.builder();
377 for (SkyKey key : dependencies) {
378 if (key.functionName().equals(SkyFunctions.CONFIGURED_TARGET)) {
379 T dependency = getValueFromKey(key);
juliexxiac880d352020-04-20 12:31:09 -0700380 Preconditions.checkState(
381 dependency != null,
382 "query-requested node '%s' was unavailable in the query environment graph. If you"
383 + " come across this error, please ping b/150301500 or contact the blaze"
384 + " configurability team.",
385 key);
juliexxia1eb769f2020-02-07 13:17:32 -0800386 boolean implicit =
387 implicitDeps == null
388 || implicitDeps.contains(
jcater83221e32020-05-28 11:37:39 -0700389 ConfiguredTargetKey.builder()
390 .setLabel(getCorrectLabel(dependency))
391 .setConfiguration(getConfiguration(dependency))
392 .build());
juliexxia1eb769f2020-02-07 13:17:32 -0800393 values.add(new ClassifiedDependency<>(dependency, implicit));
plf96622c42020-06-11 08:09:29 -0700394 } else if (key.functionName().equals(SkyFunctions.TOOLCHAIN_RESOLUTION)) {
juliexxia1eb769f2020-02-07 13:17:32 -0800395 // Also fetch these dependencies.
396 values.addAll(targetifyValues(null, graph.getDirectDeps(key)));
397 }
398 }
399 return values.build();
John Catere39e5c92019-04-23 10:28:02 -0700400 }
401
juliexxia1eb769f2020-02-07 13:17:32 -0800402 private Map<SkyKey, ImmutableList<ClassifiedDependency<T>>> targetifyValues(
403 Map<SkyKey, T> fromTargetsByKey, Map<SkyKey, ? extends Iterable<SkyKey>> input)
404 throws InterruptedException {
405 Map<SkyKey, ImmutableList<ClassifiedDependency<T>>> result = new HashMap<>();
twerthfc6c7422018-06-28 10:18:39 -0700406 for (Map.Entry<SkyKey, ? extends Iterable<SkyKey>> entry : input.entrySet()) {
juliexxia1eb769f2020-02-07 13:17:32 -0800407 SkyKey fromKey = entry.getKey();
408 result.put(fromKey, targetifyValues(fromTargetsByKey.get(fromKey), entry.getValue()));
twerthfc6c7422018-06-28 10:18:39 -0700409 }
410 return result;
411 }
412
juliexxia1eb769f2020-02-07 13:17:32 -0800413 /** A class to store a dependency with some information. */
414 private static class ClassifiedDependency<T> {
415 // True if this dependency is attached implicitly.
416 boolean implicit;
417 T dependency;
418
419 private ClassifiedDependency(T dependency, boolean implicit) {
420 this.implicit = implicit;
421 this.dependency = dependency;
422 }
423 }
424
425 private static <T> ImmutableList<T> getDependencies(
426 Collection<ClassifiedDependency<T>> classifiedDependencies) {
427 return classifiedDependencies.stream()
428 .map(dep -> dep.dependency)
429 .collect(ImmutableList.toImmutableList());
430 }
431
twerthfc6c7422018-06-28 10:18:39 -0700432 @Nullable
433 protected abstract BuildConfiguration getConfiguration(T target);
434
435 protected abstract ConfiguredTargetKey getSkyKey(T target);
436
437 @Override
438 public ThreadSafeMutableSet<T> getTransitiveClosure(
439 ThreadSafeMutableSet<T> targets, QueryExpressionContext<T> context)
440 throws InterruptedException {
441 return SkyQueryUtils.getTransitiveClosure(
442 targets, targets1 -> getFwdDeps(targets1, context), createThreadSafeMutableSet());
443 }
444
445 @Override
446 public void buildTransitiveClosure(
447 QueryExpression caller, ThreadSafeMutableSet<T> targetNodes, int maxDepth) {
448 // TODO(bazel-team): implement this. Just needed for error-checking.
449 }
450
451 @Override
452 public ImmutableList<T> getNodesOnPath(T from, T to, QueryExpressionContext<T> context)
453 throws InterruptedException {
454 return SkyQueryUtils.getNodesOnPath(
455 from,
456 to,
457 targets -> getFwdDeps(targets, context),
458 getConfiguredTargetKeyExtractor()::extractKey);
459 }
460
461 @Override
462 public <V> MutableMap<T, V> createMutableMap() {
463 return new MutableKeyExtractorBackedMapImpl<>(getConfiguredTargetKeyExtractor());
464 }
465
466 @Override
467 public Uniquifier<T> createUniquifier() {
shreyax6871cf02018-07-02 09:16:18 -0700468 return new UniquifierImpl<>(getConfiguredTargetKeyExtractor());
twerthfc6c7422018-06-28 10:18:39 -0700469 }
470
471 @Override
472 public MinDepthUniquifier<T> createMinDepthUniquifier() {
473 return new MinDepthUniquifierImpl<>(
474 getConfiguredTargetKeyExtractor(), SkyQueryEnvironment.DEFAULT_THREAD_COUNT);
475 }
476
477 /** Target patterns are resolved on the fly so no pre-work to be done here. */
478 @Override
479 protected void preloadOrThrow(QueryExpression caller, Collection<String> patterns) {}
480
481 @Override
482 public ThreadSafeMutableSet<T> getBuildFiles(
483 QueryExpression caller,
484 ThreadSafeMutableSet<T> nodes,
485 boolean buildFiles,
486 boolean loads,
487 QueryExpressionContext<T> context)
488 throws QueryException {
489 throw new QueryException("buildfiles() doesn't make sense for the configured target graph");
490 }
491
492 @Override
juliexxiacc2c6bc2020-04-20 11:12:29 -0700493 public Collection<T> getSiblingTargetsInPackage(T target) throws QueryException {
494 throw new QueryException("siblings() not supported for post analysis queries");
twerthfc6c7422018-06-28 10:18:39 -0700495 }
496
497 @Override
498 public void close() {}
juliexxia5281eee2018-10-03 12:24:01 -0700499
500 /** A wrapper class for the set of top-level configurations in a query. */
501 public static class TopLevelConfigurations {
502
juliexxia5281eee2018-10-03 12:24:01 -0700503 /** A map of non-null configured top-level targets sorted by configuration checksum. */
504 private final ImmutableMap<Label, BuildConfiguration> nonNulls;
505 /**
506 * {@code nonNulls} may often have many duplicate values in its value set so we store a sorted
507 * set of all the non-null configurations here.
508 */
509 private final ImmutableSortedSet<BuildConfiguration> nonNullConfigs;
510 /** A list of null configured top-level targets. */
511 private final ImmutableList<Label> nulls;
512
513 public TopLevelConfigurations(
514 Collection<TargetAndConfiguration> topLevelTargetsAndConfigurations) {
515 ImmutableMap.Builder<Label, BuildConfiguration> nonNullsBuilder =
516 ImmutableMap.builderWithExpectedSize(topLevelTargetsAndConfigurations.size());
517 ImmutableList.Builder<Label> nullsBuilder = new ImmutableList.Builder<>();
518 for (TargetAndConfiguration targetAndConfiguration : topLevelTargetsAndConfigurations) {
519 if (targetAndConfiguration.getConfiguration() == null) {
520 nullsBuilder.add(targetAndConfiguration.getLabel());
521 } else {
522 nonNullsBuilder.put(
523 targetAndConfiguration.getLabel(), targetAndConfiguration.getConfiguration());
524 }
525 }
526 nonNulls = nonNullsBuilder.build();
527 nonNullConfigs =
528 ImmutableSortedSet.copyOf(
529 Comparator.comparing(BuildConfiguration::checksum), nonNulls.values());
530 nulls = nullsBuilder.build();
531 }
532
gregcea91495f2019-05-07 07:27:39 -0700533 public boolean isTopLevelTarget(Label label) {
juliexxia5281eee2018-10-03 12:24:01 -0700534 return nonNulls.containsKey(label) || nulls.contains(label);
535 }
536
537 // This method returns the configuration of a top-level target if it's not null-configured and
538 // otherwise returns null (signifying it is null configured).
539 @Nullable
gregcea91495f2019-05-07 07:27:39 -0700540 public BuildConfiguration getConfigurationForTopLevelTarget(Label label) {
juliexxia5281eee2018-10-03 12:24:01 -0700541 Preconditions.checkArgument(
542 isTopLevelTarget(label),
543 "Attempting to get top-level configuration for non-top-level target %s.",
544 label);
545 return nonNulls.get(label);
546 }
547
548 public Iterable<BuildConfiguration> getConfigurations() {
549 if (nulls.isEmpty()) {
550 return nonNullConfigs;
551 } else {
Googler2edf5992018-12-17 12:56:17 -0800552 return Iterables.concat(nonNullConfigs, Collections.singletonList(null));
juliexxia5281eee2018-10-03 12:24:01 -0700553 }
554 }
555 }
twerthfc6c7422018-06-28 10:18:39 -0700556}