Add a helper class to simplify printing of toolchain resolution debug messages.

PiperOrigin-RevId: 698592208
Change-Id: If7a7bb66ef6a2d78667a8980c451d506d3e2ae53
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
index a91acc6..995db81 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
@@ -313,6 +313,7 @@
     name = "toolchain_resolution_function",
     srcs = [
         "PlatformKeys.java",
+        "ToolchainResolutionDebugPrinter.java",
         "ToolchainResolutionFunction.java",
     ],
     deps = [
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/PlatformKeys.java b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/PlatformKeys.java
index cf17760..aada3fb 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/PlatformKeys.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/PlatformKeys.java
@@ -26,7 +26,6 @@
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.skyframe.config.BuildConfigurationKey;
 import com.google.devtools.build.lib.skyframe.toolchains.ConstraintValueLookupUtil.InvalidConstraintValueException;
@@ -50,7 +49,7 @@
   private static class Builder {
     // Input data.
     private final SkyFunction.Environment environment;
-    private final boolean debug;
+    private final ToolchainResolutionDebugPrinter debugPrinter;
     private final BuildConfigurationKey configurationKey;
 
     // Internal state used during loading.
@@ -62,11 +61,11 @@
 
     private Builder(
         SkyFunction.Environment environment,
-        boolean debug,
+        ToolchainResolutionDebugPrinter debugPrinter,
         BuildConfigurationKey configurationKey,
         PlatformConfiguration platformConfiguration) {
       this.environment = environment;
-      this.debug = debug;
+      this.debugPrinter = debugPrinter;
       this.configurationKey = configurationKey;
 
       this.hostPlatformLabel = platformConfiguration.getHostPlatform();
@@ -221,20 +220,7 @@
         PlatformInfo platformInfo, List<ConstraintValueInfo> constraints) {
       ImmutableList<ConstraintValueInfo> missingConstraints =
           platformInfo.constraints().findMissing(constraints);
-      if (debug) {
-        for (ConstraintValueInfo constraint : missingConstraints) {
-          // The value for this setting is not present in the platform, or doesn't match the
-          // expected value.
-          environment
-              .getListener()
-              .handle(
-                  Event.info(
-                      String.format(
-                          "ToolchainResolution: Removed execution platform %s from"
-                              + " available execution platforms, it is missing constraint %s",
-                          platformInfo.label(), constraint.label())));
-        }
-      }
+      debugPrinter.reportRemovedExecutionPlatform(platformInfo.label(), missingConstraints);
 
       return missingConstraints.isEmpty();
     }
@@ -242,7 +228,7 @@
 
   static PlatformKeys load(
       SkyFunction.Environment environment,
-      boolean debug,
+      ToolchainResolutionDebugPrinter debugPrinter,
       BuildConfigurationKey configurationKey,
       PlatformConfiguration platformConfiguration,
       ImmutableSet<Label> execConstraintLabels)
@@ -252,7 +238,7 @@
           InvalidPlatformException,
           InvalidExecutionPlatformLabelException {
 
-    return new Builder(environment, debug, configurationKey, platformConfiguration)
+    return new Builder(environment, debugPrinter, configurationKey, platformConfiguration)
         .build(execConstraintLabels);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionDebugPrinter.java b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionDebugPrinter.java
new file mode 100644
index 0000000..979c7bf
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionDebugPrinter.java
@@ -0,0 +1,109 @@
+// Copyright 2024 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe.toolchains;
+
+import static java.util.stream.Collectors.joining;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSetMultimap;
+import com.google.devtools.build.lib.analysis.platform.ConstraintValueInfo;
+import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.events.Event;
+import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.errorprone.annotations.FormatMethod;
+import com.google.errorprone.annotations.FormatString;
+
+/** A helper interface for printing debug messages from toolchain resolution. */
+public sealed interface ToolchainResolutionDebugPrinter {
+
+  static ToolchainResolutionDebugPrinter create(boolean debug, ExtendedEventHandler eventHandler) {
+    if (debug) {
+      return new EventHandlerImpl(eventHandler);
+    }
+    return new NoopPrinter();
+  }
+
+  /** Report on which toolchains were selected. */
+  void reportSelectedToolchains(
+      Label targetPlatform,
+      Label executionPlatform,
+      ImmutableSetMultimap<ToolchainTypeInfo, Label> toolchainTypeToResolved);
+
+  /** Report on an execution platform that was skipped due to constraint mismatches. */
+  void reportRemovedExecutionPlatform(
+      Label label, ImmutableList<ConstraintValueInfo> missingConstraints);
+
+  /** A do-nothing implementation for when debug messages are suppressed. */
+  final class NoopPrinter implements ToolchainResolutionDebugPrinter {
+
+    private NoopPrinter() {}
+
+    @Override
+    public void reportSelectedToolchains(
+        Label targetPlatform,
+        Label executionPlatform,
+        ImmutableSetMultimap<ToolchainTypeInfo, Label> toolchainTypeToResolved) {}
+
+    @Override
+    public void reportRemovedExecutionPlatform(
+        Label label, ImmutableList<ConstraintValueInfo> missingConstraints) {}
+  }
+
+  /** Implement debug printing using the {@link ExtendedEventHandler}. */
+  final class EventHandlerImpl implements ToolchainResolutionDebugPrinter {
+
+    private final ExtendedEventHandler eventHandler;
+
+    private EventHandlerImpl(ExtendedEventHandler eventHandler) {
+      this.eventHandler = eventHandler;
+    }
+
+    @FormatMethod
+    private void debugMessage(@FormatString String template, Object... args) {
+      eventHandler.handle(Event.info(String.format(template, args)));
+    }
+
+    @Override
+    public void reportSelectedToolchains(
+        Label targetPlatform,
+        Label executionPlatform,
+        ImmutableSetMultimap<ToolchainTypeInfo, Label> toolchainTypeToResolved) {
+      String selectedToolchains =
+          toolchainTypeToResolved.entries().stream()
+              .map(
+                  e ->
+                      String.format(
+                          "type %s -> toolchain %s", e.getKey().typeLabel(), e.getValue()))
+              .collect(joining(", "));
+      debugMessage(
+          "ToolchainResolution: Target platform %s: Selected execution platform %s," + " %s",
+          targetPlatform, executionPlatform, selectedToolchains);
+    }
+
+    @Override
+    public void reportRemovedExecutionPlatform(
+        Label label, ImmutableList<ConstraintValueInfo> missingConstraints) {
+      // TODO: jcater - Make this one line listing all constraints.
+      for (ConstraintValueInfo constraint : missingConstraints) {
+        // The value for this setting is not present in the platform, or doesn't match the
+        // expected value.
+        debugMessage(
+            "ToolchainResolution: Removed execution platform %s from"
+                + " available execution platforms, it is missing constraint %s",
+            label, constraint.label());
+      }
+    }
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionFunction.java
index 656e28c..c8d2cf9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainResolutionFunction.java
@@ -15,7 +15,6 @@
 
 import static com.google.common.collect.ImmutableList.toImmutableList;
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
-import static java.util.stream.Collectors.joining;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.HashBasedTable;
@@ -30,7 +29,6 @@
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.platform.ToolchainTypeInfo;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.server.FailureDetails.Toolchain.Code;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.skyframe.config.BuildConfigurationKey;
@@ -86,12 +84,15 @@
                           .map(ToolchainTypeRequirement::toolchainType)
                           .collect(toImmutableSet()));
 
+      ToolchainResolutionDebugPrinter debugPrinter =
+          ToolchainResolutionDebugPrinter.create(debug, env.getListener());
+
       // Create keys for all platforms that will be used, and validate them early.
       // Do this early, to catch platform errors early.
       PlatformKeys platformKeys =
           PlatformKeys.load(
               env,
-              debug,
+              debugPrinter,
               configuration.getKey(),
               platformConfiguration,
               key.execConstraintLabels());
@@ -118,24 +119,10 @@
           key.debugTarget());
 
       UnloadedToolchainContext unloadedToolchainContext = builder.build();
-      if (debug) {
-        String selectedToolchains =
-            unloadedToolchainContext.toolchainTypeToResolved().entries().stream()
-                .map(
-                    e ->
-                        String.format(
-                            "type %s -> toolchain %s", e.getKey().typeLabel(), e.getValue()))
-                .collect(joining(", "));
-        env.getListener()
-            .handle(
-                Event.info(
-                    String.format(
-                        "ToolchainResolution: Target platform %s: Selected execution platform %s,"
-                            + " %s",
-                        unloadedToolchainContext.targetPlatform().label(),
-                        unloadedToolchainContext.executionPlatform().label(),
-                        selectedToolchains)));
-      }
+      debugPrinter.reportSelectedToolchains(
+          unloadedToolchainContext.targetPlatform().label(),
+          unloadedToolchainContext.executionPlatform().label(),
+          unloadedToolchainContext.toolchainTypeToResolved());
       return unloadedToolchainContext;
     } catch (ToolchainException e) {
       throw new ToolchainResolutionFunctionException(e);