Use DetailedExitCode in AbruptExitException

This allows code that constructs this exception to specify FailureDetail
values. Those are useful for communicating more information about failure
modes than just an exit code.

This modifies BuildTool to consume the exception's DetailedExitCode,
which is the first of many similar uses to be transformed.

---

To keep SkyDoc from depending on protobuf resources, this factors
AbruptExitException (which SkyDoc does not depend on) out of
devtools/build/lib:util (which SkyDoc does depend on). Rules which
previously depended on :util for AbruptExitException now directly
depend on its new rule.

RELNOTES: None.
PiperOrigin-RevId: 302031416
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index f341179..44c4b8e 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -203,6 +203,7 @@
     srcs = glob(
         ["util/*.java"],
         exclude = COMMAND_UTILS_SRCS + RESOURCE_UTILS_SRCS + [
+            "util/AbruptExitException.java",
             "util/BlazeClock.java",
             "util/Clock.java",
             "util/ExitCode.java",
@@ -227,7 +228,6 @@
     ),
     exports = [
         ":base-util",
-        ":exitcode-external",
         ":filetype",
         ":os_util",
         ":resource_usage",
@@ -304,6 +304,15 @@
 )
 
 java_library(
+    name = "abrupt_exit_exception",
+    srcs = ["util/AbruptExitException.java"],
+    deps = [
+        ":detailed_exit_code",
+        ":exitcode-external",
+    ],
+)
+
+java_library(
     name = "exitcode-external",
     srcs = [
         "util/ExitCode.java",
@@ -510,6 +519,7 @@
         ":transitive-info-provider",
     ],
     deps = [
+        ":abrupt_exit_exception",
         ":bug-report",
         ":build-request-options",
         ":command-utils",
@@ -630,6 +640,7 @@
         ],
     ),
     deps = [
+        ":abrupt_exit_exception",
         ":android-rules",
         ":bazel",
         ":bazel-repository",
@@ -638,6 +649,7 @@
         ":core-rules",
         ":core-workspace-rules",
         ":events",
+        ":exitcode-external",
         ":proto-rules",
         ":python-rules",
         ":shell_escaper",
@@ -687,13 +699,14 @@
     name = "bazel/BazelRepositoryModule",
     srcs = ["bazel/BazelRepositoryModule.java"],
     deps = [
+        ":abrupt_exit_exception",
         ":bazel-commands",
         ":bazel-repository",
         ":bazel-rules",
         ":build-base",
         ":events",
+        ":exitcode-external",
         ":runtime",
-        ":util",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/cache",
         "//src/main/java/com/google/devtools/build/lib/bazel/repository/downloader",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
@@ -752,6 +765,7 @@
         ],
     ),
     deps = [
+        ":abrupt_exit_exception",
         ":build-base",
         ":build-info",
         ":command-utils",
@@ -781,6 +795,7 @@
         "bazel/commands/sync.txt",
     ],
     deps = [
+        ":abrupt_exit_exception",
         ":bazel-repository",
         ":build-base",
         ":events",
@@ -788,7 +803,6 @@
         ":keep-going-option",
         ":loading-phase-threads-option",
         ":runtime",
-        ":util",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/pkgcache",
@@ -1189,6 +1203,7 @@
         "server/signal/InterruptSignalHandler.java",
     ],
     deps = [
+        ":abrupt_exit_exception",
         ":bug-report",
         ":build-base",
         ":build-request-options",
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BUILD b/src/main/java/com/google/devtools/build/lib/actions/BUILD
index 1dc573a..fd9cc03 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/actions/BUILD
@@ -30,6 +30,7 @@
     deps = [
         ":commandline_item",
         ":localhost_capacity",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:base-util",
         "//src/main/java/com/google/devtools/build/lib:bug-report",
         "//src/main/java/com/google/devtools/build/lib:command-utils",
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/debug/BUILD b/src/main/java/com/google/devtools/build/lib/bazel/debug/BUILD
index f998502..9a3577c 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/debug/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/bazel/debug/BUILD
@@ -54,10 +54,10 @@
     deps = [
         ":debugging-options",
         ":workspace-rule-event",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:runtime",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/util/io",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
         "//src/main/java/com/google/devtools/common/options",
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
index 5956f3a..31fbf10 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventservice/BUILD
@@ -25,6 +25,7 @@
     ),
     deps = [
         ":buildeventservice-options",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
diff --git a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
index 82d81e2..244db0b 100644
--- a/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/buildeventstream/transports/BUILD
@@ -11,8 +11,8 @@
     name = "transports",
     srcs = glob(["*.java"]),
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
         "//src/main/java/com/google/devtools/common/options",
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 5f4258b..8a693ab 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
@@ -334,7 +334,7 @@
       // target(s) that triggered them.
       result.setCatastrophe();
     } catch (AbruptExitException e) {
-      detailedExitCode = DetailedExitCode.justExitCode(e.getExitCode());
+      detailedExitCode = e.getDetailedExitCode();
       reportExceptionError(e);
       result.setCatastrophe();
     } catch (Throwable throwable) {
diff --git a/src/main/java/com/google/devtools/build/lib/platform/SleepPreventionModule.java b/src/main/java/com/google/devtools/build/lib/platform/SleepPreventionModule.java
index a8ad277..9a85c9c 100644
--- a/src/main/java/com/google/devtools/build/lib/platform/SleepPreventionModule.java
+++ b/src/main/java/com/google/devtools/build/lib/platform/SleepPreventionModule.java
@@ -17,7 +17,6 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.devtools.build.lib.runtime.BlazeModule;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
-import com.google.devtools.build.lib.util.AbruptExitException;
 
 /** Prevents the computer from going to sleep while a Bazel command is running. */
 public final class SleepPreventionModule extends BlazeModule {
@@ -44,14 +43,14 @@
   }
 
   @Override
-  public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
+  public void beforeCommand(CommandEnvironment env) {
     if (JniLoader.jniEnabled()) {
       SleepPrevention.pushDisableSleep();
     }
   }
 
   @Override
-  public void afterCommand() throws AbruptExitException {
+  public void afterCommand() {
     if (JniLoader.jniEnabled()) {
       SleepPrevention.popDisableSleep();
     }
diff --git a/src/main/java/com/google/devtools/build/lib/remote/BUILD b/src/main/java/com/google/devtools/build/lib/remote/BUILD
index 146477d..32560b6 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/remote/BUILD
@@ -39,11 +39,11 @@
         ":ExecutionStatusException",
         ":ReferenceCountedChannel",
         ":Retrier",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:runtime",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/analysis/platform:platform_utils",
         "//src/main/java/com/google/devtools/build/lib/authandtls",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
index cab42e2..50e6f9c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/CommandEnvironment.java
@@ -523,7 +523,7 @@
   private ExitCode finalizeExitCode() {
     // Set the pending exception so that further calls to exit(AbruptExitException) don't lead to
     // unwanted thread interrupts.
-    if (pendingException.compareAndSet(null, new AbruptExitException("", null))) {
+    if (pendingException.compareAndSet(null, new AbruptExitException("", ExitCode.RESERVED))) {
       return null;
     }
     if (Thread.currentThread() == commandThread) {
diff --git a/src/main/java/com/google/devtools/build/lib/standalone/BUILD b/src/main/java/com/google/devtools/build/lib/standalone/BUILD
index 8455614..f2e6045 100644
--- a/src/main/java/com/google/devtools/build/lib/standalone/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/standalone/BUILD
@@ -14,11 +14,11 @@
         "//src/main/tools:process-wrapper",
     ],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib:testing-support-rules",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/dynamic",
         "//src/main/java/com/google/devtools/build/lib/exec/local",
diff --git a/src/main/java/com/google/devtools/build/lib/util/AbruptExitException.java b/src/main/java/com/google/devtools/build/lib/util/AbruptExitException.java
index 3dabdfc..4158bd8 100644
--- a/src/main/java/com/google/devtools/build/lib/util/AbruptExitException.java
+++ b/src/main/java/com/google/devtools/build/lib/util/AbruptExitException.java
@@ -17,32 +17,51 @@
 /**
  * An exception thrown by various error conditions that are severe enough to halt the command (e.g.
  * even a --keep_going build). These typically need to signal to the handling code what happened.
- * Therefore, these exceptions contain a recommended ExitCode allowing the exception to "set" a
- * returned numeric exit code.
+ * Therefore, these exceptions contain a {@link DetailedExitCode} specifying a numeric exit code and
+ * a detailed failure for the command to return.
  *
- * When an instance of this exception is thrown, Blaze will try to halt as soon as reasonably
- * possible.
+ * <p>When an instance of this exception is thrown, Bazel will try to halt the command as soon as
+ * reasonably possible.
  */
 public class AbruptExitException extends Exception {
 
-  private final ExitCode exitCode;
+  private final DetailedExitCode detailedExitCode;
 
   public AbruptExitException(String message, ExitCode exitCode) {
     super(message);
-    this.exitCode = exitCode;
+    this.detailedExitCode = DetailedExitCode.justExitCode(exitCode);
   }
 
   public AbruptExitException(String message, ExitCode exitCode, Throwable cause) {
     super(message, cause);
-    this.exitCode = exitCode;
+    this.detailedExitCode = DetailedExitCode.justExitCode(exitCode);
   }
 
   public AbruptExitException(ExitCode exitCode, Throwable cause) {
     super(cause);
-    this.exitCode = exitCode;
+    this.detailedExitCode = DetailedExitCode.justExitCode(exitCode);
+  }
+
+  public AbruptExitException(String message, DetailedExitCode detailedExitCode) {
+    super(message);
+    this.detailedExitCode = detailedExitCode;
+  }
+
+  public AbruptExitException(String message, DetailedExitCode detailedExitCode, Throwable cause) {
+    super(message, cause);
+    this.detailedExitCode = detailedExitCode;
+  }
+
+  public AbruptExitException(DetailedExitCode detailedExitCode, Throwable cause) {
+    super(cause);
+    this.detailedExitCode = detailedExitCode;
   }
 
   public ExitCode getExitCode() {
-    return exitCode;
+    return detailedExitCode.getExitCode();
+  }
+
+  public DetailedExitCode getDetailedExitCode() {
+    return detailedExitCode;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/BUILD b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
index ab34d48..a241c3a 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/vfs/BUILD
@@ -62,8 +62,8 @@
     deps = [
         ":pathfragment",
         ":vfs",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:events",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/skyframe",
         "//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/skyframe/BUILD b/src/main/java/com/google/devtools/build/skyframe/BUILD
index cec51f5..985f2f1 100644
--- a/src/main/java/com/google/devtools/build/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/skyframe/BUILD
@@ -36,6 +36,7 @@
     deps = [
         ":graph_inconsistency_java_proto",
         ":skyframe-objects",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:bug-report",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:util",
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 9a39ff6..36d9891 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -427,6 +427,7 @@
     test_class = "com.google.devtools.build.lib.AllTests",
     deps = [
         ":AllTests",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:bazel-rules",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
@@ -473,6 +474,7 @@
     deps = [
         ":AllTests",
         "//src/main/java/com/google/devtools/build/lib:bazel-main",
+        "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib:server",
         "//src/main/java/com/google/devtools/build/lib:util",
@@ -516,12 +518,14 @@
     test_class = "com.google.devtools.build.lib.AllTests",
     deps = [
         ":AllTests",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:bazel-modules",
         "//src/main/java/com/google/devtools/build/lib:bazel-rules",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:build-request-options",
         "//src/main/java/com/google/devtools/build/lib:detailed_exit_code",
         "//src/main/java/com/google/devtools/build/lib:events",
+        "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:loading-phase-threads-option",
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib:string_util",
diff --git a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
index 1c85a79..1cf6f7b 100644
--- a/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/buildtool/BUILD
@@ -34,8 +34,8 @@
         "SymlinkForestTest.java",
     ],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:runtime",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/vfs",
         "//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
index 29d5fa9..359a508 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
@@ -15,10 +15,10 @@
     name = "testutil",
     srcs = glob(["*.java"]),
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:filetype",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/clock",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
diff --git a/src/test/java/com/google/devtools/build/lib/remote/BUILD b/src/test/java/com/google/devtools/build/lib/remote/BUILD
index 5aa8854..4361de5 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/remote/BUILD
@@ -40,6 +40,7 @@
     ) + NATIVE_SSL_TEST_MAYBE,
     test_class = "com.google.devtools.build.lib.AllTests",
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:exitcode-external",
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/CommandInterruptionTest.java b/src/test/java/com/google/devtools/build/lib/runtime/CommandInterruptionTest.java
index 5a4ab60..2076f60 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/CommandInterruptionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/CommandInterruptionTest.java
@@ -445,20 +445,6 @@
   }
 
   @Test
-  public void exitForbidsNullExitCode() throws Exception {
-    CommandState command = snooze.runIn(executor, dispatcher, /*expectInterruption=*/ false);
-    try {
-      command.getModuleEnvironment().exit(new AbruptExitException("", null));
-      throw new AssertionError(
-          "It shouldn't be allowed to pass an AbruptExitException with null ExitCode to exit()!");
-    } catch (NullPointerException expected) {
-      // Good!
-    }
-    command.assertNotFinishedYet();
-    command.requestExitWith(ExitCode.SUCCESS);
-  }
-
-  @Test
   public void callingExitOnceInterruptsAndOverridesExitCode() throws Exception {
     CommandState command = snooze.runIn(executor, dispatcher, /*expectInterruption=*/ false);
     command.getModuleEnvironment().exit(new AbruptExitException("", ExitCode.NO_TESTS_FOUND));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/BUILD b/src/test/java/com/google/devtools/build/lib/skyframe/BUILD
index 2d6972a..1c66855 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -26,11 +26,11 @@
     tags = ["skyframe"],
     visibility = ["//src/test/java/com/google/devtools/build/lib:__subpackages__"],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:bazel-main",
         "//src/main/java/com/google/devtools/build/lib:bazel-rules",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:events",
-        "//src/main/java/com/google/devtools/build/lib:util",
         "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/clock",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
@@ -82,12 +82,14 @@
     ],
     deps = [
         ":testutil",
+        "//src/main/java/com/google/devtools/build/lib:abrupt_exit_exception",
         "//src/main/java/com/google/devtools/build/lib:bazel-main",
         "//src/main/java/com/google/devtools/build/lib:bazel-rules",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:build-request-options",
         "//src/main/java/com/google/devtools/build/lib:detailed_exit_code",
         "//src/main/java/com/google/devtools/build/lib:events",
+        "//src/main/java/com/google/devtools/build/lib:exitcode-external",
         "//src/main/java/com/google/devtools/build/lib:keep-going-option",
         "//src/main/java/com/google/devtools/build/lib:runtime",
         "//src/main/java/com/google/devtools/build/lib:syntax",