// Copyright 2014 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.skyframe; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.ResolvedTargets; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.events.Event; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.pkgcache.FilteringPolicies; import com.google.devtools.build.lib.pkgcache.FilteringPolicy; import com.google.devtools.build.lib.pkgcache.ParsingFailedEvent; import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator; import com.google.devtools.build.lib.pkgcache.TargetPatternPreloader; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternKey; import com.google.devtools.build.lib.skyframe.TargetPatternValue.TargetPatternSkyKeyOrException; import com.google.devtools.build.lib.vfs.PathFragment; import com.google.devtools.build.skyframe.ErrorInfo; import com.google.devtools.build.skyframe.EvaluationResult; import com.google.devtools.build.skyframe.WalkableGraph; import java.util.Collection; import java.util.List; import java.util.Map; /** * Skyframe-based target pattern parsing. */ final class SkyframeTargetPatternEvaluator implements TargetPatternEvaluator, TargetPatternPreloader { private final SkyframeExecutor skyframeExecutor; SkyframeTargetPatternEvaluator(SkyframeExecutor skyframeExecutor) { this.skyframeExecutor = skyframeExecutor; } // Only used by AnalyzeCommand at this point. All build commands use SkyframeLoadingPhaseRunner. @Override public ResolvedTargets parseTargetPatternList( PathFragment relativeWorkingDirectory, ExtendedEventHandler eventHandler, List targetPatterns, FilteringPolicy policy, boolean keepGoing) throws TargetParsingException, InterruptedException { return parseTargetPatternList( relativeWorkingDirectory.getPathString(), eventHandler, ImmutableList.copyOf(targetPatterns), policy, keepGoing); } @Override public Map> preloadTargetPatterns( ExtendedEventHandler eventHandler, PathFragment relativeWorkingDirectory, Collection patterns, boolean keepGoing) throws TargetParsingException, InterruptedException { // TODO(bazel-team): This is used only in "blaze query". There are plans to dramatically change // how query works on Skyframe, in which case this method is likely to go away. ImmutableList.Builder targetPatternsAndKeysAndResultListBuilder = ImmutableList.builder(); FilteringPolicy policy = DEFAULT_FILTERING_POLICY; for (String pattern : patterns) { ImmutableList singletonPatternList = ImmutableList.of(pattern); targetPatternsAndKeysAndResultListBuilder.add(new TargetPatternsAndKeysAndResultBuilder( singletonPatternList, getTargetPatternKeys( relativeWorkingDirectory.getPathString(), eventHandler, singletonPatternList, policy, keepGoing), createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing))); } ImmutableList> batchResult = parseTargetPatternKeysBatch( targetPatternsAndKeysAndResultListBuilder.build(), SkyframeExecutor.DEFAULT_THREAD_COUNT, keepGoing, eventHandler); Preconditions.checkState(patterns.size() == batchResult.size(), patterns); ImmutableMap.Builder> resultBuilder = ImmutableMap.builder(); int i = 0; for (String pattern : patterns) { resultBuilder.put(pattern, batchResult.get(i++)); } return resultBuilder.build(); } private Iterable getTargetPatternKeys( String offset, ExtendedEventHandler eventHandler, ImmutableList targetPatterns, FilteringPolicy policy, boolean keepGoing) throws TargetParsingException { Iterable keysMaybe = TargetPatternValue.keys(targetPatterns, policy, offset); ImmutableList.Builder builder = ImmutableList.builder(); for (TargetPatternSkyKeyOrException skyKeyOrException : keysMaybe) { try { builder.add(skyKeyOrException.getSkyKey()); } catch (TargetParsingException e) { // We report a parsing failed exception to the event bus here in case the pattern did not // successfully parse (which happens before the SkyKey is created). Otherwise the // TargetPatternFunction posts the event. eventHandler.post( new ParsingFailedEvent(skyKeyOrException.getOriginalPattern(), e.getMessage())); if (!keepGoing) { throw e; } String pattern = skyKeyOrException.getOriginalPattern(); eventHandler.handle(Event.error("Skipping '" + pattern + "': " + e.getMessage())); } } return builder.build(); } /** * Loads a list of target patterns (eg, "foo/..."). When policy is set to FILTER_TESTS, * test_suites are going to be expanded. */ private ResolvedTargets parseTargetPatternList( String offset, ExtendedEventHandler eventHandler, ImmutableList targetPatterns, FilteringPolicy policy, boolean keepGoing) throws InterruptedException, TargetParsingException { return Iterables.getOnlyElement( parseTargetPatternKeysBatch( ImmutableList.of( new TargetPatternsAndKeysAndResultBuilder( targetPatterns, getTargetPatternKeys(offset, eventHandler, targetPatterns, policy, keepGoing), createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing))), SkyframeExecutor.DEFAULT_THREAD_COUNT, keepGoing, eventHandler)); } private TargetPatternsResultBuilder createTargetPatternEvaluatorUtil( FilteringPolicy policy, ExtendedEventHandler eventHandler, boolean keepGoing) { return policy == FilteringPolicies.FILTER_TESTS ? new TestTargetPatternsResultBuilder( skyframeExecutor.getPackageManager(), eventHandler, keepGoing) : new BuildTargetPatternsResultBuilder(); } private class TargetPatternsAndKeysAndResultBuilder { private final ImmutableList targetPatterns; private final Iterable patternSkyKeys; private final TargetPatternsResultBuilder resultBuilder; private TargetPatternsAndKeysAndResultBuilder( ImmutableList targetPatterns, Iterable patternSkyKeys, TargetPatternsResultBuilder resultBuilder) { this.targetPatterns = targetPatterns; this.patternSkyKeys = patternSkyKeys; this.resultBuilder = resultBuilder; } } private ImmutableList> parseTargetPatternKeysBatch( ImmutableList targetPatternsAndKeysAndResultBuilders, int numThreads, boolean keepGoing, ExtendedEventHandler eventHandler) throws InterruptedException, TargetParsingException { ImmutableList.Builder allKeysBuilder = ImmutableList.builder(); for (TargetPatternsAndKeysAndResultBuilder targetPatternsAndKeysAndResultBuilder : targetPatternsAndKeysAndResultBuilders) { allKeysBuilder.addAll(targetPatternsAndKeysAndResultBuilder.patternSkyKeys); } EvaluationResult result = skyframeExecutor.targetPatterns( allKeysBuilder.build(), numThreads, keepGoing, eventHandler); WalkableGraph walkableGraph = Preconditions.checkNotNull(result.getWalkableGraph(), result); ImmutableList.Builder> resolvedTargetsListBuilder = ImmutableList.builder(); for (TargetPatternsAndKeysAndResultBuilder targetPatternsAndKeysAndResultBuilder : targetPatternsAndKeysAndResultBuilders) { ImmutableList targetPatterns = targetPatternsAndKeysAndResultBuilder.targetPatterns; Iterable patternSkyKeys = targetPatternsAndKeysAndResultBuilder.patternSkyKeys; TargetPatternsResultBuilder resultBuilder = targetPatternsAndKeysAndResultBuilder.resultBuilder; String errorMessage = null; boolean hasError = false; for (TargetPatternKey key : patternSkyKeys) { TargetPatternValue resultValue = result.get(key); if (resultValue != null) { ResolvedTargets