Add a flag, --experimental_verbose_failures_filter, that gives finer control over failure reporting: rather than dump command lines for all failed actions, dump only for actions whose labels match a regular expression filter.

The existing --verbose_failures flag is still available as an equivalent for --experimental_verbose_failures_filter=.*

PiperOrigin-RevId: 312352624
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
index 8b589bf..28464e8 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
@@ -20,6 +20,7 @@
 import com.google.devtools.build.lib.actions.LocalHostCapacity;
 import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.util.OptionsUtils;
 import com.google.devtools.build.lib.util.RegexFilter;
 import com.google.devtools.build.lib.util.ResourceConverter;
@@ -38,6 +39,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Predicate;
 
 /**
  * Options affecting the execution phase of a build.
@@ -126,9 +128,9 @@
       documentationCategory = OptionDocumentationCategory.LOGGING,
       effectTags = {OptionEffectTag.EXECUTION},
       help =
-          "Writes intermediate parameter files to output tree even when using "
-              + "remote action execution. Useful when debugging actions. "
-              + "This is implied by --subcommands and --verbose_failures.")
+          "Writes intermediate parameter files to output tree even when using remote action"
+              + " execution. Useful when debugging actions. This is implied by --subcommands,"
+              + " --verbose_failures, and --experimental_verbose_failures_filter.")
   public boolean materializeParamFiles;
 
   @Option(
@@ -140,10 +142,13 @@
   public boolean materializeParamFilesDirectly;
 
   public boolean shouldMaterializeParamFiles() {
-    // Implied by --subcommands and --verbose_failures
+    // Implied by --subcommands and verbose_failures
     return materializeParamFiles
         || showSubcommands != ActionExecutionContext.ShowSubcommands.FALSE
-        || verboseFailures;
+        // Conservatively materialize params files if any failures may be verbose.
+        // TODO(janakr): Could try to thread action label through to here and only materialize for
+        //  those actions, but seems pretty gnarly.
+        || hasSomeVerboseFailures();
   }
 
   @Option(
@@ -151,10 +156,33 @@
       defaultValue = "false",
       documentationCategory = OptionDocumentationCategory.LOGGING,
       effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
-      help = "If a command fails, print out the full command line.")
+      help = "If any command fails, print out the full command line.")
   public boolean verboseFailures;
 
   @Option(
+      name = "experimental_verbose_failures_filter",
+      defaultValue = "null",
+      converter = RegexFilter.RegexFilterConverter.class,
+      documentationCategory = OptionDocumentationCategory.LOGGING,
+      effectTags = {OptionEffectTag.TERMINAL_OUTPUT},
+      help =
+          "If a command fails, print out the full command line if its label matches the given"
+              + " regex filter.")
+  public RegexFilter verboseFailuresFilter;
+
+  public boolean hasSomeVerboseFailures() {
+    return verboseFailures || verboseFailuresFilter != null;
+  }
+
+  public Predicate<Label> getVerboseFailuresPredicate() {
+    return verboseFailures
+        ? l -> true
+        : verboseFailuresFilter == null
+            ? l -> false
+            : l -> l == null || verboseFailuresFilter.isIncluded(l.getCanonicalForm());
+  }
+
+  @Option(
       name = "subcommands",
       abbrev = 's',
       defaultValue = "false",