blob: d230637110caf6f01d01781a6155a6aa16781fb8 [file] [log] [blame]
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.skyframe;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.actions.ActionLookupValue;
import com.google.devtools.build.lib.analysis.AspectCollection;
import com.google.devtools.build.lib.analysis.AspectCollection.AspectCycleOnPathException;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.AspectClass;
import com.google.devtools.build.lib.packages.AspectDescriptor;
import com.google.devtools.build.lib.packages.AspectParameters;
import com.google.devtools.build.lib.packages.NativeAspectClass;
import com.google.devtools.build.lib.packages.StarlarkAspect;
import com.google.devtools.build.lib.packages.StarlarkAspectClass;
import com.google.devtools.build.lib.packages.StarlarkDefinedAspect;
import com.google.devtools.build.lib.packages.StarlarkNativeAspect;
import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
import com.google.devtools.build.lib.skyframe.AspectValueKey.TopLevelAspectsKey;
import com.google.devtools.build.lib.skyframe.LoadStarlarkAspectFunction.StarlarkAspectLoadingKey;
import com.google.devtools.build.lib.skyframe.LoadStarlarkAspectFunction.StarlarkAspectLoadingValue;
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 java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;
/**
* SkyFunction to load top level aspects, build the dependency relation between them based on the
* providers they advertise and provide using {@link AspectCollection} and runs the obtained aspects
* path on the top level target.
*
* <p>Used for loading top-level aspects. At top level, in {@link
* com.google.devtools.build.lib.analysis.BuildView}, we cannot invoke two SkyFunctions one after
* another, so BuildView calls this function to do the work.
*/
public class ToplevelStarlarkAspectFunction implements SkyFunction {
ToplevelStarlarkAspectFunction() {}
@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
throws TopLevelStarlarkAspectFunctionException, InterruptedException {
TopLevelAspectsKey topLevelAspectsKey = (TopLevelAspectsKey) skyKey.argument();
ImmutableList<Aspect> topLevelAspects =
getTopLevelAspects(env, topLevelAspectsKey.getTopLevelAspectsClasses());
if (topLevelAspects == null) {
return null; // some aspects are not loaded
}
AspectCollection aspectCollection;
try {
aspectCollection = AspectCollection.create(topLevelAspects);
} catch (AspectCycleOnPathException e) {
env.getListener().handle(Event.error(e.getMessage()));
throw new TopLevelStarlarkAspectFunctionException(
new AspectCreationException(e.getMessage(), topLevelAspectsKey.getLabel()));
}
ImmutableList<AspectKey> aspectKeys =
getTopLevelAspectsKeys(aspectCollection, topLevelAspectsKey.getBaseConfiguredTargetKey());
Map<SkyKey, SkyValue> result = env.getValues(aspectKeys);
if (env.valuesMissing()) {
return null; // some aspects keys are not evaluated
}
return new TopLevelAspectsValue(result);
}
@Nullable
@Override
public String extractTag(SkyKey skyKey) {
return null;
}
@Nullable
private static ImmutableList<Aspect> getTopLevelAspects(
Environment env, ImmutableList<AspectClass> topLevelAspectsClasses)
throws InterruptedException {
ImmutableList.Builder<Aspect> topLevelAspects = ImmutableList.builder();
ImmutableList.Builder<StarlarkAspectLoadingKey> aspectLoadingKeys = ImmutableList.builder();
for (AspectClass aspectClass : topLevelAspectsClasses) {
if (aspectClass instanceof StarlarkAspectClass) {
aspectLoadingKeys.add(
LoadStarlarkAspectFunction.createStarlarkAspectLoadingKey(
(StarlarkAspectClass) aspectClass));
}
}
Map<SkyKey, SkyValue> loadedAspects = env.getValues(aspectLoadingKeys.build());
if (env.valuesMissing()) {
return null;
}
for (AspectClass aspectClass : topLevelAspectsClasses) {
if (aspectClass instanceof StarlarkAspectClass) {
StarlarkAspectLoadingValue aspectLoadingValue =
(StarlarkAspectLoadingValue)
loadedAspects.get(
LoadStarlarkAspectFunction.createStarlarkAspectLoadingKey(
(StarlarkAspectClass) aspectClass));
StarlarkAspect starlarkAspect = aspectLoadingValue.getAspect();
if (starlarkAspect instanceof StarlarkDefinedAspect) {
StarlarkDefinedAspect starlarkDefinedAspect = (StarlarkDefinedAspect) starlarkAspect;
topLevelAspects.add(
Aspect.forStarlark(
starlarkDefinedAspect.getAspectClass(),
starlarkDefinedAspect.getDefinition(AspectParameters.EMPTY),
AspectParameters.EMPTY,
/** inheritedRequiredProviders = */
null,
/** inheritedAttributeAspects = */
null));
} else {
topLevelAspects.add(Aspect.forNative(((StarlarkNativeAspect) starlarkAspect)));
}
} else {
topLevelAspects.add(Aspect.forNative((NativeAspectClass) aspectClass));
}
}
return topLevelAspects.build();
}
private static ImmutableList<AspectKey> getTopLevelAspectsKeys(
AspectCollection aspectCollection, ConfiguredTargetKey topLevelTargetKey) {
Map<AspectDescriptor, AspectKey> result = new HashMap<>();
for (AspectCollection.AspectDeps aspectDeps : aspectCollection.getUsedAspects()) {
buildAspectKey(aspectDeps, result, topLevelTargetKey);
}
return ImmutableList.copyOf(result.values());
}
private static AspectKey buildAspectKey(
AspectCollection.AspectDeps aspectDeps,
Map<AspectDescriptor, AspectKey> result,
ConfiguredTargetKey topLevelTargetKey) {
if (result.containsKey(aspectDeps.getAspect())) {
return result.get(aspectDeps.getAspect());
}
ImmutableList.Builder<AspectKey> dependentAspects = ImmutableList.builder();
for (AspectCollection.AspectDeps path : aspectDeps.getUsedAspects()) {
dependentAspects.add(buildAspectKey(path, result, topLevelTargetKey));
}
AspectKey aspectKey =
AspectValueKey.createAspectKey(
aspectDeps.getAspect(),
dependentAspects.build(),
topLevelTargetKey.getConfigurationKey(),
topLevelTargetKey);
result.put(aspectKey.getAspectDescriptor(), aspectKey);
return aspectKey;
}
/** Exceptions thrown from ToplevelStarlarkAspectFunction. */
public static class TopLevelStarlarkAspectFunctionException extends SkyFunctionException {
public TopLevelStarlarkAspectFunctionException(AspectCreationException cause) {
super(cause, Transience.PERSISTENT);
}
}
/**
* SkyValue for {@code TopLevelAspectsKey} wraps a list of the {@code AspectValue} of the top
* level aspects applied on the same top level target.
*/
public static class TopLevelAspectsValue implements ActionLookupValue {
private final Map<SkyKey, SkyValue> topLevelAspectsMap;
public TopLevelAspectsValue(Map<SkyKey, SkyValue> topLevelAspectsMap) {
this.topLevelAspectsMap = topLevelAspectsMap;
}
public ImmutableList<SkyValue> getTopLevelAspectsValues() {
return ImmutableList.copyOf(topLevelAspectsMap.values());
}
public SkyValue get(SkyKey skyKey) {
return topLevelAspectsMap.get(skyKey);
}
@Override
public ImmutableList<ActionAnalysisMetadata> getActions() {
// return topLevelAspectsMap.values().stream().
return ImmutableList.of();
}
}
}