// 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.Iterables; import com.google.common.collect.Maps; 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.EventHandler; 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.ParseFailureListener; import com.google.devtools.build.lib.pkgcache.TargetPatternEvaluator; 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.SkyKey; 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 { private final SkyframeExecutor skyframeExecutor; private String offset = ""; SkyframeTargetPatternEvaluator(SkyframeExecutor skyframeExecutor) { this.skyframeExecutor = skyframeExecutor; } @Override public ResolvedTargets parseTargetPatternList(EventHandler eventHandler, List targetPatterns, FilteringPolicy policy, boolean keepGoing) throws TargetParsingException, InterruptedException { return parseTargetPatternList(offset, eventHandler, targetPatterns, policy, keepGoing); } @Override public ResolvedTargets parseTargetPattern(EventHandler eventHandler, String pattern, boolean keepGoing) throws TargetParsingException, InterruptedException { return parseTargetPatternList(eventHandler, ImmutableList.of(pattern), DEFAULT_FILTERING_POLICY, keepGoing); } @Override public void updateOffset(PathFragment relativeWorkingDirectory) { offset = relativeWorkingDirectory.getPathString(); } @Override public String getOffset() { return offset; } @Override public Map> preloadTargetPatterns(EventHandler eventHandler, 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. // We cannot use an ImmutableMap here because there may be null values. Map> result = Maps.newHashMapWithExpectedSize(patterns.size()); for (String pattern : patterns) { // TODO(bazel-team): This could be parallelized to improve performance. [skyframe-loading] result.put(pattern, parseTargetPattern(eventHandler, pattern, keepGoing)); } return result; } /** * Loads a list of target patterns (eg, "foo/..."). When policy is set to FILTER_TESTS, * test_suites are going to be expanded. */ ResolvedTargets parseTargetPatternList(String offset, EventHandler eventHandler, List targetPatterns, FilteringPolicy policy, boolean keepGoing) throws InterruptedException, 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) { if (!keepGoing) { throw e; } String pattern = skyKeyOrException.getOriginalPattern(); eventHandler.handle(Event.error("Skipping '" + pattern + "': " + e.getMessage())); if (eventHandler instanceof ParseFailureListener) { ((ParseFailureListener) eventHandler).parsingError(pattern, e.getMessage()); } } } ImmutableList skyKeys = builder.build(); return parseTargetPatternKeys(skyKeys, SkyframeExecutor.DEFAULT_THREAD_COUNT, keepGoing, eventHandler, createTargetPatternEvaluatorUtil(policy, eventHandler, keepGoing)); } private TargetPatternsResultBuilder createTargetPatternEvaluatorUtil(FilteringPolicy policy, EventHandler eventHandler, boolean keepGoing) { return policy == FilteringPolicies.FILTER_TESTS ? new TestTargetPatternsResultBuilder(skyframeExecutor.getPackageManager(), eventHandler, keepGoing) : new BuildTargetPatternsResultBuilder(); } ResolvedTargets parseTargetPatternKeys(Iterable patternSkyKeys, int numThreads, boolean keepGoing, EventHandler eventHandler, TargetPatternsResultBuilder finalTargetSetEvaluator) throws InterruptedException, TargetParsingException { EvaluationResult result = skyframeExecutor.targetPatterns(patternSkyKeys, numThreads, keepGoing, eventHandler); String errorMessage = null; for (SkyKey key : patternSkyKeys) { TargetPatternValue resultValue = result.get(key); if (resultValue != null) { ResolvedTargets