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