Add attribute validation of mandatory native providers
and use it to validate that :java_toolchain has a JavaToolchainProvider.
--
MOS_MIGRATED_REVID=121396726
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index e1b65493..71ca85b 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -405,6 +405,7 @@
":events",
":skylarkinterface",
":syntax",
+ ":transitive-info-provider",
":util",
":vfs",
"//src/main/java/com/google/devtools/common/options",
@@ -449,6 +450,11 @@
)
java_library(
+ name = "transitive-info-provider",
+ srcs = ["analysis/TransitiveInfoProvider.java"],
+)
+
+java_library(
name = "build-base",
srcs = glob(
[
@@ -466,10 +472,16 @@
"rules/repository/*.java",
"skyframe/*.java",
],
- exclude = ["analysis/BuildInfo.java"],
+ exclude = [
+ "analysis/BuildInfo.java",
+ "analysis/TransitiveInfoProvider.java",
+ ],
) + [
"runtime/BlazeServerStartupOptions.java",
],
+ exports = [
+ ":transitive-info-provider",
+ ],
deps = [
":base-util",
":cmdline",
@@ -485,6 +497,7 @@
":packages-internal",
":shell",
":skylarkinterface",
+ ":transitive-info-provider",
":util",
":vfs",
"//src/main/java/com/google/devtools/build/lib/actions",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index faa4f2c..961158c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -1710,6 +1710,32 @@
return missingProviders.toString();
}
+ private String getMissingMandatoryNativeProviders(
+ ConfiguredTarget prerequisite, Attribute attribute) {
+ List<Class<? extends TransitiveInfoProvider>> mandatoryProvidersList =
+ attribute.getMandatoryNativeProviders();
+ if (mandatoryProvidersList.isEmpty()) {
+ return null;
+ }
+ List<Class<? extends TransitiveInfoProvider>> missing = new ArrayList<>();
+ for (Class<? extends TransitiveInfoProvider> provider : mandatoryProvidersList) {
+ if (prerequisite.getProvider(provider) == null) {
+ missing.add(provider);
+ }
+ }
+ if (missing.isEmpty()) {
+ return null;
+ }
+ StringBuilder sb = new StringBuilder();
+ for (Class<? extends TransitiveInfoProvider> provider : missing) {
+ if (sb.length() > 0) {
+ sb.append(", ");
+ }
+ sb.append(provider.getSimpleName());
+ }
+ return sb.toString();
+ }
+
/**
* Because some rules still have to use allowedRuleClasses to do rule dependency validation.
* We implemented the allowedRuleClasses OR mandatoryProvidersList mechanism. Either condition
@@ -1739,6 +1765,16 @@
}
}
+ if (!attribute.getMandatoryNativeProviders().isEmpty()) {
+ String missing = getMissingMandatoryNativeProviders(prerequisite, attribute);
+ if (missing != null) {
+ attributeError(
+ attribute.getName(),
+ "'" + prerequisite.getLabel() + "' does not have mandatory providers: " + missing);
+ return;
+ }
+ }
+
if (!attribute.getMandatoryProvidersList().isEmpty()) {
String missingMandatoryProviders = getMissingMandatoryProviders(prerequisite, attribute);
if (missingMandatoryProviders != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
index 390f830..ec80f65 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaRuleClasses.java
@@ -40,6 +40,7 @@
import com.google.devtools.build.lib.packages.RuleClass.PackageNameConstraint;
import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileTypeSet;
@@ -76,7 +77,7 @@
return builder
.add(
attr(":java_toolchain", LABEL)
- .allowedRuleClasses("java_toolchain")
+ .mandatoryNativeProviders(JavaToolchainProvider.class)
.value(JavaSemantics.JAVA_TOOLCHAIN))
.setPreferredDependencyPredicate(JavaSemantics.JAVA_SOURCE)
.build();
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index 4b9f7fe..501b46c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.syntax.ClassObject;
@@ -396,6 +397,8 @@
private PredicateWithMessage<Object> allowedValues = null;
private ImmutableList<ImmutableSet<String>> mandatoryProvidersList =
ImmutableList.<ImmutableSet<String>>of();
+ private ImmutableList<Class<? extends TransitiveInfoProvider>> mandatoryNativeProviders =
+ ImmutableList.of();
private Set<RuleAspect> aspects = new LinkedHashSet<>();
/**
@@ -803,6 +806,22 @@
}
/**
+ * Sets a list of mandatory native providers. Every configured target occurring in this label
+ * type attribute has to provide all the providers, otherwise an error is produced during the
+ * analysis phase.
+ */
+ @SafeVarargs
+ public final Builder<TYPE> mandatoryNativeProviders(
+ Class<? extends TransitiveInfoProvider>... providers) {
+ Preconditions.checkState(
+ (type == BuildType.LABEL) || (type == BuildType.LABEL_LIST),
+ "must be a label-valued type");
+ this.mandatoryNativeProviders =
+ ImmutableList.<Class<? extends TransitiveInfoProvider>>copyOf(providers);
+ return this;
+ }
+
+ /**
* Sets a list of sets of mandatory Skylark providers. Every configured target occurring in
* this label type attribute has to provide all the providers from one of those sets,
* otherwise an error is produced during the analysis phase.
@@ -939,6 +958,7 @@
condition,
allowedValues,
mandatoryProvidersList,
+ mandatoryNativeProviders,
ImmutableSet.copyOf(aspects));
}
}
@@ -1224,6 +1244,8 @@
private final ImmutableList<ImmutableSet<String>> mandatoryProvidersList;
+ private final ImmutableList<Class<? extends TransitiveInfoProvider>> mandatoryNativeProviders;
+
private final ImmutableSet<RuleAspect> aspects;
/**
@@ -1256,6 +1278,7 @@
Predicate<AttributeMap> condition,
PredicateWithMessage<Object> allowedValues,
ImmutableList<ImmutableSet<String>> mandatoryProvidersList,
+ ImmutableList<Class<? extends TransitiveInfoProvider>> mandatoryNativeProviders,
ImmutableSet<RuleAspect> aspects) {
Preconditions.checkNotNull(configTransition);
Preconditions.checkArgument(
@@ -1290,6 +1313,7 @@
this.condition = condition;
this.allowedValues = allowedValues;
this.mandatoryProvidersList = mandatoryProvidersList;
+ this.mandatoryNativeProviders = mandatoryNativeProviders;
this.aspects = aspects;
}
@@ -1488,6 +1512,11 @@
return mandatoryProvidersList;
}
+ /** Returns the list of mandatory native providers. */
+ public ImmutableList<Class<? extends TransitiveInfoProvider>> getMandatoryNativeProviders() {
+ return mandatoryNativeProviders;
+ }
+
public FileTypeSet getAllowedFileTypesPredicate() {
return allowedFileTypesForLabels;
}