aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
diff options
context:
space:
mode:
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.java184
1 files changed, 65 insertions, 119 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 5e38598317..cd7b72b867 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
@@ -69,19 +69,18 @@ import com.google.devtools.build.lib.packages.NativeClassObjectConstructor;
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.SkylarkClassObject;
-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;
@@ -719,7 +718,7 @@ public final class RuleContext extends TargetContext
Map<Optional<String>, ? extends List<? extends TransitiveInfoCollection>> map =
getSplitPrerequisites(attributeName);
return map.isEmpty()
- ? ImmutableList.<TransitiveInfoCollection>of()
+ ? ImmutableList.of()
: map.entrySet().iterator().next().getValue();
}
@@ -1978,153 +1977,100 @@ public final class RuleContext extends TargetContext
}
}
- private String getMissingMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute){
- ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList =
- attribute.getMandatoryProvidersList();
- if (mandatoryProvidersList.isEmpty()) {
- return null;
- }
- 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);
- }
- }
- 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) ? "]" : "");
+ /**
+ * 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;
}
- return missingProviders.toString();
- }
- private String getMissingMandatoryNativeProviders(
- ConfiguredTarget prerequisite, Attribute attribute) {
- List<ImmutableList<Class<? extends TransitiveInfoProvider>>> mandatoryProvidersList =
- attribute.getMandatoryNativeProvidersList();
- if (mandatoryProvidersList.isEmpty()) {
- return null;
+ if (checkRuleDependencyClassWarnings(prerequisite, attribute)) {
+ return;
}
- 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);
- }
+
+ 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) ? "[" : "");
- joinProvider.appendTo(missingProviders, providers);
- missingProviders.append((providers.size() > 1) ? "]" : "");
+
+ // not allowed rule class and some mandatory providers missing => reject.
+ if (!unfulfilledRequirements.isEmpty()) {
+ attributeError(
+ attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
}
- return missingProviders.toString();
}
/**
- * 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.
+ * Check if prerequisite should be allowed based on its rule class.
*/
- private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
- Target prerequisiteTarget = prerequisite.getTarget();
- RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject();
- String notAllowedRuleClassesMessage = null;
-
+ private boolean checkRuleDependencyClass(ConfiguredTarget prerequisite, Attribute attribute,
+ Set<String> unfulfilledRequirements) {
if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
- if (attribute.getAllowedRuleClassesPredicate().apply(ruleClass)) {
+ if (attribute.getAllowedRuleClassesPredicate().apply(
+ ((Rule) prerequisite.getTarget()).getRuleClassObject())) {
// prerequisite has an allowed rule class => accept.
- return;
+ return true;
}
// remember that the rule class that was not allowed;
// but maybe prerequisite provides required providers? do not reject yet.
- notAllowedRuleClassesMessage =
+ unfulfilledRequirements.add(
badPrerequisiteMessage(
- prerequisiteTarget.getTargetKind(),
+ prerequisite.getTarget().getTargetKind(),
prerequisite,
"expected " + attribute.getAllowedRuleClassesPredicate(),
- false);
+ false));
}
+ return false;
+ }
- if (attribute.getAllowedRuleClassesWarningPredicate().apply(ruleClass)) {
+ /**
+ * Check if prerequisite should be allowed with warning based on its rule class.
+ *
+ * If yes, also issues said warning.
+ */
+ private boolean checkRuleDependencyClassWarnings(ConfiguredTarget prerequisite,
+ Attribute attribute) {
+ if (attribute.getAllowedRuleClassesWarningPredicate().apply(
+ ((Rule) prerequisite.getTarget()).getRuleClassObject())) {
Predicate<RuleClass> allowedRuleClasses = attribute.getAllowedRuleClassesPredicate();
- reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite,
+ reportBadPrerequisite(attribute, prerequisite.getTarget().getTargetKind(), prerequisite,
allowedRuleClasses == Predicates.<RuleClass>alwaysTrue()
? null : "expected " + allowedRuleClasses,
true);
// prerequisite has a rule class allowed with a warning => accept, emitting a warning.
- return;
+ return true;
}
+ return false;
+ }
- // 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;
- }
-
- String missingProviders = getMissingMandatoryProviders(prerequisite, attribute);
- if (missingProviders != null) {
- unfulfilledRequirements.add(
- "'" + prerequisite.getLabel() + "' does not have mandatory providers: "
- + missingProviders);
- hadAllMandatoryProviders = 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 (hadAllMandatoryProviders) {
- // all mandatory providers are present => accept.
- return;
- }
+ if (requiredProviders.acceptsAny()) {
+ // If no required providers specified, we do not know if we should accept.
+ return false;
}
- // not allowed rule class and some mandatory providers missing => reject.
- if (notAllowedRuleClassesMessage != null) {
- unfulfilledRequirements.add(notAllowedRuleClassesMessage);
+ if (prerequisite.satisfies(requiredProviders)) {
+ return true;
}
- if (!unfulfilledRequirements.isEmpty()) {
- attributeError(
- attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));
- }
+ unfulfilledRequirements.add(
+ String.format("'%s' does not have mandatory providers: %s",
+ prerequisite.getLabel(),
+ prerequisite.missingProviders(requiredProviders).getDescription()));
+
+ return false;
}
private void validateDirectPrerequisite(Attribute attribute, ConfiguredTarget prerequisite) {