Add the 'supports-graceful-termination' tag to request nice termination.

If an action specifies this new requirement and it spawns subprocesses via
the process-wrapper or the linux-sandbox, then interrupting Bazel while the
action is running will cause these subprocesses to be terminated gracefully
(first with a SIGTERM, then with a SIGKILL).

Tests that implement cleanup routines on interrupt can benefit from this to
ensure that those cleanup steps take place.

We aren't making this the default for all actions to keep Ctrl+C fast
(which arguably is already too slow sometimes).

Note that for this to work consistently across the local and the sandboxed
strategies, I've also had to fix AbstractSandboxSpawnRunner to properly
await for interrupted subprocesses, just like we did for the
LocalSpawnRunner back in https://github.com/bazelbuild/bazel/commit/de8d4c7bddb729d3703c97c6bee58062e154ec34.

RELNOTES: Added support for a 'supports-graceful-termination' execution
requirement and tag, which causes Bazel to send a SIGTERM to any tagged
actions before sending a delayed SIGKILL. This is to give actions, and more
specifically tests, a chance to clean up after themselves.
PiperOrigin-RevId: 329940226
diff --git a/src/test/java/com/google/devtools/build/lib/runtime/ProcessWrapperTest.java b/src/test/java/com/google/devtools/build/lib/runtime/ProcessWrapperTest.java
index 4f6b1a8..b0b1a5f 100644
--- a/src/test/java/com/google/devtools/build/lib/runtime/ProcessWrapperTest.java
+++ b/src/test/java/com/google/devtools/build/lib/runtime/ProcessWrapperTest.java
@@ -17,6 +17,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ExecutionRequirements;
 import com.google.devtools.build.lib.vfs.FileSystem;
 import com.google.devtools.build.lib.vfs.Path;
 import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem;
@@ -54,9 +56,9 @@
     ImmutableList<String> expectedCommandLine =
         ImmutableList.<String>builder().add("/some/path").addAll(commandArguments).build();
 
-    ImmutableList<String> extraFlags = ImmutableList.of();
     ProcessWrapper processWrapper =
-        new ProcessWrapper(makeProcessWrapperBin("/some/path"), /*killDelay=*/ null, extraFlags);
+        new ProcessWrapper(
+            makeProcessWrapperBin("/some/path"), /*killDelay=*/ null, /*gracefulSigterm=*/ false);
     List<String> commandLine = processWrapper.commandLineBuilder(commandArguments).build();
 
     assertThat(commandLine).containsExactlyElementsIn(expectedCommandLine).inOrder();
@@ -65,7 +67,6 @@
   @Test
   public void testProcessWrapperCommandLineBuilder_buildsWithOptionalArguments()
       throws IOException {
-    ImmutableList<String> extraFlags = ImmutableList.of("--debug");
     ImmutableList<String> commandArguments = ImmutableList.of("echo", "hello, world");
 
     Duration timeout = Duration.ofSeconds(10);
@@ -82,12 +83,13 @@
             .add("--stdout=" + stdoutPath)
             .add("--stderr=" + stderrPath)
             .add("--stats=" + statisticsPath)
-            .addAll(extraFlags)
+            .add("--graceful_sigterm")
             .addAll(commandArguments)
             .build();
 
     ProcessWrapper processWrapper =
-        new ProcessWrapper(makeProcessWrapperBin("/path/process-wrapper"), killDelay, extraFlags);
+        new ProcessWrapper(
+            makeProcessWrapperBin("/path/process-wrapper"), killDelay, /*gracefulSigterm=*/ true);
 
     List<String> commandLine =
         processWrapper
@@ -100,4 +102,27 @@
 
     assertThat(commandLine).containsExactlyElementsIn(expectedCommandLine).inOrder();
   }
+
+  @Test
+  public void testProcessWrapperCommandLineBuilder_withExecutionInfo() throws IOException {
+    ImmutableList<String> commandArguments = ImmutableList.of("echo", "hello, world");
+
+    ProcessWrapper processWrapper =
+        new ProcessWrapper(
+            makeProcessWrapperBin("/some/path"), /*killDelay=*/ null, /*gracefulSigterm=*/ false);
+    ProcessWrapper.CommandLineBuilder builder = processWrapper.commandLineBuilder(commandArguments);
+
+    ImmutableList<String> expectedWithoutExecutionInfo =
+        ImmutableList.<String>builder().add("/some/path").addAll(commandArguments).build();
+    assertThat(builder.build()).containsExactlyElementsIn(expectedWithoutExecutionInfo).inOrder();
+
+    ImmutableList<String> expectedWithExecutionInfo =
+        ImmutableList.<String>builder()
+            .add("/some/path")
+            .add("--graceful_sigterm")
+            .addAll(commandArguments)
+            .build();
+    builder.addExecutionInfo(ImmutableMap.of(ExecutionRequirements.GRACEFUL_TERMINATION, "1"));
+    assertThat(builder.build()).containsExactlyElementsIn(expectedWithExecutionInfo).inOrder();
+  }
 }