// Copyright 2015 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.collect.Maps; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.cmdline.PackageIdentifier; import com.google.devtools.build.lib.cmdline.ResolvedTargets; import com.google.devtools.build.lib.cmdline.TargetParsingException; import com.google.devtools.build.lib.packages.NoSuchTargetException; import com.google.devtools.build.lib.packages.Package; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.util.Preconditions; import com.google.devtools.build.skyframe.WalkableGraph; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * This class encapsulates logic behind computing final target set based on separate results from a * list of target patterns (eg, //foo:all -//bar/... //foo:test). */ abstract class TargetPatternsResultBuilder { private Map<PackageIdentifier, Package> packages = null; private boolean hasError = false; /** * Sets that there was an error, during evaluation. */ public void setError() { hasError = true; } /** Returns final set of targets and sets error flag if required. */ public ResolvedTargets<Target> build(WalkableGraph walkableGraph) throws TargetParsingException, InterruptedException { precomputePackages(walkableGraph); ResolvedTargets.Builder<Target> resolvedTargetsBuilder = buildInternal(); if (hasError) { resolvedTargetsBuilder.setError(); } return resolvedTargetsBuilder.build(); } /** * Transforms {@code ResolvedTargets<Label>} to {@code ResolvedTargets<Target>}. Note that this * method is using information about packages, so {@link #precomputePackages} has to be called * before this method. */ protected ResolvedTargets.Builder<Target> transformLabelsIntoTargets( ResolvedTargets<Label> resolvedLabels) { // precomputePackages has to be called before this method. ResolvedTargets.Builder<Target> resolvedTargetsBuilder = ResolvedTargets.builder(); Preconditions.checkNotNull(packages); for (Label label : resolvedLabels.getTargets()) { resolvedTargetsBuilder.add(getExistingTarget(label)); } for (Label label : resolvedLabels.getFilteredTargets()) { resolvedTargetsBuilder.remove(getExistingTarget(label)); } return resolvedTargetsBuilder; } private void precomputePackages(WalkableGraph walkableGraph) throws InterruptedException { Set<PackageIdentifier> packagesToRequest = getPackagesIdentifiers(); packages = Maps.newHashMapWithExpectedSize(packagesToRequest.size()); for (PackageIdentifier pkgIdentifier : packagesToRequest) { packages.put(pkgIdentifier, findPackageInGraph(pkgIdentifier, walkableGraph)); } } private Target getExistingTarget(Label label) { Package pkg = Preconditions.checkNotNull(packages.get(label.getPackageIdentifier()), label); try { return pkg.getTarget(label.getName()); } catch (NoSuchTargetException e) { // This exception should not raise, because we are processing it during TargetPatternValues // evaluation in SkyframeTargetPatternEvaluator#parseTargetPatternKeys and values with errors // are not added to final result. throw new IllegalStateException(e); } } private Set<PackageIdentifier> getPackagesIdentifiers() { Set<PackageIdentifier> packagesIdentifiers = new HashSet<>(); for (Label label : getLabels()) { packagesIdentifiers.add(label.getPackageIdentifier()); } return packagesIdentifiers; } private static Package findPackageInGraph( PackageIdentifier pkgIdentifier, WalkableGraph walkableGraph) throws InterruptedException { return Preconditions.checkNotNull( ((PackageValue) walkableGraph.getValue(PackageValue.key(pkgIdentifier))), pkgIdentifier) .getPackage(); } /** * Adds the result from expansion of positive target pattern (eg, "//foo:all"). */ abstract void addLabelsOfNegativePattern(ResolvedTargets<Label> labels); /** * Adds the result from expansion of negative target pattern (eg, "-//foo:all"). */ abstract void addLabelsOfPositivePattern(ResolvedTargets<Label> labels); /** * Returns {@code ResolvedTargets.Builder<Target>} with final set of targets. Note that this * method doesn't set error flag in result. */ abstract ResolvedTargets.Builder<Target> buildInternal() throws TargetParsingException; /** * Returns target labels from all individual results. */ protected abstract Iterable<Label> getLabels(); }