We discussed several approaches to declare arguments for commands. There are three use cases that must be supported.
- Interactive shell:
- commands should feature argument completion
- commands should allow interactive prompts
- Bndtools UI
- arguments should be grouped
- interactive prompts should be converted into multiple pages of a wizard
- Scripts
- commands should be able to run without interaction (so all optional arguments should be supplied)
- slightly related, if commands retain some kind of state, that state should be CommandSession scoped (note that this is not script specific, but will become an issue once scripts are being executed)
Metatype interfaces
In this approach the arguments are grouped in interfaces.
// Simple case: one set of parameters, no interactivity @Meta.OCD interface NameAndType { enum TYPE { CLASS, INTERFACE }; @Meta.AD(name="FQN", description="The fully qualified name of the class.") FQN name(); @Meta.AD(description="The type (class or interface)") TYPE type(); } @Command() public void cmd(String... args) { NameAndType nat = m_prompt.ask(NameAndType.class, args); // arguments are available as nat.name():String and nat.type():FQN
// Complex case: multiple sets of parameters, with interactivity @Meta.OCD interface NameAndType { enum TYPE { CLASS, INTERFACE }; @Meta.AD(name="FQN", description="The fully qualified name of the class.") FQN name(); @Meta.AD(description="The type (class or interface)") TYPE type(); } @Meta.OCD interface DefaultMethods { @Meta.AD(description="generate toString method?") boolean string(); @Meta.AD(description="generate equals method?") boolean equals(); @Meta.AD(description="generate hashCode method?") boolean hashcode(); } @Command() public void cmd(String... args) { NameAndType nat = m_prompt.ask(NameAndType.class, args); if (nat.type().equals(CLASS)) { DefaultMethods methods = m_prompt.ask(DefaultMethods.class, args); }
Scripting can be implemented by recording arguments before executing the command.
Upsides:
- Questions are grouped, this is ideal for generating wizards in Bndtools
Downsides:
- The questions are "disconnected" from the command implementations. This is less obvious to program.
- Difficult to support command completion
Annotated arguments
// Simple case: one set of parameters, no interactivity @Command() public void cmd(@Argument(name="name", description="The fully qualified name of the class.") String name, @Argument(description="The type (class or interface)") FQN type) { // arguments are available as name:String and type:FQN
// Complex case: multiple sets of parameters, with interactivity @Command() public void cmd(@Argument(name="name", description="The fully qualified name of the class.") String name, @Argument(description="The type (class or interface)") FQN type) { if (type.equals(CLASS)) { boolean genString = m_prompt.ask("generate toString method?", Boolean.class, "string"); boolean genEquals = m_prompt.ask("generate equals method?", Boolean.class, "equals"); boolean genHashcode = m_prompt.ask("generate hashCode method?", Boolean.class, "hashcode");
Scripting can be implemented by recording arguments before executing the command.
Upsides:
- Obvious to implement.
- Relatively easy to support both passing arguments immediately, and asking the user for answers during execution of the command, you just write different implementations of your method.
- Easy to implement argument completion for the initial set of arguments and the interactive prompts separately, hard to do completion on a single command line for all possible arguments.
Downsides:
- No way to group questions, besides just showing all of them in the same wizard. Note that this is only a problem when multiple wizard pages are required in Bndtools (the complex case).
- No argument completion for the total set of options.
Metatype interfaces with DSL (TODO)
@Meta.OCD interface Q1 { String first(); String last(); @Condition("last=Bakker") Q2 email(); } interface Q2 { String email(); } @Command public void cmd(@Prompt(Q1.class) String... args) { Q1 q = ask(Q1.class, args); // Q1 and Q2 are available for processing
(have to go now, more later...)