Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 1 | // Copyright 2015 Google Inc. 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. |
| 14 | package com.google.devtools.build.lib.query2; |
| 15 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 16 | import com.google.common.base.Function; |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 17 | import com.google.common.base.Functions; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 18 | import com.google.common.base.Preconditions; |
| 19 | import com.google.common.base.Predicate; |
Janak Ramakrishnan | b735d2f | 2015-06-16 17:46:36 +0000 | [diff] [blame] | 20 | import com.google.common.base.Predicates; |
Janak Ramakrishnan | f6f0fcc | 2015-06-19 20:24:52 +0000 | [diff] [blame] | 21 | import com.google.common.collect.ArrayListMultimap; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 22 | import com.google.common.collect.Collections2; |
Janak Ramakrishnan | cda5b66 | 2015-06-18 23:46:36 +0000 | [diff] [blame] | 23 | import com.google.common.collect.ImmutableList; |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 24 | import com.google.common.collect.ImmutableMap; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 25 | import com.google.common.collect.ImmutableSet; |
| 26 | import com.google.common.collect.Iterables; |
| 27 | import com.google.common.collect.Maps; |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 28 | import com.google.common.collect.Multimap; |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 29 | import com.google.common.collect.Sets; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 30 | import com.google.devtools.build.lib.cmdline.ResolvedTargets; |
| 31 | import com.google.devtools.build.lib.cmdline.TargetParsingException; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 32 | import com.google.devtools.build.lib.cmdline.TargetPattern; |
David Chen | d659426 | 2015-08-21 09:39:07 +0000 | [diff] [blame^] | 33 | import com.google.devtools.build.lib.collect.CompactHashSet; |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 34 | import com.google.devtools.build.lib.events.Event; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 35 | import com.google.devtools.build.lib.events.EventHandler; |
| 36 | import com.google.devtools.build.lib.graph.Digraph; |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 37 | import com.google.devtools.build.lib.packages.NoSuchTargetException; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 38 | import com.google.devtools.build.lib.packages.NoSuchThingException; |
| 39 | import com.google.devtools.build.lib.packages.Package; |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 40 | import com.google.devtools.build.lib.packages.PackageIdentifier; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 41 | import com.google.devtools.build.lib.packages.Rule; |
| 42 | import com.google.devtools.build.lib.packages.Target; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 43 | import com.google.devtools.build.lib.pkgcache.PathPackageLocator; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 44 | import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator; |
Eric Fellheimer | a39f8a9 | 2015-07-28 19:11:23 +0000 | [diff] [blame] | 45 | import com.google.devtools.build.lib.profiler.Profiler; |
Janak Ramakrishnan | 643063d | 2015-06-25 16:21:49 +0000 | [diff] [blame] | 46 | import com.google.devtools.build.lib.query2.engine.AllRdepsFunction; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 47 | import com.google.devtools.build.lib.query2.engine.QueryEvalResult; |
| 48 | import com.google.devtools.build.lib.query2.engine.QueryException; |
| 49 | import com.google.devtools.build.lib.query2.engine.QueryExpression; |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 50 | import com.google.devtools.build.lib.skyframe.FileValue; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 51 | import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider; |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 52 | import com.google.devtools.build.lib.skyframe.PackageLookupValue; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 53 | import com.google.devtools.build.lib.skyframe.PackageValue; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 54 | import com.google.devtools.build.lib.skyframe.PrepareDepsOfPatternsValue; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 55 | import com.google.devtools.build.lib.skyframe.RecursivePackageProviderBackedTargetPatternResolver; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 56 | import com.google.devtools.build.lib.skyframe.SkyFunctions; |
| 57 | import com.google.devtools.build.lib.skyframe.TargetPatternValue; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 58 | import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; |
Mark Schaller | 8ff5b3c | 2015-07-29 17:32:11 +0000 | [diff] [blame] | 59 | import com.google.devtools.build.lib.skyframe.TransitiveTraversalValue; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 60 | import com.google.devtools.build.lib.syntax.Label; |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 61 | import com.google.devtools.build.lib.vfs.PathFragment; |
| 62 | import com.google.devtools.build.lib.vfs.RootedPath; |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 63 | import com.google.devtools.build.skyframe.EvaluationResult; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 64 | import com.google.devtools.build.skyframe.SkyFunctionName; |
| 65 | import com.google.devtools.build.skyframe.SkyKey; |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 66 | import com.google.devtools.build.skyframe.SkyValue; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 67 | import com.google.devtools.build.skyframe.WalkableGraph; |
| 68 | import com.google.devtools.build.skyframe.WalkableGraph.WalkableGraphFactory; |
| 69 | |
| 70 | import java.util.ArrayDeque; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 71 | import java.util.Collection; |
| 72 | import java.util.Deque; |
| 73 | import java.util.HashMap; |
| 74 | import java.util.HashSet; |
| 75 | import java.util.Iterator; |
| 76 | import java.util.LinkedHashSet; |
| 77 | import java.util.List; |
| 78 | import java.util.Map; |
| 79 | import java.util.Set; |
Eric Fellheimer | a39f8a9 | 2015-07-28 19:11:23 +0000 | [diff] [blame] | 80 | import java.util.logging.Logger; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 81 | |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 82 | import javax.annotation.Nullable; |
| 83 | |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 84 | /** |
| 85 | * {@link AbstractBlazeQueryEnvironment} that introspects the Skyframe graph to find forward and |
| 86 | * reverse edges. Results obtained by calling {@link #evaluateQuery} are not guaranteed to be in |
| 87 | * any particular order. As well, this class eagerly loads the full transitive closure of targets, |
| 88 | * even if the full closure isn't needed. |
| 89 | */ |
| 90 | public class SkyQueryEnvironment extends AbstractBlazeQueryEnvironment<Target> { |
| 91 | private WalkableGraph graph; |
| 92 | |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 93 | private ImmutableList<TargetPatternKey> universeTargetPatternKeys; |
| 94 | |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 95 | private final BlazeTargetAccessor accessor = new BlazeTargetAccessor(this); |
| 96 | private final int loadingPhaseThreads; |
| 97 | private final WalkableGraphFactory graphFactory; |
| 98 | private final List<String> universeScope; |
| 99 | private final String parserPrefix; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 100 | private final PathPackageLocator pkgPath; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 101 | |
Eric Fellheimer | a39f8a9 | 2015-07-28 19:11:23 +0000 | [diff] [blame] | 102 | private static final Logger LOG = Logger.getLogger(SkyQueryEnvironment.class.getName()); |
| 103 | |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 104 | public SkyQueryEnvironment(boolean keepGoing, boolean strictScope, int loadingPhaseThreads, |
| 105 | Predicate<Label> labelFilter, |
| 106 | EventHandler eventHandler, |
| 107 | Set<Setting> settings, |
| 108 | Iterable<QueryFunction> extraFunctions, String parserPrefix, |
| 109 | WalkableGraphFactory graphFactory, |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 110 | List<String> universeScope, PathPackageLocator pkgPath) { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 111 | super(keepGoing, strictScope, labelFilter, |
| 112 | eventHandler, |
| 113 | settings, |
| 114 | extraFunctions); |
| 115 | this.loadingPhaseThreads = loadingPhaseThreads; |
| 116 | this.graphFactory = graphFactory; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 117 | this.pkgPath = pkgPath; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 118 | this.universeScope = Preconditions.checkNotNull(universeScope); |
| 119 | this.parserPrefix = parserPrefix; |
| 120 | Preconditions.checkState(!universeScope.isEmpty(), |
| 121 | "No queries can be performed with an empty universe"); |
| 122 | } |
| 123 | |
| 124 | private void init() throws InterruptedException { |
Eric Fellheimer | a39f8a9 | 2015-07-28 19:11:23 +0000 | [diff] [blame] | 125 | long startTime = Profiler.nanoTimeMaybe(); |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 126 | EvaluationResult<SkyValue> result = |
| 127 | graphFactory.prepareAndGet(universeScope, loadingPhaseThreads, eventHandler); |
| 128 | graph = result.getWalkableGraph(); |
| 129 | Collection<SkyValue> values = result.values(); |
Eric Fellheimer | a39f8a9 | 2015-07-28 19:11:23 +0000 | [diff] [blame] | 130 | long duration = Profiler.nanoTimeMaybe() - startTime; |
| 131 | if (duration > 0) { |
| 132 | LOG.info("Spent " + (duration / 1000 / 1000) + " ms on evaluation and walkable graph"); |
| 133 | } |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 134 | |
| 135 | // The universe query may fail if there are errors during its evaluation, e.g. because of |
| 136 | // cycles in the target graph. |
| 137 | boolean singleValueEvaluated = values.size() == 1; |
| 138 | boolean foundError = !result.errorMap().isEmpty(); |
| 139 | boolean evaluationFoundCycle = |
| 140 | foundError && !Iterables.isEmpty(result.getError().getCycleInfo()); |
| 141 | Preconditions.checkState(singleValueEvaluated || evaluationFoundCycle, |
| 142 | "Universe query \"%s\" unexpectedly did not result in a single value as expected (%s" |
| 143 | + " values in result) and it did not fail because of a cycle.%s", |
| 144 | universeScope, values.size(), foundError ? " Error: " + result.getError().toString() : ""); |
| 145 | if (singleValueEvaluated) { |
| 146 | PrepareDepsOfPatternsValue prepareDepsOfPatternsValue = |
| 147 | (PrepareDepsOfPatternsValue) Iterables.getOnlyElement(values); |
| 148 | universeTargetPatternKeys = prepareDepsOfPatternsValue.getTargetPatternKeys(); |
| 149 | } else { |
| 150 | // The error is because of a cycle, so keep going with the graph we managed to load. |
| 151 | universeTargetPatternKeys = ImmutableList.of(); |
| 152 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | @Override |
| 156 | public QueryEvalResult<Target> evaluateQuery(QueryExpression expr) |
Janak Ramakrishnan | 8990739 | 2015-07-08 21:43:31 +0000 | [diff] [blame] | 157 | throws QueryException, InterruptedException { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 158 | // Some errors are reported as QueryExceptions and others as ERROR events (if --keep_going). The |
| 159 | // result is set to have an error iff there were errors emitted during the query, so we reset |
| 160 | // errors here. |
| 161 | eventHandler.resetErrors(); |
Janak Ramakrishnan | 8990739 | 2015-07-08 21:43:31 +0000 | [diff] [blame] | 162 | init(); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 163 | return super.evaluateQuery(expr); |
| 164 | } |
| 165 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 166 | private Map<Target, Collection<Target>> makeTargetsMap(Map<SkyKey, Iterable<SkyKey>> input) { |
| 167 | ImmutableMap.Builder<Target, Collection<Target>> result = ImmutableMap.builder(); |
| 168 | |
| 169 | for (Map.Entry<SkyKey, Target> entry : makeTargetsWithAssociations(input.keySet()).entrySet()) { |
| 170 | result.put(entry.getValue(), makeTargets(input.get(entry.getKey()))); |
| 171 | } |
| 172 | return result.build(); |
| 173 | } |
| 174 | |
| 175 | private Map<Target, Collection<Target>> getRawFwdDeps(Iterable<Target> targets) { |
| 176 | return makeTargetsMap(graph.getDirectDeps(makeKeys(targets))); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 177 | } |
| 178 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 179 | private Map<Target, Collection<Target>> getRawReverseDeps(Iterable<Target> targets) { |
| 180 | return makeTargetsMap(graph.getReverseDeps(makeKeys(targets))); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 181 | } |
| 182 | |
| 183 | private Set<Label> getAllowedDeps(Rule rule) { |
Miguel Alcon Pinto | 4ffe28d | 2015-08-19 14:29:02 +0000 | [diff] [blame] | 184 | Set<Label> allowedLabels = new HashSet<>(rule.getTransitions(dependencyFilter).values()); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 185 | allowedLabels.addAll(rule.getVisibility().getDependencyLabels()); |
Marian Lobur | fdd788e | 2015-03-25 09:36:28 +0000 | [diff] [blame] | 186 | // We should add deps from aspects, otherwise they are going to be filtered out. |
| 187 | allowedLabels.addAll(rule.getAspectLabelsSuperset(dependencyFilter)); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 188 | return allowedLabels; |
| 189 | } |
| 190 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 191 | private Collection<Target> filterFwdDeps(Target target, Collection<Target> rawFwdDeps) { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 192 | if (!(target instanceof Rule)) { |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 193 | return rawFwdDeps; |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 194 | } |
| 195 | final Set<Label> allowedLabels = getAllowedDeps((Rule) target); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 196 | return Collections2.filter(rawFwdDeps, |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 197 | new Predicate<Target>() { |
| 198 | @Override |
| 199 | public boolean apply(Target target) { |
| 200 | return allowedLabels.contains(target.getLabel()); |
| 201 | } |
| 202 | }); |
| 203 | } |
| 204 | |
Nathan Harmata | 3fae366 | 2015-04-22 20:10:48 +0000 | [diff] [blame] | 205 | @Override |
Janak Ramakrishnan | 73dd230 | 2015-06-16 17:04:25 +0000 | [diff] [blame] | 206 | public Collection<Target> getFwdDeps(Iterable<Target> targets) { |
| 207 | Set<Target> result = new HashSet<>(); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 208 | for (Map.Entry<Target, Collection<Target>> entry : getRawFwdDeps(targets).entrySet()) { |
| 209 | result.addAll(filterFwdDeps(entry.getKey(), entry.getValue())); |
Janak Ramakrishnan | 73dd230 | 2015-06-16 17:04:25 +0000 | [diff] [blame] | 210 | } |
| 211 | return result; |
| 212 | } |
| 213 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 214 | private Collection<Target> filterReverseDeps(final Target target, |
| 215 | Collection<Target> rawReverseDeps) { |
| 216 | return Collections2.filter(rawReverseDeps, new Predicate<Target>() { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 217 | @Override |
| 218 | public boolean apply(Target parent) { |
| 219 | return !(parent instanceof Rule) |
| 220 | || getAllowedDeps((Rule) parent).contains(target.getLabel()); |
| 221 | } |
| 222 | }); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 223 | |
| 224 | } |
| 225 | |
| 226 | @Override |
Janak Ramakrishnan | 73dd230 | 2015-06-16 17:04:25 +0000 | [diff] [blame] | 227 | public Collection<Target> getReverseDeps(Iterable<Target> targets) { |
| 228 | Set<Target> result = new HashSet<>(); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 229 | for (Map.Entry<Target, Collection<Target>> entry : getRawReverseDeps(targets).entrySet()) { |
| 230 | result.addAll(filterReverseDeps(entry.getKey(), entry.getValue())); |
Janak Ramakrishnan | 73dd230 | 2015-06-16 17:04:25 +0000 | [diff] [blame] | 231 | } |
| 232 | return result; |
| 233 | } |
| 234 | |
| 235 | @Override |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 236 | public Set<Target> getTransitiveClosure(Set<Target> targets) { |
| 237 | Set<Target> visited = new HashSet<>(); |
Janak Ramakrishnan | b735d2f | 2015-06-16 17:46:36 +0000 | [diff] [blame] | 238 | Collection<Target> current = targets; |
| 239 | while (!current.isEmpty()) { |
| 240 | Collection<Target> toVisit = Collections2.filter(current, |
| 241 | Predicates.not(Predicates.in(visited))); |
| 242 | current = getFwdDeps(toVisit); |
| 243 | visited.addAll(toVisit); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 244 | } |
Janak Ramakrishnan | b735d2f | 2015-06-16 17:46:36 +0000 | [diff] [blame] | 245 | return ImmutableSet.copyOf(visited); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | // Implemented with a breadth-first search. |
| 249 | @Override |
| 250 | public Set<Target> getNodesOnPath(Target from, Target to) { |
| 251 | // Tree of nodes visited so far. |
| 252 | Map<Target, Target> nodeToParent = new HashMap<>(); |
| 253 | // Contains all nodes left to visit in a (LIFO) stack. |
| 254 | Deque<Target> toVisit = new ArrayDeque<>(); |
| 255 | toVisit.add(from); |
| 256 | nodeToParent.put(from, null); |
| 257 | while (!toVisit.isEmpty()) { |
| 258 | Target current = toVisit.removeFirst(); |
| 259 | if (to.equals(current)) { |
| 260 | return ImmutableSet.copyOf(Digraph.getPathToTreeNode(nodeToParent, to)); |
| 261 | } |
Janak Ramakrishnan | cda5b66 | 2015-06-18 23:46:36 +0000 | [diff] [blame] | 262 | for (Target dep : getFwdDeps(ImmutableList.of(current))) { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 263 | if (!nodeToParent.containsKey(dep)) { |
| 264 | nodeToParent.put(dep, current); |
| 265 | toVisit.addFirst(dep); |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | // Note that the only current caller of this method checks first to see if there is a path |
| 270 | // before calling this method. It is not clear what the return value should be here. |
| 271 | return null; |
| 272 | } |
| 273 | |
| 274 | @Override |
| 275 | public Set<Target> getTargetsMatchingPattern(QueryExpression owner, String pattern) |
| 276 | throws QueryException { |
Janak Ramakrishnan | cbe2634 | 2015-08-17 18:57:57 +0000 | [diff] [blame] | 277 | Set<Target> targets = new LinkedHashSet<>(resolvedTargetPatterns.get(pattern)); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 278 | |
| 279 | // Sets.filter would be more convenient here, but can't deal with exceptions. |
| 280 | Iterator<Target> targetIterator = targets.iterator(); |
| 281 | while (targetIterator.hasNext()) { |
| 282 | Target target = targetIterator.next(); |
| 283 | if (!validateScope(target.getLabel(), strictScope)) { |
| 284 | targetIterator.remove(); |
| 285 | } |
| 286 | } |
| 287 | return targets; |
| 288 | } |
| 289 | |
| 290 | @Override |
| 291 | public Set<Target> getBuildFiles(QueryExpression caller, Set<Target> nodes) |
| 292 | throws QueryException { |
| 293 | Set<Target> dependentFiles = new LinkedHashSet<>(); |
| 294 | Set<Package> seenPackages = new HashSet<>(); |
| 295 | // Keep track of seen labels, to avoid adding a fake subinclude label that also exists as a |
| 296 | // real target. |
| 297 | Set<Label> seenLabels = new HashSet<>(); |
| 298 | |
| 299 | // Adds all the package definition files (BUILD files and build |
| 300 | // extensions) for package "pkg", to "buildfiles". |
| 301 | for (Target x : nodes) { |
| 302 | Package pkg = x.getPackage(); |
| 303 | if (seenPackages.add(pkg)) { |
| 304 | addIfUniqueLabel(pkg.getBuildFile(), seenLabels, dependentFiles); |
| 305 | for (Label subinclude |
| 306 | : Iterables.concat(pkg.getSubincludeLabels(), pkg.getSkylarkFileDependencies())) { |
| 307 | addIfUniqueLabel(getSubincludeTarget(subinclude, pkg), seenLabels, dependentFiles); |
| 308 | |
| 309 | // Also add the BUILD file of the subinclude. |
| 310 | try { |
| 311 | addIfUniqueLabel(getSubincludeTarget( |
| 312 | subinclude.getLocalTargetLabel("BUILD"), pkg), seenLabels, dependentFiles); |
| 313 | } catch (Label.SyntaxException e) { |
| 314 | throw new AssertionError("BUILD should always parse as a target name", e); |
| 315 | } |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | return dependentFiles; |
| 320 | } |
| 321 | |
| 322 | private static void addIfUniqueLabel(Target node, Set<Label> labels, Set<Target> nodes) { |
| 323 | if (labels.add(node.getLabel())) { |
| 324 | nodes.add(node); |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | private static Target getSubincludeTarget(final Label label, Package pkg) { |
Mark Schaller | b817e3f | 2015-06-04 17:14:18 +0000 | [diff] [blame] | 329 | return new FakeSubincludeTarget(label, pkg); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 330 | } |
| 331 | |
| 332 | @Override |
| 333 | public TargetAccessor<Target> getAccessor() { |
| 334 | return accessor; |
| 335 | } |
| 336 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 337 | private SkyKey getPackageKeyAndValidateLabel(Label label) throws QueryException { |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 338 | // Can't use strictScope here because we are expecting a target back. |
| 339 | validateScope(label, true); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 340 | return PackageValue.key(label.getPackageIdentifier()); |
| 341 | } |
| 342 | |
| 343 | @Override |
| 344 | public Target getTarget(Label label) throws TargetNotFoundException, QueryException { |
| 345 | SkyKey packageKey = getPackageKeyAndValidateLabel(label); |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 346 | if (!graph.exists(packageKey)) { |
| 347 | throw new QueryException(packageKey + " does not exist in graph"); |
| 348 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 349 | try { |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 350 | PackageValue packageValue = (PackageValue) graph.getValue(packageKey); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 351 | if (packageValue != null) { |
| 352 | return packageValue.getPackage().getTarget(label.getName()); |
| 353 | } else { |
| 354 | throw (NoSuchThingException) Preconditions.checkNotNull( |
| 355 | graph.getException(packageKey), label); |
| 356 | } |
| 357 | } catch (NoSuchThingException e) { |
| 358 | throw new TargetNotFoundException(e); |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | @Override |
| 363 | public void buildTransitiveClosure(QueryExpression caller, Set<Target> targets, int maxDepth) |
| 364 | throws QueryException { |
| 365 | // Everything has already been loaded, so here we just check for errors so that we can |
| 366 | // pre-emptively throw/report if needed. |
Janak Ramakrishnan | f6f0fcc | 2015-06-19 20:24:52 +0000 | [diff] [blame] | 367 | for (Map.Entry<SkyKey, Exception> entry : |
| 368 | graph.getMissingAndExceptions(makeKeys(targets)).entrySet()) { |
| 369 | if (entry.getValue() == null) { |
| 370 | throw new QueryException(entry.getKey().argument() + " does not exist in graph"); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 371 | } |
Janak Ramakrishnan | f6f0fcc | 2015-06-19 20:24:52 +0000 | [diff] [blame] | 372 | reportBuildFileError(caller, entry.getValue().getMessage()); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 373 | } |
| 374 | } |
| 375 | |
Janak Ramakrishnan | a40e7b7 | 2015-08-20 20:06:16 +0000 | [diff] [blame] | 376 | private Set<Target> filterTargetsNotInGraph(Set<Target> targets) { |
| 377 | Map<Target, SkyKey> map = Maps.toMap(targets, TARGET_TO_SKY_KEY); |
| 378 | Set<SkyKey> present = graph.getDoneValues(map.values()).keySet(); |
| 379 | if (present.size() == targets.size()) { |
| 380 | // Optimize for case of all targets being in graph. |
| 381 | return targets; |
| 382 | } |
| 383 | return Maps.filterValues(map, Predicates.in(present)).keySet(); |
| 384 | } |
| 385 | |
Nathan Harmata | 3fae366 | 2015-04-22 20:10:48 +0000 | [diff] [blame] | 386 | @Override |
Janak Ramakrishnan | cbe2634 | 2015-08-17 18:57:57 +0000 | [diff] [blame] | 387 | protected Map<String, Set<Target>> preloadOrThrow( |
| 388 | QueryExpression caller, Collection<String> patterns) |
| 389 | throws QueryException, TargetParsingException { |
Nathan Harmata | 3fae366 | 2015-04-22 20:10:48 +0000 | [diff] [blame] | 390 | GraphBackedRecursivePackageProvider provider = |
Mark Schaller | d7311e0 | 2015-07-07 16:36:09 +0000 | [diff] [blame] | 391 | new GraphBackedRecursivePackageProvider(graph, universeTargetPatternKeys); |
Janak Ramakrishnan | cbe2634 | 2015-08-17 18:57:57 +0000 | [diff] [blame] | 392 | Map<String, Set<Target>> result = Maps.newHashMapWithExpectedSize(patterns.size()); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 393 | for (String pattern : patterns) { |
| 394 | SkyKey patternKey = TargetPatternValue.key(pattern, |
| 395 | TargetPatternEvaluator.DEFAULT_FILTERING_POLICY, parserPrefix); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 396 | |
Mark Schaller | 248f044 | 2015-05-19 17:59:36 +0000 | [diff] [blame] | 397 | TargetPatternValue.TargetPatternKey targetPatternKey = |
| 398 | ((TargetPatternValue.TargetPatternKey) patternKey.argument()); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 399 | |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 400 | TargetParsingException targetParsingException = null; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 401 | if (graph.exists(patternKey)) { |
Nathan Harmata | 3fae366 | 2015-04-22 20:10:48 +0000 | [diff] [blame] | 402 | // The graph already contains a value or exception for this target pattern, so we use it. |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 403 | TargetPatternValue value = (TargetPatternValue) graph.getValue(patternKey); |
| 404 | if (value != null) { |
Nathan Harmata | 3fae366 | 2015-04-22 20:10:48 +0000 | [diff] [blame] | 405 | ResolvedTargets.Builder<Target> targetsBuilder = ResolvedTargets.builder(); |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 406 | targetsBuilder.addAll(makeTargetsFromLabels(value.getTargets().getTargets())); |
| 407 | targetsBuilder.removeAll(makeTargetsFromLabels(value.getTargets().getFilteredTargets())); |
Janak Ramakrishnan | cbe2634 | 2015-08-17 18:57:57 +0000 | [diff] [blame] | 408 | result.put(pattern, targetsBuilder.build().getTargets()); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 409 | } else { |
Janak Ramakrishnan | f7ff616 | 2015-06-02 20:20:31 +0000 | [diff] [blame] | 410 | // Because the graph was always initialized via a keep_going build, we know that the |
| 411 | // exception stored here must be a TargetParsingException. Thus the comment in |
| 412 | // SkyframeTargetPatternEvaluator#parseTargetPatternKeys describing the situation in which |
| 413 | // the exception acceptance must be looser does not apply here. |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 414 | targetParsingException = |
| 415 | (TargetParsingException) |
| 416 | Preconditions.checkNotNull(graph.getException(patternKey), pattern); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 417 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 418 | } else { |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 419 | // If the graph doesn't contain a value for this target pattern, try to directly evaluate |
| 420 | // it, by making use of packages already present in the graph. |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 421 | RecursivePackageProviderBackedTargetPatternResolver resolver = |
| 422 | new RecursivePackageProviderBackedTargetPatternResolver(provider, eventHandler, |
Mark Schaller | 248f044 | 2015-05-19 17:59:36 +0000 | [diff] [blame] | 423 | targetPatternKey.getPolicy(), pkgPath); |
Mark Schaller | 66b35f3 | 2015-05-19 21:19:37 +0000 | [diff] [blame] | 424 | TargetPattern parsedPattern = targetPatternKey.getParsedPattern(); |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 425 | try { |
Janak Ramakrishnan | a40e7b7 | 2015-08-20 20:06:16 +0000 | [diff] [blame] | 426 | result.put(pattern, filterTargetsNotInGraph(parsedPattern.eval(resolver).getTargets())); |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 427 | } catch (TargetParsingException e) { |
| 428 | targetParsingException = e; |
Mark Schaller | b889cf3 | 2015-03-17 20:55:30 +0000 | [diff] [blame] | 429 | } catch (InterruptedException e) { |
| 430 | throw new QueryException(e.getMessage()); |
| 431 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 432 | } |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 433 | |
| 434 | if (targetParsingException != null) { |
| 435 | if (!keepGoing) { |
| 436 | throw targetParsingException; |
| 437 | } else { |
| 438 | eventHandler.handle(Event.error("Evaluation of query \"" + caller + "\" failed: " |
| 439 | + targetParsingException.getMessage())); |
Janak Ramakrishnan | cbe2634 | 2015-08-17 18:57:57 +0000 | [diff] [blame] | 440 | result.put(pattern, ImmutableSet.<Target>of()); |
Mark Schaller | 895b3d2 | 2015-03-23 14:27:26 +0000 | [diff] [blame] | 441 | } |
| 442 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 443 | } |
| 444 | return result; |
| 445 | } |
| 446 | |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 447 | private Collection<Target> makeTargets(Iterable<SkyKey> keys) { |
| 448 | return makeTargetsWithAssociations(keys).values(); |
| 449 | } |
| 450 | |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 451 | private static final Function<SkyKey, Label> SKYKEY_TO_LABEL = new Function<SkyKey, Label>() { |
| 452 | @Nullable |
| 453 | @Override |
| 454 | public Label apply(SkyKey skyKey) { |
| 455 | SkyFunctionName functionName = skyKey.functionName(); |
Mark Schaller | 8ff5b3c | 2015-07-29 17:32:11 +0000 | [diff] [blame] | 456 | if (!functionName.equals(SkyFunctions.TRANSITIVE_TRAVERSAL)) { |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 457 | // Skip non-targets. |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 458 | return null; |
| 459 | } |
| 460 | return (Label) skyKey.argument(); |
| 461 | } |
| 462 | }; |
| 463 | |
| 464 | private Map<SkyKey, Target> makeTargetsWithAssociations(Iterable<SkyKey> keys) { |
| 465 | return makeTargetsWithAssociations(keys, SKYKEY_TO_LABEL); |
| 466 | } |
| 467 | |
| 468 | private Collection<Target> makeTargetsFromLabels(Iterable<Label> labels) { |
| 469 | return makeTargetsWithAssociations(labels, Functions.<Label>identity()).values(); |
| 470 | } |
| 471 | |
| 472 | private <E> Map<E, Target> makeTargetsWithAssociations(Iterable<E> keys, |
| 473 | Function<E, Label> toLabel) { |
| 474 | Multimap<SkyKey, E> packageKeyToTargetKeyMap = ArrayListMultimap.create(); |
| 475 | for (E key : keys) { |
| 476 | Label label = toLabel.apply(key); |
| 477 | if (label == null) { |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 478 | continue; |
| 479 | } |
| 480 | try { |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 481 | packageKeyToTargetKeyMap.put(getPackageKeyAndValidateLabel(label), key); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 482 | } catch (QueryException e) { |
| 483 | // Skip disallowed labels. |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 484 | } |
| 485 | } |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 486 | ImmutableMap.Builder<E, Target> result = ImmutableMap.builder(); |
Janak Ramakrishnan | f6f0fcc | 2015-06-19 20:24:52 +0000 | [diff] [blame] | 487 | Map<SkyKey, SkyValue> packageMap = graph.getDoneValues(packageKeyToTargetKeyMap.keySet()); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 488 | for (Map.Entry<SkyKey, SkyValue> entry : packageMap.entrySet()) { |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 489 | for (E targetKey : packageKeyToTargetKeyMap.get(entry.getKey())) { |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 490 | try { |
| 491 | result.put(targetKey, ((PackageValue) entry.getValue()).getPackage() |
Janak Ramakrishnan | b5a541a | 2015-06-19 20:55:01 +0000 | [diff] [blame] | 492 | .getTarget((toLabel.apply(targetKey)).getName())); |
Janak Ramakrishnan | 3685873 | 2015-06-17 16:45:47 +0000 | [diff] [blame] | 493 | } catch (NoSuchTargetException e) { |
| 494 | // Skip missing target. |
| 495 | } |
| 496 | } |
| 497 | } |
| 498 | return result.build(); |
| 499 | } |
| 500 | |
Janak Ramakrishnan | a40e7b7 | 2015-08-20 20:06:16 +0000 | [diff] [blame] | 501 | private static final Function<Target, SkyKey> TARGET_TO_SKY_KEY = |
| 502 | new Function<Target, SkyKey>() { |
| 503 | @Override |
| 504 | public SkyKey apply(Target target) { |
| 505 | return TransitiveTraversalValue.key(target.getLabel()); |
| 506 | } |
| 507 | }; |
| 508 | |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 509 | private static Iterable<SkyKey> makeKeys(Iterable<Target> targets) { |
Janak Ramakrishnan | a40e7b7 | 2015-08-20 20:06:16 +0000 | [diff] [blame] | 510 | return Iterables.transform(targets, TARGET_TO_SKY_KEY); |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 511 | } |
| 512 | |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 513 | @Override |
| 514 | public Target getOrCreate(Target target) { |
| 515 | return target; |
| 516 | } |
Janak Ramakrishnan | 643063d | 2015-06-25 16:21:49 +0000 | [diff] [blame] | 517 | |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 518 | /** |
| 519 | * Get SkyKeys for the FileValues for the given {@param pathFragments}. To do this, we look for a |
| 520 | * package lookup node for each path fragment, since package lookup nodes contain the "root" of a |
| 521 | * package. The returned SkyKeys correspond to FileValues that may not exist in the graph. |
| 522 | */ |
| 523 | private Collection<SkyKey> getSkyKeysForFileFragments(Iterable<PathFragment> pathFragments) { |
| 524 | Set<SkyKey> result = new HashSet<>(); |
| 525 | Multimap<PathFragment, PathFragment> currentToOriginal = ArrayListMultimap.create(); |
| 526 | for (PathFragment pathFragment : pathFragments) { |
| 527 | currentToOriginal.put(pathFragment, pathFragment); |
| 528 | } |
| 529 | while (!currentToOriginal.isEmpty()) { |
| 530 | Map<SkyKey, PathFragment> keys = new HashMap<>(); |
| 531 | for (PathFragment pathFragment : currentToOriginal.keySet()) { |
| 532 | keys.put( |
| 533 | PackageLookupValue.key(PackageIdentifier.createInDefaultRepo(pathFragment)), |
| 534 | pathFragment); |
| 535 | } |
| 536 | Map<SkyKey, SkyValue> lookupValues = graph.getDoneValues(keys.keySet()); |
| 537 | for (Map.Entry<SkyKey, SkyValue> entry : lookupValues.entrySet()) { |
| 538 | PackageLookupValue packageLookupValue = (PackageLookupValue) entry.getValue(); |
| 539 | PathFragment dir = keys.get(entry.getKey()); |
| 540 | if (packageLookupValue.packageExists()) { |
| 541 | Collection<PathFragment> originalFiles = currentToOriginal.get(dir); |
| 542 | Preconditions.checkState(!originalFiles.isEmpty(), entry); |
| 543 | for (PathFragment fileName : originalFiles) { |
| 544 | result.add( |
| 545 | FileValue.key(RootedPath.toRootedPath(packageLookupValue.getRoot(), fileName))); |
| 546 | } |
| 547 | } |
| 548 | currentToOriginal.removeAll(dir); |
| 549 | } |
| 550 | Multimap<PathFragment, PathFragment> newCurrentToOriginal = ArrayListMultimap.create(); |
| 551 | for (PathFragment pathFragment : currentToOriginal.keySet()) { |
| 552 | PathFragment parent = pathFragment.getParentDirectory(); |
| 553 | if (parent != null) { |
| 554 | newCurrentToOriginal.putAll(parent, currentToOriginal.get(pathFragment)); |
| 555 | } |
| 556 | } |
| 557 | currentToOriginal = newCurrentToOriginal; |
| 558 | } |
| 559 | return result; |
| 560 | } |
| 561 | |
| 562 | /** |
| 563 | * Calculates the set of {@link Package} objects, represented as source file targets, that depend |
| 564 | * on the given list of BUILD files and subincludes (other files are filtered out). |
| 565 | */ |
| 566 | @Nullable |
| 567 | Set<Target> getRBuildFiles(Collection<PathFragment> fileIdentifiers) { |
| 568 | Collection<SkyKey> files = getSkyKeysForFileFragments(fileIdentifiers); |
| 569 | Collection<SkyKey> current = graph.getDoneValues(files).keySet(); |
| 570 | Set<SkyKey> resultKeys = CompactHashSet.create(); |
| 571 | while (!current.isEmpty()) { |
| 572 | Collection<Iterable<SkyKey>> reverseDeps = graph.getReverseDeps(current).values(); |
| 573 | current = new HashSet<>(); |
| 574 | for (SkyKey rdep : Iterables.concat(reverseDeps)) { |
| 575 | if (rdep.functionName().equals(SkyFunctions.PACKAGE)) { |
| 576 | resultKeys.add(rdep); |
| 577 | } else if (!rdep.functionName().equals(SkyFunctions.PACKAGE_LOOKUP)) { |
| 578 | // Packages may depend on subpackages for existence, but we don't report them as rdeps. |
| 579 | current.add(rdep); |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | Map<SkyKey, SkyValue> packageValues = graph.getDoneValues(resultKeys); |
| 584 | if (packageValues.size() != resultKeys.size()) { |
| 585 | throw new IllegalStateException( |
| 586 | "Missing values: " + Sets.difference(resultKeys, packageValues.keySet())); |
| 587 | } |
| 588 | ImmutableSet.Builder<Target> result = ImmutableSet.builder(); |
| 589 | for (SkyValue value : packageValues.values()) { |
| 590 | result.add(((PackageValue) value).getPackage().getBuildFile()); |
| 591 | } |
| 592 | return result.build(); |
| 593 | } |
| 594 | |
Janak Ramakrishnan | 643063d | 2015-06-25 16:21:49 +0000 | [diff] [blame] | 595 | @Override |
| 596 | public Iterable<QueryFunction> getFunctions() { |
| 597 | return ImmutableList.<QueryFunction>builder() |
Janak Ramakrishnan | d802d5b | 2015-08-20 21:05:46 +0000 | [diff] [blame] | 598 | .addAll(super.getFunctions()) |
| 599 | .add(new AllRdepsFunction()) |
| 600 | .add(new RBuildFilesFunction()) |
| 601 | .build(); |
Janak Ramakrishnan | 643063d | 2015-06-25 16:21:49 +0000 | [diff] [blame] | 602 | } |
Janak Ramakrishnan | e72d522 | 2015-02-26 17:09:18 +0000 | [diff] [blame] | 603 | } |