aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools
diff options
context:
space:
mode:
authorGravatar Damien Martin-Guillerez <dmarting@google.com>2015-04-09 20:48:04 +0000
committerGravatar Ulf Adams <ulfjack@google.com>2015-04-10 08:02:30 +0000
commit29728d4c37721aa88621a8578a7c2d7bfe8b5c68 (patch)
treeb01b6032585956f1ce4312b54aab745fca2de59c /src/main/java/com/google/devtools
parent6379d2e4dc41bf32dfada75a001c39684083acd6 (diff)
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
Diffstat (limited to 'src/main/java/com/google/devtools')
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/Command.java9
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/BuildCommand.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/HelpCommand.java44
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/InfoCommand.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/ProfileCommand.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/QueryCommand.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java1
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/commands/TestCommand.java1
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsParser.java23
-rw-r--r--src/main/java/com/google/devtools/common/options/OptionsUsage.java53
10 files changed, 135 insertions, 0 deletions
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 1797cd3b46..318e3e419b 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 @@ public @interface Command {
*/
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 d6f61eb494..94a0ada3d3 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 @@ import java.util.List;
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 0539da5e44..227227f7af 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.ArrayList;
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 @@ import java.util.Map;
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 @@ public final class HelpCommand implements BlazeCommand {
} 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 @@ public final class HelpCommand implements BlazeCommand {
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 2d0e720b17..2448d90aca 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 @@ import java.util.TreeMap;
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 08cb072a9b..298768c197 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 @@ import java.util.Map;
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 7b54eb1bd0..b8f4981f78 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 @@ import java.util.Set;
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 81f0cb26e1..715ef0e385 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 @@ import java.util.List;
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 0d2ee2e1a7..6e9ddc7772 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 @@ import java.util.List;
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 9564daa5a1..4eb5ce28a5 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 @@ public class OptionsParser implements OptionsProvider {
}
/**
+ * 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 c48a53295c..fdd997c6cb 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 @@ package com.google.devtools.common.options;
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 @@ import java.util.List;
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 @@ class OptionsUsage {
}
}
+ /**
+ * 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) {