Airline provides a comprehensive system of help generators that are able to take Airline defined CLIs and output help in a variety of formats. The help system is divided into a number of concepts which cooperate together to make help configurable and extensible.
Help Hints are a mechanism by which Restrictions can provide information about their behaviour. This allows for restrictions to be self-documenting and incorporated into help output.
Hints are also used as part of Help Sections.
Help Sections are a mechanism by which @Command
annotated classes can
add additional sections into help output. This can be used to incorporate arbitrary additional content into your help
outputs.
A variety of common help sections are provided out of the box and you can create Custom Help Sections if desired:
@Copyright
annotation adds a copyright statement@Discussion
/@ExternalDiscussion
annotations add extended discussion@ExitCodes
/@ExternalExitCodes
annotations adds documentation on exit codes@Examples
/@ExternalExamples
/@ExternalTabularExamples
annotations add usage examples@HideSection
annotation is used to hide an inherited help section@License
annotation adds a license statement@ProseSection
/@ExternalProse
annotations adds custom titled text sections@Version
annotation adds a version statementHelp Generators are classes that take in CLI/Command metadata and output help in some format. The core library includes Text based help generators and additional libraries provide Markdown, HTML, MAN and Bash format help.
In order to generate help you need to create an instance of your desired generator and then pass in the metadata for your CLI/Command e.g.
Cli<ExampleRunnable> cli = new Cli<ExampleRunnable>(ShipItCli.class);
CliGlobalUsageGenerator<ExampleRunnable> helpGenerator = new CliGlobalUsageGenerator<>();
try {
helpGenerator.usage(cli.getMetadata(), System.out);
} catch (IOException e) {
e.printStackTrace();
}
In this example we output the help to System.out
but we could pass any OutputStream
we desired.
For single commands we could use CliCommandUsageGenerator
instead.
Airline provides a couple of ways you can incorporate help into your CLIs/commands to make this easily accessible to your end users.
HelpOption
For single commands you can add the HelpOption
to your command classes e.g.
@Command(name = "parent", description = "A parent command")
public class Parent implements ExampleRunnable {
@AirlineModule
protected HelpOption<ExampleRunnable> help;
@Option(name = "--parent", description = "An option provided by the parent")
private boolean parent;
public static void main(String[] args) {
ExampleExecutor.executeSingleCommand(Parent.class, args);
}
@Override
public int run() {
if (!help.showHelpIfRequested()) {
System.out.println("--parent was " + (this.parent ? "set" : "not set"));
}
return 0;
}
}
We use our normal Composition mechanism to add in HelpOption
to our command class. This will
provide a -h
/--help
option in our command. We can then use the help.showHelpIfRequested()
method to check whether
help was requested and if not proceed normally. If this method returns true
then help has been requested and output
to the user.
Help
classThe Help
class is a pre-built @Command
class that provides intelligent help for CLIs. You can simply add this to
your CLIs as one of your commands and it will add a help
command to your CLI. This command will select the
appropriate help to display depending on the arguments provided. For example calling your-cli help
will display help
for the entire CLI, whereas calling your-cli help your-command
will display command specific help for your-command
.
If you can’t incorporate Help
directly as a command because it does not extend/implement the base command type for
your CLI you can still use it indirectly. If you are using a base interface then you can simply extend the class and
add implements YourInterface
plus any necessary implementation deferring to the run()
method e.g.
public class CustomHelpCommand extends Help implements YourInterface {
@Override
public void yourMethod() {
super.run();
}
}
Alternatively the class also provides a number of static methods that you can call from your own command if you can’t extend it, for example when using a base class for your commands, e.g.
Help.help(cli.getMetadata(), args, System.out)
Where args
is a List<String>
containing the command name(s) that help is being requested on. So for our earlier
example we might call the following:
Help.help(cli.getMetadata(), Collections.singletonList("your-command"), System.out)
Note that when trying to incorporate help into a CLI one common problem that occurs is that you add restrictions which
end up get violated when users try to just invoke help on your commands. This is particularly the case when using
HelpOption
. To avoid this you will need to customise the error handler as discussed in the Error
Handling documentation and do something like the following:
public static void main(String[] args) {
com.github.rvesse.airline.Cli<ExampleRunnable> cli = new com.github.rvesse.airline.Cli<ExampleRunnable>(ShipItCli.class);
try {
// Parse with a result to allow us to inspect the results of parsing
ParseResult<ExampleRunnable> result = cli.parseWithResult(args);
if (result.wasSuccessful()) {
// Parsed successfully, so just run the command and exit
System.exit(result.getCommand().run());
} else {
// Parsing failed
// Display errors and then the help information
System.err.println(String.format("%d errors encountered:", result.getErrors().size()));
int i = 1;
for (ParseException e : result.getErrors()) {
System.err.println(String.format("Error %d: %s", i, e.getMessage()));
i++;
}
System.err.println();
com.github.rvesse.airline.help.Help.<ExampleRunnable>help(cli.getMetadata(), Arrays.asList(args), System.err);
}
} catch (Exception e) {
// Errors should be being collected so if anything is thrown it is unexpected
System.err.println(String.format("Unexpected error: %s", e.getMessage()));
e.printStackTrace(System.err);
}
// If we got here we are exiting abnormally
System.exit(1);
}
This documentation is itself open source and lives in GitHub under the docs/ directory.
I am not a professional technical writer and as the developer of this software I can often make assumptions of
knowledge that you as a user reading this may not have. Improvements to the documentation are always welcome, if you
have suggestions for the documentation please submit pull requests to the main
branch.