blob: f3000951a81ff07e138ad9eb647fe011973c74ee [file] [log] [blame]
// Copyright 2021 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.common.collect.ImmutableMap;
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.AspectsList;
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.server.FailureDetails.Analysis.Code;
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 javax.annotation.Nullable;
import net.starlark.java.eval.EvalException;
/** {@link SkyFunction} to load top level aspects and assign their parameters. */
final class LoadAspectsFunction implements SkyFunction {
@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
throws LoadAspectsFunctionException, InterruptedException {
LoadAspectsKey topLevelAspectsDetailsKey = (LoadAspectsKey) skyKey.argument();
ImmutableList<Aspect> topLevelAspects =
getTopLevelAspects(
env,
topLevelAspectsDetailsKey.getTopLevelAspectsClasses(),
topLevelAspectsDetailsKey.getTopLevelAspectsParameters());
if (topLevelAspects == null) {
return null; // some aspects are not loaded
}
return new LoadAspectsValue(topLevelAspects);
}
@Nullable
private static StarlarkDefinedAspect loadStarlarkAspect(
Environment env, StarlarkAspectClass aspectClass)
throws InterruptedException, LoadAspectsFunctionException {
StarlarkDefinedAspect starlarkAspect;
try {
BzlLoadValue bzlLoadValue =
(BzlLoadValue)
env.getValueOrThrow(
AspectFunction.bzlLoadKeyForStarlarkAspect(aspectClass),
BzlLoadFailedException.class);
if (bzlLoadValue == null) {
return null;
}
starlarkAspect = AspectFunction.loadAspectFromBzl(aspectClass, bzlLoadValue);
} catch (BzlLoadFailedException | AspectCreationException e) {
env.getListener().handle(Event.error(e.getMessage()));
throw new LoadAspectsFunctionException(
new TopLevelAspectsDetailsBuildFailedException(
e.getMessage(), Code.ASPECT_CREATION_FAILED));
}
return starlarkAspect;
}
@Nullable
private static ImmutableList<Aspect> getTopLevelAspects(
Environment env,
ImmutableList<AspectClass> topLevelAspectsClasses,
ImmutableMap<String, String> topLevelAspectsParameters)
throws InterruptedException, LoadAspectsFunctionException {
AspectsList.Builder builder = new AspectsList.Builder();
for (AspectClass aspectClass : topLevelAspectsClasses) {
if (aspectClass instanceof StarlarkAspectClass starlarkAspectClass) {
StarlarkAspect starlarkAspect = loadStarlarkAspect(env, starlarkAspectClass);
if (starlarkAspect == null) {
return null;
}
try {
builder.addAspect(starlarkAspect);
} catch (EvalException e) {
env.getListener().handle(Event.error(e.getInnermostLocation(), e.getMessageWithStack()));
throw new LoadAspectsFunctionException(
new TopLevelAspectsDetailsBuildFailedException(
e.getMessage(), Code.ASPECT_CREATION_FAILED));
}
} else {
try {
builder.addAspect((NativeAspectClass) aspectClass);
} catch (AssertionError e) {
env.getListener().handle(Event.error(e.getMessage()));
throw new LoadAspectsFunctionException(
new TopLevelAspectsDetailsBuildFailedException(
e.getMessage(), Code.ASPECT_CREATION_FAILED));
}
}
}
AspectsList aspectsList = builder.build();
try {
aspectsList.validateTopLevelAspectsParameters(topLevelAspectsParameters);
return aspectsList.buildAspects(topLevelAspectsParameters);
} catch (EvalException e) {
env.getListener().handle(Event.error(e.getInnermostLocation(), e.getMessageWithStack()));
throw new LoadAspectsFunctionException(
new TopLevelAspectsDetailsBuildFailedException(
e.getMessage(), Code.ASPECT_CREATION_FAILED));
}
}
private static final class LoadAspectsFunctionException extends SkyFunctionException {
LoadAspectsFunctionException(TopLevelAspectsDetailsBuildFailedException cause) {
super(cause, Transience.PERSISTENT);
}
}
}