Added an help command to dump all options for completion

`bazel help completion` dump all options completion pattern
for each command, giving hints on the format of the completion
residue (e.g., `label`, `path`, `{a,enum}`, ...). This
dump can be used to generate completion scripts.

--
MOS_MIGRATED_REVID=90743024
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/Command.java b/src/main/java/com/google/devtools/build/lib/runtime/Command.java
index 1797cd3..318e3e4 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/Command.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/Command.java
@@ -105,4 +105,13 @@
    */
   boolean canRunInOutputDirectory() default false;
 
+  /**
+   * Returns the type completion help for this command, that is the type arguments that this command
+   * expects. It can be a whitespace separated list if the command take several arguments. The type
+   * of each arguments can be <code>label</code>, <code>path</code>, <code>string</code>, ...
+   * It can also be a comma separated list of values, e.g. <code>{value1,value2}<code>. If a command
+   * accept several argument types, they can be combined with |, e.g <code>label|path</code>.
+   */
+  String completion() default "";
+
 }
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/BuildCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/BuildCommand.java
index d6f61eb..94a0ada 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/BuildCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/BuildCommand.java
@@ -46,6 +46,7 @@
          usesConfigurationOptions = true,
          shortDescription = "Builds the specified targets.",
          allowResidue = true,
+         completion = "label",
          help = "resource:build.txt")
 public final class BuildCommand implements BlazeCommand {
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/HelpCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/HelpCommand.java
index 0539da5..227227f 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/HelpCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/HelpCommand.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.runtime.commands;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.docgen.BlazeRuleHelpPrinter;
@@ -38,6 +39,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * The 'blaze help' command, which prints all available commands as well as
@@ -48,8 +50,11 @@
          allowResidue = true,
          mustRunInWorkspace = false,
          shortDescription = "Prints help for commands, or the index.",
+         completion = "command|{startup_options,target-syntax,info-keys}",
          help = "resource:help.txt")
 public final class HelpCommand implements BlazeCommand {
+  private static final Joiner SPACE_JOINER = Joiner.on(" ");
+
   public static class Options extends OptionsBase {
 
     @Option(name = "help_verbosity",
@@ -151,6 +156,9 @@
     } else if (helpSubject.equals("info-keys")) {
       emitInfoKeysHelp(runtime, outErr);
       return ExitCode.SUCCESS;
+    } else if (helpSubject.equals("completion")) {
+      emitCompletionHelp(runtime, outErr);
+      return ExitCode.SUCCESS;
     }
 
     BlazeCommand command = runtime.getCommandMap().get(helpSubject);
@@ -195,6 +203,42 @@
         helpVerbosity));
   }
 
+  private void emitCompletionHelp(BlazeRuntime runtime, OutErr outErr) {
+    // First startup_options
+    Iterable<BlazeModule> blazeModules = runtime.getBlazeModules();
+    ConfiguredRuleClassProvider ruleClassProvider = runtime.getRuleClassProvider();
+    Map<String, BlazeCommand> commandsByName = runtime.getCommandMap();
+    Set<String> commands = commandsByName.keySet();
+
+    outErr.printOutLn("BAZEL_COMMAND_LIST=\"" + SPACE_JOINER.join(commands) + "\"");
+
+    outErr.printOutLn("BAZEL_INFO_KEYS=\"");
+    for (InfoKey key : InfoKey.values()) {
+        outErr.printOutLn(key.getName());
+    }
+    outErr.printOutLn("\"");
+
+    outErr.printOutLn("BAZEL_STARTUP_OPTIONS=\"");
+    Iterable<Class<? extends OptionsBase>> options =
+        BlazeCommandUtils.getStartupOptions(blazeModules);
+    outErr.printOut(OptionsParser.newOptionsParser(options).getOptionsCompletion());
+    outErr.printOutLn("\"");
+
+    for (String name : commands) {
+      BlazeCommand command = commandsByName.get(name);
+      String varName = name.toUpperCase().replace("-", "_");
+      Command annotation = command.getClass().getAnnotation(Command.class);
+      if (!annotation.completion().isEmpty()) {
+        outErr.printOutLn("BAZEL_COMMAND_" + varName + "_ARGUMENT=\""
+            + annotation.completion() + "\"");
+      }
+      options = BlazeCommandUtils.getOptions(command.getClass(), blazeModules, ruleClassProvider);
+      outErr.printOutLn("BAZEL_COMMAND_" + varName + "_FLAGS=\"");
+      outErr.printOut(OptionsParser.newOptionsParser(options).getOptionsCompletion());
+      outErr.printOutLn("\"");
+    }
+  }
+
   private void emitTargetSyntaxHelp(OutErr outErr, ImmutableMap<String, String> optionCategories) {
     outErr.printOut(BlazeCommandUtils.expandHelpTopic("target-syntax",
                                     "resource:target-syntax.txt",
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
index 2d0e720..2448d90 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java
@@ -73,6 +73,7 @@
          help = "resource:info.txt",
          shortDescription = "Displays runtime info about the %{product} server.",
          options = { InfoCommand.Options.class },
+         completion = "info-key",
          // We have InfoCommand inherit from {@link BuildCommand} because we want all
          // configuration defaults specified in ~/.blazerc for {@code build} to apply to
          // {@code info} too, even though it doesn't actually do a build.
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
index 08cb072..298768c 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java
@@ -69,6 +69,7 @@
          shortDescription = "Analyzes build profile data.",
          help = "resource:analyze-profile.txt",
          allowResidue = true,
+         completion = "path",
          mustRunInWorkspace = false)
 public final class ProfileCommand implements BlazeCommand {
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
index 7b54eb1..b8f4981 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java
@@ -54,6 +54,7 @@
          shortDescription = "Executes a dependency graph query.",
          allowResidue = true,
          binaryStdOut = true,
+         completion = "label",
          canRunInOutputDirectory = true)
 public final class QueryCommand implements BlazeCommand {
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
index 81f0cb2..715ef0e 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
@@ -78,6 +78,7 @@
          help = "resource:run.txt",
          allowResidue = true,
          binaryStdOut = true,
+         completion = "label-bin",
          binaryStdErr = true)
 public class RunCommand implements BlazeCommand  {
 
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
index 0d2ee2e..6e9ddc7 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java
@@ -53,6 +53,7 @@
          options = { TestSummaryOptions.class },
          shortDescription = "Builds and runs the specified test targets.",
          help = "resource:test.txt",
+         completion = "label-test",
          allowResidue = true)
 public class TestCommand implements BlazeCommand {
   private AnsiTerminalPrinter printer;
diff --git a/src/main/java/com/google/devtools/common/options/OptionsParser.java b/src/main/java/com/google/devtools/common/options/OptionsParser.java
index 9564daa..4eb5ce2 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsParser.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsParser.java
@@ -417,6 +417,29 @@
   }
 
   /**
+   * Returns a string listing the possible flag completion for this command along with the command
+   * completion if any. See {@link OptionsUsage#getCompletion(Field, StringBuilder)} for more
+   * details on the format for the flag completion.
+   */
+  public String getOptionsCompletion() {
+    StringBuilder desc = new StringBuilder();
+
+    // List all options
+    List<Field> allFields = Lists.newArrayList();
+    for (Class<? extends OptionsBase> optionsClass : impl.getOptionsClasses()) {
+      allFields.addAll(impl.getAnnotatedFieldsFor(optionsClass));
+    }
+    for (Field optionField : allFields) {
+      String category = optionField.getAnnotation(Option.class).category();
+      if (documentationLevel(category) == DocumentationLevel.DOCUMENTED) {
+        OptionsUsage.getCompletion(optionField, desc);
+      }
+    }
+
+    return desc.toString();
+  }
+
+  /**
    * Returns a description of the option value set by the last previous call to
    * {@link #parse(OptionPriority, String, List)} that successfully set the given
    * option. If the option is of type {@link List}, the description will
diff --git a/src/main/java/com/google/devtools/common/options/OptionsUsage.java b/src/main/java/com/google/devtools/common/options/OptionsUsage.java
index c48a532..fdd997c 100644
--- a/src/main/java/com/google/devtools/common/options/OptionsUsage.java
+++ b/src/main/java/com/google/devtools/common/options/OptionsUsage.java
@@ -15,6 +15,7 @@
 
 import static com.google.devtools.common.options.OptionsParserImpl.findConverter;
 
+import com.google.common.base.Joiner;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
@@ -31,6 +32,7 @@
 class OptionsUsage {
 
   private static final Splitter NEWLINE_SPLITTER = Splitter.on('\n');
+  private static final Joiner COMMA_JOINER = Joiner.on(",");
 
   /**
    * Given an options class, render the usage string into the usage,
@@ -124,6 +126,57 @@
     }
   }
 
+  /**
+   * Returns the available completion for the given option field. The completions are the exact
+   * command line option (with the prepending '--') that one should pass. It is suitable for
+   * completion script to use. If the option expect an argument, the kind of argument is given
+   * after the equals. If the kind is a enum, the various enum values are given inside an accolade
+   * in a comma separated list. For other special kind, the type is given as a name (e.g.,
+   * <code>label</code>, <code>float</ode>, <code>path</code>...). Example outputs of this
+   * function are for, respectively, a tristate flag <code>tristate_flag</code>, a enum
+   * flag <code>enum_flag</code> which can take <code>value1</code>, <code>value2</code> and
+   * <code>value3</code>, a path fragment flag <code>path_flag</code>, a string flag
+   * <code>string_flag</code> and a void flag <code>void_flag</code>:
+   * <pre>
+   *   --tristate_flag={auto,yes,no}
+   *   --notristate_flag
+   *   --enum_flag={value1,value2,value3}
+   *   --path_flag=path
+   *   --string_flag=
+   *   --void_flag
+   * </pre>
+   *
+   * @param field The field to return completion for
+   * @param builder the string builder to store the completion values
+   */
+  static void getCompletion(Field field, StringBuilder builder) {
+    // Return the list of possible completions for this option
+    String flagName = field.getAnnotation(Option.class).name();
+    Class<?> fieldType = field.getType();
+    builder.append("--").append(flagName);
+    if (fieldType.equals(boolean.class)) {
+      builder.append("\n");
+      builder.append("--no").append(flagName).append("\n");
+    } else if (fieldType.equals(TriState.class)) {
+      builder.append("={auto,yes,no}\n");
+      builder.append("--no").append(flagName).append("\n");
+    } else if (fieldType.isEnum()) {
+      builder.append("={")
+          .append(COMMA_JOINER.join(fieldType.getEnumConstants()).toLowerCase()).append("}\n");
+    } else if (fieldType.getSimpleName().equals("Label")) {
+      // String comparison so we don't introduce a dependency to com.google.devtools.build.lib.
+      builder.append("=label\n");
+    } else if (fieldType.getSimpleName().equals("PathFragment")) {
+      builder.append("=path\n");
+    } else if (Void.class.isAssignableFrom(fieldType)) {
+      builder.append("\n");
+    } else {
+      // TODO(bazel-team): add more types. Maybe even move the completion type
+      // to the @Option annotation?
+      builder.append("=\n");
+    }
+  }
+
   private static final Comparator<Field> BY_NAME = new Comparator<Field>() {
     @Override
     public int compare(Field left, Field right) {