aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java578
1 files changed, 578 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
new file mode 100644
index 0000000000..9fc3df4578
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -0,0 +1,578 @@
+// Copyright 2014 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.ListMultimap;
+import com.google.devtools.build.lib.analysis.Aspect;
+import com.google.devtools.build.lib.analysis.CachingAnalysisEnvironment;
+import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.DependencyResolver.Dependency;
+import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget;
+import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.StoredEventHandler;
+import com.google.devtools.build.lib.packages.AspectDefinition;
+import com.google.devtools.build.lib.packages.AspectFactory;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.InputFile;
+import com.google.devtools.build.lib.packages.NoSuchPackageException;
+import com.google.devtools.build.lib.packages.NoSuchTargetException;
+import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.PackageGroup;
+import com.google.devtools.build.lib.packages.RawAttributeMapper;
+import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.skyframe.AspectFunction.AspectCreationException;
+import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Label;
+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.ValueOrException2;
+import com.google.devtools.build.skyframe.ValueOrException3;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/**
+ * SkyFunction for {@link ConfiguredTargetValue}s.
+ */
+final class ConfiguredTargetFunction implements SkyFunction {
+
+ /**
+ * Exception class that signals an error during the evaluation of a dependency.
+ */
+ public static class DependencyEvaluationException extends Exception {
+ private final SkyKey rootCauseSkyKey;
+
+ public DependencyEvaluationException(Exception cause) {
+ super(cause);
+ this.rootCauseSkyKey = null;
+ }
+
+ public DependencyEvaluationException(SkyKey rootCauseSkyKey, Exception cause) {
+ super(cause);
+ this.rootCauseSkyKey = rootCauseSkyKey;
+ }
+
+ /**
+ * Returns the key of the root cause or null if the problem was with this target.
+ */
+ public SkyKey getRootCauseSkyKey() {
+ return rootCauseSkyKey;
+ }
+
+ @Override
+ public Exception getCause() {
+ return (Exception) super.getCause();
+ }
+ }
+
+ private static final Function<Dependency, SkyKey> TO_KEYS =
+ new Function<Dependency, SkyKey>() {
+ @Override
+ public SkyKey apply(Dependency input) {
+ return ConfiguredTargetValue.key(input.getLabel(), input.getConfiguration());
+ }
+ };
+
+ private final BuildViewProvider buildViewProvider;
+
+ ConfiguredTargetFunction(BuildViewProvider buildViewProvider) {
+ this.buildViewProvider = buildViewProvider;
+ }
+
+ @Override
+ public SkyValue compute(SkyKey key, Environment env) throws ConfiguredTargetFunctionException,
+ InterruptedException {
+ SkyframeBuildView view = buildViewProvider.getSkyframeBuildView();
+
+ ConfiguredTargetKey configuredTargetKey = (ConfiguredTargetKey) key.argument();
+ LabelAndConfiguration lc = LabelAndConfiguration.of(
+ configuredTargetKey.getLabel(), configuredTargetKey.getConfiguration());
+
+ BuildConfiguration configuration = lc.getConfiguration();
+
+ PackageValue packageValue =
+ (PackageValue) env.getValue(PackageValue.key(lc.getLabel().getPackageIdentifier()));
+ if (packageValue == null) {
+ return null;
+ }
+
+ Target target;
+ try {
+ target = packageValue.getPackage().getTarget(lc.getLabel().getName());
+ } catch (NoSuchTargetException e1) {
+ throw new ConfiguredTargetFunctionException(new NoSuchTargetException(lc.getLabel(),
+ "No such target"));
+ }
+ // TODO(bazel-team): This is problematic - we create the right key, but then end up with a value
+ // that doesn't match; we can even have the same value multiple times. However, I think it's
+ // only triggered in tests (i.e., in normal operation, the configuration passed in is already
+ // null).
+ if (target instanceof InputFile) {
+ // InputFileConfiguredTarget expects its configuration to be null since it's not used.
+ configuration = null;
+ } else if (target instanceof PackageGroup) {
+ // Same for PackageGroupConfiguredTarget.
+ configuration = null;
+ }
+ TargetAndConfiguration ctgValue =
+ new TargetAndConfiguration(target, configuration);
+
+ SkyframeDependencyResolver resolver = view.createDependencyResolver(env);
+ if (resolver == null) {
+ return null;
+ }
+
+ try {
+ // Get the configuration targets that trigger this rule's configurable attributes.
+ Set<ConfigMatchingProvider> configConditions =
+ getConfigConditions(ctgValue.getTarget(), env, resolver, ctgValue);
+ if (configConditions == null) {
+ // Those targets haven't yet been resolved.
+ return null;
+ }
+
+ ListMultimap<Attribute, ConfiguredTarget> depValueMap =
+ computeDependencies(env, resolver, ctgValue, null, configConditions);
+ return createConfiguredTarget(
+ view, env, target, configuration, depValueMap, configConditions);
+ } catch (DependencyEvaluationException e) {
+ throw new ConfiguredTargetFunctionException(e.getRootCauseSkyKey(), e.getCause());
+ }
+ }
+
+ /**
+ * Computes the direct dependencies of a node in the configured target graph (a configured
+ * target or an aspect).
+ *
+ * <p>Returns null if Skyframe hasn't evaluated the required dependencies yet. In this case, the
+ * caller should also return null to Skyframe.
+ *
+ * @param env the Skyframe environment
+ * @param resolver The dependency resolver
+ * @param ctgValue The label and the configuration of the node
+ * @param aspectDefinition the aspect of the node (if null, the node is a configured target,
+ * otherwise it's an asect)
+ * @param configConditions the configuration conditions for evaluating the attributes of the node
+ * @return an attribute -&gt; direct dependency multimap
+ * @throws ConfiguredTargetFunctionException
+ */
+ @Nullable
+ static ListMultimap<Attribute, ConfiguredTarget> computeDependencies(
+ Environment env, SkyframeDependencyResolver resolver, TargetAndConfiguration ctgValue,
+ AspectDefinition aspectDefinition, Set<ConfigMatchingProvider> configConditions)
+ throws DependencyEvaluationException {
+
+ // 1. Create the map from attributes to list of (target, configuration) pairs.
+ ListMultimap<Attribute, Dependency> depValueNames;
+ try {
+ depValueNames = resolver.dependentNodeMap(ctgValue, aspectDefinition, configConditions);
+ } catch (EvalException e) {
+ env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
+ throw new DependencyEvaluationException(new ConfiguredValueCreationException(e.print()));
+ }
+
+ // 2. Resolve configured target dependencies and handle errors.
+ Map<SkyKey, ConfiguredTarget> depValues =
+ resolveConfiguredTargetDependencies(env, depValueNames.values(), ctgValue.getTarget());
+ if (depValues == null) {
+ return null;
+ }
+
+ // 3. Resolve required aspects.
+ ListMultimap<SkyKey, Aspect> depAspects = resolveAspectDependencies(
+ env, depValues, depValueNames.values());
+ if (depAspects == null) {
+ return null;
+ }
+
+ // 3. Merge the dependent configured targets and aspects into a single map.
+ return mergeAspects(depValueNames, depValues, depAspects);
+ }
+
+ /**
+ * Merges the each direct dependency configured target with the aspects associated with it.
+ *
+ * <p>Note that the combination of a configured target and its associated aspects are not
+ * represented by a Skyframe node. This is because there can possibly be many different
+ * combinations of aspects for a particular configured target, so it would result in a
+ * combinatiorial explosion of Skyframe nodes.
+ */
+ private static ListMultimap<Attribute, ConfiguredTarget> mergeAspects(
+ ListMultimap<Attribute, Dependency> depValueNames,
+ Map<SkyKey, ConfiguredTarget> depConfiguredTargetMap,
+ ListMultimap<SkyKey, Aspect> depAspectMap) {
+ ListMultimap<Attribute, ConfiguredTarget> result = ArrayListMultimap.create();
+
+ for (Map.Entry<Attribute, Dependency> entry : depValueNames.entries()) {
+ Dependency dep = entry.getValue();
+ SkyKey depKey = TO_KEYS.apply(dep);
+ ConfiguredTarget depConfiguredTarget = depConfiguredTargetMap.get(depKey);
+ result.put(entry.getKey(),
+ RuleConfiguredTarget.mergeAspects(depConfiguredTarget, depAspectMap.get(depKey)));
+ }
+
+ return result;
+ }
+
+ /**
+ * Given a list of {@link Dependency} objects, returns a multimap from the {@link SkyKey} of the
+ * dependency to the {@link Aspect} instances that should be merged into it.
+ *
+ * <p>Returns null if the required aspects are not computed yet.
+ */
+ @Nullable
+ private static ListMultimap<SkyKey, Aspect> resolveAspectDependencies(Environment env,
+ Map<SkyKey, ConfiguredTarget> configuredTargetMap, Iterable<Dependency> deps)
+ throws DependencyEvaluationException {
+ ListMultimap<SkyKey, Aspect> result = ArrayListMultimap.create();
+ Set<SkyKey> aspectKeys = new HashSet<>();
+ for (Dependency dep : deps) {
+ for (Class<? extends ConfiguredAspectFactory> depAspect : dep.getAspects()) {
+ aspectKeys.add(AspectValue.key(dep.getLabel(), dep.getConfiguration(), depAspect));
+ }
+ }
+
+ Map<SkyKey, ValueOrException3<
+ AspectCreationException, NoSuchThingException, ConfiguredValueCreationException>>
+ depAspects = env.getValuesOrThrow(aspectKeys, AspectCreationException.class,
+ NoSuchThingException.class, ConfiguredValueCreationException.class);
+
+ for (Dependency dep : deps) {
+ SkyKey depKey = TO_KEYS.apply(dep);
+ ConfiguredTarget depConfiguredTarget = configuredTargetMap.get(depKey);
+ List<AspectValue> aspects = new ArrayList<>();
+ for (Class<? extends ConfiguredAspectFactory> depAspect : dep.getAspects()) {
+ if (!aspectMatchesConfiguredTarget(depConfiguredTarget, depAspect)) {
+ continue;
+ }
+
+ SkyKey aspectKey = AspectValue.key(dep.getLabel(), dep.getConfiguration(), depAspect);
+ AspectValue aspectValue = null;
+ try {
+ aspectValue = (AspectValue) depAspects.get(aspectKey).get();
+ } catch (ConfiguredValueCreationException e) {
+ // The configured target should have been created in resolveConfiguredTargetDependencies()
+ throw new IllegalStateException(e);
+ } catch (NoSuchThingException | AspectCreationException e) {
+ AspectFactory depAspectFactory = AspectFactory.Util.create(depAspect);
+ throw new DependencyEvaluationException(new ConfiguredValueCreationException(
+ String.format("Evaluation of aspect %s on %s failed: %s",
+ depAspectFactory.getDefinition().getName(), dep.getLabel(), e.toString())));
+ }
+
+ if (aspectValue == null) {
+ // Dependent aspect has either not been computed yet or is in error.
+ return null;
+ }
+ result.put(depKey, aspectValue.get());
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean aspectMatchesConfiguredTarget(ConfiguredTarget dep,
+ Class<? extends ConfiguredAspectFactory> aspectFactory) {
+ AspectDefinition aspectDefinition = AspectFactory.Util.create(aspectFactory).getDefinition();
+ for (Class<?> provider : aspectDefinition.getRequiredProviders()) {
+ if (dep.getProvider((Class<? extends TransitiveInfoProvider>) provider) == null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns which aspects are computable based on the precise set of providers direct dependencies
+ * publish (and not the upper estimate in their rule definition).
+ *
+ * <p>An aspect is computable for a particular configured target if the configured target supplies
+ * all the providers the aspect requires.
+ *
+ * @param upperEstimate a multimap from attribute to the upper estimates computed by
+ * {@link com.google.devtools.build.lib.analysis.DependencyResolver}.
+ * @param configuredTargetDeps a multimap from attribute to the directly dependent configured
+ * targets
+ * @return a multimap from attribute to the more precise {@link Dependency} objects
+ */
+ private static ListMultimap<Attribute, Dependency> getComputableAspects(
+ ListMultimap<Attribute, Dependency> upperEstimate,
+ Map<SkyKey, ConfiguredTarget> configuredTargetDeps) {
+ ListMultimap<Attribute, Dependency> result = ArrayListMultimap.create();
+ for (Map.Entry<Attribute, Dependency> entry : upperEstimate.entries()) {
+ ConfiguredTarget dep =
+ configuredTargetDeps.get(TO_KEYS.apply(entry.getValue()));
+ List<Class<? extends ConfiguredAspectFactory>> depAspects = new ArrayList<>();
+ for (Class<? extends ConfiguredAspectFactory> candidate : entry.getValue().getAspects()) {
+ boolean ok = true;
+ for (Class<?> requiredProvider :
+ AspectFactory.Util.create(candidate).getDefinition().getRequiredProviders()) {
+ if (dep.getProvider((Class<? extends TransitiveInfoProvider>) requiredProvider) == null) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ depAspects.add(candidate);
+ }
+ }
+
+ result.put(entry.getKey(), new Dependency(
+ entry.getValue().getLabel(), entry.getValue().getConfiguration(),
+ ImmutableSet.copyOf(depAspects)));
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the set of {@link ConfigMatchingProvider}s that key the configurable attributes
+ * used by this rule.
+ *
+ * <p>>If the configured targets supplying those providers aren't yet resolved by the
+ * dependency resolver, returns null.
+ */
+ @Nullable
+ static Set<ConfigMatchingProvider> getConfigConditions(Target target, Environment env,
+ SkyframeDependencyResolver resolver, TargetAndConfiguration ctgValue)
+ throws DependencyEvaluationException {
+ if (!(target instanceof Rule)) {
+ return ImmutableSet.of();
+ }
+
+ ImmutableSet.Builder<ConfigMatchingProvider> configConditions = ImmutableSet.builder();
+
+ // Collect the labels of the configured targets we need to resolve.
+ ListMultimap<Attribute, LabelAndConfiguration> configLabelMap = ArrayListMultimap.create();
+ RawAttributeMapper attributeMap = RawAttributeMapper.of(((Rule) target));
+ for (Attribute a : ((Rule) target).getAttributes()) {
+ for (Label configLabel : attributeMap.getConfigurabilityKeys(a.getName(), a.getType())) {
+ if (!Type.Selector.isReservedLabel(configLabel)) {
+ configLabelMap.put(a, LabelAndConfiguration.of(
+ configLabel, ctgValue.getConfiguration()));
+ }
+ }
+ }
+ if (configLabelMap.isEmpty()) {
+ return ImmutableSet.of();
+ }
+
+ // Collect the corresponding Skyframe configured target values. Abort early if they haven't
+ // been computed yet.
+ Collection<Dependency> configValueNames =
+ resolver.resolveRuleLabels(ctgValue, null, configLabelMap);
+ Map<SkyKey, ConfiguredTarget> configValues =
+ resolveConfiguredTargetDependencies(env, configValueNames, target);
+ if (configValues == null) {
+ return null;
+ }
+
+ // Get the configured targets as ConfigMatchingProvider interfaces.
+ for (Dependency entry : configValueNames) {
+ ConfiguredTarget value = configValues.get(TO_KEYS.apply(entry));
+ // The code above guarantees that value is non-null here.
+ ConfigMatchingProvider provider = value.getProvider(ConfigMatchingProvider.class);
+ if (provider != null) {
+ configConditions.add(provider);
+ } else {
+ // Not a valid provider for configuration conditions.
+ String message =
+ entry.getLabel() + " is not a valid configuration key for " + target.getLabel();
+ env.getListener().handle(Event.error(TargetUtils.getLocationMaybe(target), message));
+ throw new DependencyEvaluationException(new ConfiguredValueCreationException(message));
+ }
+ }
+
+ return configConditions.build();
+ }
+
+ /***
+ * Resolves the targets referenced in depValueNames and returns their ConfiguredTarget
+ * instances.
+ *
+ * <p>Returns null if not all instances are available yet.
+ *
+ */
+ @Nullable
+ private static Map<SkyKey, ConfiguredTarget> resolveConfiguredTargetDependencies(
+ Environment env, Collection<Dependency> deps, Target target)
+ throws DependencyEvaluationException {
+ boolean ok = !env.valuesMissing();
+ String message = null;
+ Iterable<SkyKey> depKeys = Iterables.transform(deps, TO_KEYS);
+ // TODO(bazel-team): maybe having a two-exception argument is better than typing a generic
+ // Exception here.
+ Map<SkyKey, ValueOrException2<NoSuchTargetException,
+ NoSuchPackageException>> depValuesOrExceptions = env.getValuesOrThrow(depKeys,
+ NoSuchTargetException.class, NoSuchPackageException.class);
+ Map<SkyKey, ConfiguredTarget> depValues = new HashMap<>(depValuesOrExceptions.size());
+ SkyKey childKey = null;
+ NoSuchThingException transitiveChildException = null;
+ for (Map.Entry<SkyKey, ValueOrException2<NoSuchTargetException, NoSuchPackageException>> entry
+ : depValuesOrExceptions.entrySet()) {
+ ConfiguredTargetKey depKey = (ConfiguredTargetKey) entry.getKey().argument();
+ LabelAndConfiguration depLabelAndConfiguration = LabelAndConfiguration.of(
+ depKey.getLabel(), depKey.getConfiguration());
+ Label depLabel = depLabelAndConfiguration.getLabel();
+ ConfiguredTargetValue depValue = null;
+ NoSuchThingException directChildException = null;
+ try {
+ depValue = (ConfiguredTargetValue) entry.getValue().get();
+ } catch (NoSuchTargetException e) {
+ if (depLabel.equals(e.getLabel())) {
+ directChildException = e;
+ } else {
+ childKey = entry.getKey();
+ transitiveChildException = e;
+ }
+ } catch (NoSuchPackageException e) {
+ if (depLabel.getPackageName().equals(e.getPackageName())) {
+ directChildException = e;
+ } else {
+ childKey = entry.getKey();
+ transitiveChildException = e;
+ }
+ }
+ // If an exception wasn't caused by a direct child target value, we'll treat it the same
+ // as any other missing dep by setting ok = false below, and returning null at the end.
+ if (directChildException != null) {
+ // Only update messages for missing targets we depend on directly.
+ message = TargetUtils.formatMissingEdge(target, depLabel, directChildException);
+ env.getListener().handle(Event.error(TargetUtils.getLocationMaybe(target), message));
+ }
+
+ if (depValue == null) {
+ ok = false;
+ } else {
+ depValues.put(entry.getKey(), depValue.getConfiguredTarget());
+ }
+ }
+ if (message != null) {
+ throw new DependencyEvaluationException(new NoSuchTargetException(message));
+ }
+ if (childKey != null) {
+ throw new DependencyEvaluationException(childKey, transitiveChildException);
+ }
+ if (!ok) {
+ return null;
+ } else {
+ return depValues;
+ }
+ }
+
+
+ @Override
+ public String extractTag(SkyKey skyKey) {
+ return Label.print(((ConfiguredTargetKey) skyKey.argument()).getLabel());
+ }
+
+ @Nullable
+ private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view,
+ Environment env, Target target, BuildConfiguration configuration,
+ ListMultimap<Attribute, ConfiguredTarget> depValueMap,
+ Set<ConfigMatchingProvider> configConditions)
+ throws ConfiguredTargetFunctionException,
+ InterruptedException {
+ boolean extendedSanityChecks = configuration != null && configuration.extendedSanityChecks();
+
+ StoredEventHandler events = new StoredEventHandler();
+ BuildConfiguration ownerConfig = (configuration == null)
+ ? null : configuration.getArtifactOwnerConfiguration();
+ boolean allowRegisteringActions = configuration == null || configuration.isActionsEnabled();
+ CachingAnalysisEnvironment analysisEnvironment = view.createAnalysisEnvironment(
+ new ConfiguredTargetKey(target.getLabel(), ownerConfig), false,
+ extendedSanityChecks, events, env, allowRegisteringActions);
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ ConfiguredTarget configuredTarget = view.createConfiguredTarget(target, configuration,
+ analysisEnvironment, depValueMap, configConditions);
+
+ events.replayOn(env.getListener());
+ if (events.hasErrors()) {
+ analysisEnvironment.disable(target);
+ throw new ConfiguredTargetFunctionException(new ConfiguredValueCreationException(
+ "Analysis of target '" + target.getLabel() + "' failed; build aborted"));
+ }
+ Preconditions.checkState(!analysisEnvironment.hasErrors(),
+ "Analysis environment hasError() but no errors reported");
+ if (env.valuesMissing()) {
+ return null;
+ }
+
+ analysisEnvironment.disable(target);
+ Preconditions.checkNotNull(configuredTarget, target);
+
+ return new ConfiguredTargetValue(configuredTarget,
+ ImmutableList.copyOf(analysisEnvironment.getRegisteredActions()));
+ }
+
+ /**
+ * An exception indicating that there was a problem during the construction of
+ * a ConfiguredTargetValue.
+ */
+ public static final class ConfiguredValueCreationException extends Exception {
+
+ public ConfiguredValueCreationException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Used to declare all the exception types that can be wrapped in the exception thrown by
+ * {@link ConfiguredTargetFunction#compute}.
+ */
+ public static final class ConfiguredTargetFunctionException extends SkyFunctionException {
+ public ConfiguredTargetFunctionException(NoSuchTargetException e) {
+ super(e, Transience.PERSISTENT);
+ }
+
+ private ConfiguredTargetFunctionException(ConfiguredValueCreationException error) {
+ super(error, Transience.PERSISTENT);
+ };
+
+ private ConfiguredTargetFunctionException(
+ @Nullable SkyKey childKey, Exception transitiveError) {
+ super(transitiveError, childKey);
+ }
+ }
+}