Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

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.

Code Block
// 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 main(cmd(String... args) {	
	NameAndType nat = m_prompt.ask(NameAndType.class, values);
 
	System.out.println("N: " + nat.name());
	System.out.println("T: " + nat.type());args);
	// arguments are available as nat.name():String and nat.type():FQN
Code Block
// 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.

...

Annotated arguments

Code Block
// Simple case: one set of parameters, no interactivity
@Command()
public void maincmd(@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
Code Block
// 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.
  • Easy 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)

Code Block
@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...)