blob: fe267b94f28710b1a56bbeb8475c910f25770548 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
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
laurentlb3d2a68c2017-06-30 00:32:04 +020016import static com.google.common.collect.ImmutableSet.toImmutableSet;
17
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010018import com.google.common.base.Predicate;
nharmatabf2e2d82017-06-21 23:12:51 +020019import com.google.common.collect.ImmutableList;
Janak Ramakrishnancbe26342015-08-17 18:57:57 +000020import com.google.common.collect.Maps;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000021import com.google.devtools.build.lib.cmdline.Label;
nharmatabf2e2d82017-06-21 23:12:51 +020022import com.google.devtools.build.lib.cmdline.PackageIdentifier;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000023import com.google.devtools.build.lib.cmdline.ResolvedTargets;
24import com.google.devtools.build.lib.cmdline.TargetParsingException;
nharmatabf2e2d82017-06-21 23:12:51 +020025import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
Klaus Aehlig777b30d2017-02-24 16:30:15 +000026import com.google.devtools.build.lib.events.ExtendedEventHandler;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import com.google.devtools.build.lib.graph.Digraph;
28import com.google.devtools.build.lib.graph.Node;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010029import com.google.devtools.build.lib.packages.Attribute;
30import com.google.devtools.build.lib.packages.NoSuchThingException;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010031import com.google.devtools.build.lib.packages.OutputFile;
32import com.google.devtools.build.lib.packages.Package;
33import com.google.devtools.build.lib.packages.Rule;
34import com.google.devtools.build.lib.packages.Target;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010035import com.google.devtools.build.lib.pkgcache.TargetEdgeObserver;
36import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator;
37import com.google.devtools.build.lib.pkgcache.TargetProvider;
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +000038import com.google.devtools.build.lib.pkgcache.TransitivePackageLoader;
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +000039import com.google.devtools.build.lib.query2.engine.Callback;
Miguel Alcon Pintob6510262015-12-10 17:50:15 +000040import com.google.devtools.build.lib.query2.engine.DigraphQueryEvalResult;
Nathan Harmatae9826b42017-03-07 18:05:21 +000041import com.google.devtools.build.lib.query2.engine.MinDepthUniquifier;
Janak Ramakrishnana46125c2015-02-11 16:51:37 +000042import com.google.devtools.build.lib.query2.engine.QueryEvalResult;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010043import com.google.devtools.build.lib.query2.engine.QueryException;
44import com.google.devtools.build.lib.query2.engine.QueryExpression;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000045import com.google.devtools.build.lib.query2.engine.QueryUtil.MinDepthUniquifierImpl;
nharmatabf2e2d82017-06-21 23:12:51 +020046import com.google.devtools.build.lib.query2.engine.QueryUtil.MutableKeyExtractorBackedMapImpl;
47import com.google.devtools.build.lib.query2.engine.QueryUtil.ThreadSafeMutableKeyExtractorBackedSetImpl;
Nathan Harmatae9826b42017-03-07 18:05:21 +000048import com.google.devtools.build.lib.query2.engine.QueryUtil.UniquifierImpl;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010049import com.google.devtools.build.lib.query2.engine.SkyframeRestartQueryException;
Nathan Harmata7a5a2362017-03-08 22:42:01 +000050import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback;
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +000051import com.google.devtools.build.lib.query2.engine.Uniquifier;
Mark Schaller6df81792015-12-10 18:47:47 +000052import com.google.devtools.build.lib.util.Preconditions;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053import com.google.devtools.build.lib.vfs.PathFragment;
Nathan Harmata5bb9cc92016-09-30 21:28:30 +000054import java.io.IOException;
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +000055import java.util.ArrayList;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010056import java.util.Collection;
Janak Ramakrishnanee6208b2016-01-07 20:17:41 +000057import java.util.HashMap;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010058import java.util.HashSet;
59import java.util.Iterator;
60import java.util.LinkedHashSet;
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +000061import java.util.List;
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000062import java.util.Map;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010063import java.util.Set;
64
65/**
66 * The environment of a Blaze query. Not thread-safe.
67 */
Janak Ramakrishnana46125c2015-02-11 16:51:37 +000068public class BlazeQueryEnvironment extends AbstractBlazeQueryEnvironment<Target> {
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +000069 private static final int MAX_DEPTH_FULL_SCAN_LIMIT = 20;
Janak Ramakrishnanee6208b2016-01-07 20:17:41 +000070 private final Map<String, Set<Target>> resolvedTargetPatterns = new HashMap<>();
Janak Ramakrishnane72d5222015-02-26 17:09:18 +000071 private final TargetPatternEvaluator targetPatternEvaluator;
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +000072 private final TransitivePackageLoader transitivePackageLoader;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010073 private final TargetProvider targetProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010074 private final Digraph<Target> graph = new Digraph<>();
75 private final ErrorPrintingTargetEdgeErrorObserver errorObserver;
76 private final LabelVisitor labelVisitor;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010077 protected final int loadingPhaseThreads;
78
Janak Ramakrishnana46125c2015-02-11 16:51:37 +000079 private final BlazeTargetAccessor accessor = new BlazeTargetAccessor(this);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010080
81 /**
82 * Note that the correct operation of this class critically depends on the Reporter being a
83 * singleton object, shared by all cooperating classes contributing to Query.
Klaus Aehlig777b30d2017-02-24 16:30:15 +000084 *
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010085 * @param strictScope if true, fail the whole query if a label goes out of scope.
Klaus Aehlig777b30d2017-02-24 16:30:15 +000086 * @param loadingPhaseThreads the number of threads to use during loading the packages for the
87 * query.
88 * @param labelFilter a predicate that determines if a specific label is allowed to be visited
89 * during query execution. If it returns false, the query execution is stopped with an error
90 * message.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010091 * @param settings a set of enabled settings
92 */
Klaus Aehlig777b30d2017-02-24 16:30:15 +000093 BlazeQueryEnvironment(
94 TransitivePackageLoader transitivePackageLoader,
Ulf Adams1509cc82017-02-09 13:25:38 +000095 TargetProvider targetProvider,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010096 TargetPatternEvaluator targetPatternEvaluator,
97 boolean keepGoing,
98 boolean strictScope,
99 int loadingPhaseThreads,
100 Predicate<Label> labelFilter,
Klaus Aehlig777b30d2017-02-24 16:30:15 +0000101 ExtendedEventHandler eventHandler,
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100102 Set<Setting> settings,
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000103 Iterable<QueryFunction> extraFunctions) {
104 super(keepGoing, strictScope, labelFilter, eventHandler, settings, extraFunctions);
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000105 this.targetPatternEvaluator = targetPatternEvaluator;
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +0000106 this.transitivePackageLoader = transitivePackageLoader;
Ulf Adams1509cc82017-02-09 13:25:38 +0000107 this.targetProvider = targetProvider;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100108 this.errorObserver = new ErrorPrintingTargetEdgeErrorObserver(this.eventHandler);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100109 this.loadingPhaseThreads = loadingPhaseThreads;
Ulf Adams1509cc82017-02-09 13:25:38 +0000110 this.labelVisitor = new LabelVisitor(targetProvider, dependencyFilter);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100111 }
112
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100113 @Override
mschallerfe883872017-07-17 22:40:11 +0200114 public void close() {
115 // BlazeQueryEnvironment has no resources that need to be cleaned up.
116 }
117
118 @Override
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000119 public DigraphQueryEvalResult<Target> evaluateQuery(
120 QueryExpression expr,
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000121 ThreadSafeOutputFormatterCallback<Target> callback)
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000122 throws QueryException, InterruptedException, IOException {
Janak Ramakrishnanee6208b2016-01-07 20:17:41 +0000123 resolvedTargetPatterns.clear();
Nathan Harmata5bb9cc92016-09-30 21:28:30 +0000124 QueryEvalResult queryEvalResult = super.evaluateQuery(expr, callback);
125 return new DigraphQueryEvalResult<>(
126 queryEvalResult.getSuccess(), queryEvalResult.isEmpty(), graph);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100127 }
128
129 @Override
nharmata50f72492017-08-11 21:31:03 +0200130 public Collection<Target> getSiblingTargetsInPackage(Target target) {
131 Collection<Target> siblings = target.getPackage().getTargets().values();
132 // Ensure that the sibling targets are in the graph being built-up.
133 siblings.forEach(this::getNode);
134 return siblings;
135 }
136
137 @Override
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000138 public QueryTaskFuture<Void> getTargetsMatchingPattern(
139 QueryExpression owner, String pattern, Callback<Target> callback) {
140 try {
141 getTargetsMatchingPatternImpl(pattern, callback);
142 return immediateSuccessfulFuture(null);
143 } catch (QueryException e) {
144 return immediateFailedFuture(e);
145 } catch (InterruptedException e) {
146 return immediateCancelledFuture();
147 }
148 }
149
150 private void getTargetsMatchingPatternImpl(String pattern, Callback<Target> callback)
Janak Ramakrishnan3c0adb22016-08-15 21:54:55 +0000151 throws QueryException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100152 // We can safely ignore the boolean error flag. The evaluateQuery() method above wraps the
153 // entire query computation in an error sensor.
154
Janak Ramakrishnancbe26342015-08-17 18:57:57 +0000155 Set<Target> targets = new LinkedHashSet<>(resolvedTargetPatterns.get(pattern));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100156
157 // Sets.filter would be more convenient here, but can't deal with exceptions.
158 Iterator<Target> targetIterator = targets.iterator();
159 while (targetIterator.hasNext()) {
160 Target target = targetIterator.next();
161 if (!validateScope(target.getLabel(), strictScope)) {
162 targetIterator.remove();
163 }
164 }
165
166 Set<PathFragment> packages = new HashSet<>();
167 for (Target target : targets) {
168 packages.add(target.getLabel().getPackageFragment());
169 }
170
171 Set<Target> result = new LinkedHashSet<>();
172 for (Target target : targets) {
173 result.add(getOrCreate(target));
174
175 // Preservation of graph order: it is important that targets obtained via
176 // a wildcard such as p:* are correctly ordered w.r.t. each other, so to
177 // ensure this, we add edges between any pair of directly connected
178 // targets in this set.
179 if (target instanceof OutputFile) {
180 OutputFile outputFile = (OutputFile) target;
181 if (targets.contains(outputFile.getGeneratingRule())) {
182 makeEdge(outputFile, outputFile.getGeneratingRule());
183 }
184 } else if (target instanceof Rule) {
185 Rule rule = (Rule) target;
186 for (Label label : rule.getLabels(dependencyFilter)) {
187 if (!packages.contains(label.getPackageFragment())) {
188 continue; // don't cause additional package loading
189 }
190 try {
191 if (!validateScope(label, strictScope)) {
192 continue; // Don't create edges to targets which are out of scope.
193 }
194 Target to = getTargetOrThrow(label);
195 if (targets.contains(to)) {
196 makeEdge(rule, to);
197 }
198 } catch (NoSuchThingException e) {
199 /* ignore */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100200 }
201 }
202 }
203 }
Janak Ramakrishnan71cdea42016-08-16 15:14:41 +0000204 callback.process(result);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100205 }
206
Ulf Adams3ab82f72015-09-04 12:10:53 +0000207 @Override
Janak Ramakrishnan71cdea42016-08-16 15:14:41 +0000208 public Target getTarget(Label label)
209 throws TargetNotFoundException, QueryException, InterruptedException {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100210 // Can't use strictScope here because we are expecting a target back.
211 validateScope(label, true);
212 try {
Janak Ramakrishnana41a5032015-02-06 21:27:27 +0000213 return getNode(getTargetOrThrow(label)).getLabel();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100214 } catch (NoSuchThingException e) {
215 throw new TargetNotFoundException(e);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100216 }
217 }
218
219 private Node<Target> getNode(Target target) {
220 return graph.createNode(target);
221 }
222
223 private Collection<Node<Target>> getNodes(Iterable<Target> target) {
224 Set<Node<Target>> result = new LinkedHashSet<>();
225 for (Target t : target) {
226 result.add(getNode(t));
227 }
228 return result;
229 }
230
231 @Override
232 public Target getOrCreate(Target target) {
233 return getNode(target).getLabel();
234 }
235
236 @Override
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000237 public Collection<Target> getFwdDeps(Iterable<Target> targets) {
nharmatabf2e2d82017-06-21 23:12:51 +0200238 ThreadSafeMutableSet<Target> result = createThreadSafeMutableSet();
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000239 for (Target target : targets) {
Janak Ramakrishnancda5b662015-06-18 23:46:36 +0000240 result.addAll(getTargetsFromNodes(getNode(target).getSuccessors()));
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000241 }
242 return result;
243 }
244
245 @Override
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000246 public Collection<Target> getReverseDeps(Iterable<Target> targets) {
nharmatabf2e2d82017-06-21 23:12:51 +0200247 ThreadSafeMutableSet<Target> result = createThreadSafeMutableSet();
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000248 for (Target target : targets) {
Janak Ramakrishnancda5b662015-06-18 23:46:36 +0000249 result.addAll(getTargetsFromNodes(getNode(target).getPredecessors()));
Janak Ramakrishnan73dd2302015-06-16 17:04:25 +0000250 }
251 return result;
252 }
253
254 @Override
nharmatabf2e2d82017-06-21 23:12:51 +0200255 public ThreadSafeMutableSet<Target> getTransitiveClosure(
256 ThreadSafeMutableSet<Target> targetNodes) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100257 for (Target node : targetNodes) {
258 checkBuilt(node);
259 }
260 return getTargetsFromNodes(graph.getFwdReachable(getNodes(targetNodes)));
261 }
262
263 /**
264 * Checks that the graph rooted at 'targetNode' has been completely built;
265 * fails if not. Callers of {@link #getTransitiveClosure} must ensure that
266 * {@link #buildTransitiveClosure} has been called before.
267 *
268 * <p>It would be inefficient and failure-prone to make getTransitiveClosure
269 * call buildTransitiveClosure directly. Also, it would cause
270 * nondeterministic behavior of the operators, since the set of packages
271 * loaded (and hence errors reported) would depend on the ordering details of
272 * the query operators' implementations.
273 */
274 private void checkBuilt(Target targetNode) {
275 Preconditions.checkState(
276 labelVisitor.hasVisited(targetNode.getLabel()),
277 "getTransitiveClosure(%s) called without prior call to buildTransitiveClosure()",
278 targetNode);
279 }
280
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100281 @Override
282 public void buildTransitiveClosure(QueryExpression caller,
nharmatabf2e2d82017-06-21 23:12:51 +0200283 ThreadSafeMutableSet<Target> targetNodes,
Janak Ramakrishnan89907392015-07-08 21:43:31 +0000284 int maxDepth) throws QueryException, InterruptedException {
nharmatabf2e2d82017-06-21 23:12:51 +0200285 preloadTransitiveClosure(targetNodes, maxDepth);
286 labelVisitor.syncWithVisitor(eventHandler, targetNodes, keepGoing,
Janak Ramakrishnan89907392015-07-08 21:43:31 +0000287 loadingPhaseThreads, maxDepth, errorObserver, new GraphBuildingObserver());
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100288
289 if (errorObserver.hasErrors()) {
290 reportBuildFileError(caller, "errors were encountered while computing transitive closure");
291 }
292 }
293
294 @Override
nharmatabf2e2d82017-06-21 23:12:51 +0200295 public Iterable<Target> getNodesOnPath(Target from, Target to) {
296 ImmutableList.Builder<Target> builder = ImmutableList.builder();
297 for (Node<Target> node : graph.getShortestPath(getNode(from), getNode(to))) {
298 builder.add(node.getLabel());
299 }
300 return builder.build();
301 }
302
303 @ThreadSafe
304 @Override
305 public ThreadSafeMutableSet<Target> createThreadSafeMutableSet() {
306 return new ThreadSafeMutableKeyExtractorBackedSetImpl<>(
307 TargetKeyExtractor.INSTANCE, Target.class);
308 }
309
310 @Override
311 public <V> MutableMap<Target, V> createMutableMap() {
312 return new MutableKeyExtractorBackedMapImpl<>(TargetKeyExtractor.INSTANCE);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100313 }
314
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +0000315 @Override
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +0000316 public Uniquifier<Target> createUniquifier() {
Nathan Harmatae9826b42017-03-07 18:05:21 +0000317 return new UniquifierImpl<>(TargetKeyExtractor.INSTANCE);
318 }
319
320 @Override
321 public MinDepthUniquifier<Target> createMinDepthUniquifier() {
Nathan Harmata7a5a2362017-03-08 22:42:01 +0000322 return new MinDepthUniquifierImpl<>(TargetKeyExtractor.INSTANCE, /*concurrencyLevel=*/ 1);
Miguel Alcon Pinto42984f32015-11-06 19:05:13 +0000323 }
324
nharmatabf2e2d82017-06-21 23:12:51 +0200325 private void preloadTransitiveClosure(ThreadSafeMutableSet<Target> targets, int maxDepth)
Ulf Adams43765af2017-02-07 16:06:39 +0000326 throws InterruptedException {
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +0000327 if (maxDepth >= MAX_DEPTH_FULL_SCAN_LIMIT && transitivePackageLoader != null) {
328 // Only do the full visitation if "maxDepth" is large enough. Otherwise, the benefits of
329 // preloading will be outweighed by the cost of doing more work than necessary.
laurentlb3d2a68c2017-06-30 00:32:04 +0200330 Set<Label> labels = targets.stream().map(Target::getLabel).collect(toImmutableSet());
Ulf Adams43765af2017-02-07 16:06:39 +0000331 transitivePackageLoader.sync(eventHandler, labels, keepGoing, loadingPhaseThreads);
Janak Ramakrishnanfe1056f2015-02-11 21:16:06 +0000332 }
333 }
334
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100335 /**
336 * It suffices to synchronize the modifications of this.graph from within the
337 * GraphBuildingObserver, because that's the only concurrent part.
338 * Concurrency is always encapsulated within the evaluation of a single query
339 * operator (e.g. deps(), somepath(), etc).
340 */
341 private class GraphBuildingObserver implements TargetEdgeObserver {
342
343 @Override
344 public synchronized void edge(Target from, Attribute attribute, Target to) {
345 Preconditions.checkState(attribute == null ||
346 dependencyFilter.apply(((Rule) from), attribute),
347 "Disallowed edge from LabelVisitor: %s --> %s", from, to);
348 makeEdge(from, to);
349 }
350
351 @Override
352 public synchronized void node(Target node) {
353 graph.createNode(node);
354 }
355
356 @Override
357 public void missingEdge(Target target, Label to, NoSuchThingException e) {
358 // No - op.
359 }
360 }
361
362 private void makeEdge(Target from, Target to) {
363 graph.addEdge(from, to);
364 }
365
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100366 private Target getTargetOrThrow(Label label)
367 throws NoSuchThingException, SkyframeRestartQueryException, InterruptedException {
368 Target target = targetProvider.getTarget(eventHandler, label);
369 if (target == null) {
370 throw new SkyframeRestartQueryException();
371 }
372 return target;
373 }
374
375 // TODO(bazel-team): rename this to getDependentFiles when all implementations
376 // of QueryEnvironment is fixed.
377 @Override
nharmatabf2e2d82017-06-21 23:12:51 +0200378 public ThreadSafeMutableSet<Target> getBuildFiles(
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000379 final QueryExpression caller,
nharmatabf2e2d82017-06-21 23:12:51 +0200380 ThreadSafeMutableSet<Target> nodes,
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000381 boolean buildFiles,
382 boolean subincludes,
383 boolean loads)
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100384 throws QueryException {
nharmatabf2e2d82017-06-21 23:12:51 +0200385 ThreadSafeMutableSet<Target> dependentFiles = createThreadSafeMutableSet();
386 Set<PackageIdentifier> seenPackages = new HashSet<>();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100387 // Keep track of seen labels, to avoid adding a fake subinclude label that also exists as a
388 // real target.
389 Set<Label> seenLabels = new HashSet<>();
390
391 // Adds all the package definition files (BUILD files and build
392 // extensions) for package "pkg", to "buildfiles".
393 for (Target x : nodes) {
394 Package pkg = x.getPackage();
nharmatabf2e2d82017-06-21 23:12:51 +0200395 if (seenPackages.add(pkg.getPackageIdentifier())) {
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000396 if (buildFiles) {
397 addIfUniqueLabel(getNode(pkg.getBuildFile()), seenLabels, dependentFiles);
398 }
399
400 List<Label> extensions = new ArrayList<>();
401 if (subincludes) {
402 extensions.addAll(pkg.getSubincludeLabels());
403 }
404 if (loads) {
405 extensions.addAll(pkg.getSkylarkFileDependencies());
406 }
407
408 for (Label subinclude : extensions) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100409 addIfUniqueLabel(getSubincludeTarget(subinclude, pkg), seenLabels, dependentFiles);
410
411 // Also add the BUILD file of the subinclude.
Han-Wen Nienhuysc13c0022015-12-15 19:08:38 +0000412 if (buildFiles) {
nharmata59c16f62017-08-07 19:49:09 +0200413 addIfUniqueLabel(
414 getSubincludeTarget(
415 Label.createUnvalidated(subinclude.getPackageIdentifier(), "BUILD"), pkg),
416 seenLabels,
417 dependentFiles);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100418 }
419 }
420 }
421 }
422 return dependentFiles;
423 }
Ulf Adams3ab82f72015-09-04 12:10:53 +0000424 @Override
Janak Ramakrishnanee6208b2016-01-07 20:17:41 +0000425 protected void preloadOrThrow(QueryExpression caller, Collection<String> patterns)
Janak Ramakrishnan71cdea42016-08-16 15:14:41 +0000426 throws TargetParsingException, InterruptedException {
Janak Ramakrishnanee6208b2016-01-07 20:17:41 +0000427 if (!resolvedTargetPatterns.keySet().containsAll(patterns)) {
Janak Ramakrishnan71cdea42016-08-16 15:14:41 +0000428 // Note that this may throw a RuntimeException if deps are missing in Skyframe and this is
429 // being called from within a SkyFunction.
430 resolvedTargetPatterns.putAll(
431 Maps.transformValues(
432 targetPatternEvaluator.preloadTargetPatterns(eventHandler, patterns, keepGoing),
laurentlb3d2a68c2017-06-30 00:32:04 +0200433 ResolvedTargets::getTargets));
Janak Ramakrishnane72d5222015-02-26 17:09:18 +0000434 }
435 }
436
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100437 private static void addIfUniqueLabel(Node<Target> node, Set<Label> labels, Set<Target> nodes) {
438 if (labels.add(node.getLabel().getLabel())) {
439 nodes.add(node.getLabel());
440 }
441 }
442
443 private Node<Target> getSubincludeTarget(final Label label, Package pkg) {
Mark Schallerb817e3f2015-06-04 17:14:18 +0000444 return getNode(new FakeSubincludeTarget(label, pkg));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100445 }
446
447 @Override
448 public TargetAccessor<Target> getAccessor() {
449 return accessor;
450 }
451
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100452 /** Given a set of target nodes, returns the targets. */
nharmatabf2e2d82017-06-21 23:12:51 +0200453 private ThreadSafeMutableSet<Target> getTargetsFromNodes(Iterable<Node<Target>> input) {
454 ThreadSafeMutableSet<Target> result = createThreadSafeMutableSet();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100455 for (Node<Target> node : input) {
456 result.add(node.getLabel());
457 }
458 return result;
459 }
460}