Create a mode to propagate AnalysisFailureInfo for rule errors instead of failing a build
This new functionality is tied to --experimental_allow_analysis_failures : This feature is designed to facilitate in-build (analysis-phase) testing rules.
Progress toward #6237.
RELNOTES: None.
PiperOrigin-RevId: 215820356
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 f1902f2..66d071e 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
@@ -85,7 +85,6 @@
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.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
@@ -181,7 +180,7 @@
private final BuildConfiguration hostConfiguration;
private final ConfigurationFragmentPolicy configurationFragmentPolicy;
private final ImmutableList<Class<? extends BuildConfiguration.Fragment>> universalFragments;
- private final ErrorReporter reporter;
+ private final RuleErrorConsumer reporter;
@Nullable private final ToolchainContext toolchainContext;
private final ConstraintSemantics constraintSemantics;
@@ -294,6 +293,22 @@
}
/**
+ * If this target's configuration suppresses analysis failures, this returns a list
+ * of strings, where each string corresponds to a description of an error that occurred during
+ * processing this target.
+ *
+ * @throws IllegalStateException if this target's configuration does not suppress analysis
+ * failures (if {@code getConfiguration().allowAnalysisFailures()} is false)
+ */
+ public List<String> getSuppressedErrorMessages() {
+ Preconditions.checkState(getConfiguration().allowAnalysisFailures(),
+ "Error messages can only be retrieved via RuleContext if allow_analysis_failures is true");
+ Preconditions.checkState(reporter instanceof SuppressingErrorReporter,
+ "Unexpected error reporter");
+ return ((SuppressingErrorReporter) reporter).getErrorMessages();
+ }
+
+ /**
* If this <code>RuleContext</code> is for an aspect implementation, returns that aspect.
* (it is the last aspect in the list of aspects applied to a target; all other aspects
* are the ones main aspect sees as specified by its "required_aspect_providers")
@@ -357,13 +372,6 @@
return getAnalysisEnvironment().hasErrors();
}
- @Override
- public void assertNoErrors() throws RuleErrorException {
- if (hasErrors()) {
- throw new RuleErrorException();
- }
- }
-
/**
* Returns an immutable map from attribute name to list of configured targets for that attribute.
*/
@@ -502,12 +510,6 @@
reporter.ruleError(message);
}
- @Override
- public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
- reporter.ruleError(message);
- throw new RuleErrorException();
- }
-
/**
* Convenience function for subclasses to report non-attribute-specific
* warnings in the current rule.
@@ -529,13 +531,6 @@
reporter.attributeError(attrName, message);
}
- @Override
- public RuleErrorException throwWithAttributeError(String attrName, String message)
- throws RuleErrorException {
- reporter.attributeError(attrName, message);
- throw new RuleErrorException();
- }
-
/**
* Like attributeError, but does not mark the configured target as errored.
*
@@ -1436,7 +1431,7 @@
private final BuildConfiguration configuration;
private final BuildConfiguration hostConfiguration;
private final PrerequisiteValidator prerequisiteValidator;
- private final ErrorReporter reporter;
+ private final RuleErrorConsumer reporter;
private OrderedSetMultimap<Attribute, ConfiguredTargetAndData> prerequisiteMap;
private ImmutableMap<Label, ConfigMatchingProvider> configConditions;
private NestedSet<PackageGroupContents> visibility;
@@ -1461,7 +1456,11 @@
this.configuration = Preconditions.checkNotNull(configuration);
this.hostConfiguration = Preconditions.checkNotNull(hostConfiguration);
this.prerequisiteValidator = prerequisiteValidator;
- reporter = new ErrorReporter(env, target.getAssociatedRule(), getRuleClassNameForLogging());
+ if (configuration.allowAnalysisFailures()) {
+ reporter = new SuppressingErrorReporter();
+ } else {
+ reporter = new ErrorReporter(env, target.getAssociatedRule(), getRuleClassNameForLogging());
+ }
}
@VisibleForTesting
@@ -1694,26 +1693,10 @@
}
@Override
- public RuleErrorException throwWithRuleError(String message) throws RuleErrorException {
- throw reporter.throwWithRuleError(message);
- }
-
- @Override
- public RuleErrorException throwWithAttributeError(String attrName, String message)
- throws RuleErrorException {
- throw reporter.throwWithAttributeError(attrName, message);
- }
-
- @Override
public boolean hasErrors() {
return reporter.hasErrors();
}
- @Override
- public void assertNoErrors() throws RuleErrorException {
- reporter.assertNoErrors();
- }
-
private String badPrerequisiteMessage(
ConfiguredTargetAndData prerequisite, String reason, boolean isWarning) {
String msgReason = reason != null ? " (" + reason + ")" : "";
@@ -2026,6 +2009,41 @@
protected Location getAttributeLocation(String attrName) {
return rule.getAttributeLocation(attrName);
}
+ }
+ /**
+ * Implementation of an error consumer which does not post any events, saves rule and attribute
+ * errors for future consumption, and drops warnings.
+ */
+ public static final class SuppressingErrorReporter implements RuleErrorConsumer {
+ private final List<String> errorMessages = Lists.newArrayList();
+
+ @Override
+ public void ruleWarning(String message) {}
+
+ @Override
+ public void ruleError(String message) {
+ errorMessages.add(message);
+ }
+
+ @Override
+ public void attributeWarning(String attrName, String message) {}
+
+ @Override
+ public void attributeError(String attrName, String message) {
+ errorMessages.add(message);
+ }
+
+ @Override
+ public boolean hasErrors() {
+ return !errorMessages.isEmpty();
+ }
+
+ /**
+ * Returns the error message strings reported to this error consumer.
+ */
+ public List<String> getErrorMessages() {
+ return errorMessages;
+ }
}
}