aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java85
1 files changed, 81 insertions, 4 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
index 0242f3a79c..f2a12e7b34 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfigurationFragmentFunction.java
@@ -15,6 +15,7 @@ package com.google.devtools.build.lib.skyframe;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ListMultimap;
import com.google.devtools.build.lib.analysis.BlazeDirectories;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -24,10 +25,16 @@ import com.google.devtools.build.lib.analysis.config.InvalidConfigurationExcepti
import com.google.devtools.build.lib.analysis.config.PackageProviderForConfigurations;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
+import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
+import com.google.devtools.build.lib.packages.AggregatingAttributeMapper;
+import com.google.devtools.build.lib.packages.Attribute;
+import com.google.devtools.build.lib.packages.AttributeMap.AcceptsLabelAttribute;
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.Package;
+import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClassProvider;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.skyframe.ConfigurationFragmentValue.ConfigurationFragmentKey;
@@ -38,12 +45,15 @@ import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.io.IOException;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
/**
* A builder for {@link ConfigurationFragmentValue}s.
*/
-public class ConfigurationFragmentFunction implements SkyFunction {
-
+public final class ConfigurationFragmentFunction implements SkyFunction {
private final Supplier<ImmutableList<ConfigurationFragmentFactory>> configurationFragments;
private final RuleClassProvider ruleClassProvider;
@@ -66,7 +76,11 @@ public class ConfigurationFragmentFunction implements SkyFunction {
new SkyframePackageLoaderWithValueEnvironment(env, ruleClassProvider);
ConfigurationEnvironment confEnv = new ConfigurationBuilderEnvironment(packageProvider);
Fragment fragment = factory.create(confEnv, buildOptions);
-
+
+ if (env.valuesMissing()) {
+ return null;
+ }
+ sanityCheck(fragment, buildOptions, packageProvider);
if (env.valuesMissing()) {
return null;
}
@@ -80,7 +94,70 @@ public class ConfigurationFragmentFunction implements SkyFunction {
throw new ConfigurationFragmentFunctionException(e);
}
}
-
+
+ /**
+ * Checks that the implicit labels are reachable from the loaded labels. The loaded labels are
+ * those returned from {@link BuildOptions#getAllLabels()}, and the implicit ones are those that
+ * are returned from {@link Fragment#getImplicitLabels}.
+ */
+ private void sanityCheck(Fragment fragment, BuildOptions buildOptions,
+ PackageProviderForConfigurations packageProvider) throws InvalidConfigurationException {
+ if (fragment == null) {
+ return;
+ }
+ ListMultimap<String, Label> implicitLabels = fragment.getImplicitLabels();
+ if (implicitLabels.isEmpty()) {
+ return;
+ }
+ // Sanity check that the implicit labels are all in the transitive closure of explicit ones.
+ // This also registers all targets in the cache entry and validates them on subsequent requests.
+ Set<Label> reachableLabels = new HashSet<>();
+ for (Map.Entry<String, Label> entry : buildOptions.getAllLabels().entries()) {
+ Label label = entry.getValue();
+ try {
+ collectAllTransitiveLabels(packageProvider, reachableLabels, label);
+ } catch (NoSuchThingException e) {
+ packageProvider.getEventHandler().handle(Event.error(e.getMessage()));
+ throw new InvalidConfigurationException(
+ String.format("Failed to load required %s target: '%s'", entry.getKey(), label));
+ }
+ }
+ if (packageProvider.valuesMissing()) {
+ return;
+ }
+ for (Map.Entry<String, Label> entry : implicitLabels.entries()) {
+ if (!reachableLabels.contains(entry.getValue())) {
+ throw new InvalidConfigurationException(
+ String.format("The required %s target is not transitively reachable from a "
+ + "command-line option: '%s'", entry.getKey(), entry.getValue()));
+ }
+ }
+ }
+
+ private void collectAllTransitiveLabels(PackageProviderForConfigurations packageProvider,
+ Set<Label> reachableLabels, Label from) throws NoSuchThingException {
+ if (!reachableLabels.add(from)) {
+ return;
+ }
+ Target fromTarget = packageProvider.getTarget(from);
+ if (fromTarget == null) {
+ return;
+ }
+ if (fromTarget instanceof Rule) {
+ Rule rule = (Rule) fromTarget;
+ final Set<Label> allLabels = new LinkedHashSet<>();
+ AggregatingAttributeMapper.of(rule).visitLabels(new AcceptsLabelAttribute() {
+ @Override
+ public void acceptLabelAttribute(Label label, Attribute attribute) {
+ allLabels.add(label);
+ }
+ });
+ for (Label label : allLabels) {
+ collectAllTransitiveLabels(packageProvider, reachableLabels, label);
+ }
+ }
+ }
+
private ConfigurationFragmentFactory getFactory(Class<? extends Fragment> fragmentType) {
for (ConfigurationFragmentFactory factory : configurationFragments.get()) {
if (factory.creates().equals(fragmentType)) {