// Copyright 2018 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.MoreObjects; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedSet; import com.google.devtools.build.lib.analysis.TargetAndConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfiguration; import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection; import com.google.devtools.build.lib.analysis.config.BuildOptions; import com.google.devtools.build.lib.analysis.config.FragmentClassSet; import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import com.google.devtools.build.lib.events.ExtendedEventHandler; import com.google.devtools.build.lib.packages.NoSuchPackageException; import com.google.devtools.build.lib.packages.NoSuchTargetException; import com.google.devtools.build.lib.packages.Target; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import com.google.devtools.build.skyframe.SkyFunctionName; import com.google.devtools.build.skyframe.SkyKey; import com.google.devtools.build.skyframe.SkyValue; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; /** * A value referring to a set of build configuration keys in order to reconstruct the * legacy {@link BuildConfigurationCollection} as well as a set of top level configured target keys * that are subsequently requested to trigger the analysis phase. * *

The public interface returns {@link BuildConfigurationCollection} and {@link * TargetAndConfiguration} even though these are not internally stored - the construction of these * objects requires additional Skyframe calls. The intention is that these are temporary until a * larger fraction of the code has been ported to Skyframe, at which point we'll use the internal * representation. */ @Immutable @ThreadSafe @AutoCodec public final class PrepareAnalysisPhaseValue implements SkyValue { private final BuildConfigurationValue.Key hostConfigurationKey; private final ImmutableList targetConfigurationKeys; private final ImmutableList topLevelCtKeys; PrepareAnalysisPhaseValue( BuildConfigurationValue.Key hostConfigurationKey, ImmutableList targetConfigurationKeys, ImmutableList topLevelCtKeys) { this.hostConfigurationKey = Preconditions.checkNotNull(hostConfigurationKey); this.targetConfigurationKeys = Preconditions.checkNotNull(targetConfigurationKeys); this.topLevelCtKeys = Preconditions.checkNotNull(topLevelCtKeys); } /** * Returns the legacy {@link BuildConfigurationCollection}. Note that this performs additional * Skyframe calls, which may be expensive. */ public BuildConfigurationCollection getConfigurations( ExtendedEventHandler eventHandler, SkyframeExecutor skyframeExecutor) throws InvalidConfigurationException { BuildConfiguration hostConfiguration = skyframeExecutor.getConfiguration(eventHandler, hostConfigurationKey); Collection targetConfigurations = skyframeExecutor.getConfigurations(eventHandler, targetConfigurationKeys).values(); return new BuildConfigurationCollection(targetConfigurations, hostConfiguration); } /** * Returns the intended top-level targets and configurations for the build. Note that this * performs additional Skyframe calls for the involved configurations and targets, which may be * expensive. */ public Collection getTopLevelCts( ExtendedEventHandler eventHandler, SkyframeExecutor skyframeExecutor) { List result = new ArrayList<>(); Map configs = skyframeExecutor.getConfigurations( eventHandler, topLevelCtKeys .stream() .map(ctk -> ctk.getConfigurationKey()) .filter(Predicates.notNull()) .collect(Collectors.toSet())); // TODO(ulfjack): This performs one Skyframe call per top-level target. This is not a // regression, but we should fix it nevertheless, either by doing a bulk lookup call or by // migrating the consumers of these to Skyframe so they can directly request the values. for (ConfiguredTargetKey key : topLevelCtKeys) { Target target; try { target = skyframeExecutor.getPackageManager().getTarget(eventHandler, key.getLabel()); } catch (NoSuchPackageException | NoSuchTargetException | InterruptedException e) { throw new RuntimeException("Failed to get package from TargetPatternPhaseValue", e); } BuildConfiguration config = key.getConfigurationKey() == null ? null : configs.get(key.getConfigurationKey()); result.add(new TargetAndConfiguration(target, config)); } return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PrepareAnalysisPhaseValue)) { return false; } PrepareAnalysisPhaseValue that = (PrepareAnalysisPhaseValue) obj; return this.hostConfigurationKey.equals(that.hostConfigurationKey) && this.targetConfigurationKeys.equals(that.targetConfigurationKeys) && this.topLevelCtKeys.equals(that.topLevelCtKeys); } @Override public int hashCode() { return Objects.hash( this.hostConfigurationKey, this.targetConfigurationKeys, this.topLevelCtKeys); } /** Create a prepare analysis phase key. */ @ThreadSafe public static SkyKey key( FragmentClassSet fragments, BuildOptions.OptionsDiffForReconstruction optionsDiff, Set multiCpu, Collection