New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically print usage/version when help option specified on command line #161

Closed
remkop opened this Issue Aug 5, 2017 · 2 comments

Comments

Projects
None yet
1 participant
@remkop
Owner

remkop commented Aug 5, 2017

A commonly requested feature ( #151, #145 ) is to automatically print usage help when an option annotated with the help=true attribute was specified on the command line. However, the semantics of the @Option(help=true) attribute is only to stop validation (to prevent "missing required option" errors). Picocli doesn't know whether to print usage help or version information, for example.

#145 introduced two new @Option attributes: usageHelp and versionHelp.

This ticket proposes two additional @Command attributes:

  • autoPrintHelp
  • version

The version attribute is a string, intended to be used by Command authors to specify version information. The CommandLine class will have an additional method commandVersion(PrintStream) that prints the version information from the annotated domain object to the specified stream.

The autoPrintHelp attribute is an enum with values: OFF, STDOUT and STDERR.

Example usage:

@Command(version = "MyCommand v1.2.3", autoPrintHelp = CommandLine.Stream.STDOUT)
class MyCommand {
    @Option(names = {"-V", "--version"}, versionHelp=true, description = "print version information and exit")
    private boolean version;

    @Option(names = { "-h", "--help"}, usageHelp=true, description = "print usage help and exit")
    private boolean help;
}

// All of the below invocations result in the usage help being printed to standard out,
// without any need for the application to explicitly call CommandLine.usage():

CommandLine.populateCommand(new MyCommand(), "-h");
CommandLine.run(new MyCommand(), "-h");
new CommandLine(new MyCommand()).parse("-h");
@remkop

This comment has been minimized.

Show comment
Hide comment
@remkop

remkop Aug 5, 2017

Owner

Potential problem

Users want to either execute the command or ask for help about the command, but not both. How can we avoid doing both?

If autoPrintHelp is on, can picocli prevent the application from executing when help/version info was printed?

  1. GOOD: CommandLine.run(Runnable, String...):
    • picocli could skip the call to Runnable:run if it printed help.
  2. POSSIBLE: CommandLine.parse(String...) returns a list of CommandLine objects.
    • One idea is to return an empty list if help/version info was printed.
  3. POSSIBLE: CommandLine.populateCommand(Object, String...):
    • One idea is to return null if help/version info was printed.

Is this a good trade-off?

This raises the question whether it is really a good idea to automatically print usage help/version info...

Before

The objective was to allow application authors to omit code like

if (isHelpRequested) {
    CommandLine.usage(this, System.out);
    return;
}

After

After adding a bunch of code: two annotation attributes (autoPrintHelp and version) and a Stream enum (OFF, STDERR and STDOUT), application authors still need to write code like this:

List<CommandLine> parsedCommands = new CommandLine(new App()).parse(args);
if (parsedCommands.isEmpty()) {
    return; // help or version was printed
}

or

App app = CommandLine.populateCommand(new App(), args);
if (app == null) {
    return;  // help or version was printed
}

This does not seem like an improvement...

Conclusion

Perhaps autoPrintHelp is not a good idea after all?

  • We have more complexity but did not gain more convenience. The application still requires if/else conditionals, but with autoPrintHelp it is no longer obvious why this if/else is necessary... It is not intuitively obvious that parse returns an empty list when usage help was printed.
  • Fragile (mistakes cost more): NullPointerException or IndexOutOfBoundsException if we forget to check the parse result.
  • Fragile (multiple places to change): Suppose the application author changes the annotation value of autoPrintHelp to OFF. Now the application is broken unless the author also adds code to print help and abort execution if help was requested. (So changes are required in two places instead of just one.)
Owner

remkop commented Aug 5, 2017

Potential problem

Users want to either execute the command or ask for help about the command, but not both. How can we avoid doing both?

If autoPrintHelp is on, can picocli prevent the application from executing when help/version info was printed?

  1. GOOD: CommandLine.run(Runnable, String...):
    • picocli could skip the call to Runnable:run if it printed help.
  2. POSSIBLE: CommandLine.parse(String...) returns a list of CommandLine objects.
    • One idea is to return an empty list if help/version info was printed.
  3. POSSIBLE: CommandLine.populateCommand(Object, String...):
    • One idea is to return null if help/version info was printed.

Is this a good trade-off?

This raises the question whether it is really a good idea to automatically print usage help/version info...

Before

The objective was to allow application authors to omit code like

if (isHelpRequested) {
    CommandLine.usage(this, System.out);
    return;
}

After

After adding a bunch of code: two annotation attributes (autoPrintHelp and version) and a Stream enum (OFF, STDERR and STDOUT), application authors still need to write code like this:

List<CommandLine> parsedCommands = new CommandLine(new App()).parse(args);
if (parsedCommands.isEmpty()) {
    return; // help or version was printed
}

or

App app = CommandLine.populateCommand(new App(), args);
if (app == null) {
    return;  // help or version was printed
}

This does not seem like an improvement...

Conclusion

Perhaps autoPrintHelp is not a good idea after all?

  • We have more complexity but did not gain more convenience. The application still requires if/else conditionals, but with autoPrintHelp it is no longer obvious why this if/else is necessary... It is not intuitively obvious that parse returns an empty list when usage help was printed.
  • Fragile (mistakes cost more): NullPointerException or IndexOutOfBoundsException if we forget to check the parse result.
  • Fragile (multiple places to change): Suppose the application author changes the annotation value of autoPrintHelp to OFF. Now the application is broken unless the author also adds code to print help and abort execution if help was requested. (So changes are required in two places instead of just one.)
@remkop

This comment has been minimized.

Show comment
Hide comment
@remkop

remkop Aug 5, 2017

Owner

That said, adding a @Command version attribute and a CommandLine:printCommandVersion(PrintStream) method still seem useful ideas. I created a separate ticket #162 for this.

Owner

remkop commented Aug 5, 2017

That said, adding a @Command version attribute and a CommandLine:printCommandVersion(PrintStream) method still seem useful ideas. I created a separate ticket #162 for this.

@remkop remkop added the wontfix label Aug 5, 2017

@remkop remkop closed this Aug 5, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment