Encode some environmental execution failures with FailureDetails
Details failures represented by EnvironmentalExecException in some
general execution contexts (e.g. AbstractAction, SpawnAction,
StarlarkAction) and some language-specific implementations (e.g.
JavaCompileAction, CppCompileAction, IncludeScanning).
The nullability of EnvironmentalExecException's FailureDetails field
is temporary, and intended to bridge between this CL and its immediate
follow-ups.
RELNOTES: None.
PiperOrigin-RevId: 315815272
diff --git a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
index 217182c..10c5165 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/AbstractAction.java
@@ -30,6 +30,7 @@
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.AspectDescriptor;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
import com.google.devtools.build.lib.skylarkbuildapi.ActionApi;
import com.google.devtools.build.lib.skylarkbuildapi.CommandLineArgsApi;
@@ -398,20 +399,25 @@
* checking, this method must be called.
*/
protected void checkInputsForDirectories(
- EventHandler eventHandler, MetadataProvider metadataProvider) throws IOException {
+ EventHandler eventHandler, MetadataProvider metadataProvider) throws ExecException {
// Report "directory dependency checking" warning only for non-generated directories (generated
// ones will be reported earlier).
for (Artifact input : getMandatoryInputs().toList()) {
// Assume that if the file did not exist, we would not have gotten here.
- if (input.isSourceArtifact() && metadataProvider.getMetadata(input).getType().isDirectory()) {
- // TODO(ulfjack): What about dependency checking of special files?
- eventHandler.handle(
- Event.warn(
- getOwner().getLocation(),
- String.format(
- "input '%s' to %s is a directory; "
- + "dependency checking of directories is unsound",
- input.prettyPrint(), getOwner().getLabel())));
+ try {
+ if (input.isSourceArtifact()
+ && metadataProvider.getMetadata(input).getType().isDirectory()) {
+ // TODO(ulfjack): What about dependency checking of special files?
+ eventHandler.handle(
+ Event.warn(
+ getOwner().getLocation(),
+ String.format(
+ "input '%s' to %s is a directory; "
+ + "dependency checking of directories is unsound",
+ input.prettyPrint(), getOwner().getLabel())));
+ }
+ } catch (IOException e) {
+ throw new EnvironmentalExecException(e, Code.INPUT_DIRECTORY_CHECK_IO_EXCEPTION);
}
}
}
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 b529b89..6aa9d7f 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
@@ -82,12 +82,15 @@
}
public ActionExecutionException(
- String message, ActionAnalysisMetadata action, boolean catastrophe, ExitCode exitCode) {
+ String message,
+ ActionAnalysisMetadata action,
+ boolean catastrophe,
+ DetailedExitCode detailedExitCode) {
super(message);
this.action = action;
this.catastrophe = catastrophe;
- this.detailedExitCode = DetailedExitCode.justExitCode(exitCode);
- this.rootCauses = rootCausesFromAction(action, detailedExitCode);
+ this.detailedExitCode = detailedExitCode;
+ this.rootCauses = rootCausesFromAction(action, this.detailedExitCode);
}
public ActionExecutionException(
diff --git a/src/main/java/com/google/devtools/build/lib/actions/EnvironmentalExecException.java b/src/main/java/com/google/devtools/build/lib/actions/EnvironmentalExecException.java
index 37df0c9..55a60d1 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/EnvironmentalExecException.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/EnvironmentalExecException.java
@@ -15,8 +15,13 @@
package com.google.devtools.build.lib.actions;
import com.google.common.base.Throwables;
+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.FailureDetail;
+import com.google.devtools.build.lib.util.DetailedExitCode;
import com.google.devtools.build.lib.util.ExitCode;
import java.io.IOException;
+import javax.annotation.Nullable;
/**
* An ExecException which is reports an issue executing an action due to an external problem on the
@@ -32,34 +37,43 @@
* directory or denied file system access.
*/
public class EnvironmentalExecException extends ExecException {
- public EnvironmentalExecException(IOException cause) {
+ // TODO(b/138456686): Make this not nullable.
+ @Nullable private final FailureDetail failureDetail;
+
+ public EnvironmentalExecException(IOException cause, FailureDetails.Execution.Code code) {
super("unexpected I/O exception", cause);
+ this.failureDetail =
+ FailureDetail.newBuilder().setExecution(Execution.newBuilder().setCode(code)).build();
+ }
+
+ public EnvironmentalExecException(IOException cause, FailureDetail failureDetail) {
+ super(failureDetail.getMessage(), cause);
+ this.failureDetail = failureDetail;
}
public EnvironmentalExecException(String message, Throwable cause) {
super(message, cause);
+ failureDetail = null;
}
public EnvironmentalExecException(String message) {
super(message);
+ failureDetail = null;
}
@Override
public ActionExecutionException toActionExecutionException(
String messagePrefix, boolean verboseFailures, Action action) {
- if (getCause() != null) {
- String message =
- messagePrefix
- + " failed due to "
- + getMessage()
- + "\n"
- + Throwables.getStackTraceAsString(getCause());
- return new ActionExecutionException(
- message, action, isCatastrophic(), ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
- } else {
- String message = messagePrefix + " failed due to " + getMessage();
- return new ActionExecutionException(
- message, action, isCatastrophic(), ExitCode.LOCAL_ENVIRONMENTAL_ERROR);
- }
+ String message =
+ String.format(
+ "%s failed due to %s%s",
+ messagePrefix,
+ getMessage(),
+ getCause() == null ? "" : ("\n" + Throwables.getStackTraceAsString(getCause())));
+ DetailedExitCode detailedExitCode =
+ failureDetail == null
+ ? DetailedExitCode.justExitCode(ExitCode.LOCAL_ENVIRONMENTAL_ERROR)
+ : DetailedExitCode.of(failureDetail.toBuilder().setMessage(message).build());
+ return new ActionExecutionException(message, action, isCatastrophic(), detailedExitCode);
}
}
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 dd89c11..95e66af 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -1414,6 +1414,7 @@
"//src/main/java/com/google/devtools/build/lib/syntax:evaluator",
"//src/main/java/com/google/devtools/build/lib/util",
"//src/main/java/com/google/devtools/build/lib/util:string",
+ "//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/actions/LocalTemplateExpansionStrategy.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/LocalTemplateExpansionStrategy.java
index cba7c74..01fe4df 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/LocalTemplateExpansionStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/LocalTemplateExpansionStrategy.java
@@ -18,12 +18,13 @@
import com.google.devtools.build.lib.actions.ArtifactPathResolver;
import com.google.devtools.build.lib.actions.EnvironmentalExecException;
import com.google.devtools.build.lib.actions.SpawnContinuation;
+import com.google.devtools.build.lib.server.FailureDetails;
import com.google.devtools.build.lib.util.StringUtilities;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
-/** Strategy to perform tempate expansion locally */
+/** Strategy to perform template expansion locally. */
public class LocalTemplateExpansionStrategy implements TemplateExpansionContext {
public static final Class<LocalTemplateExpansionStrategy> TYPE =
LocalTemplateExpansionStrategy.class;
@@ -46,7 +47,9 @@
.beginWriteOutputToFile(
action, ctx, deterministicWriter, action.makeExecutable(), /*isRemotable=*/ true);
} catch (IOException e) {
- return SpawnContinuation.failedWithExecException(new EnvironmentalExecException(e));
+ return SpawnContinuation.failedWithExecException(
+ new EnvironmentalExecException(
+ e, FailureDetails.Execution.Code.LOCAL_TEMPLATE_EXPANSION_FAILURE));
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
index 8ae3bdf..d677b57 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SpawnAction.java
@@ -49,7 +49,6 @@
import com.google.devtools.build.lib.actions.CommandLines.ExpandedCommandLines;
import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
import com.google.devtools.build.lib.actions.EmptyRunfilesSupplier;
-import com.google.devtools.build.lib.actions.EnvironmentalExecException;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
import com.google.devtools.build.lib.actions.ParamFileInfo;
@@ -88,7 +87,6 @@
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.annotations.FormatMethod;
import com.google.errorprone.annotations.FormatString;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@@ -304,7 +302,8 @@
}
/** Hook for subclasses to perform work before the spawn is executed. */
- protected void beforeExecute(ActionExecutionContext actionExecutionContext) throws IOException {}
+ protected void beforeExecute(ActionExecutionContext actionExecutionContext)
+ throws ExecException {}
/**
* Hook for subclasses to perform work after the spawn is executed. This method is only executed
@@ -313,7 +312,7 @@
*/
protected void afterExecute(
ActionExecutionContext actionExecutionContext, List<SpawnResult> spawnResults)
- throws IOException, ExecException {}
+ throws ExecException {}
@Override
public final ActionContinuationOrResult beginExecution(
@@ -324,9 +323,8 @@
try {
beforeExecute(actionExecutionContext);
spawn = getSpawn(actionExecutionContext);
- } catch (IOException e) {
- throw toActionExecutionException(
- new EnvironmentalExecException(e), actionExecutionContext.showVerboseFailures(label));
+ } catch (ExecException e) {
+ throw toActionExecutionException(e, actionExecutionContext.showVerboseFailures(label));
} catch (CommandLineExpansionException e) {
throw createDetailedException(e, Code.COMMAND_LINE_EXPANSION_FAILURE);
}
@@ -1404,9 +1402,6 @@
return ActionContinuationOrResult.of(ActionResult.create(nextContinuation.get()));
}
return new SpawnActionContinuation(actionExecutionContext, nextContinuation, label);
- } catch (IOException e) {
- throw toActionExecutionException(
- new EnvironmentalExecException(e), actionExecutionContext.showVerboseFailures(label));
} catch (ExecException e) {
throw toActionExecutionException(e, actionExecutionContext.showVerboseFailures(label));
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/StarlarkAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/StarlarkAction.java
index 6950b57..2fef68c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/StarlarkAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/StarlarkAction.java
@@ -26,6 +26,7 @@
import com.google.devtools.build.lib.actions.CommandLineExpansionException;
import com.google.devtools.build.lib.actions.CommandLines;
import com.google.devtools.build.lib.actions.CommandLines.CommandLineLimits;
+import com.google.devtools.build.lib.actions.EnvironmentalExecException;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ExecutionRequirements;
import com.google.devtools.build.lib.actions.ResourceSet;
@@ -37,6 +38,9 @@
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;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.server.FailureDetails.StarlarkAction.Code;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -175,7 +179,7 @@
@Override
protected void afterExecute(
ActionExecutionContext actionExecutionContext, List<SpawnResult> spawnResults)
- throws IOException, ExecException {
+ throws ExecException {
if (!unusedInputsList.isPresent()) {
return;
}
@@ -195,6 +199,10 @@
}
usedInputs.remove(line);
}
+ } catch (IOException e) {
+ throw new EnvironmentalExecException(
+ e,
+ createFailureDetail("Unused inputs read failure", Code.UNUSED_INPUT_LIST_READ_FAILURE));
}
updateInputs(NestedSetBuilder.wrap(Order.STABLE_ORDER, usedInputs.values()));
}
@@ -210,6 +218,13 @@
return allInputs;
}
+ private static FailureDetail createFailureDetail(String message, Code detailedCode) {
+ return FailureDetail.newBuilder()
+ .setMessage(message)
+ .setStarlarkAction(FailureDetails.StarlarkAction.newBuilder().setCode(detailedCode))
+ .build();
+ }
+
/** Builder class to construct {@link StarlarkAction} instances. */
public static class Builder extends SpawnAction.Builder {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/extra/ExtraAction.java b/src/main/java/com/google/devtools/build/lib/analysis/extra/ExtraAction.java
index 34a5673..541b274 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/extra/ExtraAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/extra/ExtraAction.java
@@ -29,12 +29,15 @@
import com.google.devtools.build.lib.actions.CommandLines;
import com.google.devtools.build.lib.actions.CommandLines.CommandLineLimits;
import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
+import com.google.devtools.build.lib.actions.EnvironmentalExecException;
+import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
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.Execution.Code;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import java.io.IOException;
import java.util.Collection;
@@ -156,13 +159,17 @@
@Override
protected void afterExecute(
ActionExecutionContext actionExecutionContext, List<SpawnResult> spawnResults)
- throws IOException {
+ throws ExecException {
// PHASE 3: create dummy output.
// If the user didn't specify output, we need to create dummy output
// to make blaze schedule this action.
if (createDummyOutput) {
for (Artifact output : getOutputs()) {
- FileSystemUtils.touchFile(actionExecutionContext.getInputPath(output));
+ try {
+ FileSystemUtils.touchFile(actionExecutionContext.getInputPath(output));
+ } catch (IOException e) {
+ throw new EnvironmentalExecException(e, Code.EXTRA_ACTION_OUTPUT_CREATION_FAILURE);
+ }
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java
index 788e2af..fd3ada0 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestRunnerAction.java
@@ -55,6 +55,7 @@
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.Execution.Code;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.util.LoggingUtil;
import com.google.devtools.build.lib.util.Pair;
@@ -815,7 +816,8 @@
} catch (ExecException e) {
throw e.toActionExecutionException(this);
} catch (IOException e) {
- throw new EnvironmentalExecException(e).toActionExecutionException(this);
+ throw new EnvironmentalExecException(e, Code.TEST_RUNNER_IO_EXCEPTION)
+ .toActionExecutionException(this);
}
}
@@ -1105,7 +1107,8 @@
} catch (ExecException e) {
throw e.toActionExecutionException(TestRunnerAction.this);
} catch (IOException e) {
- throw new EnvironmentalExecException(e).toActionExecutionException(TestRunnerAction.this);
+ throw new EnvironmentalExecException(e, Code.TEST_RUNNER_IO_EXCEPTION)
+ .toActionExecutionException(TestRunnerAction.this);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaAction.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaAction.java
index 19cb6a6..453bfbc 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaAction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/ninja/actions/NinjaAction.java
@@ -27,6 +27,7 @@
import com.google.devtools.build.lib.actions.CommandLines;
import com.google.devtools.build.lib.actions.CommandLines.CommandLineLimits;
import com.google.devtools.build.lib.actions.EnvironmentalExecException;
+import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
@@ -108,7 +109,7 @@
}
@Override
- protected void beforeExecute(ActionExecutionContext actionExecutionContext) throws IOException {
+ protected void beforeExecute(ActionExecutionContext actionExecutionContext) throws ExecException {
if (!TrackSourceDirectoriesFlag.trackSourceDirectories()) {
checkInputsForDirectories(
actionExecutionContext.getEventHandler(), actionExecutionContext.getMetadataProvider());
diff --git a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
index feaa37c..723f0fe 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/AbstractSpawnStrategy.java
@@ -44,6 +44,9 @@
import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionContext;
import com.google.devtools.build.lib.profiler.Profiler;
import com.google.devtools.build.lib.profiler.SilentCloseable;
+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.Spawn.Code;
import com.google.devtools.build.lib.util.CommandFailureUtils;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.Path;
@@ -137,7 +140,12 @@
} catch (InterruptedIOException e) {
throw new InterruptedException(e.getMessage());
} catch (IOException e) {
- throw new EnvironmentalExecException(e);
+ throw new EnvironmentalExecException(
+ e,
+ FailureDetail.newBuilder()
+ .setMessage("Exec failed due to IOException")
+ .setSpawn(FailureDetails.Spawn.newBuilder().setCode(Code.EXEC_IO_EXCEPTION))
+ .build());
} catch (SpawnExecException e) {
ex = e;
spawnResult = e.getSpawnResult();
diff --git a/src/main/java/com/google/devtools/build/lib/exec/BUILD b/src/main/java/com/google/devtools/build/lib/exec/BUILD
index 491df37..1d4cb16 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/exec/BUILD
@@ -26,6 +26,7 @@
"//src/main/java/com/google/devtools/build/lib/util/io",
"//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",
],
@@ -133,6 +134,7 @@
"//src/main/java/com/google/devtools/build/lib/profiler",
"//src/main/java/com/google/devtools/build/lib/profiler:google-auto-profiler-utils",
"//src/main/java/com/google/devtools/build/lib/vfs",
+ "//src/main/protobuf:failure_details_java_proto",
"//third_party:guava",
],
)
@@ -324,6 +326,7 @@
"//src/main/java/com/google/devtools/build/lib/util/io",
"//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",
"//src/main/protobuf:test_status_java_proto",
"//third_party:guava",
"//third_party:jsr305",
@@ -354,6 +357,7 @@
"//src/main/java/com/google/devtools/build/lib/util/io:out-err",
"//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",
],
@@ -373,6 +377,7 @@
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:output_service",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
+ "//src/main/protobuf:failure_details_java_proto",
"//third_party:guava",
],
)
diff --git a/src/main/java/com/google/devtools/build/lib/exec/FileWriteStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/FileWriteStrategy.java
index dab66bf..826ea39 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/FileWriteStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/FileWriteStrategy.java
@@ -24,6 +24,7 @@
import com.google.devtools.build.lib.analysis.actions.FileWriteActionContext;
import com.google.devtools.build.lib.profiler.AutoProfiler;
import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
import com.google.devtools.build.lib.vfs.Path;
import java.io.BufferedOutputStream;
import java.io.IOException;
@@ -60,7 +61,8 @@
outputPath.setExecutable(true);
}
} catch (IOException e) {
- return SpawnContinuation.failedWithExecException(new EnvironmentalExecException(e));
+ return SpawnContinuation.failedWithExecException(
+ new EnvironmentalExecException(e, Code.FILE_WRITE_IO_EXCEPTION));
}
}
return SpawnContinuation.immediate();
diff --git a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
index 75d7e41..c11ca37 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/StandaloneTestStrategy.java
@@ -46,6 +46,7 @@
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.Reporter;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.io.FileOutErr;
import com.google.devtools.build.lib.vfs.FileStatus;
@@ -585,7 +586,7 @@
streamed.close();
}
} catch (IOException e) {
- throw new EnvironmentalExecException(e);
+ throw new EnvironmentalExecException(e, Code.TEST_OUT_ERR_IO_EXCEPTION);
}
// SpawnActionContext guarantees the first entry to correspond to the spawn passed in (there
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
index 067adb5..c8aeb0b 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeHelper.java
@@ -23,6 +23,7 @@
import com.google.devtools.build.lib.actions.EnvironmentalExecException;
import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.FilesetOutputSymlink;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
import com.google.devtools.build.lib.shell.Command;
import com.google.devtools.build.lib.shell.CommandException;
import com.google.devtools.build.lib.util.CommandBuilder;
@@ -140,7 +141,7 @@
symlinkTreeRoot.createDirectoryAndParents();
FileSystemUtils.copyFile(inputManifest, getOutputManifest());
} catch (IOException e) {
- throw new EnvironmentalExecException(e);
+ throw new EnvironmentalExecException(e, Code.SYMLINK_TREE_MANIFEST_COPY_IO_EXCEPTION);
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
index 4a1f766..5ff0a40 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/SymlinkTreeStrategy.java
@@ -27,6 +27,7 @@
import com.google.devtools.build.lib.analysis.actions.SymlinkTreeActionContext;
import com.google.devtools.build.lib.profiler.AutoProfiler;
import com.google.devtools.build.lib.profiler.GoogleAutoProfilerUtils;
+import com.google.devtools.build.lib.server.FailureDetails.Execution.Code;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.OutputService;
@@ -71,12 +72,7 @@
: actionExecutionContext.getInputPath(action.getInputManifest());
Map<PathFragment, PathFragment> symlinks;
if (action.getRunfiles() != null) {
- try {
- symlinks =
- Maps.transformValues(runfilesToMap(action, actionExecutionContext), TO_PATH);
- } catch (IOException e) {
- throw new EnvironmentalExecException(e);
- }
+ symlinks = Maps.transformValues(runfilesToMap(action, actionExecutionContext), TO_PATH);
} else {
Preconditions.checkState(action.isFilesetTree());
Preconditions.checkNotNull(inputManifest);
@@ -105,7 +101,8 @@
.createSymlinksDirectly(
action.getOutputManifest().getPath().getParentDirectory(), runfiles);
} catch (IOException e) {
- throw new EnvironmentalExecException(e).toActionExecutionException(action);
+ throw new EnvironmentalExecException(e, Code.SYMLINK_TREE_CREATION_IO_EXCEPTION)
+ .toActionExecutionException(action);
}
Path inputManifest =
@@ -133,7 +130,7 @@
}
private static Map<PathFragment, Artifact> runfilesToMap(
- SymlinkTreeAction action, ActionExecutionContext actionExecutionContext) throws IOException {
+ SymlinkTreeAction action, ActionExecutionContext actionExecutionContext) {
// This call outputs warnings about overlapping symlinks. However, this is already called by the
// SourceManifestAction, so it can happen that we generate the warning twice. If the input
// manifest is null, then we print the warning. Otherwise we assume that the
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 656374b..69aee2d 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
@@ -118,6 +118,7 @@
"//src/main/java/net/starlark/java/annot",
"//src/main/protobuf:crosstool_config_java_proto",
"//src/main/protobuf:extra_actions_base_java_proto",
+ "//src/main/protobuf:failure_details_java_proto",
"//third_party:auto_value",
"//third_party:flogger",
"//third_party:guava",
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 b55046d..a5fef2f 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
@@ -72,6 +72,9 @@
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.rules.cpp.IncludeScanner.IncludeScanningHeaderData;
+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.skyframe.ActionExecutionValue;
import com.google.devtools.build.lib.skylarkbuildapi.CommandLineArgsApi;
import com.google.devtools.build.lib.syntax.EvalException;
@@ -424,12 +427,12 @@
} catch (ExecutionException e) {
Throwables.throwIfInstanceOf(e.getCause(), ExecException.class);
Throwables.throwIfInstanceOf(e.getCause(), InterruptedException.class);
- if (e.getCause() instanceof IORuntimeException) {
+ IOException ioException = getIoExceptionIfAny(e);
+ if (ioException != null) {
throw new EnvironmentalExecException(
- ((IORuntimeException) e.getCause()).getCauseIOException());
- }
- if (e.getCause() instanceof IOException) {
- throw new EnvironmentalExecException((IOException) e.getCause());
+ ioException,
+ createFailureDetail(
+ "Find used headers failure", Code.FIND_USED_HEADERS_IO_EXCEPTION));
}
Throwables.throwIfUnchecked(e.getCause());
throw new IllegalStateException(e.getCause());
@@ -443,6 +446,18 @@
}
}
+ @Nullable
+ private static IOException getIoExceptionIfAny(ExecutionException e) {
+ IOException ioException = null;
+ if (e.getCause() instanceof IORuntimeException) {
+ ioException = ((IORuntimeException) e.getCause()).getCauseIOException();
+ }
+ if (e.getCause() instanceof IOException) {
+ ioException = (IOException) e.getCause();
+ }
+ return ioException;
+ }
+
/**
* Filters discovered headers according to declared rule inputs. This fundamentally mirrors the
* behavior of {@link #validateInclusions} and just removes inputs that would be considered
@@ -1904,7 +1919,8 @@
}
}
} catch (IOException e) {
- throw new EnvironmentalExecException(e)
+ throw new EnvironmentalExecException(
+ e, createFailureDetail("OutErr copy failure", Code.COPY_OUT_ERR_FAILURE))
.toActionExecutionException(
getRawProgressMessage(),
actionExecutionContext.showVerboseFailures(getOwner().getLabel()),
@@ -1913,4 +1929,11 @@
}
}
}
+
+ private static FailureDetail createFailureDetail(String message, Code detailedCode) {
+ return FailureDetail.newBuilder()
+ .setMessage(message)
+ .setCppCompile(CppCompile.newBuilder().setCode(detailedCode))
+ .build();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanning.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanning.java
index a01d398..37078d0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanning.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/IncludeScanning.java
@@ -31,6 +31,9 @@
import com.google.devtools.build.lib.profiler.SilentCloseable;
import com.google.devtools.build.lib.rules.cpp.IncludeScanner.IncludeScannerSupplier;
import com.google.devtools.build.lib.rules.cpp.IncludeScanner.IncludeScanningHeaderData;
+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.IncludeScanning.Code;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -117,7 +120,8 @@
},
MoreExecutors.directExecutor());
} catch (IOException e) {
- throw new EnvironmentalExecException(e);
+ throw new EnvironmentalExecException(
+ e, createFailureDetail("Include scanning IOException", Code.SCANNING_IO_EXCEPTION));
}
}
@@ -152,4 +156,11 @@
}
return inputs;
}
+
+ private static FailureDetail createFailureDetail(String message, Code detailedCode) {
+ return FailureDetail.newBuilder()
+ .setMessage(message)
+ .setIncludeScanning(FailureDetails.IncludeScanning.newBuilder().setCode(detailedCode))
+ .build();
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleAction.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleAction.java
index 5dcd61f..32d7518 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleAction.java
@@ -24,13 +24,13 @@
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.actions.CommandLines;
import com.google.devtools.build.lib.actions.CommandLines.CommandLineLimits;
+import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.RunfilesSupplier;
import com.google.devtools.build.lib.actions.SpawnResult;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.skyframe.TrackSourceDirectoriesFlag;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import java.io.IOException;
import java.util.List;
/**
@@ -73,7 +73,7 @@
}
@Override
- protected void beforeExecute(ActionExecutionContext actionExecutionContext) throws IOException {
+ protected void beforeExecute(ActionExecutionContext actionExecutionContext) throws ExecException {
if (!TrackSourceDirectoriesFlag.trackSourceDirectories()) {
checkInputsForDirectories(
actionExecutionContext.getEventHandler(), actionExecutionContext.getMetadataProvider());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
index d59a9af..096307d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
@@ -549,21 +549,25 @@
return Deps.Dependencies.parseFrom(input);
} catch (IOException e) {
throw toActionExecutionException(
- new EnvironmentalExecException(e),
+ new EnvironmentalExecException(
+ e, createFailureDetail(".jdeps read IOException", Code.JDEPS_READ_IO_EXCEPTION)),
actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
}
}
private ActionExecutionException createActionExecutionException(Exception e, Code detailedCode) {
DetailedExitCode detailedExitCode =
- DetailedExitCode.of(
- FailureDetail.newBuilder()
- .setMessage(Strings.nullToEmpty(e.getMessage()))
- .setJavaCompile(JavaCompile.newBuilder().setCode(detailedCode))
- .build());
+ DetailedExitCode.of(createFailureDetail(Strings.nullToEmpty(e.getMessage()), detailedCode));
return new ActionExecutionException(e, this, /*catastrophe=*/ false, detailedExitCode);
}
+ private static FailureDetail createFailureDetail(String message, Code detailedCode) {
+ return FailureDetail.newBuilder()
+ .setMessage(message)
+ .setJavaCompile(JavaCompile.newBuilder().setCode(detailedCode))
+ .build();
+ }
+
private final class JavaActionContinuation extends ActionContinuationOrResult {
private final ActionExecutionContext actionExecutionContext;
@Nullable private final ReducedClasspath reducedClasspath;
@@ -610,7 +614,17 @@
// Fall back to running with the full classpath. This requires first deleting potential
// artifacts generated by the reduced action and clearing the metadata caches.
- deleteOutputs(actionExecutionContext.getExecRoot());
+ try {
+ deleteOutputs(actionExecutionContext.getExecRoot());
+ } catch (IOException e) {
+ throw toActionExecutionException(
+ new EnvironmentalExecException(
+ e,
+ createFailureDetail(
+ "Failed to delete reduced action outputs",
+ Code.REDUCED_CLASSPATH_FALLBACK_CLEANUP_FAILURE)),
+ actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
+ }
actionExecutionContext.getMetadataHandler().resetOutputs(getOutputs());
Spawn spawn;
try {
@@ -627,10 +641,6 @@
.beginExecution(spawn, actionExecutionContext);
return new JavaFallbackActionContinuation(
actionExecutionContext, results, fallbackContinuation);
- } catch (IOException e) {
- throw toActionExecutionException(
- new EnvironmentalExecException(e),
- actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
} catch (ExecException e) {
throw toActionExecutionException(
e, actionExecutionContext.showVerboseFailures(getOwner().getLabel()));
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 9c31fd2..afac067 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -131,6 +131,8 @@
WorkspaceStatus workspace_status = 158;
JavaCompile java_compile = 159;
ActionRewinding action_rewinding = 160;
+ CppCompile cpp_compile = 161;
+ StarlarkAction starlark_action = 162;
}
reserved 102; // For internal use
@@ -188,6 +190,7 @@
EXECUTION_DENIED = 5 [(metadata) = { exit_code: 1 }];
REMOTE_CACHE_FAILED = 6 [(metadata) = { exit_code: 34 }];
COMMAND_LINE_EXPANSION_FAILURE = 7 [(metadata) = { exit_code: 1 }];
+ EXEC_IO_EXCEPTION = 8 [(metadata) = { exit_code: 36 }];
}
Code code = 1;
@@ -350,6 +353,15 @@
[(metadata) = { exit_code: 36 }];
LOCAL_OUTPUT_DIRECTORY_SYMLINK_FAILURE = 7 [(metadata) = { exit_code: 36 }];
ACTION_INPUT_FILES_MISSING = 8 [(metadata) = { exit_code: 1 }];
+ LOCAL_TEMPLATE_EXPANSION_FAILURE = 9 [(metadata) = { exit_code: 36 }];
+ INPUT_DIRECTORY_CHECK_IO_EXCEPTION = 10 [(metadata) = { exit_code: 36 }];
+ EXTRA_ACTION_OUTPUT_CREATION_FAILURE = 11 [(metadata) = { exit_code: 36 }];
+ TEST_RUNNER_IO_EXCEPTION = 12 [(metadata) = { exit_code: 36 }];
+ FILE_WRITE_IO_EXCEPTION = 13 [(metadata) = { exit_code: 36 }];
+ TEST_OUT_ERR_IO_EXCEPTION = 14 [(metadata) = { exit_code: 36 }];
+ SYMLINK_TREE_MANIFEST_COPY_IO_EXCEPTION = 15
+ [(metadata) = { exit_code: 36 }];
+ SYMLINK_TREE_CREATION_IO_EXCEPTION = 16 [(metadata) = { exit_code: 36 }];
}
Code code = 1;
@@ -590,6 +602,7 @@
enum Code {
INCLUDE_SCANNING_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
INITIALIZE_INCLUDE_HINTS_ERROR = 1 [(metadata) = { exit_code: 36 }];
+ SCANNING_IO_EXCEPTION = 2 [(metadata) = { exit_code: 36 }];
}
Code code = 1;
@@ -789,6 +802,9 @@
JAVA_COMPILE_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
REDUCED_CLASSPATH_FAILURE = 1 [(metadata) = { exit_code: 1 }];
COMMAND_LINE_EXPANSION_FAILURE = 2 [(metadata) = { exit_code: 1 }];
+ JDEPS_READ_IO_EXCEPTION = 3 [(metadata) = { exit_code: 36 }];
+ REDUCED_CLASSPATH_FALLBACK_CLEANUP_FAILURE = 4
+ [(metadata) = { exit_code: 36 }];
}
Code code = 1;
@@ -803,3 +819,22 @@
Code code = 1;
}
+
+message CppCompile {
+ enum Code {
+ CPP_COMPILE_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ FIND_USED_HEADERS_IO_EXCEPTION = 1 [(metadata) = { exit_code: 36 }];
+ COPY_OUT_ERR_FAILURE = 2 [(metadata) = { exit_code: 36 }];
+ }
+
+ Code code = 1;
+}
+
+message StarlarkAction {
+ enum Code {
+ STARLARK_ACTION_UNKNOWN = 0 [(metadata) = { exit_code: 37 }];
+ UNUSED_INPUT_LIST_READ_FAILURE = 1 [(metadata) = { exit_code: 36 }];
+ }
+
+ Code code = 1;
+}