Add a FailureDetail for Packages in error due to an error constructing a Rule in the Package. File bug reports in various places when we're missing a FailureDetail.
PiperOrigin-RevId: 423098609
diff --git a/src/main/java/com/google/devtools/build/lib/events/Event.java b/src/main/java/com/google/devtools/build/lib/events/Event.java
index b941028..ce99ffee 100644
--- a/src/main/java/com/google/devtools/build/lib/events/Event.java
+++ b/src/main/java/com/google/devtools/build/lib/events/Event.java
@@ -24,7 +24,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
-import java.util.function.Function;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@@ -404,22 +403,6 @@
}
/**
- * Converts a list of {@link SyntaxError}s to events, each with a specified property, and replays
- * them on {@code handler}.
- */
- public static <T> void replayEventsOn(
- EventHandler handler,
- List<SyntaxError> errors,
- Class<T> propertyType,
- Function<SyntaxError, T> toProperty) {
- for (SyntaxError error : errors) {
- handler.handle(
- Event.error(error.location(), error.message())
- .withProperty(propertyType, toProperty.apply(error)));
- }
- }
-
- /**
* Returns a {@link StarlarkThread.PrintHandler} that sends {@link EventKind#DEBUG} events to the
* provided {@link EventHandler}.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BUILD b/src/main/java/com/google/devtools/build/lib/packages/BUILD
index 146d5cf..fcfa651 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/packages/BUILD
@@ -66,6 +66,7 @@
"//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_factory",
"//src/main/java/com/google/devtools/build/lib/analysis:rule_definition_environment",
"//src/main/java/com/google/devtools/build/lib/analysis:transitive_info_provider",
+ "//src/main/java/com/google/devtools/build/lib/bugreport",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/cmdline:LabelValidator",
"//src/main/java/com/google/devtools/build/lib/collect",
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Package.java b/src/main/java/com/google/devtools/build/lib/packages/Package.java
index 25c5112..b540928 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Package.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Package.java
@@ -28,6 +28,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.LabelConstants;
import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
@@ -868,9 +869,7 @@
*/
public static Event error(Location location, String message, Code code) {
Event error = Event.error(location, message);
- // The DetailedExitCode's message is the base event's toString because that string nicely
- // includes the location value.
- return error.withProperty(DetailedExitCode.class, createDetailedCode(error.toString(), code));
+ return error.withProperty(DetailedExitCode.class, createDetailedCode(message, code));
}
private static DetailedExitCode createDetailedCode(String errorMessage, Code code) {
@@ -1306,7 +1305,9 @@
}
/**
- * Declares that errors were encountering while loading this package.
+ * Declares that errors were encountering while loading this package. If called, {@link
+ * #addEvent} or {@link #addEvents} should already have been called with an {@link Event} of
+ * type {@link EventKind#ERROR} that includes a {@link FailureDetail}.
*/
public Builder setContainsErrors() {
containsErrors = true;
@@ -1346,6 +1347,7 @@
return failureDetailOverride;
}
+ List<Event> undetailedEvents = null;
for (Event event : this.events) {
if (event.getKind() != EventKind.ERROR) {
continue;
@@ -1354,6 +1356,16 @@
if (detailedExitCode != null && detailedExitCode.getFailureDetail() != null) {
return detailedExitCode.getFailureDetail();
}
+ if (containsErrors) {
+ if (undetailedEvents == null) {
+ undetailedEvents = new ArrayList<>();
+ }
+ undetailedEvents.add(event);
+ }
+ }
+ if (undetailedEvents != null) {
+ BugReport.sendBugReport(
+ new IllegalStateException("Package has undetailed error from " + undetailedEvents));
}
return null;
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageGroup.java b/src/main/java/com/google/devtools/build/lib/packages/PackageGroup.java
index 8c7ff9b..f863a65 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/PackageGroup.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/PackageGroup.java
@@ -34,7 +34,7 @@
* can be asked if a specific package is included in it.
*/
public class PackageGroup implements Target {
- private boolean containsErrors;
+ private final boolean containsErrors;
private final Label label;
private final Location location;
private final Package containingPackage;
@@ -55,13 +55,14 @@
// TODO(bazel-team): Consider refactoring so constructor takes a PackageGroupContents.
ImmutableList.Builder<PackageSpecification> packagesBuilder = ImmutableList.builder();
+ boolean errorsFound = false;
for (String packageSpecification : packageSpecifications) {
PackageSpecification specification = null;
try {
specification =
PackageSpecification.fromString(label.getRepository(), packageSpecification);
} catch (PackageSpecification.InvalidPackageSpecificationException e) {
- containsErrors = true;
+ errorsFound = true;
eventHandler.handle(
Package.error(location, e.getMessage(), Code.INVALID_PACKAGE_SPECIFICATION));
}
@@ -70,6 +71,7 @@
packagesBuilder.add(specification);
}
}
+ this.containsErrors = errorsFound;
this.packageSpecifications = PackageGroupContents.create(packagesBuilder.build());
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Rule.java b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
index 59598f2..ba42c48 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Rule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Rule.java
@@ -36,6 +36,7 @@
import com.google.devtools.build.lib.packages.License.DistributionType;
import com.google.devtools.build.lib.packages.Package.ConfigSettingVisibilityPolicy;
import com.google.devtools.build.lib.packages.RuleClass.ToolchainResolutionMode;
+import com.google.devtools.build.lib.server.FailureDetails.PackageLoading;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -813,7 +814,7 @@
}
void reportError(String message, EventHandler eventHandler) {
- eventHandler.handle(Event.error(location, message));
+ eventHandler.handle(Package.error(location, message, PackageLoading.Code.STARLARK_EVAL_ERROR));
this.containsErrors = true;
}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index 963956d..623177a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -24,6 +24,7 @@
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.packages.Package.NameConflictException;
import com.google.devtools.build.lib.packages.PackageFactory.EnvironmentExtension;
+import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.PackageLoading;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -172,6 +173,13 @@
} catch (SyntaxError.Exception ex) {
// compilation failed
Event.replayEventsOn(localReporter, ex.errors());
+ builder.setFailureDetailOverride(
+ FailureDetails.FailureDetail.newBuilder()
+ .setMessage(ex.getMessage())
+ .setPackageLoading(
+ FailureDetails.PackageLoading.newBuilder()
+ .setCode(PackageLoading.Code.SYNTAX_ERROR))
+ .build());
}
// cleanup (success or failure)
diff --git a/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java b/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
index 83e7efa..09a83c1 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/common/AbstractBlazeQueryEnvironment.java
@@ -22,6 +22,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.flogger.GoogleLogger;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.TargetParsingException;
import com.google.devtools.build.lib.events.ErrorSensingEventHandler;
@@ -244,7 +245,13 @@
QueryExpression expression, String message, DetailedExitCode detailedExitCode)
throws QueryException {
if (!keepGoing) {
- throw new QueryException(expression, message, detailedExitCode.getFailureDetail());
+ if (detailedExitCode != null) {
+ throw new QueryException(expression, message, detailedExitCode.getFailureDetail());
+ } else {
+ BugReport.sendBugReport(
+ new IllegalStateException("Undetailed failure: " + message + " for " + expression));
+ throw new QueryException(expression, message, Code.NON_DETAILED_ERROR);
+ }
}
eventHandler.handle(createErrorEvent(expression, message, detailedExitCode));
}
diff --git a/src/main/java/com/google/devtools/build/lib/query2/common/BUILD b/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
index 648a689..9cd7ea4 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/query2/common/BUILD
@@ -14,6 +14,7 @@
"AbstractBlazeQueryEnvironment.java",
],
deps = [
+ "//src/main/java/com/google/devtools/build/lib/bugreport",
"//src/main/java/com/google/devtools/build/lib/cmdline",
"//src/main/java/com/google/devtools/build/lib/events",
"//src/main/java/com/google/devtools/build/lib/packages",
diff --git a/src/main/java/com/google/devtools/build/lib/query2/query/TargetEdgeErrorObserver.java b/src/main/java/com/google/devtools/build/lib/query2/query/TargetEdgeErrorObserver.java
index cadea50..6ce7f5d 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/query/TargetEdgeErrorObserver.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/query/TargetEdgeErrorObserver.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.query2.query;
+import com.google.devtools.build.lib.bugreport.BugReport;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.concurrent.ThreadSafety;
import com.google.devtools.build.lib.packages.Attribute;
@@ -93,6 +94,9 @@
FailureDetail failureDetail = node.getPackage().getFailureDetail();
if (failureDetail != null) {
errorCode.compareAndSet(/*expect=*/ null, /*update=*/ DetailedExitCode.of(failureDetail));
+ } else {
+ BugReport.sendBugReport(
+ new IllegalStateException("Undetailed error from package: " + node));
}
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java
index a5051ab..16a335d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisFailureReportingTest.java
@@ -81,7 +81,9 @@
assertThat(cause).isInstanceOf(LoadingFailedCause.class);
assertThat(cause.getLabel()).isEqualTo(topLevel);
assertThat(((LoadingFailedCause) cause).getMessage())
- .isEqualTo("Target '//foo:foo' contains an error and its package is in error");
+ .isEqualTo(
+ "Target '//foo:foo' contains an error and its package is in error: //foo:foo: missing"
+ + " value for mandatory attribute 'outs' in 'genrule' rule");
}
@Test
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/AbstractQueryTest.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/AbstractQueryTest.java
index c9b13a8..7d7e9cd 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/AbstractQueryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/AbstractQueryTest.java
@@ -16,6 +16,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat;
import static com.google.devtools.build.lib.testutil.TestConstants.GENRULE_SETUP;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.fail;
@@ -1800,6 +1801,28 @@
}
@Test
+ public void badRuleInDeps() throws Exception {
+ runBadRuleInDeps(Code.STARLARK_EVAL_ERROR);
+ }
+
+ protected final void runBadRuleInDeps(Object code) throws Exception {
+ writeFile("foo/BUILD", "sh_library(name = 'foo', deps = ['//bar:bar'])");
+ writeFile("bar/BUILD", "sh_library(name = 'bar', srcs = 'bad_single_file')");
+ EvalThrowsResult evalThrowsResult =
+ evalThrows("deps(//foo:foo)", /*unconditionallyThrows=*/ false);
+ FailureDetail.Builder failureDetailBuilder = FailureDetail.newBuilder();
+ if (code instanceof FailureDetails.PackageLoading.Code) {
+ failureDetailBuilder.setPackageLoading(
+ FailureDetails.PackageLoading.newBuilder().setCode((Code) code));
+ } else if (code instanceof Query.Code) {
+ failureDetailBuilder.setQuery(FailureDetails.Query.newBuilder().setCode((Query.Code) code));
+ }
+ assertThat(evalThrowsResult.getFailureDetail())
+ .comparingExpectedFieldsOnly()
+ .isEqualTo(failureDetailBuilder.build());
+ }
+
+ @Test
public void buildfilesBazel() throws Exception {
writeFile("bar/BUILD.bazel");
writeFile("bar/bar.bzl", "sym = 0");
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
index 2009df8..86eeec5 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
@@ -60,6 +60,7 @@
"//src/test/java/com/google/devtools/build/lib/testutil:TestConstants",
"//src/test/java/com/google/devtools/build/lib/testutil:TestPackageFactoryBuilderFactory",
"//src/test/java/com/google/devtools/build/skyframe:testutil",
+ "//third_party:error_prone_annotations",
"//third_party:guava",
"//third_party:jsr305",
"//third_party:junit4",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
index 6a86c0f..73fb8ee 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
@@ -707,6 +707,9 @@
@Override
public void testRegression1309697() {}
+ @Override
+ public void badRuleInDeps() {}
+
// Can't handle cycles.
@Override
public void testDotDotDotWithCycle() {}
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
index 135a233..28cf41b 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/SkyframeQueryHelper.java
@@ -71,6 +71,7 @@
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.common.options.Options;
import com.google.devtools.common.options.OptionsProvider;
+import com.google.errorprone.annotations.ForOverride;
import java.io.IOException;
import java.util.AbstractSet;
import java.util.ArrayList;
@@ -152,6 +153,7 @@
this.blockUniverseEvaluationErrors = blockUniverseEvaluationErrors;
}
+ @ForOverride
protected QueryEnvironmentFactory makeQueryEnvironmentFactory() {
return new QueryEnvironmentFactory();
}