Python provider is now available in Skylark
Using mandatoryProvidersList to validate python rules' dependency.
Added a SkylarkProvider named 'py' which is a SkylarkClassObject in Java and a
struct in Skylark. Native python rule and Skylark python rule should have this provider
so that they can depend on each other.
RELNOTES[NEW]: Native python rule can depend on skylark rule as long as skylark
rule provides 'py' provider.
--
MOS_MIGRATED_REVID=116241504
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 9fd4fd4..8fa5cb5 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
@@ -16,6 +16,7 @@
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -1557,16 +1558,10 @@
}
}
- if (attribute.isStrictLabelCheckingEnabled()) {
- if (prerequisiteTarget instanceof Rule) {
- RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject();
- if (!attribute.getAllowedRuleClassesPredicate().apply(ruleClass)) {
- boolean allowedWithWarning = attribute.getAllowedRuleClassesWarningPredicate()
- .apply(ruleClass);
- reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisiteLabel,
- "expected " + attribute.getAllowedRuleClassesPredicate(), allowedWithWarning);
- }
- } else if (prerequisiteTarget instanceof FileTarget) {
+ if (prerequisiteTarget instanceof Rule) {
+ validateRuleDependency(prerequisite, attribute);
+ } else if (prerequisiteTarget instanceof FileTarget) {
+ if (attribute.isStrictLabelCheckingEnabled()) {
if (!attribute.getAllowedFileTypesPredicate()
.apply(((FileTarget) prerequisiteTarget).getFilename())) {
if (prerequisiteTarget instanceof InputFile
@@ -1660,10 +1655,10 @@
}
}
- private void validateMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute) {
+ private String getMissingMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute){
List<ImmutableSet<String>> mandatoryProvidersList = attribute.getMandatoryProvidersList();
if (mandatoryProvidersList.isEmpty()) {
- return;
+ return null;
}
List<List<String>> missingProvidersList = new ArrayList<>();
for (ImmutableSet<String> providers : mandatoryProvidersList) {
@@ -1674,7 +1669,7 @@
}
}
if (missing.isEmpty()) {
- return;
+ return null;
} else {
missingProvidersList.add(missing);
}
@@ -1691,16 +1686,55 @@
missingProviders.append("'")
.append((providers.size() > 1) ? "]" : "");
}
- attributeError(
- attribute.getName(),
- "'" + prerequisite.getLabel() + "' does not have mandatory provider "
- + missingProviders);
+ return missingProviders.toString();
+ }
+
+ /**
+ * Because some rules still have to use allowedRuleClasses to do rule dependency validation.
+ * We implemented the allowedRuleClasses OR mandatoryProvidersList mechanism. Either condition
+ * is satisfied, we consider the dependency valid.
+ */
+ private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
+ Target prerequisiteTarget = prerequisite.getTarget();
+ Label prerequisiteLabel = prerequisiteTarget.getLabel();
+ RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject();
+ Boolean allowed = null;
+ Boolean allowedWithWarning = null;
+
+ if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
+ allowed = attribute.getAllowedRuleClassesPredicate().apply(ruleClass);
+ if (allowed) {
+ return;
+ }
+ }
+
+ if (attribute.getAllowedRuleClassesWarningPredicate()
+ != Predicates.<RuleClass>alwaysTrue()) {
+ allowedWithWarning = attribute.getAllowedRuleClassesWarningPredicate().apply(ruleClass);
+ if (allowedWithWarning) {
+ reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisiteLabel,
+ "expected " + attribute.getAllowedRuleClassesPredicate(), true);
+ return;
+ }
+ }
+
+ if (!attribute.getMandatoryProvidersList().isEmpty()) {
+ String missingMandatoryProviders = getMissingMandatoryProviders(prerequisite, attribute);
+ if (missingMandatoryProviders != null) {
+ attributeError(
+ attribute.getName(),
+ "'" + prerequisite.getLabel() + "' does not have mandatory provider "
+ + missingMandatoryProviders);
+ }
+ } else if (Boolean.FALSE.equals(allowed)) {
+ reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisiteLabel,
+ "expected " + attribute.getAllowedRuleClassesPredicate(), false);
+ }
}
private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) {
validateDirectPrerequisiteType(prerequisite, attribute);
validateDirectPrerequisiteFileTypes(prerequisite, attribute);
- validateMandatoryProviders(prerequisite, attribute);
if (attribute.performPrereqValidatorCheck()) {
prerequisiteValidator.validate(this, prerequisite, attribute);
}