Remove undetailed BuildFailedException constructors

Encodes execution-phase cycle and non-action failures with
FailureDetails.

Drive-by detailing of a new CleanCommand failure mode.

RELNOTES: None.
PiperOrigin-RevId: 318347785
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BuildFailedException.java b/src/main/java/com/google/devtools/build/lib/actions/BuildFailedException.java
index ddc3dad..8969094 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/BuildFailedException.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/BuildFailedException.java
@@ -45,10 +45,6 @@
   private final boolean errorAlreadyShown;
   private final DetailedExitCode detailedExitCode;
 
-  public BuildFailedException() {
-    this(null);
-  }
-
   public BuildFailedException(String message) {
     this(
         message,
@@ -67,15 +63,6 @@
         detailedExitCode);
   }
 
-  public BuildFailedException(String message, boolean catastrophic) {
-    this(
-        message,
-        catastrophic,
-        NestedSetBuilder.emptySet(Order.STABLE_ORDER),
-        /*errorAlreadyShown=*/ false,
-        DetailedExitCode.justExitCode(ExitCode.BUILD_FAILURE));
-  }
-
   public BuildFailedException(
       String message,
       boolean catastrophic,
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
index 89490aa..3d99f98 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/SkyframeBuilder.java
@@ -41,6 +41,9 @@
 import com.google.devtools.build.lib.profiler.Profiler;
 import com.google.devtools.build.lib.profiler.SilentCloseable;
 import com.google.devtools.build.lib.runtime.KeepGoingOption;
+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.ActionExecutionInactivityWatchdog;
 import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
 import com.google.devtools.build.lib.skyframe.Builder;
@@ -50,7 +53,6 @@
 import com.google.devtools.build.lib.util.AbruptExitException;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.DetailedExitCode.DetailedExitCodeComparator;
-import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.LoggingUtil;
 import com.google.devtools.build.lib.vfs.ModifiedFileSet;
 import com.google.devtools.build.skyframe.CycleInfo;
@@ -229,13 +231,9 @@
       return;
     }
 
-    if (options.getOptions(KeepGoingOption.class).keepGoing) {
-      // Use the exit code with the highest priority.
-      throw new BuildFailedException(
-          null, Collections.max(detailedExitCodes, DetailedExitCodeComparator.INSTANCE));
-    } else {
-      throw new BuildFailedException();
-    }
+    // Use the exit code with the highest priority.
+    throw new BuildFailedException(
+        null, Collections.max(detailedExitCodes, DetailedExitCodeComparator.INSTANCE));
   }
 
   /**
@@ -247,8 +245,8 @@
    *   <li>{@code null}, if {@code result} had no errors
    *   <li>{@code e} if result had errors and one of them specified a {@link DetailedExitCode} value
    *       {@code e}
-   *   <li>{@code DetailedExitCode.justExitCode(ExitCode.BUILD_FAILURE)} if result had errors but
-   *       none specified a {@link DetailedExitCode} value
+   *   <li>a {@link DetailedExitCode} with {@link Code.NON_ACTION_EXECUTION_FAILURE} if result had
+   *       errors but none specified a {@link DetailedExitCode} value
    * </ol>
    *
    * <p>Throws on catastrophic failures and, if !keepGoing, on any failure.
@@ -289,7 +287,9 @@
 
         return detailedExitCode != null
             ? detailedExitCode
-            : DetailedExitCode.justExitCode(ExitCode.BUILD_FAILURE);
+            : createDetailedExitCode(
+                "keep_going execution failed without an action failure",
+                Code.NON_ACTION_EXECUTION_FAILURE);
       }
       ErrorInfo errorInfo = Preconditions.checkNotNull(result.getError(), result);
       Exception exception = errorInfo.getException();
@@ -299,7 +299,8 @@
         // during evaluation (otherwise, it wouldn't have bothered to find a cycle). So the best
         // we can do is throw a generic build failure exception, since we've already reported the
         // cycles above.
-        throw new BuildFailedException(null, /* catastrophic= */ false);
+        throw new BuildFailedException(
+            null, createDetailedExitCode("cycle found during execution", Code.CYCLE));
       } else {
         rethrow(exception);
       }
@@ -355,4 +356,11 @@
     return count;
   }
 
+  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/runtime/commands/CleanCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/CleanCommand.java
index 98cfd82..1a62a69 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/CleanCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/CleanCommand.java
@@ -35,7 +35,6 @@
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.shell.CommandException;
 import com.google.devtools.build.lib.util.CommandBuilder;
-import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.InterruptedFailureDetails;
 import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.Pair;
@@ -136,7 +135,8 @@
     if (!residue.isEmpty()) {
       String message = "Unrecognized arguments: " + Joiner.on(' ').join(residue);
       env.getReporter().handle(Event.error(message));
-      return BlazeCommandResult.exitCode(ExitCode.COMMAND_LINE_ERROR);
+      return BlazeCommandResult.failureDetail(
+          createFailureDetail(message, Code.ARGUMENTS_NOT_RECOGNIZED));
     }
 
     Options cleanOptions = options.getOptions(Options.class);
@@ -322,10 +322,14 @@
     }
 
     private FailureDetail getFailureDetail() {
-      return FailureDetail.newBuilder()
-          .setMessage(getMessage())
-          .setCleanCommand(FailureDetails.CleanCommand.newBuilder().setCode(detailedCode))
-          .build();
+      return createFailureDetail(getMessage(), detailedCode);
     }
   }
+
+  private static FailureDetail createFailureDetail(String message, Code detailedCode) {
+    return FailureDetail.newBuilder()
+        .setMessage(message)
+        .setCleanCommand(FailureDetails.CleanCommand.newBuilder().setCode(detailedCode))
+        .build();
+  }
 }
diff --git a/src/main/protobuf/failure_details.proto b/src/main/protobuf/failure_details.proto
index 6147481..fb70bbc 100644
--- a/src/main/protobuf/failure_details.proto
+++ b/src/main/protobuf/failure_details.proto
@@ -405,6 +405,8 @@
         [(metadata) = { exit_code: 1 }];
     ACTION_FS_OUT_ERR_DIRECTORY_CREATION_FAILURE = 33
         [(metadata) = { exit_code: 1 }];
+    NON_ACTION_EXECUTION_FAILURE = 34 [(metadata) = { exit_code: 1 }];
+    CYCLE = 35 [(metadata) = { exit_code: 1 }];
   }
 
   Code code = 1;
@@ -724,6 +726,7 @@
     EXECROOT_DELETE_FAILURE = 7 [(metadata) = { exit_code: 36 }];
     EXECROOT_TEMP_MOVE_FAILURE = 8 [(metadata) = { exit_code: 36 }];
     ASYNC_EXECROOT_DELETE_FAILURE = 9 [(metadata) = { exit_code: 6 }];
+    ARGUMENTS_NOT_RECOGNIZED = 10 [(metadata) = { exit_code: 2 }];
   }
 
   Code code = 1;
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index 427a132..e3f37ab 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -73,6 +73,9 @@
 import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
 import com.google.devtools.build.lib.remote.options.RemoteOutputsMode;
 import com.google.devtools.build.lib.runtime.KeepGoingOption;
+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.AspectValueKey.AspectKey;
 import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction;
 import com.google.devtools.build.lib.skyframe.PackageLookupFunction.CrossRepositoryLabelViolationStrategy;
@@ -85,6 +88,7 @@
 import com.google.devtools.build.lib.testutil.TestRuleClassProvider;
 import com.google.devtools.build.lib.testutil.TestUtils;
 import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.io.TimestampGranularityMonitor;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -357,9 +361,11 @@
             hasCycles |= !Iterables.isEmpty(cycles);
           }
           if (hasCycles) {
-            throw new BuildFailedException(CYCLE_MSG);
+            throw new BuildFailedException(CYCLE_MSG, createDetailedExitCode(Code.CYCLE));
           } else if (result.errorMap().isEmpty() || keepGoing) {
-            throw new BuildFailedException();
+            // The specific detailed code used here doesn't matter.
+            throw new BuildFailedException(
+                null, createDetailedExitCode(Code.NON_ACTION_EXECUTION_FAILURE));
           } else {
             SkyframeBuilder.rethrow(Preconditions.checkNotNull(result.getError().getException()));
           }
@@ -486,6 +492,13 @@
     }
   }
 
+  private static DetailedExitCode createDetailedExitCode(Code detailedCode) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setExecution(Execution.newBuilder().setCode(detailedCode))
+            .build());
+  }
+
   /** {@link TestAction} that copies its single input to its single output. */
   protected static class CopyingAction extends TestAction {
     CopyingAction(Runnable effect, Artifact input, Artifact output) {