aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
diff options
context:
space:
mode:
authorGravatar dslomov <dslomov@google.com>2017-08-01 20:47:59 +0200
committerGravatar Dmitry Lomov <dslomov@google.com>2017-08-02 10:40:02 +0200
commit7df851524497afd7b1833418cc639d9c8f417451 (patch)
tree5a8f0c12749fdda9731bc9571c7e4f780ef09c5c /src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
parent71238601b8ca147cfd4f9498e11d8517b25ac69a (diff)
Automated rollback of commit c32e1b1efcd703b3780de47fba62974123593d71.
*** Reason for rollback *** Breaks depot b/64250728 *** Original change description *** Use RequiredProviders to validate rule prerequisites in RuleContext. We now use a unified way to check provider requirements everywhere. RELNOTES: None. PiperOrigin-RevId: 163862067
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java186
1 files changed, 120 insertions, 66 deletions
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 de978e0940..771189afa6 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
@@ -70,17 +70,18 @@ import com.google.devtools.build.lib.packages.NativeProvider;
import com.google.devtools.build.lib.packages.OutputFile;
import com.google.devtools.build.lib.packages.PackageSpecification;
import com.google.devtools.build.lib.packages.RawAttributeMapper;
-import com.google.devtools.build.lib.packages.RequiredProviders;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.packages.RuleErrorConsumer;
+import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.AliasProvider;
import com.google.devtools.build.lib.rules.MakeVariableProvider;
import com.google.devtools.build.lib.rules.fileset.FilesetProvider;
import com.google.devtools.build.lib.shell.ShellUtils;
+import com.google.devtools.build.lib.syntax.ClassObject;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.LabelClass;
@@ -1974,101 +1975,154 @@ public final class RuleContext extends TargetContext
}
}
- /**
- * Because some rules still have to use allowedRuleClasses to do rule dependency validation. A
- * dependency is valid if it is from a rule in allowedRuledClasses, OR if all of the providers
- * in requiredProviders are provided by the target.
- */
- private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
-
- Set<String> unfulfilledRequirements = new LinkedHashSet<>();
- if (checkRuleDependencyClass(prerequisite, attribute, unfulfilledRequirements)) {
- return;
+ private String getMissingMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute){
+ ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList =
+ attribute.getMandatoryProvidersList();
+ if (mandatoryProvidersList.isEmpty()) {
+ return null;
}
-
- if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
- return;
+ List<List<String>> missingProvidersList = new ArrayList<>();
+ for (ImmutableSet<SkylarkProviderIdentifier> providers : mandatoryProvidersList) {
+ List<String> missing = new ArrayList<>();
+ for (SkylarkProviderIdentifier provider : providers) {
+ // A rule may require a built-in provider that is always implicitly provided, e.g. "files"
+ ImmutableSet<String> availableKeys =
+ ImmutableSet.copyOf(((ClassObject) prerequisite).getKeys());
+ if ((prerequisite.get(provider) == null)
+ && !(provider.isLegacy() && availableKeys.contains(provider.getLegacyId()))) {
+ missing.add(provider.toString());
+ }
+ }
+ if (missing.isEmpty()) {
+ return null;
+ } else {
+ missingProvidersList.add(missing);
+ }
}
-
- if (checkRuleDependencyMandatoryProviders(prerequisite, attribute, unfulfilledRequirements)) {
- return;
+ StringBuilder missingProviders = new StringBuilder();
+ Joiner joinProvider = Joiner.on("', '");
+ for (List<String> providers : missingProvidersList) {
+ if (missingProviders.length() > 0) {
+ missingProviders.append(" or ");
+ }
+ missingProviders.append((providers.size() > 1) ? "[" : "")
+ .append("'");
+ joinProvider.appendTo(missingProviders, providers);
+ missingProviders.append("'")
+ .append((providers.size() > 1) ? "]" : "");
}
+ return missingProviders.toString();
+ }
- // not allowed rule class and some mandatory providers missing => reject.
- if (!unfulfilledRequirements.isEmpty()) {
- attributeError(
- attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
+ private String getMissingMandatoryNativeProviders(
+ ConfiguredTarget prerequisite, Attribute attribute) {
+ List<ImmutableList<Class<? extends TransitiveInfoProvider>>> mandatoryProvidersList =
+ attribute.getMandatoryNativeProvidersList();
+ if (mandatoryProvidersList.isEmpty()) {
+ return null;
+ }
+ List<List<String>> missingProvidersList = new ArrayList<>();
+ for (ImmutableList<Class<? extends TransitiveInfoProvider>> providers
+ : mandatoryProvidersList) {
+ List<String> missing = new ArrayList<>();
+ for (Class<? extends TransitiveInfoProvider> provider : providers) {
+ if (prerequisite.getProvider(provider) == null) {
+ missing.add(provider.getSimpleName());
+ }
+ }
+ if (missing.isEmpty()) {
+ return null;
+ } else {
+ missingProvidersList.add(missing);
+ }
+ }
+ StringBuilder missingProviders = new StringBuilder();
+ Joiner joinProvider = Joiner.on(", ");
+ for (List<String> providers : missingProvidersList) {
+ if (missingProviders.length() > 0) {
+ missingProviders.append(" or ");
+ }
+ missingProviders.append((providers.size() > 1) ? "[" : "");
+ joinProvider.appendTo(missingProviders, providers);
+ missingProviders.append((providers.size() > 1) ? "]" : "");
}
+ return missingProviders.toString();
}
- /** Check if prerequisite should be allowed based on its rule class. */
- private boolean checkRuleDependencyClass(
- ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
+ /**
+ * Because some rules still have to use allowedRuleClasses to do rule dependency validation.
+ * A dependency is valid if it is from a rule in allowedRuleClasses, OR if all of the providers
+ * in mandatoryNativeProviders AND mandatoryProvidersList are provided by the target.
+ */
+ private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
+ Target prerequisiteTarget = prerequisite.getTarget();
+ RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject();
+ String notAllowedRuleClassesMessage = null;
+
if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
- if (attribute
- .getAllowedRuleClassesPredicate()
- .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
+ if (attribute.getAllowedRuleClassesPredicate().apply(ruleClass)) {
// prerequisite has an allowed rule class => accept.
- return true;
+ return;
}
// remember that the rule class that was not allowed;
// but maybe prerequisite provides required providers? do not reject yet.
- unfulfilledRequirements.add(
+ notAllowedRuleClassesMessage =
badPrerequisiteMessage(
- prerequisite.getTarget().getTargetKind(),
+ prerequisiteTarget.getTargetKind(),
prerequisite,
"expected " + attribute.getAllowedRuleClassesPredicate(),
- false));
+ false);
}
- return false;
- }
- /**
- * Check if prerequisite should be allowed with warning based on its rule class.
- *
- * <p>If yes, also issues said warning.
- */
- private boolean checkRuleDependencyClassWarnings(
- ConfiguredTarget prerequisite, Attribute attribute) {
- if (attribute
- .getAllowedRuleClassesWarningPredicate()
- .apply(((Rule) prerequisite.getTarget()).getRuleClassObject())) {
+ if (attribute.getAllowedRuleClassesWarningPredicate().apply(ruleClass)) {
Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
- reportBadPrerequisite(
- attribute,
- prerequisite.getTarget().getTargetKind(),
- prerequisite,
+ reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite,
allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
? null
: "expected " + allowedRuleClasses,
true);
// prerequisite has a rule class allowed with a warning => accept, emitting a warning.
- return true;
+ return;
}
- return false;
- }
- /** Check if prerequisite should be allowed based on required providers on the attribute. */
- private boolean checkRuleDependencyMandatoryProviders(
- ConfiguredTarget prerequisite, Attribute attribute, Set<String> unfulfilledRequirements) {
- RequiredProviders requiredProviders = attribute.getRequiredProviders();
+ // If we get here, we have no allowed rule class.
+ // If mandatory providers are specified, try them.
+ Set<String> unfulfilledRequirements = new LinkedHashSet<>();
+ if (!attribute.getMandatoryNativeProvidersList().isEmpty()
+ || !attribute.getMandatoryProvidersList().isEmpty()) {
+ boolean hadAllMandatoryProviders = true;
+
+ String missingNativeProviders = getMissingMandatoryNativeProviders(prerequisite, attribute);
+ if (missingNativeProviders != null) {
+ unfulfilledRequirements.add(
+ "'" + prerequisite.getLabel() + "' does not have mandatory providers: "
+ + missingNativeProviders);
+ hadAllMandatoryProviders = false;
+ }
- if (requiredProviders.acceptsAny()) {
- // If no required providers specified, we do not know if we should accept.
- return false;
- }
+ String missingProviders = getMissingMandatoryProviders(prerequisite, attribute);
+ if (missingProviders != null) {
+ unfulfilledRequirements.add(
+ "'" + prerequisite.getLabel() + "' does not have mandatory providers: "
+ + missingProviders);
+ hadAllMandatoryProviders = false;
+ }
- if (prerequisite.satisfies(requiredProviders)) {
- return true;
+ if (hadAllMandatoryProviders) {
+ // all mandatory providers are present => accept.
+ return;
+ }
}
- unfulfilledRequirements.add(
- String.format(
- "'%s' does not have mandatory providers: %s",
- prerequisite.getLabel(),
- prerequisite.missingProviders(requiredProviders).getDescription()));
+ // not allowed rule class and some mandatory providers missing => reject.
+ if (notAllowedRuleClassesMessage != null) {
+ unfulfilledRequirements.add(notAllowedRuleClassesMessage);
+ }
- return false;
+ if (!unfulfilledRequirements.isEmpty()) {
+ attributeError(
+ attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
+ }
}
private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) {