| // 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.retrieveRemoteSkyValue; | |
| import com.google.common.base.Preconditions; | |
| import com.google.common.base.Supplier; | |
| 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.ConfiguredAspect.NonApplicableAspect; | |
| 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.DeclaredExecGroup; | |
| 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.RetrievalContext; | |
| import com.google.devtools.build.lib.skyframe.serialization.SkyValueRetriever.SerializableSkyKeyComputeState; | |
| import com.google.devtools.build.lib.skyframe.serialization.analysis.RemoteAnalysisCacheReaderDepsProvider; | |
| 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.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.io.IOException; | |
| 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.EvalException; | |
| /** | |
| * 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; | |
| private final Supplier<RemoteAnalysisCacheReaderDepsProvider> cachingDependenciesSupplier; | |
| private final AnalysisProgressReceiver analysisProgressReceiver; | |
| AspectFunction( | |
| BuildViewProvider buildViewProvider, | |
| RuleClassProvider ruleClassProvider, | |
| boolean storeTransitivePackages, | |
| PrerequisitePackageFunction prerequisitePackages, | |
| BaseTargetPrerequisitesSupplier baseTargetPrerequisitesSupplier, | |
| Supplier<RemoteAnalysisCacheReaderDepsProvider> cachingDependenciesSupplier, | |
| AnalysisProgressReceiver analysisProgressReceiver) { | |
| this.buildViewProvider = buildViewProvider; | |
| this.ruleClassProvider = ruleClassProvider; | |
| this.storeTransitivePackages = storeTransitivePackages; | |
| this.prerequisitePackages = prerequisitePackages; | |
| this.baseTargetPrerequisitesSupplier = baseTargetPrerequisitesSupplier; | |
| this.cachingDependenciesSupplier = cachingDependenciesSupplier; | |
| this.analysisProgressReceiver = analysisProgressReceiver; | |
| } | |
| static class State | |
| implements SerializableSkyKeyComputeState, UnloadedToolchainContextsProducer.ResultSink { | |
| @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; | |
| @Nullable // Initialized lazily | |
| private RetrievalContext retrievalContext = null; | |
| 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 RetrievalContext getRetrievalContext() { | |
| if (retrievalContext == null) { | |
| retrievalContext = new RetrievalContext(); | |
| } | |
| return retrievalContext; | |
| } | |
| } | |
| 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(); | |
| java.util.function.Supplier<State> stateSupplier = | |
| () -> new State(storeTransitivePackages, prerequisitePackages); | |
| RemoteAnalysisCacheReaderDepsProvider remoteCachingDependencies = | |
| cachingDependenciesSupplier.get(); | |
| if (remoteCachingDependencies.mode().isRetrievalEnabled()) { | |
| switch (retrieveRemoteSkyValue(key, env, remoteCachingDependencies, stateSupplier)) { | |
| case SkyValueRetriever.Restart unused: | |
| return null; | |
| case SkyValueRetriever.RetrievedValue v: | |
| analysisProgressReceiver.doneDownloadedConfiguredAspect(); | |
| return v.value(); | |
| case SkyValueRetriever.NoCachedData unused: | |
| break; | |
| } | |
| } | |
| State state = env.getState(stateSupplier); | |
| 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(); | |
| // PrerequisitesProducer should skip creating aspects on materializer targets. | |
| Preconditions.checkState(!target.isMaterializerRule()); | |
| // 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())) { | |
| var result = | |
| AspectValue.create( | |
| key, | |
| aspect, | |
| ConfiguredAspect.NonApplicableAspect.INSTANCE, | |
| computeDependenciesState.transitivePackages()); | |
| // TODO(lberki): Call tryUploadAsync() only in one place | |
| SkyValueRetrieverUtils.tryUploadAsync(remoteCachingDependencies, key, result, env); | |
| return result; | |
| } | |
| if (AliasProvider.isAlias(associatedTarget)) { | |
| var result = | |
| createAliasAspect( | |
| env, | |
| targetAndConfiguration, | |
| aspect, | |
| key, | |
| associatedTarget, | |
| computeDependenciesState.transitiveState); | |
| if (result != null) { | |
| // TODO(lberki): Call tryUploadAsync() only in one place | |
| SkyValueRetrieverUtils.tryUploadAsync(remoteCachingDependencies, key, result, env); | |
| } | |
| return result; | |
| } | |
| // 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 (associatedTarget.getConfigurationKey() == null || !targetSatisfiesAspect(target, aspect)) { | |
| // Aspects cannot apply to PackageGroups or InputFiles, the only cases where configuration key | |
| // is null. They also cannot apply to targets that don't satisfy the aspect's requirements. | |
| var result = | |
| AspectValue.create( | |
| key, | |
| aspect, | |
| ConfiguredAspect.NonApplicableAspect.INSTANCE, | |
| computeDependenciesState.transitivePackages()); | |
| // TODO(lberki): Call tryUploadAsync() only in one place | |
| SkyValueRetrieverUtils.tryUploadAsync(remoteCachingDependencies, key, result, env); | |
| return result; | |
| } | |
| 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, | |
| // Relevant for exec-config deps of the aspect itself. May need to pass the actual | |
| // key if there's a use case for an aspect to be applied to exec-config deps of an | |
| // aspect. | |
| /* loadExecAspectsKey= */ null, | |
| 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.contextMap().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, depValueMap); | |
| } catch (MergingException e) { | |
| env.getListener().handle(Event.error(target.getLocation(), e.getMessage())); | |
| throw new AspectFunctionException( | |
| new AspectCreationException(e.getMessage(), target.getLabel(), configuration)); | |
| } | |
| SkyValue result = | |
| createAspect( | |
| env, | |
| key, | |
| topologicalAspectPath, | |
| aspect, | |
| aspectFactory, | |
| target, | |
| associatedTarget, | |
| configuration, | |
| dependencyContext.configConditions(), | |
| toolchainContexts, | |
| baseTargetToolchainContexts, | |
| computeDependenciesState.execGroupCollectionBuilder, | |
| depValueMap, | |
| computeDependenciesState.transitiveState, | |
| starlarkExecTransition.orElse(null)); | |
| if (result != null) { | |
| SkyValueRetrieverUtils.tryUploadAsync(remoteCachingDependencies, key, result, env); | |
| } | |
| return result; | |
| } 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())); | |
| } | |
| // Exception while evaluating the aspect {@code attr_aspects} and {@code toolchains_aspects} | |
| // functions. | |
| if (e.getCause() instanceof EvalException cause) { | |
| throw new AspectFunctionException( | |
| new AspectCreationException(cause.getMessage(), key.getLabel(), configuration)); | |
| } | |
| // 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 | InvalidExecGroupException 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, | |
| OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> depValueMap) | |
| throws MergingException { | |
| if (baseTargetUnloadedToolchainContexts == null) { | |
| return null; | |
| } | |
| String description = | |
| "aspect " + aspect.getDescriptor().getDescription() + " applied to " + target; | |
| ToolchainCollection.Builder<AspectBaseTargetResolvedToolchainContext> targetContextsBuilder = | |
| ToolchainCollection.builder(); | |
| for (Map.Entry<String, UnloadedToolchainContext> unloadedContext : | |
| baseTargetUnloadedToolchainContexts.contextMap().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, InvalidExecGroupException { | |
| // 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); | |
| } | |
| /** 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) { | |
| // Assigned target might not be configured yet, in which case Skyframe restart is needed. | |
| 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 = | |
| DeclaredExecGroup.process( | |
| aspectDefinition.execGroups(), | |
| aspectDefinition.execCompatibleWith(), | |
| /* execGroupExecWith= */ ImmutableMultimap.of(), | |
| 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(); | |
| ConfiguredTarget nextTarget = baseConfiguredTarget.getActualNoFollow(); | |
| if (aliasChain.size() > 1) { | |
| Preconditions.checkState(aliasChain.get(1).equals(nextTarget.getOriginalLabel())); | |
| } | |
| AspectKey actualKey = | |
| buildAliasAspectKey( | |
| originalKey, nextTarget.getOriginalLabel(), nextTarget.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.Metadata> transitivePackages = | |
| storeTransitivePackages | |
| ? NestedSetBuilder.<Package.Metadata>stableOrder() | |
| .add(originalTarget.getPackageMetadata()) | |
| .addTransitive(transitiveState.transitivePackages()) | |
| .addTransitive(real.getTransitivePackages()) | |
| .build() | |
| : null; | |
| analysisProgressReceiver.doneConfigureAspect(); | |
| 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 { | |
| try { | |
| CurrentRuleTracker.beginConfiguredAspect(aspect.getAspectClass()); | |
| if (analysisEnvironment | |
| .getStarlarkSemantics() | |
| .get(BuildLanguageOptions.NESTED_SET_COUNT_LIMIT) | |
| > 0) { | |
| NestedSet.beginTargetNestedSetCount(); | |
| } | |
| configuredAspect = | |
| view.getConfiguredTargetFactory() | |
| .createAspect( | |
| analysisEnvironment, | |
| associatedTarget, | |
| associatedConfiguredTarget, | |
| topologicalAspectPath, | |
| aspectFactory, | |
| aspect, | |
| directDeps, | |
| configConditions, | |
| toolchainContexts, | |
| baseTargetToolchainContexts, | |
| execGroupCollectionBuilder, | |
| configuration, | |
| transitiveState.transitivePackages(), | |
| key, | |
| starlarkExecTransition); | |
| } catch (IOException e) { | |
| throw new AspectFunctionException(e); | |
| } 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 { | |
| NestedSet.endTargetNestedSetCount(); | |
| CurrentRuleTracker.endConfiguredAspect(); | |
| } | |
| } | |
| events.replayOn(env.getListener()); | |
| if (events.hasErrors()) { | |
| analysisEnvironment.disable(associatedTarget); | |
| String msg = | |
| "Analysis of target '%s' (config: %s) failed" | |
| .formatted( | |
| associatedTarget.getLabel(), | |
| configuration != null ? configuration.getOptions().shortId() : "none"); | |
| 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); | |
| if (configuredAspect != NonApplicableAspect.INSTANCE) { | |
| analysisProgressReceiver.doneConfigureAspect(); | |
| } | |
| return AspectValue.create(key, aspect, configuredAspect, transitiveState.transitivePackages()); | |
| } | |
| private static boolean targetSatisfiesAspect(Target target, Aspect aspect) { | |
| if (target.isRule()) { | |
| return ((Rule) target).satisfies(aspect.getDefinition().getRequiredProviders()); | |
| } | |
| if (aspect.getDefinition().applyToFiles() || aspect.getDefinition().applyToGeneratingRules()) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| @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); | |
| } | |
| public AspectFunctionException(IOException cause) { | |
| super(cause, Transience.TRANSIENT); | |
| } | |
| } | |
| } |