twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 1 | // Copyright 2018 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.query2; |
| 15 | |
John Cater | e39e5c9 | 2019-04-23 10:28:02 -0700 | [diff] [blame] | 16 | |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 17 | import com.google.common.base.Preconditions; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 18 | import com.google.common.collect.ImmutableList; |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 19 | import com.google.common.collect.ImmutableMap; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 20 | import com.google.common.collect.ImmutableSet; |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 21 | import com.google.common.collect.ImmutableSortedSet; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 22 | import com.google.common.collect.Iterables; |
| 23 | import com.google.common.collect.Maps; |
| 24 | import com.google.common.collect.Sets; |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 25 | import com.google.devtools.build.lib.analysis.TargetAndConfiguration; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 26 | import com.google.devtools.build.lib.analysis.config.BuildConfiguration; |
John Cater | b3b3e8b | 2019-04-03 09:18:42 -0700 | [diff] [blame] | 27 | import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 28 | import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget; |
| 29 | import com.google.devtools.build.lib.cmdline.Label; |
| 30 | import com.google.devtools.build.lib.cmdline.TargetParsingException; |
| 31 | import com.google.devtools.build.lib.cmdline.TargetPattern; |
| 32 | import com.google.devtools.build.lib.collect.compacthashset.CompactHashSet; |
| 33 | import com.google.devtools.build.lib.concurrent.MultisetSemaphore; |
| 34 | import com.google.devtools.build.lib.events.Event; |
| 35 | import com.google.devtools.build.lib.events.ExtendedEventHandler; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 36 | import com.google.devtools.build.lib.packages.DependencyFilter; |
| 37 | import com.google.devtools.build.lib.packages.NoSuchTargetException; |
| 38 | import com.google.devtools.build.lib.packages.Rule; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 39 | import com.google.devtools.build.lib.packages.Target; |
| 40 | import com.google.devtools.build.lib.pkgcache.FilteringPolicies; |
| 41 | import com.google.devtools.build.lib.pkgcache.PackageManager; |
| 42 | import com.google.devtools.build.lib.pkgcache.PathPackageLocator; |
| 43 | import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator; |
| 44 | import com.google.devtools.build.lib.query2.engine.KeyExtractor; |
| 45 | import com.google.devtools.build.lib.query2.engine.MinDepthUniquifier; |
| 46 | import com.google.devtools.build.lib.query2.engine.QueryEnvironment; |
| 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; |
| 50 | import com.google.devtools.build.lib.query2.engine.QueryExpressionContext; |
| 51 | import com.google.devtools.build.lib.query2.engine.QueryUtil.MinDepthUniquifierImpl; |
| 52 | import com.google.devtools.build.lib.query2.engine.QueryUtil.MutableKeyExtractorBackedMapImpl; |
| 53 | import com.google.devtools.build.lib.query2.engine.QueryUtil.UniquifierImpl; |
| 54 | import com.google.devtools.build.lib.query2.engine.ThreadSafeOutputFormatterCallback; |
| 55 | import com.google.devtools.build.lib.query2.engine.Uniquifier; |
| 56 | import com.google.devtools.build.lib.rules.AliasConfiguredTarget; |
leba | d52f31d | 2019-03-25 20:05:31 -0700 | [diff] [blame] | 57 | import com.google.devtools.build.lib.skyframe.BlacklistedPackagePrefixesValue; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 58 | import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey; |
| 59 | import com.google.devtools.build.lib.skyframe.ConfiguredTargetValue; |
| 60 | import com.google.devtools.build.lib.skyframe.GraphBackedRecursivePackageProvider; |
| 61 | import com.google.devtools.build.lib.skyframe.PackageValue; |
| 62 | import com.google.devtools.build.lib.skyframe.RecursivePackageProviderBackedTargetPatternResolver; |
| 63 | import com.google.devtools.build.lib.skyframe.RecursivePkgValueRootPackageExtractor; |
| 64 | import com.google.devtools.build.lib.skyframe.SkyFunctions; |
| 65 | import com.google.devtools.build.lib.skyframe.SkyframeExecutor; |
| 66 | import com.google.devtools.build.lib.skyframe.TargetPatternValue; |
| 67 | import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; |
leba | d52f31d | 2019-03-25 20:05:31 -0700 | [diff] [blame] | 68 | import com.google.devtools.build.lib.vfs.PathFragment; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 69 | import com.google.devtools.build.skyframe.SkyKey; |
| 70 | import com.google.devtools.build.skyframe.WalkableGraph; |
| 71 | import java.io.IOException; |
nharmata | b585261 | 2018-11-05 10:49:11 -0800 | [diff] [blame] | 72 | import java.io.OutputStream; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 73 | import java.util.ArrayList; |
| 74 | import java.util.Collection; |
| 75 | import java.util.Collections; |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 76 | import java.util.Comparator; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 77 | import java.util.HashMap; |
| 78 | import java.util.Map; |
| 79 | import java.util.Set; |
| 80 | import java.util.function.Function; |
| 81 | import java.util.function.Supplier; |
| 82 | import java.util.stream.Collectors; |
| 83 | import javax.annotation.Nullable; |
| 84 | |
| 85 | /** |
| 86 | * {@link QueryEnvironment} that runs queries based on results from the analysis phase. |
| 87 | * |
| 88 | * <p>This environment can theoretically be used for multiple queries, but currently is only ever |
| 89 | * used for one over the course of its lifetime. If this ever changed to be used for multiple, the |
| 90 | * {@link TargetAccessor} field should be initialized on a per-query basis not a per-environment |
| 91 | * basis. |
| 92 | * |
| 93 | * <p>Aspects are also not supported, but probably should be in some fashion. |
| 94 | */ |
twerth | 8c11fe9 | 2018-07-10 05:59:01 -0700 | [diff] [blame] | 95 | public abstract class PostAnalysisQueryEnvironment<T> extends AbstractBlazeQueryEnvironment<T> { |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 96 | protected final TopLevelConfigurations topLevelConfigurations; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 97 | protected final BuildConfiguration hostConfiguration; |
| 98 | private final String parserPrefix; |
| 99 | private final PathPackageLocator pkgPath; |
| 100 | private final Supplier<WalkableGraph> walkableGraphSupplier; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 101 | protected WalkableGraph graph; |
| 102 | |
| 103 | private static final Function<SkyKey, ConfiguredTargetKey> SKYKEY_TO_CTKEY = |
| 104 | skyKey -> (ConfiguredTargetKey) skyKey.argument(); |
| 105 | private static final ImmutableList<TargetPatternKey> ALL_PATTERNS; |
| 106 | |
| 107 | static { |
| 108 | TargetPattern targetPattern; |
| 109 | try { |
| 110 | targetPattern = TargetPattern.defaultParser().parse("//..."); |
| 111 | } catch (TargetParsingException e) { |
| 112 | throw new IllegalStateException(e); |
| 113 | } |
| 114 | ALL_PATTERNS = |
| 115 | ImmutableList.of( |
| 116 | new TargetPatternKey( |
cparsons | dac2135 | 2019-05-03 11:41:17 -0700 | [diff] [blame] | 117 | targetPattern, FilteringPolicies.NO_FILTER, false, "", ImmutableSet.of())); |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | protected RecursivePackageProviderBackedTargetPatternResolver resolver; |
| 121 | |
| 122 | public PostAnalysisQueryEnvironment( |
| 123 | boolean keepGoing, |
| 124 | ExtendedEventHandler eventHandler, |
| 125 | Iterable<QueryFunction> extraFunctions, |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 126 | TopLevelConfigurations topLevelConfigurations, |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 127 | BuildConfiguration hostConfiguration, |
| 128 | String parserPrefix, |
| 129 | PathPackageLocator pkgPath, |
| 130 | Supplier<WalkableGraph> walkableGraphSupplier, |
nharmata | f4023b9 | 2018-11-07 14:33:51 -0800 | [diff] [blame] | 131 | Set<Setting> settings) { |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 132 | super(keepGoing, true, Rule.ALL_LABELS, eventHandler, settings, extraFunctions); |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 133 | this.topLevelConfigurations = topLevelConfigurations; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 134 | this.hostConfiguration = hostConfiguration; |
| 135 | this.parserPrefix = parserPrefix; |
| 136 | this.pkgPath = pkgPath; |
| 137 | this.walkableGraphSupplier = walkableGraphSupplier; |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 138 | } |
| 139 | |
twerth | 8c11fe9 | 2018-07-10 05:59:01 -0700 | [diff] [blame] | 140 | public abstract ImmutableList<NamedThreadSafeOutputFormatterCallback<T>> |
| 141 | getDefaultOutputFormatters( |
| 142 | TargetAccessor<T> accessor, |
nharmata | b585261 | 2018-11-05 10:49:11 -0800 | [diff] [blame] | 143 | ExtendedEventHandler eventHandler, |
| 144 | OutputStream outputStream, |
twerth | 8c11fe9 | 2018-07-10 05:59:01 -0700 | [diff] [blame] | 145 | SkyframeExecutor skyframeExecutor, |
| 146 | BuildConfiguration hostConfiguration, |
John Cater | b3b3e8b | 2019-04-03 09:18:42 -0700 | [diff] [blame] | 147 | @Nullable TransitionFactory<Rule> trimmingTransitionFactory, |
twerth | 8c11fe9 | 2018-07-10 05:59:01 -0700 | [diff] [blame] | 148 | PackageManager packageManager); |
| 149 | |
| 150 | public abstract String getOutputFormat(); |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 151 | |
| 152 | protected abstract KeyExtractor<T, ConfiguredTargetKey> getConfiguredTargetKeyExtractor(); |
| 153 | |
| 154 | @Override |
| 155 | public QueryEvalResult evaluateQuery( |
| 156 | QueryExpression expr, ThreadSafeOutputFormatterCallback<T> callback) |
| 157 | throws QueryException, InterruptedException, IOException { |
| 158 | beforeEvaluateQuery(); |
| 159 | return super.evaluateQuery(expr, callback); |
| 160 | } |
| 161 | |
| 162 | private void beforeEvaluateQuery() throws QueryException { |
| 163 | graph = walkableGraphSupplier.get(); |
| 164 | GraphBackedRecursivePackageProvider graphBackedRecursivePackageProvider = |
| 165 | new GraphBackedRecursivePackageProvider( |
| 166 | graph, ALL_PATTERNS, pkgPath, new RecursivePkgValueRootPackageExtractor()); |
| 167 | resolver = |
| 168 | new RecursivePackageProviderBackedTargetPatternResolver( |
| 169 | graphBackedRecursivePackageProvider, |
| 170 | eventHandler, |
| 171 | FilteringPolicies.NO_FILTER, |
| 172 | MultisetSemaphore.unbounded()); |
| 173 | checkSettings(settings); |
| 174 | } |
| 175 | |
| 176 | // Check to make sure the settings requested are currently supported by this class |
| 177 | private void checkSettings(Set<Setting> settings) throws QueryException { |
| 178 | if (settings.contains(Setting.NO_NODEP_DEPS) |
| 179 | || settings.contains(Setting.TESTS_EXPRESSION_STRICT)) { |
| 180 | settings = |
| 181 | Sets.difference( |
| 182 | settings, ImmutableSet.of(Setting.NO_HOST_DEPS, Setting.NO_IMPLICIT_DEPS)); |
| 183 | throw new QueryException( |
| 184 | String.format( |
| 185 | "The following filter(s) are not currently supported by configured query: %s", |
| 186 | settings.toString())); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | public BuildConfiguration getHostConfiguration() { |
| 191 | return hostConfiguration; |
| 192 | } |
| 193 | |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 194 | // TODO(bazel-team): It's weird that this untemplated function exists. Fix? Or don't implement? |
| 195 | @Override |
| 196 | public Target getTarget(Label label) throws TargetNotFoundException, InterruptedException { |
| 197 | try { |
| 198 | return ((PackageValue) |
| 199 | walkableGraphSupplier.get().getValue(PackageValue.key(label.getPackageIdentifier()))) |
| 200 | .getPackage() |
| 201 | .getTarget(label.getName()); |
| 202 | } catch (NoSuchTargetException e) { |
| 203 | throw new TargetNotFoundException(e); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | @Override |
| 208 | public T getOrCreate(T target) { |
| 209 | return target; |
| 210 | } |
| 211 | |
| 212 | /** |
| 213 | * This method has to exist because {@link AliasConfiguredTarget#getLabel()} returns the label of |
| 214 | * the "actual" target instead of the alias target. Grr. |
| 215 | */ |
| 216 | public abstract Label getCorrectLabel(T target); |
| 217 | |
| 218 | @Nullable |
| 219 | protected abstract T getHostConfiguredTarget(Label label) throws InterruptedException; |
| 220 | |
| 221 | @Nullable |
| 222 | protected abstract T getTargetConfiguredTarget(Label label) throws InterruptedException; |
| 223 | |
| 224 | @Nullable |
| 225 | protected abstract T getNullConfiguredTarget(Label label) throws InterruptedException; |
| 226 | |
| 227 | @Nullable |
gregce | a91495f | 2019-05-07 07:27:39 -0700 | [diff] [blame^] | 228 | public ConfiguredTargetValue getConfiguredTargetValue(SkyKey key) throws InterruptedException { |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 229 | return (ConfiguredTargetValue) walkableGraphSupplier.get().getValue(key); |
| 230 | } |
| 231 | |
gregce | a91495f | 2019-05-07 07:27:39 -0700 | [diff] [blame^] | 232 | public ImmutableSet<PathFragment> getBlacklistedPackagePrefixesPathFragments() |
leba | d52f31d | 2019-03-25 20:05:31 -0700 | [diff] [blame] | 233 | throws InterruptedException { |
| 234 | return ((BlacklistedPackagePrefixesValue) |
| 235 | walkableGraphSupplier.get().getValue(BlacklistedPackagePrefixesValue.key())) |
| 236 | .getPatterns(); |
| 237 | } |
| 238 | |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 239 | @Nullable |
| 240 | protected abstract T getValueFromKey(SkyKey key) throws InterruptedException; |
| 241 | |
cparsons | dac2135 | 2019-05-03 11:41:17 -0700 | [diff] [blame] | 242 | protected TargetPattern getPattern(String pattern) throws TargetParsingException { |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 243 | TargetPatternKey targetPatternKey = |
| 244 | ((TargetPatternKey) |
| 245 | TargetPatternValue.key( |
| 246 | pattern, TargetPatternEvaluator.DEFAULT_FILTERING_POLICY, parserPrefix) |
| 247 | .argument()); |
| 248 | return targetPatternKey.getParsedPattern(); |
| 249 | } |
| 250 | |
gregce | a91495f | 2019-05-07 07:27:39 -0700 | [diff] [blame^] | 251 | public ThreadSafeMutableSet<T> getFwdDeps(Iterable<T> targets) throws InterruptedException { |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 252 | Map<SkyKey, T> targetsByKey = Maps.newHashMapWithExpectedSize(Iterables.size(targets)); |
| 253 | for (T target : targets) { |
| 254 | targetsByKey.put(getSkyKey(target), target); |
| 255 | } |
| 256 | Map<SkyKey, Collection<T>> directDeps = |
| 257 | targetifyValues(graph.getDirectDeps(targetsByKey.keySet())); |
| 258 | if (targetsByKey.size() != directDeps.size()) { |
| 259 | Iterable<ConfiguredTargetKey> missingTargets = |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 260 | Sets.difference(targetsByKey.keySet(), directDeps.keySet()).stream() |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 261 | .map(SKYKEY_TO_CTKEY) |
| 262 | .collect(Collectors.toList()); |
| 263 | eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets)); |
| 264 | } |
| 265 | ThreadSafeMutableSet<T> result = createThreadSafeMutableSet(); |
| 266 | for (Map.Entry<SkyKey, Collection<T>> entry : directDeps.entrySet()) { |
| 267 | result.addAll(filterFwdDeps(targetsByKey.get(entry.getKey()), entry.getValue())); |
| 268 | } |
| 269 | return result; |
| 270 | } |
| 271 | |
juliexxia | a880c0c | 2018-08-21 09:35:01 -0700 | [diff] [blame] | 272 | @Override |
| 273 | public ThreadSafeMutableSet<T> getFwdDeps(Iterable<T> targets, QueryExpressionContext<T> context) |
| 274 | throws InterruptedException { |
| 275 | return getFwdDeps(targets); |
| 276 | } |
| 277 | |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 278 | private Collection<T> filterFwdDeps(T configTarget, Collection<T> rawFwdDeps) { |
| 279 | if (settings.isEmpty()) { |
| 280 | return rawFwdDeps; |
| 281 | } |
| 282 | return getAllowedDeps(configTarget, rawFwdDeps); |
| 283 | } |
| 284 | |
| 285 | @Override |
| 286 | public Collection<T> getReverseDeps(Iterable<T> targets, QueryExpressionContext<T> context) |
| 287 | throws InterruptedException { |
| 288 | Map<SkyKey, T> targetsByKey = Maps.newHashMapWithExpectedSize(Iterables.size(targets)); |
| 289 | for (T target : targets) { |
| 290 | targetsByKey.put(getSkyKey(target), target); |
| 291 | } |
| 292 | Map<SkyKey, Collection<T>> reverseDepsByKey = |
| 293 | targetifyValues(graph.getReverseDeps(targetsByKey.keySet())); |
| 294 | if (targetsByKey.size() != reverseDepsByKey.size()) { |
| 295 | Iterable<ConfiguredTargetKey> missingTargets = |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 296 | Sets.difference(targetsByKey.keySet(), reverseDepsByKey.keySet()).stream() |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 297 | .map(SKYKEY_TO_CTKEY) |
| 298 | .collect(Collectors.toList()); |
| 299 | eventHandler.handle(Event.warn("Targets were missing from graph: " + missingTargets)); |
| 300 | } |
| 301 | Map<T, Collection<T>> reverseDepsByCT = new HashMap<>(); |
| 302 | for (Map.Entry<SkyKey, Collection<T>> entry : reverseDepsByKey.entrySet()) { |
| 303 | reverseDepsByCT.put(targetsByKey.get(entry.getKey()), entry.getValue()); |
| 304 | } |
| 305 | return reverseDepsByCT.isEmpty() ? Collections.emptyList() : filterReverseDeps(reverseDepsByCT); |
| 306 | } |
| 307 | |
| 308 | private Collection<T> filterReverseDeps(Map<T, Collection<T>> rawReverseDeps) { |
| 309 | Set<T> result = CompactHashSet.create(); |
| 310 | for (Map.Entry<T, Collection<T>> targetAndRdeps : rawReverseDeps.entrySet()) { |
| 311 | ImmutableSet.Builder<T> ruleDeps = ImmutableSet.builder(); |
| 312 | for (T parent : targetAndRdeps.getValue()) { |
| 313 | if (parent instanceof RuleConfiguredTarget |
| 314 | && dependencyFilter != DependencyFilter.ALL_DEPS) { |
| 315 | ruleDeps.add(parent); |
| 316 | } else { |
| 317 | result.add(parent); |
| 318 | } |
| 319 | } |
Googler | 82e5554 | 2018-11-05 14:15:26 -0800 | [diff] [blame] | 320 | result.addAll(getAllowedDeps(targetAndRdeps.getKey(), ruleDeps.build())); |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 321 | } |
| 322 | return result; |
| 323 | } |
| 324 | |
| 325 | /** |
| 326 | * @param target source target |
| 327 | * @param deps next level of deps to filter |
| 328 | */ |
| 329 | protected Collection<T> getAllowedDeps(T target, Collection<T> deps) { |
| 330 | // It's possible to query on a target that's configured in the host configuration. In those |
| 331 | // cases if --nohost_deps is turned on, we only allow reachable targets that are ALSO in the |
| 332 | // host config. This is somewhat counterintuitive and subject to change in the future but seems |
| 333 | // like the best option right now. |
| 334 | if (settings.contains(Setting.NO_HOST_DEPS)) { |
| 335 | BuildConfiguration currentConfig = getConfiguration(target); |
| 336 | if (currentConfig != null && currentConfig.isHostConfiguration()) { |
| 337 | deps = |
| 338 | deps.stream() |
| 339 | .filter( |
| 340 | dep -> |
| 341 | getConfiguration(dep) != null |
| 342 | && getConfiguration(dep).isHostConfiguration()) |
| 343 | .collect(Collectors.toList()); |
| 344 | } else { |
| 345 | deps = |
| 346 | deps.stream() |
| 347 | .filter( |
| 348 | dep -> |
| 349 | getConfiguration(dep) != null |
| 350 | && !getConfiguration(dep).isHostConfiguration()) |
| 351 | .collect(Collectors.toList()); |
| 352 | } |
| 353 | } |
twerth | a1a57a5 | 2018-07-18 05:34:13 -0700 | [diff] [blame] | 354 | if (settings.contains(Setting.NO_IMPLICIT_DEPS)) { |
| 355 | RuleConfiguredTarget ruleConfiguredTarget = getRuleConfiguredTarget(target); |
| 356 | if (ruleConfiguredTarget != null) { |
| 357 | Set<ConfiguredTargetKey> implicitDeps = ruleConfiguredTarget.getImplicitDeps(); |
| 358 | deps = |
| 359 | deps.stream() |
| 360 | .filter( |
| 361 | dep -> |
| 362 | !implicitDeps.contains( |
| 363 | ConfiguredTargetKey.of(getCorrectLabel(dep), getConfiguration(dep)))) |
| 364 | .collect(Collectors.toList()); |
| 365 | } |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 366 | } |
| 367 | return deps; |
| 368 | } |
| 369 | |
twerth | a1a57a5 | 2018-07-18 05:34:13 -0700 | [diff] [blame] | 370 | protected abstract RuleConfiguredTarget getRuleConfiguredTarget(T target); |
| 371 | |
John Cater | e39e5c9 | 2019-04-23 10:28:02 -0700 | [diff] [blame] | 372 | protected Collection<T> targetifyValues(Iterable<SkyKey> dependencies) |
| 373 | throws InterruptedException { |
| 374 | Collection<T> values = new ArrayList<>(); |
| 375 | for (SkyKey key : dependencies) { |
| 376 | if (key.functionName().equals(SkyFunctions.CONFIGURED_TARGET)) { |
| 377 | values.add(getValueFromKey(key)); |
| 378 | } else if (key.functionName().equals(SkyFunctions.TOOLCHAIN_RESOLUTION)) { |
| 379 | // Also fetch these dependencies. |
| 380 | Collection<T> toolchainDeps = targetifyValues(graph.getDirectDeps(key)); |
| 381 | values.addAll(toolchainDeps); |
| 382 | } |
| 383 | } |
| 384 | return values; |
| 385 | } |
| 386 | |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 387 | protected Map<SkyKey, Collection<T>> targetifyValues( |
| 388 | Map<SkyKey, ? extends Iterable<SkyKey>> input) throws InterruptedException { |
| 389 | Map<SkyKey, Collection<T>> result = new HashMap<>(); |
| 390 | for (Map.Entry<SkyKey, ? extends Iterable<SkyKey>> entry : input.entrySet()) { |
John Cater | e39e5c9 | 2019-04-23 10:28:02 -0700 | [diff] [blame] | 391 | result.put(entry.getKey(), targetifyValues(entry.getValue())); |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 392 | } |
| 393 | return result; |
| 394 | } |
| 395 | |
| 396 | @Nullable |
| 397 | protected abstract BuildConfiguration getConfiguration(T target); |
| 398 | |
| 399 | protected abstract ConfiguredTargetKey getSkyKey(T target); |
| 400 | |
| 401 | @Override |
| 402 | public ThreadSafeMutableSet<T> getTransitiveClosure( |
| 403 | ThreadSafeMutableSet<T> targets, QueryExpressionContext<T> context) |
| 404 | throws InterruptedException { |
| 405 | return SkyQueryUtils.getTransitiveClosure( |
| 406 | targets, targets1 -> getFwdDeps(targets1, context), createThreadSafeMutableSet()); |
| 407 | } |
| 408 | |
| 409 | @Override |
| 410 | public void buildTransitiveClosure( |
| 411 | QueryExpression caller, ThreadSafeMutableSet<T> targetNodes, int maxDepth) { |
| 412 | // TODO(bazel-team): implement this. Just needed for error-checking. |
| 413 | } |
| 414 | |
| 415 | @Override |
| 416 | public ImmutableList<T> getNodesOnPath(T from, T to, QueryExpressionContext<T> context) |
| 417 | throws InterruptedException { |
| 418 | return SkyQueryUtils.getNodesOnPath( |
| 419 | from, |
| 420 | to, |
| 421 | targets -> getFwdDeps(targets, context), |
| 422 | getConfiguredTargetKeyExtractor()::extractKey); |
| 423 | } |
| 424 | |
| 425 | @Override |
| 426 | public <V> MutableMap<T, V> createMutableMap() { |
| 427 | return new MutableKeyExtractorBackedMapImpl<>(getConfiguredTargetKeyExtractor()); |
| 428 | } |
| 429 | |
| 430 | @Override |
| 431 | public Uniquifier<T> createUniquifier() { |
shreyax | 6871cf0 | 2018-07-02 09:16:18 -0700 | [diff] [blame] | 432 | return new UniquifierImpl<>(getConfiguredTargetKeyExtractor()); |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | @Override |
| 436 | public MinDepthUniquifier<T> createMinDepthUniquifier() { |
| 437 | return new MinDepthUniquifierImpl<>( |
| 438 | getConfiguredTargetKeyExtractor(), SkyQueryEnvironment.DEFAULT_THREAD_COUNT); |
| 439 | } |
| 440 | |
| 441 | /** Target patterns are resolved on the fly so no pre-work to be done here. */ |
| 442 | @Override |
| 443 | protected void preloadOrThrow(QueryExpression caller, Collection<String> patterns) {} |
| 444 | |
| 445 | @Override |
| 446 | public ThreadSafeMutableSet<T> getBuildFiles( |
| 447 | QueryExpression caller, |
| 448 | ThreadSafeMutableSet<T> nodes, |
| 449 | boolean buildFiles, |
| 450 | boolean loads, |
| 451 | QueryExpressionContext<T> context) |
| 452 | throws QueryException { |
| 453 | throw new QueryException("buildfiles() doesn't make sense for the configured target graph"); |
| 454 | } |
| 455 | |
| 456 | @Override |
| 457 | public Collection<T> getSiblingTargetsInPackage(T target) { |
| 458 | throw new UnsupportedOperationException("siblings() not supported"); |
| 459 | } |
| 460 | |
| 461 | @Override |
| 462 | public void close() {} |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 463 | |
| 464 | /** A wrapper class for the set of top-level configurations in a query. */ |
| 465 | public static class TopLevelConfigurations { |
| 466 | |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 467 | /** A map of non-null configured top-level targets sorted by configuration checksum. */ |
| 468 | private final ImmutableMap<Label, BuildConfiguration> nonNulls; |
| 469 | /** |
| 470 | * {@code nonNulls} may often have many duplicate values in its value set so we store a sorted |
| 471 | * set of all the non-null configurations here. |
| 472 | */ |
| 473 | private final ImmutableSortedSet<BuildConfiguration> nonNullConfigs; |
| 474 | /** A list of null configured top-level targets. */ |
| 475 | private final ImmutableList<Label> nulls; |
| 476 | |
| 477 | public TopLevelConfigurations( |
| 478 | Collection<TargetAndConfiguration> topLevelTargetsAndConfigurations) { |
| 479 | ImmutableMap.Builder<Label, BuildConfiguration> nonNullsBuilder = |
| 480 | ImmutableMap.builderWithExpectedSize(topLevelTargetsAndConfigurations.size()); |
| 481 | ImmutableList.Builder<Label> nullsBuilder = new ImmutableList.Builder<>(); |
| 482 | for (TargetAndConfiguration targetAndConfiguration : topLevelTargetsAndConfigurations) { |
| 483 | if (targetAndConfiguration.getConfiguration() == null) { |
| 484 | nullsBuilder.add(targetAndConfiguration.getLabel()); |
| 485 | } else { |
| 486 | nonNullsBuilder.put( |
| 487 | targetAndConfiguration.getLabel(), targetAndConfiguration.getConfiguration()); |
| 488 | } |
| 489 | } |
| 490 | nonNulls = nonNullsBuilder.build(); |
| 491 | nonNullConfigs = |
| 492 | ImmutableSortedSet.copyOf( |
| 493 | Comparator.comparing(BuildConfiguration::checksum), nonNulls.values()); |
| 494 | nulls = nullsBuilder.build(); |
| 495 | } |
| 496 | |
gregce | a91495f | 2019-05-07 07:27:39 -0700 | [diff] [blame^] | 497 | public boolean isTopLevelTarget(Label label) { |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 498 | return nonNulls.containsKey(label) || nulls.contains(label); |
| 499 | } |
| 500 | |
| 501 | // This method returns the configuration of a top-level target if it's not null-configured and |
| 502 | // otherwise returns null (signifying it is null configured). |
| 503 | @Nullable |
gregce | a91495f | 2019-05-07 07:27:39 -0700 | [diff] [blame^] | 504 | public BuildConfiguration getConfigurationForTopLevelTarget(Label label) { |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 505 | Preconditions.checkArgument( |
| 506 | isTopLevelTarget(label), |
| 507 | "Attempting to get top-level configuration for non-top-level target %s.", |
| 508 | label); |
| 509 | return nonNulls.get(label); |
| 510 | } |
| 511 | |
| 512 | public Iterable<BuildConfiguration> getConfigurations() { |
| 513 | if (nulls.isEmpty()) { |
| 514 | return nonNullConfigs; |
| 515 | } else { |
Googler | 2edf599 | 2018-12-17 12:56:17 -0800 | [diff] [blame] | 516 | return Iterables.concat(nonNullConfigs, Collections.singletonList(null)); |
juliexxia | 5281eee | 2018-10-03 12:24:01 -0700 | [diff] [blame] | 517 | } |
| 518 | } |
| 519 | } |
twerth | fc6c742 | 2018-06-28 10:18:39 -0700 | [diff] [blame] | 520 | } |