| // 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 static com.google.common.collect.ImmutableList.toImmutableList; |
| import static com.google.devtools.build.lib.skyframe.DependencyResolver.getPrioritizedDetailedExitCode; |
| import static com.google.devtools.build.lib.skyframe.SkyValueRetrieverUtils.maybeFetchSkyValueRemotely; |
| import static com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.INITIAL_STATE; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableMultimap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Lists; |
| import com.google.devtools.build.lib.actions.ActionConflictException; |
| import com.google.devtools.build.lib.actions.ActionLookupKey; |
| import com.google.devtools.build.lib.analysis.AliasProvider; |
| import com.google.devtools.build.lib.analysis.AspectBaseTargetResolvedToolchainContext; |
| import com.google.devtools.build.lib.analysis.AspectValue; |
| import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment; |
| import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment.MissingDepException; |
| import com.google.devtools.build.lib.analysis.ConfiguredAspect; |
| import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory; |
| import com.google.devtools.build.lib.analysis.ConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.ConfiguredTargetValue; |
| import com.google.devtools.build.lib.analysis.DependencyKind; |
| import com.google.devtools.build.lib.analysis.ExecGroupCollection; |
| import com.google.devtools.build.lib.analysis.ExecGroupCollection.InvalidExecGroupException; |
| import com.google.devtools.build.lib.analysis.IncompatiblePlatformProvider; |
| import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException; |
| import com.google.devtools.build.lib.analysis.ResolvedToolchainContext; |
| import com.google.devtools.build.lib.analysis.TargetAndConfiguration; |
| import com.google.devtools.build.lib.analysis.ToolchainCollection; |
| import com.google.devtools.build.lib.analysis.TransitiveDependencyState; |
| import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue; |
| import com.google.devtools.build.lib.analysis.config.ConfigConditions; |
| import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException; |
| import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader; |
| import com.google.devtools.build.lib.analysis.config.StarlarkExecTransitionLoader.StarlarkExecTransitionLoadingException; |
| import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget; |
| import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.MergingException; |
| import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo; |
| import com.google.devtools.build.lib.analysis.producers.DependencyContext; |
| import com.google.devtools.build.lib.analysis.producers.DependencyContextProducer; |
| import com.google.devtools.build.lib.analysis.producers.UnloadedToolchainContextsInputs; |
| import com.google.devtools.build.lib.analysis.producers.UnloadedToolchainContextsProducer; |
| import com.google.devtools.build.lib.analysis.starlark.StarlarkAttributeTransitionProvider; |
| import com.google.devtools.build.lib.bugreport.BugReport; |
| import com.google.devtools.build.lib.causes.Cause; |
| import com.google.devtools.build.lib.causes.LabelCause; |
| import com.google.devtools.build.lib.cmdline.Label; |
| import com.google.devtools.build.lib.cmdline.PackageIdentifier; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; |
| import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; |
| import com.google.devtools.build.lib.events.Event; |
| import com.google.devtools.build.lib.events.StoredEventHandler; |
| import com.google.devtools.build.lib.packages.Aspect; |
| import com.google.devtools.build.lib.packages.AspectDefinition; |
| import com.google.devtools.build.lib.packages.Attribute; |
| import com.google.devtools.build.lib.packages.BuildFileContainsErrorsException; |
| import com.google.devtools.build.lib.packages.NativeAspectClass; |
| import com.google.devtools.build.lib.packages.NoSuchTargetException; |
| import com.google.devtools.build.lib.packages.NoSuchThingException; |
| import com.google.devtools.build.lib.packages.OutputFile; |
| import com.google.devtools.build.lib.packages.Package; |
| import com.google.devtools.build.lib.packages.Rule; |
| import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; |
| import com.google.devtools.build.lib.packages.RuleClassProvider; |
| import com.google.devtools.build.lib.packages.StarlarkAspectClass; |
| import com.google.devtools.build.lib.packages.StarlarkDefinedAspect; |
| import com.google.devtools.build.lib.packages.Target; |
| import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions; |
| import com.google.devtools.build.lib.profiler.memory.CurrentRuleTracker; |
| import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey; |
| import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider; |
| import com.google.devtools.build.lib.skyframe.config.BuildConfigurationKey; |
| import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever; |
| import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.RetrievalResult; |
| import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.SerializationState; |
| import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.SerializationStateProvider; |
| import com.google.devtools.build.lib.skyframe.serialization.analysis.RemoteAnalysisCachingDependenciesProvider; |
| import com.google.devtools.build.lib.skyframe.toolchains.ToolchainContextUtil; |
| import com.google.devtools.build.lib.skyframe.toolchains.ToolchainException; |
| import com.google.devtools.build.lib.skyframe.toolchains.UnloadedToolchainContext; |
| import com.google.devtools.build.lib.util.OrderedSetMultimap; |
| import com.google.devtools.build.lib.util.Pair; |
| import com.google.devtools.build.skyframe.SkyFunction; |
| import com.google.devtools.build.skyframe.SkyFunction.Environment.SkyKeyComputeState; |
| import com.google.devtools.build.skyframe.SkyFunctionException; |
| import com.google.devtools.build.skyframe.SkyKey; |
| import com.google.devtools.build.skyframe.SkyValue; |
| import com.google.devtools.build.skyframe.SkyframeLookupResult; |
| import com.google.devtools.build.skyframe.state.Driver; |
| import com.google.devtools.build.skyframe.state.StateMachine; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Optional; |
| import javax.annotation.Nullable; |
| import net.starlark.java.eval.StarlarkSemantics; |
| |
| /** |
| * The Skyframe function that generates aspects. |
| * |
| * <p>This class, together with {@link ConfiguredTargetFunction} drives the analysis phase. For more |
| * information, see {@link com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory}. |
| * |
| * <p>{@link AspectFunction} takes a SkyKey containing an {@link AspectKey} [a tuple of (target |
| * label, configurations, aspect class and aspect parameters)], loads an {@link Aspect} from aspect |
| * class and aspect parameters, gets a {@link ConfiguredTarget} for label and configurations, and |
| * then creates a {@link ConfiguredAspect} for a given {@link AspectKey}. |
| * |
| * <p>See {@link com.google.devtools.build.lib.packages.AspectClass} documentation for an overview |
| * of aspect-related classes |
| * |
| * @see com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory |
| * @see com.google.devtools.build.lib.packages.AspectClass |
| */ |
| final class AspectFunction implements SkyFunction { |
| private final BuildViewProvider buildViewProvider; |
| private final RuleClassProvider ruleClassProvider; |
| |
| /** |
| * Indicates whether the set of packages transitively loaded for a given {@link AspectValue} will |
| * be needed later (see {@link |
| * com.google.devtools.build.lib.analysis.ConfiguredObjectValue#getTransitivePackages}). If not, |
| * they are not collected and stored. |
| */ |
| private final boolean storeTransitivePackages; |
| |
| /** |
| * Packages of prerequisites. |
| * |
| * <p>See {@link ConfiguredTargetFunction#prerequisitePackages} for more details. |
| */ |
| private final PrerequisitePackageFunction prerequisitePackages; |
| |
| /** |
| * Used to look up configured targets and configurations of the underlying target dependencies |
| * without adding dependency edges to them. |
| * |
| * <p>A regular {@code Skyframe} lookup of the target's dependencies while evaluating the aspect |
| * propagation logic adds unnecessary dependency edges between the aspect and its target's |
| * dependencies. Instead {@link BaseTargetPrerequisitesSupplier} function is used to directly look |
| * up the dependency values. |
| * |
| * <p>Regular {@code Skyframe} lookup is used to get the {@link ConfiguredTargetValue}s of the |
| * aspect's implicit dependencies and its underlying target to establish a dependency from the |
| * {@link AspectValue} to them. While aspect explicit attributes can only be of types: string, |
| * integer or boolean so no dependencies will be created from them. |
| * |
| * <p>This is safe from incrementality perspective because if a dependency is invalidated, the |
| * underlying target will be invalidated and transitively invalidates the {@link AspectValue}. |
| */ |
| private final BaseTargetPrerequisitesSupplier baseTargetPrerequisitesSupplier; |
| |
| AspectFunction( |
| BuildViewProvider buildViewProvider, |
| RuleClassProvider ruleClassProvider, |
| boolean storeTransitivePackages, |
| PrerequisitePackageFunction prerequisitePackages, |
| BaseTargetPrerequisitesSupplier baseTargetPrerequisitesSupplier) { |
| this.buildViewProvider = buildViewProvider; |
| this.ruleClassProvider = ruleClassProvider; |
| this.storeTransitivePackages = storeTransitivePackages; |
| this.prerequisitePackages = prerequisitePackages; |
| this.baseTargetPrerequisitesSupplier = baseTargetPrerequisitesSupplier; |
| } |
| |
| static class State |
| implements SkyKeyComputeState, |
| UnloadedToolchainContextsProducer.ResultSink, |
| SerializationStateProvider { |
| @Nullable InitialValues initialValues; |
| |
| final DependencyResolver.State computeDependenciesState; |
| |
| /** |
| * Computes the {@link UnloadedToolchainContext} collection for the underlying target of the |
| * aspect. |
| * |
| * <p>One of {@link #baseTargetUnloadedToolchainContexts}, {@link |
| * #baseTargetUnloadedToolchainContextsError} or {@link #baseTargetHasNoToolchains} will be set |
| * upon completion. |
| */ |
| @Nullable // Non-null when in-flight. |
| Driver baseTargetUnloadedToolchainContextsProducer; |
| |
| @Nullable ToolchainCollection<UnloadedToolchainContext> baseTargetUnloadedToolchainContexts; |
| |
| @Nullable ToolchainException baseTargetUnloadedToolchainContextsError; |
| |
| // Will be true if the target doesn't require toolchain resolution. |
| boolean baseTargetHasNoToolchains; |
| |
| private SerializationState serializationState = INITIAL_STATE; |
| |
| private State( |
| boolean storeTransitivePackages, PrerequisitePackageFunction prerequisitePackages) { |
| this.computeDependenciesState = |
| new DependencyResolver.State(storeTransitivePackages, prerequisitePackages); |
| } |
| |
| @Override |
| public void acceptUnloadedToolchainContexts( |
| @Nullable ToolchainCollection<UnloadedToolchainContext> value) { |
| this.baseTargetUnloadedToolchainContexts = value; |
| if (this.baseTargetUnloadedToolchainContexts == null) { |
| this.baseTargetHasNoToolchains = true; |
| } |
| } |
| |
| @Override |
| public void acceptUnloadedToolchainContextsError(ToolchainException error) { |
| this.baseTargetUnloadedToolchainContextsError = error; |
| } |
| |
| @Override |
| public SerializationState getSerializationState() { |
| return serializationState; |
| } |
| |
| @Override |
| public void setSerializationState(SerializationState state) { |
| this.serializationState = state; |
| } |
| } |
| |
| private static class InitialValues { |
| @Nullable private final Aspect aspect; |
| @Nullable private final ConfiguredAspectFactory aspectFactory; |
| private final ConfiguredTarget baseConfiguredTarget; |
| |
| private InitialValues( |
| @Nullable Aspect aspect, |
| @Nullable ConfiguredAspectFactory aspectFactory, |
| ConfiguredTarget baseConfiguredTarget) { |
| this.aspect = aspect; |
| this.aspectFactory = aspectFactory; |
| this.baseConfiguredTarget = baseConfiguredTarget; |
| } |
| } |
| |
| @Nullable |
| @Override |
| public SkyValue compute(SkyKey skyKey, Environment env) |
| throws AspectFunctionException, InterruptedException { |
| AspectKey key = (AspectKey) skyKey.argument(); |
| State state = env.getState(() -> new State(storeTransitivePackages, prerequisitePackages)); |
| |
| RemoteAnalysisCachingDependenciesProvider analysisCachingDeps = |
| buildViewProvider.getSkyframeBuildView().getRemoteAnalysisCachingDependenciesProvider(); |
| if (analysisCachingDeps.enabled()) { |
| RetrievalResult retrievalResult = |
| maybeFetchSkyValueRemotely(key, env, analysisCachingDeps, state); |
| switch (retrievalResult) { |
| case SkyValueRetriever.Restart unused: |
| return null; |
| case SkyValueRetriever.RetrievedValue v: |
| return v.value(); |
| case SkyValueRetriever.NoCachedData unused: |
| break; |
| } |
| } |
| |
| DependencyResolver.State computeDependenciesState = state.computeDependenciesState; |
| if (state.initialValues == null) { |
| InitialValues initialValues = getInitialValues(computeDependenciesState, key, env); |
| if (initialValues == null) { |
| return null; |
| } |
| state.initialValues = initialValues; |
| } |
| Aspect aspect = state.initialValues.aspect; |
| ConfiguredAspectFactory aspectFactory = state.initialValues.aspectFactory; |
| ConfiguredTarget associatedTarget = state.initialValues.baseConfiguredTarget; |
| TargetAndConfiguration targetAndConfiguration = computeDependenciesState.targetAndConfiguration; |
| Target target = targetAndConfiguration.getTarget(); |
| BuildConfigurationValue configuration = targetAndConfiguration.getConfiguration(); |
| |
| // If the target is incompatible, then there's not much to do. The intent here is to create an |
| // AspectValue that doesn't trigger any of the associated target's dependencies to be evaluated |
| // against this aspect. |
| if (associatedTarget.get(IncompatiblePlatformProvider.PROVIDER) != null |
| || |
| // Similarly, aspects that propagate into post-NoConfigTransition targets can't access |
| // most flags or dependencies and are likely to be unsound. So make aspects propagating to |
| // these configurations no-ops. |
| (configuration != null && configuration.getOptions().hasNoConfig())) { |
| return AspectValue.create( |
| key, |
| aspect, |
| ConfiguredAspect.NonApplicableAspect.INSTANCE, |
| computeDependenciesState.transitivePackages()); |
| } |
| |
| if (AliasProvider.isAlias(associatedTarget)) { |
| return createAliasAspect( |
| env, |
| targetAndConfiguration, |
| aspect, |
| key, |
| associatedTarget, |
| computeDependenciesState.transitiveState); |
| } |
| // If we get here, label should match original label, and therefore the target we looked up |
| // above indeed corresponds to associatedTarget.getLabel(). |
| Preconditions.checkState( |
| associatedTarget.getOriginalLabel().equals(associatedTarget.getLabel()), |
| "Non-alias %s should have matching label but found %s", |
| associatedTarget.getOriginalLabel(), |
| associatedTarget.getLabel()); |
| |
| // If the incompatible flag is set, the top-level aspect should not be applied on top-level |
| // targets whose rules do not advertise the aspect's required providers. The aspect should not |
| // also propagate to these targets dependencies. |
| StarlarkSemantics starlarkSemantics = PrecomputedValue.STARLARK_SEMANTICS.get(env); |
| if (starlarkSemantics == null) { |
| return null; |
| } |
| boolean checkRuleAdvertisedProviders = |
| starlarkSemantics.getBool( |
| BuildLanguageOptions.INCOMPATIBLE_TOP_LEVEL_ASPECTS_REQUIRE_PROVIDERS); |
| if (checkRuleAdvertisedProviders) { |
| if (target instanceof Rule) { |
| if (!aspect |
| .getDefinition() |
| .getRequiredProviders() |
| .isSatisfiedBy(((Rule) target).getRuleClassObject().getAdvertisedProviders())) { |
| return AspectValue.create( |
| key, |
| aspect, |
| ConfiguredAspect.NonApplicableAspect.INSTANCE, |
| computeDependenciesState.transitivePackages()); |
| } |
| } |
| } |
| |
| ImmutableList<Aspect> topologicalAspectPath; |
| if (key.getBaseKeys().isEmpty()) { |
| topologicalAspectPath = ImmutableList.of(aspect); |
| } else { |
| LinkedHashSet<AspectKey> orderedKeys = new LinkedHashSet<>(); |
| collectAspectKeysInTopologicalOrder(key.getBaseKeys(), orderedKeys); |
| SkyframeLookupResult aspectValues = env.getValuesAndExceptions(orderedKeys); |
| if (env.valuesMissing()) { |
| return null; |
| } |
| ImmutableList.Builder<Aspect> topologicalAspectPathBuilder = |
| ImmutableList.builderWithExpectedSize(orderedKeys.size() + 1); |
| for (AspectKey aspectKey : orderedKeys) { |
| AspectValue aspectValue = (AspectValue) aspectValues.get(aspectKey); |
| if (aspectValue == null) { |
| BugReport.logUnexpected( |
| "aspectValue for: '%s' was missing, this should never happen", aspectKey); |
| return null; |
| } |
| topologicalAspectPathBuilder.add(aspectValue.getAspect()); |
| } |
| topologicalAspectPath = topologicalAspectPathBuilder.add(aspect).build(); |
| |
| List<ConfiguredAspect> directlyRequiredAspects = |
| Lists.transform(key.getBaseKeys(), k -> ((AspectValue) aspectValues.get(k))); |
| try { |
| associatedTarget = MergedConfiguredTarget.of(associatedTarget, directlyRequiredAspects); |
| } catch (MergingException e) { |
| env.getListener().handle(Event.error(target.getLocation(), e.getMessage())); |
| throw new AspectFunctionException( |
| new AspectCreationException(e.getMessage(), target.getLabel(), configuration)); |
| } |
| } |
| |
| try { |
| var dependencyContext = getDependencyContext(computeDependenciesState, key, aspect, env); |
| if (dependencyContext == null) { |
| return null; |
| } |
| |
| ToolchainCollection<UnloadedToolchainContext> baseTargetUnloadedToolchainContexts = null; |
| if (target.isRule()) { |
| Pair<ToolchainCollection<UnloadedToolchainContext>, Boolean> contextOrRestart = |
| getBaseTargetUnloadedToolchainContexts( |
| state, targetAndConfiguration, key.getBaseConfiguredTargetKey(), env); |
| if (contextOrRestart.second) { |
| return null; // Need Skyframe deps. |
| } else { |
| baseTargetUnloadedToolchainContexts = contextOrRestart.first; |
| } |
| } |
| |
| Optional<StarlarkAttributeTransitionProvider> starlarkExecTransition; |
| try { |
| starlarkExecTransition = |
| StarlarkExecTransitionLoader.loadStarlarkExecTransition( |
| targetAndConfiguration.getConfiguration() == null |
| ? null |
| : targetAndConfiguration.getConfiguration().getOptions(), |
| (bzlKey) -> |
| (BzlLoadValue) env.getValueOrThrow(bzlKey, BzlLoadFailedException.class)); |
| if (starlarkExecTransition == null) { |
| return null; // Need Skyframe deps. |
| } |
| } catch (StarlarkExecTransitionLoadingException | InterruptedException e) { |
| throw new AspectCreationException(e.getMessage(), key.getLabel(), configuration); |
| } |
| |
| OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> depValueMap = |
| DependencyResolver.computeDependencies( |
| computeDependenciesState, |
| ConfiguredTargetKey.fromConfiguredTarget(associatedTarget), |
| topologicalAspectPath, |
| buildViewProvider.getSkyframeBuildView().getStarlarkTransitionCache(), |
| starlarkExecTransition.orElse(null), |
| env, |
| env.getListener(), |
| baseTargetPrerequisitesSupplier, |
| baseTargetUnloadedToolchainContexts); |
| if (!computeDependenciesState.transitiveRootCauses().isEmpty()) { |
| NestedSet<Cause> causes = computeDependenciesState.transitiveRootCauses().build(); |
| throw new AspectFunctionException( |
| new AspectCreationException( |
| "Loading failed", causes, getPrioritizedDetailedExitCode(causes))); |
| } |
| if (depValueMap == null) { |
| return null; |
| } |
| |
| // Load the requested toolchains into the ToolchainContext, now that we have dependencies. |
| ToolchainCollection<UnloadedToolchainContext> unloadedToolchainContexts = |
| dependencyContext.unloadedToolchainContexts(); |
| ToolchainCollection<ResolvedToolchainContext> toolchainContexts = null; |
| if (unloadedToolchainContexts != null) { |
| String targetDescription = |
| "aspect " + aspect.getDescriptor().getDescription() + " applied to " + target; |
| ToolchainCollection.Builder<ResolvedToolchainContext> contextsBuilder = |
| ToolchainCollection.builder(); |
| for (Map.Entry<String, UnloadedToolchainContext> unloadedContext : |
| unloadedToolchainContexts.getContextMap().entrySet()) { |
| ImmutableSet<ConfiguredTargetAndData> toolchainDependencies = |
| ImmutableSet.copyOf( |
| depValueMap.get(DependencyKind.forExecGroup(unloadedContext.getKey()))); |
| contextsBuilder.addContext( |
| unloadedContext.getKey(), |
| ResolvedToolchainContext.load( |
| unloadedContext.getValue(), targetDescription, toolchainDependencies)); |
| } |
| toolchainContexts = contextsBuilder.build(); |
| } |
| ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts; |
| try { |
| baseTargetToolchainContexts = |
| getBaseTargetToolchainContexts( |
| baseTargetUnloadedToolchainContexts, |
| aspect, |
| target, |
| topologicalAspectPath, |
| depValueMap); |
| } catch (MergingException e) { |
| env.getListener().handle(Event.error(target.getLocation(), e.getMessage())); |
| throw new AspectFunctionException( |
| new AspectCreationException(e.getMessage(), target.getLabel(), configuration)); |
| } |
| return createAspect( |
| env, |
| key, |
| topologicalAspectPath, |
| aspect, |
| aspectFactory, |
| target, |
| associatedTarget, |
| configuration, |
| dependencyContext.configConditions(), |
| toolchainContexts, |
| baseTargetToolchainContexts, |
| computeDependenciesState.execGroupCollectionBuilder, |
| depValueMap, |
| computeDependenciesState.transitiveState, |
| starlarkExecTransition.orElse(null)); |
| } catch (DependencyEvaluationException e) { |
| // TODO(bazel-team): consolidate all env.getListener().handle() calls in this method, like in |
| // ConfiguredTargetFunction. This encourages clear, consistent user messages (ideally without |
| // the programmer having to think about it). |
| if (!e.depReportedOwnError()) { |
| env.getListener().handle(Event.error(e.getLocation(), e.getMessage())); |
| } |
| if (e.getCause() instanceof ConfiguredValueCreationException cause) { |
| throw new AspectFunctionException( |
| new AspectCreationException( |
| cause.getMessage(), cause.getRootCauses(), cause.getDetailedExitCode())); |
| } |
| // Cast to InconsistentAspectOrderException as a consistency check. If you add any |
| // DependencyEvaluationException constructors, you may need to change this code, too. |
| InconsistentAspectOrderException cause = (InconsistentAspectOrderException) e.getCause(); |
| env.getListener().handle(Event.error(cause.getLocation(), cause.getMessage())); |
| throw new AspectFunctionException( |
| new AspectCreationException(cause.getMessage(), key.getLabel(), configuration)); |
| } catch (AspectCreationException e) { |
| throw new AspectFunctionException(e); |
| } catch (ConfiguredValueCreationException e) { |
| throw new AspectFunctionException(e); |
| } catch (ToolchainException e) { |
| throw new AspectFunctionException( |
| new AspectCreationException( |
| e.getMessage(), new LabelCause(key.getLabel(), e.getDetailedExitCode()))); |
| } |
| } |
| |
| /** |
| * Returns the {@link ToolchainCollection} of {@link AspectBaseTargetResolvedToolchainContext}s |
| * for the base target. |
| */ |
| @Nullable |
| private static ToolchainCollection<AspectBaseTargetResolvedToolchainContext> |
| getBaseTargetToolchainContexts( |
| ToolchainCollection<UnloadedToolchainContext> baseTargetUnloadedToolchainContexts, |
| Aspect aspect, |
| Target target, |
| ImmutableList<Aspect> aspectsPath, |
| OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> depValueMap) |
| throws MergingException { |
| if (baseTargetUnloadedToolchainContexts == null |
| || !canAspectsPropagateToToolchains(aspectsPath, target)) { |
| return null; |
| } |
| String description = |
| "aspect " + aspect.getDescriptor().getDescription() + " applied to " + target; |
| |
| ToolchainCollection.Builder<AspectBaseTargetResolvedToolchainContext> targetContextsBuilder = |
| ToolchainCollection.builder(); |
| |
| for (Map.Entry<String, UnloadedToolchainContext> unloadedContext : |
| baseTargetUnloadedToolchainContexts.getContextMap().entrySet()) { |
| // For each requested toolchain type, collect the targets of its resolved toolchains. If |
| // multiple types are resolved to the same toolchain, the `ConfiguredTargetAndData` |
| // of the toolchain can be different for each of them depending on the aspects |
| // propagating to each toolchain type. |
| ImmutableMultimap.Builder<ToolchainTypeInfo, ConfiguredTargetAndData> toolchainsDeps = |
| ImmutableMultimap.builder(); |
| |
| for (var toolchainTypeInfo : unloadedContext.getValue().toolchainTypeToResolved().keySet()) { |
| toolchainsDeps.putAll( |
| toolchainTypeInfo, |
| ImmutableSet.copyOf( |
| depValueMap.get( |
| DependencyKind.forBaseTargetExecGroup( |
| unloadedContext.getKey(), toolchainTypeInfo.typeLabel())))); |
| } |
| |
| targetContextsBuilder.addContext( |
| unloadedContext.getKey(), |
| AspectBaseTargetResolvedToolchainContext.load( |
| unloadedContext.getValue(), description, toolchainsDeps.build())); |
| } |
| |
| return targetContextsBuilder.build(); |
| } |
| |
| /** |
| * Returns the {@link ToolchainCollection} of {@link UnloadedToolchainContext}s for the base |
| * target and whether a Skyframe restart is needed. |
| * |
| * <p>{@code state.baseTargetUnloadedToolchainContexts} can be evaluated to {@code null} if the |
| * base target doesn't require toolchain resolution (see {@link |
| * com.google.devtools.build.lib.packages.RuleClass.ToolchainResolutionMode}). That's why an extra |
| * boolean is returned to distinguish between the case when {@code |
| * state.baseTargetUnloadedToolchainContexts} is null because a Skyframe restart is needed and |
| * when it is already evaluated to null. |
| */ |
| private Pair<ToolchainCollection<UnloadedToolchainContext>, Boolean> |
| getBaseTargetUnloadedToolchainContexts( |
| State state, |
| TargetAndConfiguration targetAndConfiguration, |
| ConfiguredTargetKey configuredTargetKey, |
| Environment env) |
| throws InterruptedException, ToolchainException { |
| |
| // if the base target's toolchain contexts are already evaluated, return them. |
| if (state.baseTargetUnloadedToolchainContexts != null || state.baseTargetHasNoToolchains) { |
| return Pair.of(state.baseTargetUnloadedToolchainContexts, false); |
| } |
| |
| // initiate evaluating the base target's toolchain contexts. |
| if (state.baseTargetUnloadedToolchainContextsProducer == null) { |
| UnloadedToolchainContextsInputs unloadedToolchainContextsInputs = |
| DependencyResolver.getUnloadedToolchainContextsInputs( |
| targetAndConfiguration, |
| configuredTargetKey.getExecutionPlatformLabel(), |
| ruleClassProvider, |
| env.getListener()); |
| state.baseTargetUnloadedToolchainContextsProducer = |
| new Driver( |
| new UnloadedToolchainContextsProducer( |
| unloadedToolchainContextsInputs, |
| baseTargetPrerequisitesSupplier, |
| (UnloadedToolchainContextsProducer.ResultSink) state, |
| t -> { |
| return StateMachine.DONE; |
| })); |
| } |
| if (state.baseTargetUnloadedToolchainContextsProducer.drive(env)) { |
| state.baseTargetUnloadedToolchainContextsProducer = null; |
| } else { |
| // Skyframe restart is needed |
| return Pair.of(null, true); |
| } |
| var error = state.baseTargetUnloadedToolchainContextsError; |
| if (error != null) { |
| throw error; |
| } |
| |
| // base target's toolchain contexts are evaluated in this iteration without requiring a |
| // Skyframe restart. |
| return Pair.of(state.baseTargetUnloadedToolchainContexts, false); |
| } |
| |
| /** |
| * Returns true if it is possible to propagate the aspects to the target's toolchains based on the |
| * conditions: |
| * |
| * <p>The base target is a rule. |
| * |
| * <p>At least one of the aspects in the aspects path propagates to toolchains. |
| */ |
| private static boolean canAspectsPropagateToToolchains( |
| ImmutableList<Aspect> topologicalAspectPath, Target baseTarget) { |
| if (!baseTarget.isRule()) { |
| return false; |
| } |
| |
| return topologicalAspectPath.stream() |
| .anyMatch(aspect -> aspect.getDefinition().propagatesToToolchains()); |
| } |
| |
| /** Populates {@code state.execGroupCollection} as a side effect. */ |
| @Nullable // Null if a Skyframe restart is needed. |
| private DependencyContext getDependencyContext( |
| DependencyResolver.State state, AspectKey key, Aspect aspect, Environment env) |
| throws InterruptedException, ConfiguredValueCreationException, ToolchainException { |
| if (state.dependencyContext != null) { |
| return state.dependencyContext; |
| } |
| if (state.dependencyContextProducer == null) { |
| TargetAndConfiguration targetAndConfiguration = state.targetAndConfiguration; |
| UnloadedToolchainContextsInputs unloadedToolchainContextsInputs = |
| getUnloadedToolchainContextsInputs( |
| aspect.getDefinition(), |
| key.getConfigurationKey(), |
| targetAndConfiguration.getConfiguration()); |
| state.execGroupCollectionBuilder = unloadedToolchainContextsInputs; |
| state.dependencyContextProducer = |
| new Driver( |
| new DependencyContextProducer( |
| unloadedToolchainContextsInputs, |
| targetAndConfiguration, |
| key.getConfigurationKey(), |
| state.transitiveState, |
| (DependencyContextProducer.ResultSink) state)); |
| } |
| if (state.dependencyContextProducer.drive(env)) { |
| state.dependencyContextProducer = null; |
| } |
| |
| // During error bubbling, the state machine might not be done, but still emit an error. |
| var error = state.dependencyContextError; |
| if (error != null) { |
| switch (error.kind()) { |
| case TOOLCHAIN: |
| throw error.toolchain(); |
| case CONFIGURED_VALUE_CREATION: |
| throw error.configuredValueCreation(); |
| case INCOMPATIBLE_TARGET: |
| throw new IllegalStateException("Unexpected error: " + error.incompatibleTarget()); |
| case VALIDATION: |
| throw new IllegalStateException("Unexpected error: " + error.validation()); |
| } |
| throw new IllegalStateException("unreachable"); |
| } |
| |
| return state.dependencyContext; // Null if not yet done. |
| } |
| |
| static BzlLoadValue.Key bzlLoadKeyForStarlarkAspect(StarlarkAspectClass starlarkAspectClass) { |
| Label extensionLabel = starlarkAspectClass.getExtensionLabel(); |
| return StarlarkBuiltinsValue.isBuiltinsRepo(extensionLabel.getRepository()) |
| ? BzlLoadValue.keyForBuiltins(extensionLabel) |
| : BzlLoadValue.keyForBuild(extensionLabel); |
| } |
| |
| @Nullable |
| private static InitialValues getInitialValues( |
| DependencyResolver.State state, AspectKey key, Environment env) |
| throws AspectFunctionException, InterruptedException { |
| ActionLookupKey configuredTargetLookupKey = key.getBaseConfiguredTargetKey(); |
| PackageIdentifier basePackageKey = |
| key.getBaseConfiguredTargetKey().getLabel().getPackageIdentifier(); |
| var initialKeys = |
| ImmutableSet.<SkyKey>builder().add(configuredTargetLookupKey).add(basePackageKey); |
| |
| BuildConfigurationKey configurationKey = key.getConfigurationKey(); |
| if (configurationKey != null) { |
| initialKeys.add(configurationKey); |
| } |
| |
| StarlarkAspectClass starlarkAspectClass; |
| BzlLoadValue.Key bzlLoadKey; |
| if (key.getAspectClass() instanceof NativeAspectClass) { |
| starlarkAspectClass = null; |
| bzlLoadKey = null; |
| } else { |
| Preconditions.checkState( |
| key.getAspectClass() instanceof StarlarkAspectClass, "Unknown aspect class: %s", key); |
| starlarkAspectClass = (StarlarkAspectClass) key.getAspectClass(); |
| initialKeys.add(bzlLoadKey = bzlLoadKeyForStarlarkAspect(starlarkAspectClass)); |
| } |
| |
| SkyframeLookupResult initialValues = env.getValuesAndExceptions(initialKeys.build()); |
| if (env.valuesMissing()) { |
| return null; |
| } |
| |
| ConfiguredTarget baseConfiguredTarget; |
| try { |
| var baseConfiguredTargetValue = |
| (ConfiguredTargetValue) |
| initialValues.getOrThrow( |
| configuredTargetLookupKey, ConfiguredValueCreationException.class); |
| if (baseConfiguredTargetValue == null) { |
| BugReport.logUnexpected( |
| "Unexpected exception with %s and AspectKey %s", key.getBaseConfiguredTargetKey(), key); |
| return null; |
| } |
| baseConfiguredTarget = baseConfiguredTargetValue.getConfiguredTarget(); |
| } catch (ConfiguredValueCreationException e) { |
| throw new AspectFunctionException( |
| new AspectCreationException(e.getMessage(), e.getRootCauses(), e.getDetailedExitCode())); |
| } |
| Preconditions.checkState( |
| Objects.equals(key.getConfigurationKey(), baseConfiguredTarget.getConfigurationKey()), |
| "Aspect not in same configuration as base configured target: %s, %s", |
| key, |
| baseConfiguredTarget); |
| |
| // Keep this in sync with the same code in ConfiguredTargetFunction. |
| Package basePackage = ((PackageValue) initialValues.get(basePackageKey)).getPackage(); |
| if (basePackage.containsErrors()) { |
| throw new AspectFunctionException( |
| new BuildFileContainsErrorsException(key.getLabel().getPackageIdentifier())); |
| } |
| Target target; |
| try { |
| target = basePackage.getTarget(baseConfiguredTarget.getOriginalLabel().getName()); |
| } catch (NoSuchTargetException e) { |
| throw new IllegalStateException("Name already verified", e); |
| } |
| |
| BuildConfigurationValue configuration = |
| configurationKey == null |
| ? null |
| : (BuildConfigurationValue) initialValues.get(configurationKey); |
| |
| state.targetAndConfiguration = new TargetAndConfiguration(target, configuration); |
| |
| ConfiguredAspectFactory aspectFactory; |
| Aspect aspect; |
| if (bzlLoadKey == null) { |
| NativeAspectClass nativeAspectClass = (NativeAspectClass) key.getAspectClass(); |
| aspectFactory = (ConfiguredAspectFactory) nativeAspectClass; |
| aspect = Aspect.forNative(nativeAspectClass, key.getParameters()); |
| } else { |
| StarlarkDefinedAspect starlarkAspect; |
| try { |
| BzlLoadValue bzlLoadvalue; |
| try { |
| bzlLoadvalue = |
| (BzlLoadValue) initialValues.getOrThrow(bzlLoadKey, BzlLoadFailedException.class); |
| if (bzlLoadvalue == null) { |
| BugReport.logUnexpected( |
| "Unexpected exception with %s and AspectKey %s", bzlLoadKey, key); |
| return null; |
| } |
| } catch (BzlLoadFailedException e) { |
| throw new AspectCreationException( |
| e.getMessage(), starlarkAspectClass.getExtensionLabel(), e.getDetailedExitCode()); |
| } |
| starlarkAspect = loadAspectFromBzl(starlarkAspectClass, bzlLoadvalue); |
| } catch (AspectCreationException e) { |
| env.getListener().handle(Event.error(e.getMessage())); |
| throw new AspectFunctionException(e); |
| } |
| aspectFactory = new StarlarkAspectFactory(starlarkAspect); |
| aspect = |
| Aspect.forStarlark( |
| starlarkAspect.getAspectClass(), |
| starlarkAspect.getDefinition(key.getParameters()), |
| key.getParameters()); |
| } |
| |
| return new InitialValues(aspect, aspectFactory, baseConfiguredTarget); |
| } |
| |
| /** |
| * Loads a Starlark-defined aspect from an extension file. |
| * |
| * @throws AspectCreationException if the value loaded is not a {@link StarlarkDefinedAspect} |
| */ |
| static StarlarkDefinedAspect loadAspectFromBzl( |
| StarlarkAspectClass starlarkAspectClass, BzlLoadValue bzlLoadValue) |
| throws AspectCreationException { |
| Label extensionLabel = starlarkAspectClass.getExtensionLabel(); |
| String starlarkValueName = starlarkAspectClass.getExportedName(); |
| Object starlarkValue = bzlLoadValue.getModule().getGlobal(starlarkValueName); |
| if (!(starlarkValue instanceof StarlarkDefinedAspect)) { |
| throw new AspectCreationException( |
| String.format( |
| starlarkValue == null ? "%s is not exported from %s" : "%s from %s is not an aspect", |
| starlarkValueName, |
| extensionLabel), |
| extensionLabel); |
| } |
| return (StarlarkDefinedAspect) starlarkValue; |
| } |
| |
| private static UnloadedToolchainContextsInputs getUnloadedToolchainContextsInputs( |
| AspectDefinition aspectDefinition, |
| @Nullable BuildConfigurationKey configurationKey, |
| @Nullable BuildConfigurationValue configuration) { |
| if (configuration == null) { |
| // Configuration can be null in the case of aspects applied to input files. In this case, |
| // there are no toolchains being used. |
| return UnloadedToolchainContextsInputs.empty(); |
| } |
| |
| boolean useAutoExecGroups = shouldUseAutoExecGroups(aspectDefinition, configuration); |
| var processedExecGroups = |
| ExecGroupCollection.process( |
| aspectDefinition.execGroups(), |
| aspectDefinition.execCompatibleWith(), |
| aspectDefinition.getToolchainTypes(), |
| useAutoExecGroups); |
| // Note: `configuration.getOptions().hasNoConfig()` is handled early in #compute. |
| return UnloadedToolchainContextsInputs.create( |
| processedExecGroups, |
| ToolchainContextUtil.createDefaultToolchainContextKey( |
| configurationKey, |
| aspectDefinition.execCompatibleWith(), |
| /* debugTarget= */ false, |
| /* useAutoExecGroups= */ useAutoExecGroups, |
| aspectDefinition.getToolchainTypes(), |
| /* parentExecutionPlatformLabel= */ null)); |
| } |
| |
| private static boolean shouldUseAutoExecGroups( |
| AspectDefinition aspectDefinition, BuildConfigurationValue configuration) { |
| // TODO: b/370558813 - Use AutoExecGroupsMode for aspects, as well. |
| ImmutableMap<String, Attribute> aspectAttributes = aspectDefinition.getAttributes(); |
| if (aspectAttributes.containsKey("$use_auto_exec_groups")) { |
| return (boolean) aspectAttributes.get("$use_auto_exec_groups").getDefaultValueUnchecked(); |
| } |
| return configuration.useAutoExecGroups(); |
| } |
| |
| /** |
| * Collects {@link AspectKey} dependencies by performing a postorder traversal over {@link |
| * AspectKey#getBaseKeys}. |
| * |
| * <p>The resulting set of {@code orderedKeys} is topologically ordered: each aspect key appears |
| * after all of its dependencies. |
| */ |
| private static void collectAspectKeysInTopologicalOrder( |
| List<AspectKey> baseKeys, LinkedHashSet<AspectKey> orderedKeys) { |
| for (AspectKey key : baseKeys) { |
| if (!orderedKeys.contains(key)) { |
| collectAspectKeysInTopologicalOrder(key.getBaseKeys(), orderedKeys); |
| orderedKeys.add(key); |
| } |
| } |
| } |
| |
| /** |
| * Computes the given aspectKey of an alias-like target, by depending on the corresponding key of |
| * the next target in the alias chain (if there are more), or the "real" configured target. |
| */ |
| @Nullable |
| private AspectValue createAliasAspect( |
| Environment env, |
| TargetAndConfiguration targetAndConfiguration, |
| Aspect aspect, |
| AspectKey originalKey, |
| ConfiguredTarget baseConfiguredTarget, |
| TransitiveDependencyState transitiveState) |
| throws InterruptedException { |
| ImmutableList<Label> aliasChain = |
| baseConfiguredTarget.getProvider(AliasProvider.class).getAliasChain(); |
| |
| AspectKey actualKey; |
| if (aliasChain.size() > 1) { |
| // If there is another alias in the chain, follows it, creating the next alias aspect. |
| actualKey = |
| buildAliasAspectKey( |
| originalKey, aliasChain.get(1), baseConfiguredTarget.getConfigurationKey()); |
| } else { |
| // Otherwise, creates an aspect of the real configured target using its real configuration key |
| // which includes any transitions. |
| actualKey = |
| buildAliasAspectKey( |
| originalKey, |
| baseConfiguredTarget.getLabel(), |
| baseConfiguredTarget.getActual().getConfigurationKey()); |
| } |
| |
| return createAliasAspect( |
| env, targetAndConfiguration.getTarget(), originalKey, aspect, actualKey, transitiveState); |
| } |
| |
| @Nullable |
| private AspectValue createAliasAspect( |
| Environment env, |
| Target originalTarget, |
| AspectKey originalKey, |
| Aspect aspect, |
| AspectKey depKey, |
| TransitiveDependencyState transitiveState) |
| throws InterruptedException { |
| // Compute the AspectValue of the target the alias refers to (which can itself be either an |
| // alias or a real target) |
| AspectValue real = (AspectValue) env.getValue(depKey); |
| if (env.valuesMissing()) { |
| return null; |
| } |
| |
| NestedSet<Package> transitivePackages = |
| storeTransitivePackages |
| ? NestedSetBuilder.<Package>stableOrder() |
| .add(originalTarget.getPackage()) |
| .addTransitive(transitiveState.transitivePackages()) |
| .addTransitive(real.getTransitivePackages()) |
| .build() |
| : null; |
| return AspectValue.createForAlias( |
| originalKey, aspect, ConfiguredAspect.forAlias(real), transitivePackages); |
| } |
| |
| private static AspectKey buildAliasAspectKey( |
| AspectKey originalKey, Label aliasLabel, BuildConfigurationKey configurationKey) { |
| ImmutableList<AspectKey> aliasedBaseKeys = |
| originalKey.getBaseKeys().stream() |
| .map(baseKey -> buildAliasAspectKey(baseKey, aliasLabel, configurationKey)) |
| .collect(toImmutableList()); |
| return AspectKeyCreator.createAspectKey( |
| originalKey.getAspectDescriptor(), |
| aliasedBaseKeys, |
| ConfiguredTargetKey.builder() |
| .setLabel(aliasLabel) |
| .setConfigurationKey(configurationKey) |
| .build()); |
| } |
| |
| @Nullable |
| private AspectValue createAspect( |
| Environment env, |
| AspectKey key, |
| ImmutableList<Aspect> topologicalAspectPath, |
| Aspect aspect, |
| ConfiguredAspectFactory aspectFactory, |
| Target associatedTarget, |
| ConfiguredTarget associatedConfiguredTarget, |
| BuildConfigurationValue configuration, |
| ConfigConditions configConditions, |
| @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts, |
| @Nullable |
| ToolchainCollection<AspectBaseTargetResolvedToolchainContext> baseTargetToolchainContexts, |
| @Nullable ExecGroupCollection.Builder execGroupCollectionBuilder, |
| OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> directDeps, |
| TransitiveDependencyState transitiveState, |
| StarlarkAttributeTransitionProvider starlarkExecTransition) |
| throws AspectFunctionException, InterruptedException { |
| // Should be successfully evaluated and cached from the loading phase. |
| StarlarkBuiltinsValue starlarkBuiltinsValue = |
| (StarlarkBuiltinsValue) env.getValue(StarlarkBuiltinsValue.key()); |
| if (env.valuesMissing()) { |
| return null; |
| } |
| |
| SkyframeBuildView view = buildViewProvider.getSkyframeBuildView(); |
| |
| StoredEventHandler events = new StoredEventHandler(); |
| CachingAnalysisEnvironment analysisEnvironment = |
| view.createAnalysisEnvironment(key, events, env, configuration, starlarkBuiltinsValue); |
| |
| ConfiguredAspect configuredAspect; |
| if (aspect.getDefinition().applyToGeneratingRules() |
| && associatedTarget instanceof OutputFile outputFile) { |
| Label label = outputFile.getGeneratingRule().getLabel(); |
| return createAliasAspect( |
| env, associatedTarget, key, aspect, key.withLabel(label), transitiveState); |
| } else if (aspectMatchesConfiguredTarget( |
| associatedConfiguredTarget, associatedTarget instanceof Rule, aspect)) { |
| try { |
| CurrentRuleTracker.beginConfiguredAspect(aspect.getAspectClass()); |
| configuredAspect = |
| view.getConfiguredTargetFactory() |
| .createAspect( |
| analysisEnvironment, |
| associatedTarget, |
| associatedConfiguredTarget, |
| topologicalAspectPath, |
| aspectFactory, |
| aspect, |
| directDeps, |
| configConditions, |
| toolchainContexts, |
| baseTargetToolchainContexts, |
| execGroupCollectionBuilder, |
| configuration, |
| transitiveState.transitivePackages(), |
| key, |
| starlarkExecTransition); |
| } catch (MissingDepException e) { |
| Preconditions.checkState(env.valuesMissing()); |
| return null; |
| } catch (ActionConflictException e) { |
| throw new AspectFunctionException(e); |
| } catch (RuleErrorException e) { |
| throw new AspectFunctionException(e); |
| } catch (InvalidExecGroupException e) { |
| throw new AspectFunctionException(e); |
| } finally { |
| CurrentRuleTracker.endConfiguredAspect(); |
| } |
| } else { |
| configuredAspect = ConfiguredAspect.NonApplicableAspect.INSTANCE; |
| } |
| |
| events.replayOn(env.getListener()); |
| if (events.hasErrors()) { |
| analysisEnvironment.disable(associatedTarget); |
| String msg = "Analysis of target '" + associatedTarget.getLabel() + "' failed"; |
| throw new AspectFunctionException( |
| new AspectCreationException(msg, key.getLabel(), configuration)); |
| } |
| Preconditions.checkState( |
| !analysisEnvironment.hasErrors(), "Analysis environment hasError() but no errors reported"); |
| |
| if (env.valuesMissing()) { |
| return null; |
| } |
| |
| analysisEnvironment.disable(associatedTarget); |
| Preconditions.checkNotNull(configuredAspect); |
| |
| return AspectValue.create(key, aspect, configuredAspect, transitiveState.transitivePackages()); |
| } |
| |
| private static boolean aspectMatchesConfiguredTarget( |
| ConfiguredTarget ct, boolean isRule, Aspect aspect) { |
| if (!aspect.getDefinition().applyToFiles() |
| && !aspect.getDefinition().applyToGeneratingRules() |
| && !isRule) { |
| return false; |
| } |
| if (ct.getConfigurationKey() == null) { |
| // Aspects cannot apply to PackageGroups or InputFiles, the only cases where this is null. |
| return false; |
| } |
| // We need to check the configured target's providers against the aspect's required providers |
| // because top-level aspects do not check advertised providers of top-level targets. |
| return ct.satisfies(aspect.getDefinition().getRequiredProviders()); |
| } |
| |
| @Override |
| public String extractTag(SkyKey skyKey) { |
| AspectKey aspectKey = (AspectKey) skyKey.argument(); |
| return Label.print(aspectKey.getLabel()); |
| } |
| |
| /** Used to indicate errors during the computation of an {@link AspectValue}. */ |
| public static final class AspectFunctionException extends SkyFunctionException { |
| public AspectFunctionException(NoSuchThingException e) { |
| super(e, Transience.PERSISTENT); |
| } |
| |
| public AspectFunctionException(AspectCreationException e) { |
| super(e, Transience.PERSISTENT); |
| } |
| |
| public AspectFunctionException(ConfiguredValueCreationException e) { |
| super(e, Transience.PERSISTENT); |
| } |
| |
| public AspectFunctionException(InvalidExecGroupException e) { |
| super(e, Transience.PERSISTENT); |
| } |
| |
| public AspectFunctionException(ActionConflictException cause) { |
| super(cause, Transience.PERSISTENT); |
| } |
| |
| public AspectFunctionException(RuleErrorException cause) { |
| super(cause, Transience.PERSISTENT); |
| } |
| } |
| } |