diff options
author | 2017-08-01 20:47:59 +0200 | |
---|---|---|
committer | 2017-08-02 10:40:02 +0200 | |
commit | 7df851524497afd7b1833418cc639d9c8f417451 (patch) | |
tree | 5a8f0c12749fdda9731bc9571c7e4f780ef09c5c /src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java | |
parent | 71238601b8ca147cfd4f9498e11d8517b25ac69a (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.java | 186 |
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) { |