Refactor root cause reporting in ConfiguredTargetFunction
We now track Causes instead of plain Labels, which will allow us to do better reporting in the future. Add basic tests.
PiperOrigin-RevId: 198380468
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 748451b..a310fad 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -41,11 +41,16 @@
import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException;
import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
import com.google.devtools.build.lib.buildeventstream.BuildEventId;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
+import com.google.devtools.build.lib.causes.Cause;
+import com.google.devtools.build.lib.causes.LoadingFailedCause;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.Attribute;
@@ -78,6 +83,7 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Semaphore;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
/**
@@ -161,7 +167,7 @@
SkyframeBuildView view = buildViewProvider.getSkyframeBuildView();
NestedSetBuilder<Package> transitivePackagesForPackageRootResolution =
storeTransitivePackagesForPackageRootResolution ? NestedSetBuilder.stableOrder() : null;
- NestedSetBuilder<Label> transitiveLoadingRootCauses = NestedSetBuilder.stableOrder();
+ NestedSetBuilder<Cause> transitiveRootCauses = NestedSetBuilder.stableOrder();
ConfiguredTargetKey configuredTargetKey = (ConfiguredTargetKey) key.argument();
Label label = configuredTargetKey.getLabel();
@@ -197,7 +203,8 @@
new ConfiguredValueCreationException(e.getMessage(), label, configuration));
}
if (pkg.containsErrors()) {
- transitiveLoadingRootCauses.add(label);
+ transitiveRootCauses.add(
+ new LoadingFailedCause(label, new NoSuchTargetException(target).getMessage()));
}
if (transitivePackagesForPackageRootResolution != null) {
transitivePackagesForPackageRootResolution.add(pkg);
@@ -241,7 +248,7 @@
resolver,
ctgValue,
transitivePackagesForPackageRootResolution,
- transitiveLoadingRootCauses,
+ transitiveRootCauses,
((ConfiguredRuleClassProvider) ruleClassProvider).getTrimmingTransitionFactory());
if (env.valuesMissing()) {
return null;
@@ -253,9 +260,10 @@
// more root causes during computeDependencies.
// Note that this doesn't apply to AspectFunction, because aspects can't have configurable
// attributes.
- if (!transitiveLoadingRootCauses.isEmpty() && configConditions != NO_CONFIG_CONDITIONS) {
+ if (!transitiveRootCauses.isEmpty() && configConditions != NO_CONFIG_CONDITIONS) {
throw new ConfiguredTargetFunctionException(
- new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
+ new ConfiguredValueCreationException(
+ "Cannot compute config conditions", configuration, transitiveRootCauses.build()));
}
// Determine what toolchains are needed by this target.
@@ -288,14 +296,15 @@
ruleClassProvider,
view.getHostConfiguration(configuration),
transitivePackagesForPackageRootResolution,
- transitiveLoadingRootCauses,
+ transitiveRootCauses,
defaultBuildOptions);
if (env.valuesMissing()) {
return null;
}
- if (!transitiveLoadingRootCauses.isEmpty()) {
+ if (!transitiveRootCauses.isEmpty()) {
throw new ConfiguredTargetFunctionException(
- new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
+ new ConfiguredValueCreationException(
+ "Analysis failed", configuration, transitiveRootCauses.build()));
}
Preconditions.checkNotNull(depValueMap);
ConfiguredTargetValue ans =
@@ -315,21 +324,15 @@
// Check if this is caused by an unresolved toolchain, and report it as such.
if (toolchainContext != null) {
- ImmutableSet.Builder<Label> causes = new ImmutableSet.Builder<Label>();
- if (cvce.getAnalysisRootCause() != null) {
- causes.add(cvce.getAnalysisRootCause());
- }
- if (!cvce.getRootCauses().isEmpty()) {
- causes.addAll(cvce.getRootCauses());
- }
Set<Label> toolchainDependencyErrors =
- toolchainContext.filterToolchainLabels(causes.build());
+ toolchainContext.filterToolchainLabels(
+ Iterables.transform(cvce.getRootCauses(), Cause::getLabel));
if (!toolchainDependencyErrors.isEmpty()) {
env.getListener()
.handle(
Event.error(
String.format(
- "While resolving toolchains for target %s: %s",
+ "XXX - While resolving toolchains for target %s: %s",
target.getLabel(), e.getCause().getMessage())));
}
}
@@ -352,13 +355,11 @@
new ConfiguredValueCreationException(e.getMessage(), target.getLabel(), configuration));
}
} catch (AspectCreationException e) {
- // getAnalysisRootCause may be null if the analysis of the aspect itself failed.
- Label analysisRootCause = target.getLabel();
- if (e.getAnalysisRootCause() != null) {
- analysisRootCause = e.getAnalysisRootCause();
- }
throw new ConfiguredTargetFunctionException(
- new ConfiguredValueCreationException(e.getMessage(), analysisRootCause, configuration));
+ new ConfiguredValueCreationException(
+ e.getMessage(),
+ configuration,
+ e.getCauses()));
} catch (ToolchainContextException e) {
// We need to throw a ConfiguredValueCreationException, so either find one or make one.
ConfiguredValueCreationException cvce;
@@ -415,7 +416,7 @@
RuleClassProvider ruleClassProvider,
BuildConfiguration hostConfiguration,
@Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution,
- NestedSetBuilder<Label> transitiveLoadingRootCauses,
+ NestedSetBuilder<Cause> transitiveRootCauses,
BuildOptions defaultBuildOptions)
throws DependencyEvaluationException, ConfiguredTargetFunctionException,
AspectCreationException, InterruptedException {
@@ -431,14 +432,15 @@
toolchainContext == null
? ImmutableSet.of()
: toolchainContext.getResolvedToolchainLabels(),
- transitiveLoadingRootCauses,
+ transitiveRootCauses,
defaultBuildOptions,
((ConfiguredRuleClassProvider) ruleClassProvider).getTrimmingTransitionFactory());
} catch (EvalException e) {
// EvalException can only be thrown by computed Skylark attributes in the current rule.
env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
throw new DependencyEvaluationException(
- new ConfiguredValueCreationException(e.print(), ctgValue.getLabel()));
+ new ConfiguredValueCreationException(
+ e.print(), ctgValue.getLabel(), ctgValue.getConfiguration()));
} catch (InvalidConfigurationException e) {
throw new DependencyEvaluationException(e);
} catch (InconsistentAspectOrderException e) {
@@ -469,9 +471,10 @@
Map<SkyKey, ConfiguredTargetAndData> depValues =
resolveConfiguredTargetDependencies(
env,
+ ctgValue,
depValueNames.values(),
transitivePackagesForPackageRootResolution,
- transitiveLoadingRootCauses);
+ transitiveRootCauses);
if (depValues == null) {
return null;
}
@@ -492,7 +495,8 @@
Event.error(ctgValue.getTarget().getLocation(), e.getMessage()));
throw new ConfiguredTargetFunctionException(
- new ConfiguredValueCreationException(e.getMessage(), ctgValue.getLabel()));
+ new ConfiguredValueCreationException(
+ e.getMessage(), ctgValue.getLabel(), ctgValue.getConfiguration()));
}
}
@@ -510,7 +514,7 @@
SkyframeDependencyResolver resolver,
TargetAndConfiguration ctgValue,
@Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution,
- NestedSetBuilder<Label> transitiveLoadingRootCauses,
+ NestedSetBuilder<Cause> transitiveRootCauses,
@Nullable RuleTransitionFactory trimmingTransitionFactory)
throws DependencyEvaluationException, InterruptedException {
if (!(target instanceof Rule)) {
@@ -538,7 +542,7 @@
Collection<Dependency> configValueNames;
try {
configValueNames = resolver.resolveRuleLabels(
- ctgValue, configLabelMap, transitiveLoadingRootCauses, trimmingTransitionFactory);
+ ctgValue, configLabelMap, transitiveRootCauses, trimmingTransitionFactory);
} catch (InconsistentAspectOrderException e) {
throw new DependencyEvaluationException(e);
}
@@ -560,9 +564,10 @@
Map<SkyKey, ConfiguredTargetAndData> configValues =
resolveConfiguredTargetDependencies(
env,
+ ctgValue,
configValueNames,
transitivePackagesForPackageRootResolution,
- transitiveLoadingRootCauses);
+ transitiveRootCauses);
if (configValues == null) {
return null;
}
@@ -580,8 +585,9 @@
String message =
entry.getLabel() + " is not a valid configuration key for " + target.getLabel();
env.getListener().handle(Event.error(TargetUtils.getLocationMaybe(target), message));
- throw new DependencyEvaluationException(new ConfiguredValueCreationException(
- message, target.getLabel()));
+ throw new DependencyEvaluationException(
+ new ConfiguredValueCreationException(
+ message, ctgValue.getLabel(), ctgValue.getConfiguration()));
}
}
@@ -597,12 +603,13 @@
@Nullable
private static Map<SkyKey, ConfiguredTargetAndData> resolveConfiguredTargetDependencies(
Environment env,
+ TargetAndConfiguration ctgValue,
Collection<Dependency> deps,
@Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution,
- NestedSetBuilder<Label> transitiveLoadingRootCauses)
+ NestedSetBuilder<Cause> transitiveRootCauses)
throws DependencyEvaluationException, InterruptedException {
boolean missedValues = env.valuesMissing();
- boolean failed = false;
+ String failWithMessage = null;
// Naively we would like to just fetch all requested ConfiguredTargets, together with their
// Packages. However, some ConfiguredTargets are AliasConfiguredTargets, which means that their
// associated Targets (and therefore associated Packages) don't correspond to their own Labels.
@@ -677,12 +684,8 @@
}
}
} catch (ConfiguredValueCreationException e) {
- // TODO(ulfjack): If there is an analysis root cause, we drop all loading root causes.
- if (e.getAnalysisRootCause() != null) {
- throw new DependencyEvaluationException(e);
- }
- transitiveLoadingRootCauses.addTransitive(e.loadingRootCauses);
- failed = true;
+ transitiveRootCauses.addTransitive(e.rootCauses);
+ failWithMessage = e.getMessage();
}
}
if (aliasDepsToRedo.isEmpty()) {
@@ -693,9 +696,10 @@
}
if (missedValues) {
return null;
- } else if (failed) {
+ } else if (failWithMessage != null) {
throw new DependencyEvaluationException(
- new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
+ new ConfiguredValueCreationException(
+ failWithMessage, ctgValue.getConfiguration(), transitiveRootCauses.build()));
} else {
return result;
}
@@ -753,11 +757,21 @@
events.replayOn(env.getListener());
if (events.hasErrors()) {
analysisEnvironment.disable(target);
+ NestedSet<Cause> rootCauses = NestedSetBuilder.wrap(
+ Order.STABLE_ORDER,
+ events.getEvents().stream()
+ .filter((event) -> event.getKind() == EventKind.ERROR)
+ .map((event) ->
+ new AnalysisFailedCause(
+ target.getLabel(),
+ ConfiguredValueCreationException.toId(configuration),
+ event.getMessage()))
+ .collect(Collectors.toList()));
throw new ConfiguredTargetFunctionException(
new ConfiguredValueCreationException(
"Analysis of target '" + target.getLabel() + "' failed; build aborted",
- target.getLabel(),
- configuration));
+ configuration,
+ rootCauses));
}
Preconditions.checkState(!analysisEnvironment.hasErrors(),
"Analysis environment hasError() but no errors reported");
@@ -804,51 +818,41 @@
*/
@AutoCodec
public static final class ConfiguredValueCreationException extends Exception {
- private final NestedSet<Label> loadingRootCauses;
- // TODO(ulfjack): Collect all analysis root causes, not just the first one.
- @Nullable private final Label analysisRootCause;
- @Nullable private final BuildEventId configuration;
-
- private ConfiguredValueCreationException(
- String message, Label currentTarget, BuildConfiguration configuration) {
- this(
- message,
- Preconditions.checkNotNull(currentTarget),
- NestedSetBuilder.<Label>emptySet(Order.STABLE_ORDER),
- configuration == null ? null : configuration.getEventId());
+ private static ConfigurationId toId(BuildConfiguration config) {
+ return config == null ? null : config.getEventId().asStreamProto().getConfiguration();
}
+ @Nullable private final BuildEventId configuration;
+ private final NestedSet<Cause> rootCauses;
+
@AutoCodec.VisibleForSerialization
@AutoCodec.Instantiator
ConfiguredValueCreationException(
String message,
- Label analysisRootCause,
- NestedSet<Label> loadingRootCauses,
- BuildEventId configuration) {
+ @Nullable BuildEventId configuration,
+ NestedSet<Cause> rootCauses) {
super(message);
- this.loadingRootCauses = loadingRootCauses;
- this.analysisRootCause = analysisRootCause;
+ this.rootCauses = rootCauses;
this.configuration = configuration;
}
- private ConfiguredValueCreationException(String message, Label currentTarget) {
- this(message, currentTarget, /*configuration=*/ null);
+ private ConfiguredValueCreationException(
+ String message, Label currentTarget, @Nullable BuildConfiguration configuration) {
+ this(
+ message,
+ configuration == null ? null : configuration.getEventId(),
+ NestedSetBuilder.<Cause>stableOrder()
+ .add(new AnalysisFailedCause(currentTarget, toId(configuration), message))
+ .build());
}
- private ConfiguredValueCreationException(String message, NestedSet<Label> rootCauses) {
- this(message, /*analysisRootCause=*/ null, rootCauses, /*configuration=*/ null);
+ private ConfiguredValueCreationException(
+ String message, @Nullable BuildConfiguration configuration, NestedSet<Cause> rootCauses) {
+ this(message, configuration == null ? null : configuration.getEventId(), rootCauses);
}
- private ConfiguredValueCreationException(NestedSet<Label> rootCauses) {
- this("Loading failed", rootCauses);
- }
-
- public NestedSet<Label> getRootCauses() {
- return loadingRootCauses;
- }
-
- @Nullable public Label getAnalysisRootCause() {
- return analysisRootCause;
+ public NestedSet<Cause> getRootCauses() {
+ return rootCauses;
}
@Nullable public BuildEventId getConfiguration() {