Encode build configuration failures with FailureDetails
Eliminates the second-to-last remaining use of DetailedExitCode without
FailureDetails.
Cleans up an incorrect use of BUILD_CONFIGURATION_UNKNOWN, a default
protobuf enum value.
RELNOTES: None.
PiperOrigin-RevId: 332872475
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index 9534265..b0031a2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -1697,7 +1697,10 @@
name = "config/invalid_configuration_exception",
srcs = ["config/InvalidConfigurationException.java"],
deps = [
+ "//src/main/java/com/google/devtools/build/lib/skyframe:detailed_exceptions",
+ "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/protobuf:failure_details_java_proto",
+ "//third_party:guava",
"//third_party:jsr305",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
index e602252..7d1fbe2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationCollection.java
@@ -16,6 +16,7 @@
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import java.util.HashMap;
/**
@@ -45,7 +46,7 @@
BuildConfiguration old = cacheKeyConflictDetector.put(config.checksum(), config);
if (old != null) {
throw new InvalidConfigurationException(
- "Conflicting configurations: " + config + " & " + old);
+ "Conflicting configurations: " + config + " & " + old, Code.CONFLICTING_CONFIGURATIONS);
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java b/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
index 7f2a7f4..25c08c7 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/InvalidConfigurationException.java
@@ -13,39 +13,64 @@
// limitations under the License.
package com.google.devtools.build.lib.analysis.config;
+import com.google.common.base.Strings;
+import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.skyframe.DetailedException;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import javax.annotation.Nullable;
/**
* Thrown if the configuration options lead to an invalid configuration, or if any of the
* configuration labels cannot be loaded.
*/
-public class InvalidConfigurationException extends Exception {
+public class InvalidConfigurationException extends Exception implements DetailedException {
- @Nullable private final Code detailedCode;
+ @Nullable private final DetailedExitCode detailedExitCode;
public InvalidConfigurationException(String message) {
super(message);
- this.detailedCode = null;
+ this.detailedExitCode = null;
+ }
+
+ public InvalidConfigurationException(String message, Code code) {
+ super(message);
+ this.detailedExitCode = createDetailedExitCode(message, code);
}
public InvalidConfigurationException(String message, Throwable cause) {
super(message, cause);
- this.detailedCode = null;
+ this.detailedExitCode = null;
}
public InvalidConfigurationException(Throwable cause) {
super(cause.getMessage(), cause);
- this.detailedCode = null;
+ this.detailedExitCode = null;
}
- public InvalidConfigurationException(Code detailedCode, Exception cause) {
+ public InvalidConfigurationException(Code code, Throwable cause) {
super(cause.getMessage(), cause);
- this.detailedCode = detailedCode;
+ this.detailedExitCode = createDetailedExitCode(cause.getMessage(), code);
}
- @Nullable
- public Code getDetailedCode() {
- return detailedCode;
+ public InvalidConfigurationException(DetailedExitCode detailedExitCode, Throwable cause) {
+ super(cause.getMessage(), cause);
+ this.detailedExitCode = detailedExitCode;
+ }
+
+ @Override
+ public DetailedExitCode getDetailedExitCode() {
+ return detailedExitCode != null
+ ? detailedExitCode
+ : createDetailedExitCode(getMessage(), Code.INVALID_CONFIGURATION);
+ }
+
+ private static DetailedExitCode createDetailedExitCode(@Nullable String message, Code code) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(Strings.nullToEmpty(message))
+ .setBuildConfiguration(FailureDetails.BuildConfiguration.newBuilder().setCode(code))
+ .build());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
index fb00fbb..61e2a20 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/AnalysisPhaseRunner.java
@@ -42,6 +42,7 @@
import com.google.devtools.build.lib.profiler.SilentCloseable;
import com.google.devtools.build.lib.runtime.BlazeModule;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
+import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.BuildConfigurationValue;
import com.google.devtools.build.lib.skyframe.BuildInfoCollectionFunction;
@@ -99,7 +100,7 @@
buildOptions.get(CoreOptions.class).instrumentationFilter =
new RegexFilter.RegexFilterConverter().convert(instrumentationFilter);
} catch (OptionsParsingException e) {
- throw new InvalidConfigurationException(e);
+ throw new InvalidConfigurationException(Code.HEURISTIC_INSTRUMENTATION_FILTER_INVALID, e);
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
index 5eeed4b..079326f 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequest.java
@@ -23,7 +23,6 @@
import com.google.devtools.build.lib.analysis.AnalysisOptions;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
-import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
import com.google.devtools.build.lib.buildeventstream.BuildEventProtocolOptions;
import com.google.devtools.build.lib.exec.ExecutionOptions;
import com.google.devtools.build.lib.packages.semantics.BuildLanguageOptions;
@@ -269,7 +268,7 @@
*
* @return list of warnings
*/
- public List<String> validateOptions() throws InvalidConfigurationException {
+ public List<String> validateOptions() {
List<String> warnings = new ArrayList<>();
int localTestJobs = getExecutionOptions().localTestJobs;
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
index 7eb2896..53feadb 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildTool.java
@@ -52,6 +52,7 @@
import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.server.FailureDetails.ActionQuery;
+import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Interrupted.Code;
import com.google.devtools.build.lib.skyframe.SequencedSkyframeExecutor;
@@ -153,7 +154,8 @@
if (!"build".equals(request.getCommandName()) && !"test".equals(request.getCommandName())) {
throw new InvalidConfigurationException(
"The experimental setting to select multiple CPUs is only supported for 'build' and "
- + "'test' right now!");
+ + "'test' right now!",
+ BuildConfiguration.Code.MULTI_CPU_PREREQ_UNMET);
}
}
@@ -443,7 +445,7 @@
detailedExitCode = DetailedExitCode.success();
reportExceptionError(e);
} catch (InvalidConfigurationException e) {
- detailedExitCode = DetailedExitCode.justExitCode(ExitCode.COMMAND_LINE_ERROR);
+ detailedExitCode = e.getDetailedExitCode();
reportExceptionError(e);
// TODO(gregce): With "global configurations" we cannot tie a configuration creation failure
// to a single target and have to halt the entire build. Once configurations are genuinely
@@ -570,7 +572,7 @@
* settings that conflict.
*/
@VisibleForTesting
- public void validateOptions(BuildRequest request) throws InvalidConfigurationException {
+ public void validateOptions(BuildRequest request) {
for (String issue : request.validateOptions()) {
getReporter().handle(Event.warn(issue));
}
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
index 7ee7ea3..a3a8575 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
@@ -13,7 +13,6 @@
// limitations under the License.
package com.google.devtools.build.lib.runtime.commands;
-import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
@@ -61,7 +60,6 @@
import com.google.devtools.build.lib.runtime.commands.info.UsedHeapSizeInfoItem;
import com.google.devtools.build.lib.runtime.commands.info.WorkspaceInfoItem;
import com.google.devtools.build.lib.server.FailureDetails;
-import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Interrupted;
import com.google.devtools.build.lib.util.AbruptExitException;
@@ -170,18 +168,7 @@
/*keepGoing=*/ true);
} catch (InvalidConfigurationException e) {
env.getReporter().handle(Event.error(e.getMessage()));
- throw new AbruptExitRuntimeException(
- DetailedExitCode.of(
- ExitCode.COMMAND_LINE_ERROR,
- FailureDetail.newBuilder()
- .setMessage(Strings.nullToEmpty(e.getMessage()))
- .setBuildConfiguration(
- FailureDetails.BuildConfiguration.newBuilder()
- .setCode(
- e.getDetailedCode() == null
- ? Code.BUILD_CONFIGURATION_UNKNOWN
- : e.getDetailedCode()))
- .build()));
+ throw new AbruptExitRuntimeException(e.getDetailedExitCode());
} catch (AbruptExitException e) {
throw new AbruptExitRuntimeException(e.getDetailedExitCode());
} catch (InterruptedException e) {
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
index c95caf7..0d6f17c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
@@ -41,6 +41,7 @@
import com.google.devtools.build.lib.events.ErrorSensingEventHandler;
import com.google.devtools.build.lib.packages.NoSuchThingException;
import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
import com.google.devtools.build.lib.skyframe.PrepareAnalysisPhaseValue.PrepareAnalysisPhaseKey;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.skyframe.SkyFunction;
@@ -142,7 +143,8 @@
.forEach(config -> config.reportInvalidOptions(nosyEventHandler));
if (nosyEventHandler.hasErrors()) {
throw new PrepareAnalysisPhaseFunctionException(
- new InvalidConfigurationException("Build options are invalid"));
+ new InvalidConfigurationException(
+ "Build options are invalid", Code.INVALID_BUILD_OPTIONS));
}
// We get the list of labels from the TargetPatternPhaseValue, so we are reasonably certain that
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index c6863d3..ed87c6d 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -1516,7 +1516,8 @@
ErrorSensingEventHandler.withoutPropertyValueTracking(eventHandler);
topLevelTargetConfigs.forEach(config -> config.reportInvalidOptions(nosyEventHandler));
if (nosyEventHandler.hasErrors()) {
- throw new InvalidConfigurationException("Build options are invalid");
+ throw new InvalidConfigurationException(
+ "Build options are invalid", Code.INVALID_BUILD_OPTIONS);
}
return new BuildConfigurationCollection(topLevelTargetConfigs, hostConfig);
}
@@ -1952,12 +1953,12 @@
Throwable e = error.getException();
// Wrap loading failed exceptions
if (e instanceof NoSuchThingException) {
- e = new InvalidConfigurationException(e);
+ e = new InvalidConfigurationException(((NoSuchThingException) e).getDetailedExitCode(), e);
} else if (e == null && !error.getCycleInfo().isEmpty()) {
getCyclesReporter().reportCycles(error.getCycleInfo(), firstError.getKey(), eventHandler);
e =
new InvalidConfigurationException(
- "cannot load build configuration because of this cycle");
+ "cannot load build configuration because of this cycle", Code.CYCLE);
}
if (e != null) {
Throwables.throwIfInstanceOf(e, InvalidConfigurationException.class);
@@ -2135,7 +2136,7 @@
depFragments,
BuildOptions.diffForReconstruction(defaultBuildOptions, toOption));
} catch (OptionsParsingException e) {
- throw new InvalidConfigurationException(e);
+ throw new InvalidConfigurationException(Code.INVALID_BUILD_OPTIONS, e);
}
}
@@ -2962,9 +2963,9 @@
getCyclesReporter().reportCycles(errorInfo.getCycleInfo(), key, eventHandler);
e =
new InvalidConfigurationException(
- "cannot load build configuration because of this cycle");
+ "cannot load build configuration because of this cycle", Code.CYCLE);
} else if (e instanceof NoSuchThingException) {
- e = new InvalidConfigurationException(e);
+ e = new InvalidConfigurationException(((NoSuchThingException) e).getDetailedExitCode(), e);
}
if (e != null) {
Throwables.throwIfInstanceOf(e, InvalidConfigurationException.class);