Encode additional ActionExecution failures with FailureDetails
Deletes an undetailed ActionExecutionException overload.
Deletes TargetOutOfDateException because its distinguished type is
nowhere meaningful.
RELNOTES: None.
PiperOrigin-RevId: 315842104
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionException.java b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionException.java
index 6aa9d7f..87cb251 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionException.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionExecutionException.java
@@ -73,15 +73,6 @@
}
public ActionExecutionException(
- String message, ActionAnalysisMetadata action, boolean catastrophe) {
- super(message);
- this.action = action;
- this.catastrophe = catastrophe;
- this.detailedExitCode = DetailedExitCode.justExitCode(ExitCode.BUILD_FAILURE);
- this.rootCauses = rootCausesFromAction(action, detailedExitCode);
- }
-
- public ActionExecutionException(
String message,
ActionAnalysisMetadata action,
boolean catastrophe,
diff --git a/src/main/java/com/google/devtools/build/lib/actions/FailAction.java b/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
index e169ddc..3b6e9b8 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/FailAction.java
@@ -17,7 +17,11 @@
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.FailAction.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
/**
@@ -49,7 +53,16 @@
@Override
public ActionResult execute(ActionExecutionContext actionExecutionContext)
throws ActionExecutionException {
- throw new ActionExecutionException(errorMessage, this, false);
+ throw new ActionExecutionException(
+ errorMessage,
+ this,
+ false,
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage("FailAction intentional failure")
+ .setFailAction(
+ FailureDetails.FailAction.newBuilder().setCode(Code.INTENTIONAL_FAILURE))
+ .build()));
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/actions/TargetOutOfDateException.java b/src/main/java/com/google/devtools/build/lib/actions/TargetOutOfDateException.java
deleted file mode 100644
index ee68861..0000000
--- a/src/main/java/com/google/devtools/build/lib/actions/TargetOutOfDateException.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.google.devtools.build.lib.actions;
-
-/**
- * An exception indicating that a target is out of date.
- */
-public class TargetOutOfDateException extends ActionExecutionException {
-
- public TargetOutOfDateException(Action action) {
- super (action.prettyPrint() + " is not up-to-date", action, false);
- }
-
-}
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 95e66af..be63362 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -1374,8 +1374,10 @@
"//src/main/java/com/google/devtools/build/lib/collect/nestedset",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//src/main/java/com/google/devtools/build/lib/util",
+ "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+ "//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/PseudoAction.java b/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
index 6684a62..8c43ba2 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/PseudoAction.java
@@ -24,7 +24,11 @@
import com.google.devtools.build.lib.actions.CommandLineExpansionException;
import com.google.devtools.build.lib.actions.extra.ExtraActionInfo;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.server.FailureDetails.Execution;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.protobuf.Extension;
import com.google.protobuf.MessageLite;
@@ -62,8 +66,15 @@
@Override
public ActionResult execute(ActionExecutionContext actionExecutionContext)
throws ActionExecutionException {
- throw new ActionExecutionException(
- mnemonic + "ExtraAction should not be executed.", this, false);
+ String message = mnemonic + "ExtraAction should not be executed.";
+ DetailedExitCode detailedCode =
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setExecution(
+ Execution.newBuilder().setCode(Code.PSEUDO_ACTION_EXECUTION_PROHIBITED))
+ .build());
+ throw new ActionExecutionException(message, this, false, detailedCode);
}
@Override
@@ -86,7 +97,7 @@
try {
return super.getExtraActionInfo(actionKeyContext).setExtension(infoExtension, getInfo());
} catch (CommandLineExpansionException e) {
- throw new AssertionError("PsedoAction command line expansion cannot fail");
+ throw new AssertionError("PseudoAction command line expansion cannot fail");
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
index 73c58e4..c5c7562 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkAction.java
@@ -26,8 +26,12 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.SymlinkAction.Code;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -203,32 +207,32 @@
Path inputPath = actionExecutionContext.getInputPath(getPrimaryInput());
try {
- // Validate that input path is a file with the executable bit is set.
+ // Validate that input path is a file with the executable bit set.
if (!inputPath.isFile()) {
+ String message =
+ String.format("'%s' is not a file", getInputs().getSingleton().prettyPrint());
throw new ActionExecutionException(
- "'" + getInputs().getSingleton().prettyPrint() + "' is not a file", this, false);
+ message, this, false, createDetailedExitCode(message, Code.EXECUTABLE_INPUT_NOT_FILE));
}
if (!inputPath.isExecutable()) {
+ String message =
+ String.format(
+ "failed to create symbolic link '%s': file '%s' is not executable",
+ Iterables.getOnlyElement(getOutputs()).prettyPrint(),
+ getInputs().getSingleton().prettyPrint());
throw new ActionExecutionException(
- "failed to create symbolic link '"
- + Iterables.getOnlyElement(getOutputs()).prettyPrint()
- + "': file '"
- + getInputs().getSingleton().prettyPrint()
- + "' is not executable",
- this,
- false);
+ message, this, false, createDetailedExitCode(message, Code.EXECUTABLE_INPUT_IS_NOT));
}
} catch (IOException e) {
- throw new ActionExecutionException(
- "failed to create symbolic link '"
- + Iterables.getOnlyElement(getOutputs()).prettyPrint()
- + "' to the '"
- + getInputs().getSingleton().prettyPrint()
- + "' due to I/O error: "
- + e.getMessage(),
- e,
- this,
- false);
+ String message =
+ String.format(
+ "failed to create symbolic link '%s' to the '%s' due to I/O error: %s",
+ Iterables.getOnlyElement(getOutputs()).prettyPrint(),
+ getInputs().getSingleton().prettyPrint(),
+ e.getMessage());
+ DetailedExitCode detailedExitCode =
+ createDetailedExitCode(message, Code.EXECUTABLE_INPUT_CHECK_IO_EXCEPTION);
+ throw new ActionExecutionException(message, e, this, false, detailedExitCode);
}
}
@@ -314,4 +318,12 @@
public boolean mayInsensitivelyPropagateInputs() {
return true;
}
+
+ private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setSymlinkAction(FailureDetails.SymlinkAction.newBuilder().setCode(detailedCode))
+ .build());
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
index 69aee2d..5c3d5e5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/BUILD
@@ -105,6 +105,7 @@
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/go",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/platform",
"//src/main/java/com/google/devtools/build/lib/util",
+ "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
"//src/main/java/com/google/devtools/build/lib/util:filetype",
"//src/main/java/com/google/devtools/build/lib/util:os",
"//src/main/java/com/google/devtools/build/lib/util:shell_escaper",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
index 01919c5..7ba1879 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
@@ -81,6 +81,7 @@
import com.google.devtools.build.lib.syntax.Sequence;
import com.google.devtools.build.lib.syntax.StarlarkList;
import com.google.devtools.build.lib.util.DependencySet;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.util.ShellEscaper;
import com.google.devtools.build.lib.util.io.FileOutErr;
@@ -534,13 +535,12 @@
try {
options = getCompilerOptions();
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile command for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
commandLineKey = computeCommandLineKey(options);
List<PathFragment> systemIncludeDirs = getSystemIncludeDirs(options);
@@ -625,8 +625,9 @@
throw lostInputsExceptionForTimedOutNestedSetExpansion(entry.getKey(), iterator, e);
}
BugReport.sendBugReport(e);
- throw new ActionExecutionException(
- "Timed out expanding modules", this, /*catastrophe=*/ false);
+ String message = "Timed out expanding modules";
+ DetailedExitCode code = createDetailedExitCode(message, Code.MODULE_EXPANSION_TIMEOUT);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
for (Artifact module : modules) {
@@ -882,13 +883,12 @@
try {
return getEnvironment(ImmutableMap.of());
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile environment variables for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile environment variables for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
@@ -1111,12 +1111,13 @@
includePath = includePath.relativeTo(prefix);
}
if (includePath.isAbsolute() || includePath.containsUplevelReferences()) {
- throw new ActionExecutionException(
+ String message =
String.format(
"The include path '%s' references a path outside of the execution root.",
- includePath),
- this,
- false);
+ includePath);
+ DetailedExitCode code =
+ createDetailedExitCode(message, Code.INCLUDE_PATH_OUTSIDE_EXEC_ROOT);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
}
@@ -1404,13 +1405,12 @@
ParameterFileType.GCC_QUOTED,
StandardCharsets.ISO_8859_1);
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile command for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
@@ -1508,13 +1508,12 @@
getOutputs(),
estimateResourceConsumptionLocal());
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile command for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
@@ -1659,13 +1658,12 @@
.build());
return discoveredInputs;
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile environment variables for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile environment variables for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
@@ -1931,6 +1929,10 @@
}
}
+ static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(createFailureDetail(message, detailedCode));
+ }
+
private static FailureDetail createFailureDetail(String message, Code detailedCode) {
return FailureDetail.newBuilder()
.setMessage(message)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
index 47918a8..a8c4e603 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppLinkAction.java
@@ -56,12 +56,16 @@
import com.google.devtools.build.lib.exec.SpawnStrategyResolver;
import com.google.devtools.build.lib.rules.cpp.Link.LinkingMode;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs.LibraryToLink;
+import com.google.devtools.build.lib.server.FailureDetails.CppLink;
+import com.google.devtools.build.lib.server.FailureDetails.CppLink.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.skylarkbuildapi.CommandLineArgsApi;
import com.google.devtools.build.lib.syntax.EvalException;
import com.google.devtools.build.lib.syntax.Location;
import com.google.devtools.build.lib.syntax.Sequence;
import com.google.devtools.build.lib.syntax.StarlarkList;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.util.ShellEscaper;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -333,13 +337,12 @@
getOutputs(),
estimateResourceConsumptionLocal());
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate link command for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate link command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
}
@@ -395,9 +398,12 @@
FileSystemUtils.touchFile(actionExecutionContext.getInputPath(output));
}
} catch (IOException | CommandLineExpansionException e) {
- throw new ActionExecutionException("failed to create fake link command for rule '"
- + getOwner().getLabel() + ": " + e.getMessage(),
- this, false);
+ String message =
+ String.format(
+ "failed to create fake link command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.FAKE_COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, false, code);
}
}
@@ -585,4 +591,12 @@
throw new EvalException(Location.BUILTIN, exception);
}
}
+
+ private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setCppLink(CppLink.newBuilder().setCode(detailedCode))
+ .build());
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
index 88ba5a1..3ec4a8b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/FakeCppCompileAction.java
@@ -42,6 +42,8 @@
import com.google.devtools.build.lib.packages.StarlarkSemanticsOptions;
import com.google.devtools.build.lib.rules.cpp.CcCommon.CoptsFilter;
import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
+import com.google.devtools.build.lib.server.FailureDetails.CppCompile.Code;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.ShellEscaper;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
@@ -250,13 +252,12 @@
})
.collect(joining(" "));
} catch (CommandLineExpansionException e) {
- throw new ActionExecutionException(
- "failed to generate compile command for rule '"
- + getOwner().getLabel()
- + ": "
- + e.getMessage(),
- this,
- /* catastrophe= */ false);
+ String message =
+ String.format(
+ "failed to generate compile command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, /*catastrophe=*/ false, code);
}
// Write the command needed to build the real .o file to the fake .o file.
@@ -285,8 +286,12 @@
+ argv
+ "\n");
} catch (IOException e) {
- throw new ActionExecutionException("failed to create fake compile command for rule '"
- + getOwner().getLabel() + ": " + e.getMessage(), this, false);
+ String message =
+ String.format(
+ "failed to create fake compile command for rule '%s: %s",
+ getOwner().getLabel(), e.getMessage());
+ DetailedExitCode code = createDetailedExitCode(message, Code.FAKE_COMMAND_GENERATION_FAILURE);
+ throw new ActionExecutionException(message, this, false, code);
}
return ActionResult.create(spawnResults);
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeProblems.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeProblems.java
index 4994af6..4988e77 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeProblems.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeProblems.java
@@ -17,6 +17,10 @@
import com.google.devtools.build.lib.actions.Action;
import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.server.FailureDetails.CppCompile;
+import com.google.devtools.build.lib.server.FailureDetails.CppCompile.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.util.DetailedExitCode;
/**
* Accumulator for problems encountered while reading or validating inclusion
@@ -45,7 +49,14 @@
void assertProblemFree(Action action, Artifact sourceFile) throws ActionExecutionException {
if (hasProblems()) {
- throw new ActionExecutionException(getMessage(action, sourceFile), action, false);
+ String message = getMessage(action, sourceFile);
+ DetailedExitCode code =
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setCppCompile(CppCompile.newBuilder().setCode(Code.UNDECLARED_INCLUSIONS))
+ .build());
+ throw new ActionExecutionException(message, action, false, code);
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendAction.java
index bf50286..62f908f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/LtoBackendAction.java
@@ -35,6 +35,10 @@
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.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.LtoAction;
+import com.google.devtools.build.lib.server.FailureDetails.LtoAction.Code;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -135,13 +139,13 @@
if (!line.isEmpty()) {
PathFragment execPath = PathFragment.create(line);
if (execPath.isAbsolute()) {
- throw new ActionExecutionException(
- "Absolute paths not allowed in imports file "
- + actionExecutionContext.getInputPath(imports)
- + ": "
- + execPath,
- this,
- false);
+ String message =
+ String.format(
+ "Absolute paths not allowed in imports file %s: %s",
+ actionExecutionContext.getInputPath(imports), execPath);
+ DetailedExitCode code =
+ createDetailedExitCode(message, Code.INVALID_ABSOLUTE_PATH_IN_IMPORTS);
+ throw new ActionExecutionException(message, this, false, code);
}
importSet.add(PathFragment.create(line));
}
@@ -166,7 +170,7 @@
bitcodeInputSet.toList().stream()
.map(Artifact::getExecPath)
.collect(Collectors.toSet()));
- throw new ActionExecutionException(
+ String message =
String.format(
"error computing inputs from imports file: %s, missing bitcode files (first 10): %s",
actionExecutionContext.getInputPath(imports),
@@ -175,9 +179,9 @@
.map(Object::toString)
.sorted()
.limit(10)
- .collect(Collectors.joining(", "))),
- this,
- false);
+ .collect(Collectors.joining(", ")));
+ DetailedExitCode code = createDetailedExitCode(message, Code.MISSING_BITCODE_FILES);
+ throw new ActionExecutionException(message, this, false, code);
}
updateInputs(
NestedSetBuilder.fromNestedSet(bitcodeInputSet)
@@ -186,6 +190,14 @@
return bitcodeInputSet;
}
+ private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setLtoAction(LtoAction.newBuilder().setCode(detailedCode))
+ .build());
+ }
+
@Override
public NestedSet<Artifact> getMandatoryInputs() {
return mandatoryInputs;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
index fc60abd..f7002e3 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionExecutionFunction.java
@@ -1064,8 +1064,10 @@
// We don't create a specific cause for the artifact as we do in #handleMissingFile because
// it likely has no label, so we'd have to use the Action's label anyway. Just use the
// default ActionFailed event constructed by ActionExecutionException.
- throw new ActionExecutionException(
- "discovered input file does not exist", actionForError, false);
+ String message = "discovered input file does not exist";
+ DetailedExitCode code =
+ createDetailedExitCode(message, Code.DISCOVERED_INPUT_DOES_NOT_EXIST);
+ throw new ActionExecutionException(message, actionForError, false, code);
}
if (retrievedMetadata instanceof TreeArtifactValue) {
TreeArtifactValue treeValue = (TreeArtifactValue) retrievedMetadata;
@@ -1758,15 +1760,20 @@
private static ActionExecutionException createMissingInputsException(
Action action, List<LabelCause> missingArtifactCauses) {
String message = missingArtifactCauses.size() + " input file(s) do not exist";
+ Code detailedCode = Code.ACTION_INPUT_FILES_MISSING;
return new ActionExecutionException(
message,
action,
NestedSetBuilder.wrap(Order.STABLE_ORDER, missingArtifactCauses),
/*catastrophe=*/ false,
- DetailedExitCode.of(
- FailureDetail.newBuilder()
- .setMessage(message)
- .setExecution(Execution.newBuilder().setCode(Code.ACTION_INPUT_FILES_MISSING))
- .build()));
+ createDetailedExitCode(message, detailedCode));
+ }
+
+ private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setExecution(Execution.newBuilder().setCode(detailedCode))
+ .build());
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
index 7a002d4..b477855 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeActionExecutor.java
@@ -68,7 +68,6 @@
import com.google.devtools.build.lib.actions.ScanningActionEvent;
import com.google.devtools.build.lib.actions.SpawnResult.MetadataLog;
import com.google.devtools.build.lib.actions.StoppedScanningActionEvent;
-import com.google.devtools.build.lib.actions.TargetOutOfDateException;
import com.google.devtools.build.lib.actions.UserExecException;
import com.google.devtools.build.lib.actions.cache.MetadataHandler;
import com.google.devtools.build.lib.buildtool.BuildRequestOptions;
@@ -85,10 +84,15 @@
import com.google.devtools.build.lib.remote.options.RemoteOptions;
import com.google.devtools.build.lib.rules.cpp.IncludeScannable;
import com.google.devtools.build.lib.runtime.KeepGoingOption;
+import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.Execution;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.ActionExecutionState.ActionStep;
import com.google.devtools.build.lib.skyframe.ActionExecutionState.ActionStepOrResult;
import com.google.devtools.build.lib.skyframe.ActionExecutionState.SharedActionCallback;
import com.google.devtools.build.lib.util.CrashFailureDetails;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystem;
@@ -379,8 +383,6 @@
/**
* Executes the provided action on the current thread. Returns the ActionExecutionValue with the
* result, either computed here or already computed on another thread.
- *
- * <p>For use from {@link ArtifactFunction} only.
*/
@SuppressWarnings("SynchronizeOnNonFinalField")
ActionExecutionValue executeAction(
@@ -397,7 +399,9 @@
// We can't execute an action (e.g. because --check_???_up_to_date option was used). Fail
// the build instead.
synchronized (reporter) {
- TargetOutOfDateException e = new TargetOutOfDateException(action);
+ String message = action.prettyPrint() + " is not up-to-date";
+ DetailedExitCode code = createDetailedExitCode(message, Code.ACTION_NOT_UP_TO_DATE);
+ ActionExecutionException e = new ActionExecutionException(message, action, false, code);
reporter.handle(Event.error(e.getMessage()));
recordExecutionError();
throw e;
@@ -865,7 +869,11 @@
logger.atWarning().withCause(e).log(
"failed to delete output files before executing action: '%s'", action);
throw toActionExecutionException(
- "failed to delete output files before executing action", e, action, null);
+ "failed to delete output files before executing action",
+ e,
+ action,
+ null,
+ Code.ACTION_OUTPUTS_DELETION_FAILURE);
}
} else {
// There's nothing to delete when the action file system is used, but we must ensure
@@ -1032,7 +1040,8 @@
"not all outputs were created or valid",
null,
action,
- outputAlreadyDumped ? null : fileOutErr);
+ outputAlreadyDumped ? null : fileOutErr,
+ Code.ACTION_OUTPUTS_NOT_CREATED);
}
if (outputService != null && finalizeActions) {
@@ -1041,7 +1050,12 @@
outputService.finalizeAction(action, metadataHandler);
} catch (EnvironmentalExecException | IOException e) {
logger.atWarning().withCause(e).log("unable to finalize action: '%s'", action);
- throw toActionExecutionException("unable to finalize action", e, action, fileOutErr);
+ throw toActionExecutionException(
+ "unable to finalize action",
+ e,
+ action,
+ fileOutErr,
+ Code.ACTION_FINALIZATION_FAILURE);
}
}
@@ -1465,19 +1479,33 @@
* @param action The action that failed
* @param actionOutput The output of the failed Action. May be null, if there is no output to
* display
+ * @param detailedCode The fine-grained failure code describing the failure
*/
private ActionExecutionException toActionExecutionException(
- String message, Throwable cause, Action action, FileOutErr actionOutput) {
+ String message,
+ Throwable cause,
+ Action action,
+ FileOutErr actionOutput,
+ FailureDetails.Execution.Code detailedCode) {
+ DetailedExitCode code = createDetailedExitCode(message, detailedCode);
ActionExecutionException ex;
if (cause == null) {
- ex = new ActionExecutionException(message, action, false);
+ ex = new ActionExecutionException(message, action, false, code);
} else {
- ex = new ActionExecutionException(message, cause, action, false);
+ ex = new ActionExecutionException(message, cause, action, false, code);
}
printError(ex.getMessage(), action, actionOutput);
return ex;
}
+ private static DetailedExitCode createDetailedExitCode(String message, Code detailedCode) {
+ return DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setMessage(message)
+ .setExecution(Execution.newBuilder().setCode(detailedCode))
+ .build());
+ }
+
/**
* For the action 'action' that failed due to 'message' with the output 'actionOutput', notify the
* user about the error. To notify the user, the method first displays the output of the action
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 58d1844..a776044 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -135,6 +135,10 @@
StarlarkAction starlark_action = 162;
NinjaAction ninja_action = 163;
DynamicExecution dynamic_execution = 164;
+ FailAction fail_action = 166;
+ SymlinkAction symlink_action = 167;
+ CppLink cpp_link = 168;
+ LtoAction lto_action = 169;
}
reserved 102; // For internal use
@@ -372,6 +376,12 @@
SYMLINK_TREE_CREATION_COMMAND_EXCEPTION = 18
[(metadata) = { exit_code: 36 }];
ACTION_INPUT_READ_IO_EXCEPTION = 19 [(metadata) = { exit_code: 36 }];
+ ACTION_NOT_UP_TO_DATE = 20 [(metadata) = { exit_code: 1 }];
+ PSEUDO_ACTION_EXECUTION_PROHIBITED = 21 [(metadata) = { exit_code: 1 }];
+ DISCOVERED_INPUT_DOES_NOT_EXIST = 22 [(metadata) = { exit_code: 1 }];
+ ACTION_OUTPUTS_DELETION_FAILURE = 23 [(metadata) = { exit_code: 1 }];
+ ACTION_OUTPUTS_NOT_CREATED = 24 [(metadata) = { exit_code: 1 }];
+ ACTION_FINALIZATION_FAILURE = 25 [(metadata) = { exit_code: 1 }];
}
Code code = 1;
@@ -805,6 +815,7 @@
ABNORMAL_TERMINATION = 2 [(metadata) = { exit_code: 1 }];
EXEC_FAILED = 3 [(metadata) = { exit_code: 1 }];
PARSE_FAILURE = 4 [(metadata) = { exit_code: 36 }];
+ VALIDATION_FAILURE = 5 [(metadata) = { exit_code: 1 }];
}
Code code = 1;
@@ -839,6 +850,11 @@
FIND_USED_HEADERS_IO_EXCEPTION = 1 [(metadata) = { exit_code: 36 }];
COPY_OUT_ERR_FAILURE = 2 [(metadata) = { exit_code: 36 }];
D_FILE_READ_FAILURE = 3 [(metadata) = { exit_code: 36 }];
+ COMMAND_GENERATION_FAILURE = 4 [(metadata) = { exit_code: 1 }];
+ MODULE_EXPANSION_TIMEOUT = 5 [(metadata) = { exit_code: 1 }];
+ INCLUDE_PATH_OUTSIDE_EXEC_ROOT = 6 [(metadata) = { exit_code: 1 }];
+ FAKE_COMMAND_GENERATION_FAILURE = 7 [(metadata) = { exit_code: 1 }];
+ UNDECLARED_INCLUSIONS = 8 [(metadata) = { exit_code: 1 }];
}
Code code = 1;
@@ -871,3 +887,43 @@
Code code = 1;
}
+
+message FailAction {
+ enum Code {
+ FAIL_ACTION_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ INTENTIONAL_FAILURE = 1 [(metadata) = { exit_code: 1 }];
+ }
+
+ Code code = 1;
+}
+
+message SymlinkAction {
+ enum Code {
+ SYMLINK_ACTION_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ EXECUTABLE_INPUT_NOT_FILE = 1 [(metadata) = { exit_code: 1 }];
+ EXECUTABLE_INPUT_IS_NOT = 2 [(metadata) = { exit_code: 1 }];
+ EXECUTABLE_INPUT_CHECK_IO_EXCEPTION = 3 [(metadata) = { exit_code: 1 }];
+ }
+
+ Code code = 1;
+}
+
+message CppLink {
+ enum Code {
+ CPP_LINK_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ COMMAND_GENERATION_FAILURE = 1 [(metadata) = { exit_code: 1 }];
+ FAKE_COMMAND_GENERATION_FAILURE = 2 [(metadata) = { exit_code: 1 }];
+ }
+
+ Code code = 1;
+}
+
+message LtoAction {
+ enum Code {
+ LTO_ACTION_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ INVALID_ABSOLUTE_PATH_IN_IMPORTS = 1 [(metadata) = { exit_code: 1 }];
+ MISSING_BITCODE_FILES = 2 [(metadata) = { exit_code: 1 }];
+ }
+
+ Code code = 1;
+}
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerTest.java b/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerTest.java
index de31ed7..08d23db 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/BuildEventStreamerTest.java
@@ -1151,12 +1151,18 @@
public void testSuccessfulActionsAreNotPublishedByDefault() {
EventBusHandler handler = new EventBusHandler();
eventBus.register(handler);
-
ActionExecutedEvent failedActionExecutedEvent =
new ActionExecutedEvent(
ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
new ActionsTestUtil.NullAction(),
- new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
+ new ActionExecutionException(
+ "Exception",
+ /* action= */ null,
+ /* catastrophe= */ false,
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setSpawn(Spawn.newBuilder().setCode(Code.EXECUTION_DENIED))
+ .build())),
ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
/* stdout= */ null,
/* stderr= */ null,
@@ -1192,7 +1198,14 @@
new ActionExecutedEvent(
ActionsTestUtil.DUMMY_ARTIFACT.getExecPath(),
new ActionsTestUtil.NullAction(),
- new ActionExecutionException("Exception", /* action= */ null, /* catastrophe= */ false),
+ new ActionExecutionException(
+ "Exception",
+ /* action= */ null,
+ /* catastrophe= */ false,
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setSpawn(Spawn.newBuilder().setCode(Code.EXECUTION_DENIED))
+ .build())),
ActionsTestUtil.DUMMY_ARTIFACT.getPath(),
/* stdout= */ null,
/* stderr= */ null,
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
index d4b3e65..a406dc5 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ParallelBuilderTest.java
@@ -41,10 +41,14 @@
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.EventKind;
import com.google.devtools.build.lib.events.PrintingEventHandler;
+import com.google.devtools.build.lib.server.FailureDetails.Crash;
+import com.google.devtools.build.lib.server.FailureDetails.Crash.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.testutil.BlazeTestUtils;
import com.google.devtools.build.lib.testutil.Suite;
import com.google.devtools.build.lib.testutil.TestSpec;
import com.google.devtools.build.lib.testutil.TestUtils;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -684,7 +688,12 @@
throw new RuntimeException(e);
}
completedTasks.getAndIncrement();
- throw new ActionExecutionException("This is a catastrophe", this, true);
+ DetailedExitCode code =
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setCrash(Crash.newBuilder().setCode(Code.CRASH_UNKNOWN))
+ .build());
+ throw new ActionExecutionException("This is a catastrophe", this, true, code);
}
return super.execute(actionExecutionContext);
}
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
index 1ee43a4..dc4a43d 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactBuildTest.java
@@ -53,11 +53,15 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventCollector;
import com.google.devtools.build.lib.events.EventKind;
+import com.google.devtools.build.lib.server.FailureDetails.Crash;
+import com.google.devtools.build.lib.server.FailureDetails.Crash.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.skyframe.ActionTemplateExpansionValue.ActionTemplateExpansionKey;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationDepsUtils;
import com.google.devtools.build.lib.skyframe.serialization.testutils.SerializationTester;
import com.google.devtools.build.lib.testutil.TestUtils;
import com.google.devtools.build.lib.util.CrashFailureDetails;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -1052,7 +1056,13 @@
@Override
public ActionResult execute(ActionExecutionContext actionExecutionContext)
throws ActionExecutionException {
- throw new ActionExecutionException("Throwing dummy action", this, /*catastrophe=*/ true);
+ DetailedExitCode code =
+ DetailedExitCode.of(
+ FailureDetail.newBuilder()
+ .setCrash(Crash.newBuilder().setCode(Code.CRASH_UNKNOWN))
+ .build());
+ throw new ActionExecutionException(
+ "Throwing dummy action", this, /*catastrophe=*/ true, code);
}
}
}