Improve config output by displaying more data about configurations.

Includes:
  fragments included in the configuration, as well as the actual underlying options.
  new --dump_all option which dumps every known configuration, including the configuration key.
PiperOrigin-RevId: 254459598
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
index 4a40bee..0263f75 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfiguration.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.analysis.config;
 
 import static java.util.Comparator.comparing;
+import static java.util.stream.Collectors.joining;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Suppliers;
@@ -208,10 +209,19 @@
 
   public void describe(StringBuilder sb) {
     sb.append("BuildConfiguration ").append(checksum()).append(":\n");
+    // Fragments.
+    sb.append("  fragments: ")
+        .append(
+            getFragmentsMap().keySet().stream()
+                .sorted(comparing(Class::getName))
+                .map(Class::getName)
+                .collect(joining(",")))
+        .append("\n");
+    // Options.
     getOptions().getFragmentClasses().stream()
         .sorted(comparing(Class::getName))
-        .map(fragmentClass -> getOptions().get(fragmentClass))
-        .forEach(fragment -> fragment.describe(sb));
+        .map(optionsClass -> getOptions().get(optionsClass))
+        .forEach(options -> options.describe(sb));
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentClassSet.java b/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentClassSet.java
index 9d695a7..3973327 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentClassSet.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/FragmentClassSet.java
@@ -14,6 +14,8 @@
 
 package com.google.devtools.build.lib.analysis.config;
 
+import static java.util.stream.Collectors.joining;
+
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Interner;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
@@ -98,4 +100,10 @@
     maybeInitializeFingerprintAndHashCode();
     return hashCode;
   }
+
+  @Override
+  public String toString() {
+    return String.format(
+        "FragmentClassSet[%s]", fragments.stream().map(Class::getName).collect(joining(",")));
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
index c402f8c..76c42a2 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/ConfigCommand.java
@@ -31,12 +31,17 @@
 import com.google.devtools.build.lib.runtime.BlazeCommandResult;
 import com.google.devtools.build.lib.runtime.Command;
 import com.google.devtools.build.lib.runtime.CommandEnvironment;
+import com.google.devtools.build.lib.runtime.commands.ConfigCommand.ConfigOptions;
 import com.google.devtools.build.lib.skyframe.BuildConfigurationValue;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
 import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.skyframe.InMemoryMemoizingEvaluator;
+import com.google.devtools.common.options.Option;
 import com.google.devtools.common.options.OptionDefinition;
+import com.google.devtools.common.options.OptionDocumentationCategory;
+import com.google.devtools.common.options.OptionEffectTag;
+import com.google.devtools.common.options.OptionsBase;
 import com.google.devtools.common.options.OptionsParser;
 import com.google.devtools.common.options.OptionsParsingResult;
 import java.io.OutputStreamWriter;
@@ -52,6 +57,7 @@
     name = "config",
     builds = true,
     inherits = {BuildCommand.class},
+    options = {ConfigOptions.class},
     usesConfigurationOptions = true,
     shortDescription = "Displays details of configurations.",
     allowResidue = true,
@@ -60,6 +66,17 @@
     help = "resource:config.txt")
 public class ConfigCommand implements BlazeCommand {
 
+  /** Options for the "config" command. */
+  public static class ConfigOptions extends OptionsBase {
+    @Option(
+        name = "dump_all",
+        defaultValue = "false",
+        documentationCategory = OptionDocumentationCategory.OUTPUT_PARAMETERS,
+        effectTags = {OptionEffectTag.AFFECTS_OUTPUTS},
+        help = "If set, dump all known configurations instead of just the ids.")
+    public boolean dumpAll;
+  }
+
   @Override
   public void editOptions(OptionsParser optionsParser) {}
 
@@ -72,7 +89,11 @@
             new OutputStreamWriter(env.getReporter().getOutErr().getOutputStream(), UTF_8))) {
 
       if (options.getResidue().isEmpty()) {
-        return reportOnConfigurations(writer, configurations.keySet());
+        if (options.getOptions(ConfigOptions.class).dumpAll) {
+          return reportAllConfigurations(writer, env);
+        } else {
+          return reportConfigurationIds(writer, configurations.keySet());
+        }
       }
 
       if (options.getResidue().size() == 1) {
@@ -130,14 +151,6 @@
     }
   }
 
-  private BlazeCommandResult reportOnConfigurations(
-      PrintWriter writer, ImmutableSet<String> configurationIds) {
-    writer.println("Available configurations:");
-    writer.println(configurationIds.stream().collect(Collectors.joining("\n")));
-
-    return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
-  }
-
   private ImmutableMap<String, BuildConfiguration> findConfigurations(CommandEnvironment env) {
     InMemoryMemoizingEvaluator evaluator =
         (InMemoryMemoizingEvaluator)
@@ -152,6 +165,39 @@
                 BuildConfiguration::checksum, Functions.identity(), (config1, config2) -> config1));
   }
 
+  private BlazeCommandResult reportAllConfigurations(PrintWriter writer, CommandEnvironment env) {
+    InMemoryMemoizingEvaluator evaluator =
+        (InMemoryMemoizingEvaluator)
+            env.getRuntime().getWorkspace().getSkyframeExecutor().getEvaluatorForTesting();
+    ImmutableMap<BuildConfigurationValue.Key, BuildConfigurationValue> configs =
+        evaluator.getDoneValues().entrySet().stream()
+            .filter(e -> SkyFunctions.BUILD_CONFIGURATION.equals(e.getKey().functionName()))
+            .collect(
+                toImmutableMap(
+                    e -> (BuildConfigurationValue.Key) e.getKey(),
+                    e -> (BuildConfigurationValue) e.getValue()));
+
+    for (Map.Entry<BuildConfigurationValue.Key, BuildConfigurationValue> entry :
+        configs.entrySet()) {
+      writer.print("BuildConfigurationValue.Key: ");
+      writer.println(entry.getKey().toString());
+
+      writer.print("BuildConfigurationValue:\n");
+      StringBuilder sb = new StringBuilder();
+      entry.getValue().getConfiguration().describe(sb);
+      writer.print(sb.toString());
+    }
+    return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
+  }
+
+  private BlazeCommandResult reportConfigurationIds(
+      PrintWriter writer, ImmutableSet<String> configurationIds) {
+    writer.println("Available configurations:");
+    writer.println(configurationIds.stream().collect(Collectors.joining("\n")));
+
+    return BlazeCommandResult.exitCode(ExitCode.SUCCESS);
+  }
+
   private Table<Class<? extends FragmentOptions>, String, Pair<Object, Object>> diffConfigurations(
       BuildConfiguration config1, BuildConfiguration config2) {
     Table<Class<? extends FragmentOptions>, String, Pair<Object, Object>> diffs =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
index 924a601..26092e0 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildConfigurationValue.java
@@ -189,6 +189,7 @@
 
     @Override
     public String toString() {
+      // This format is depended on by integration tests.
       return "BuildConfigurationValue.Key[" + optionsDiff.getChecksum() + "]";
     }
   }