Files
picocli/docs/index.adoc
2019-11-27 00:35:36 +09:00

5380 lines
221 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
= picocli - a mighty tiny command line interface
//:author: Remko Popma
//:email: rpopma@apache.org
:revnumber: 4.1.2-SNAPSHOT
:revdate: 2019-11-27
:toc: left
:numbered:
:toclevels: 2
:toc-title: Features
:source-highlighter: coderay
//:source-highlighter: highlightjs
//:highlightjs-theme: darkula
:icons: font
:imagesdir: images
[link=https://github.com/remkop/picocli]
image::https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png[Fork me on GitHub,float="right"]
++++
<iframe src="https://ghbtns.com/github-btn.html?user=remkop&repo=picocli&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" style="float:right"></iframe>
++++
[quote]
Every main method deserves picocli!
image:logo/horizontal.png[picocli the Mighty Tiny Command Line Interface,width=800]
The user manual for the latest release is at http://picocli.info.
For the busy and impatient: there is also a link:quick-guide.html[Quick Guide].
== Introduction
Picocli aims to be the easiest way to create rich command line applications that can run on and off the JVM.
Picocli is a one-file framework for creating Java command line applications with almost zero code.
Supports a variety of command line syntax styles including POSIX, GNU, MS-DOS and more.
Generates highly customizable usage help messages with <<ANSI Colors and Styles,ANSI colors and styles>>.
Picocli-based applications can have link:autocomplete.html[command line TAB completion] showing available options, option parameters and subcommands, for any level of nested subcommands.
Picocli-based applications can be ahead-of-time compiled to image:https://www.graalvm.org/resources/img/logo-colored.svg[GraalVM]
<<GraalVM Native Image,native images>>, with extremely fast startup time and lower memory requirements, which can be distributed as a single executable file.
image:checksum-usage-help.png[Screenshot of usage help with Ansi codes enabled]
Another distinguishing feature of picocli is how it aims
to let users run picocli-based applications without requiring picocli as an external dependency:
all the source code lives in a single file, to encourage application authors to include it _in source form_.
How it works: annotate your class and picocli initializes it from the command line arguments,
converting the input to strongly typed values in the fields of your class.
.A full working example picocli-based command line application
[[CheckSum-application]]
[source,java]
----
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
import java.math.BigInteger;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.util.concurrent.Callable;
@Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0",
description = "Prints the checksum (MD5 by default) of a file to STDOUT.")
class CheckSum implements Callable<Integer> {
@Parameters(index = "0", description = "The file whose checksum to calculate.")
private File file;
@Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
private String algorithm = "MD5";
// this example implements Callable, so parsing, error handling and handling user
// requests for usage help or version help can be done with one line of code.
public static void main(String... args) {
int exitCode = new CommandLine(new CheckSum()).execute(args);
System.exit(exitCode);
}
@Override
public Integer call() throws Exception { // your business logic goes here...
byte[] fileContents = Files.readAllBytes(file.toPath());
byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
System.out.printf("%0" + (digest.length*2) + "x%n", new BigInteger(1, digest));
return 0;
}
}
----
Implement `Runnable` or `Callable`, and your command can be <<Executing Commands,executed>> in one line of code.
The example above uses the `CommandLine.execute` method
to parse the command line, handle errors, handle requests for usage and version help, and invoke the business logic.
Applications can call `System.exit` with the returned exit code to signal success or failure to their caller.
The <<Mixin Standard Help Options,mixinStandardHelpOptions>> attribute adds `--help` and `--version` options to your application.
== Getting Started
You can add picocli as an external dependency to your project, or you can include it as source.
=== Add as External Dependency
Below are examples of configuring Gradle or Maven to use picocli as an external dependency in your project.
==== Gradle
----
compile 'info.picocli:picocli:4.1.2-SNAPSHOT'
----
==== Maven
----
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.1.2-SNAPSHOT</version>
</dependency>
----
=== Add as Source
To include as source, get the source code from the link:https://github.com/remkop/picocli/blob/master/src/main/java/picocli/CommandLine.java[GitHub file]. Copy and paste it into a file called `CommandLine.java`, add it to your project, and enjoy!
=== Annotation Processor
The `picocli-codegen` module includes an annotation processor that can build a model from the picocli annotations at compile time rather than at runtime.
Enabling this annotation processor in your project is optional, but strongly recommended. Use this if youre interested in:
* **Compile time error checking**. The annotation processor shows errors for invalid annotations and attributes immediately when you compile, instead of during testing at runtime, resulting in shorter feedback cycles.
* **Graal native images**. The annotation processor generates and updates https://github.com/oracle/graal/blob/master/substratevm/CONFIGURE.md[Graal configuration] files under
`META-INF/native-image/picocli-generated/$project` during compilation, to be included in the application jar.
This includes configuration files for https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md[reflection], https://github.com/oracle/graal/blob/master/substratevm/RESOURCES.md[resources] and https://github.com/oracle/graal/blob/master/substratevm/DYNAMIC_PROXY.md[dynamic proxies].
By embedding these configuration files, your jar is instantly Graal-enabled.
In most cases no further configuration is needed when generating a native image.
==== Processor option: `project`
The picocli annotation processor supports a number of https://github.com/remkop/picocli/tree/master/picocli-codegen#picocli-processor-options[options], most important of which is the `project` option to control the output subdirectory: the generated files are written to `META-INF/native-image/picocli-generated/${project}`. A good convention is to use the Maven `${groupId}/${artifactId}` as the value; a unique subdirectory ensures your jar can be shaded with other jars that may also contain generated configuration files.
To configure this option, pass the `-Aproject=<some value>` to the javac compiler. The examples below show how to do this for Maven and Gradle.
==== Enabling the Annotation Processor
===== IDE
https://immutables.github.io/apt.html[This page] shows the steps to configure Eclipse and IntelliJ IDEA to enable annotation processing.
===== Maven
```
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- annotationProcessorPaths requires maven-compiler-plugin version 3.5 or higher -->
<version>${maven-compiler-plugin-version}</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
<version>4.1.2-SNAPSHOT</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Aproject=${groupId}/${artifactId}</arg>
</compilerArgs>
</configuration>
</plugin>
```
See the https://github.com/remkop/picocli/tree/master/picocli-codegen[`picocli-codegen` README] for more details.
===== Gradle
```
dependencies {
compile 'info.picocli:picocli:4.1.2-SNAPSHOT'
annotationProcessor 'info.picocli:picocli-codegen:4.1.2-SNAPSHOT'
}
```
```
compileJava {
options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
}
```
See the https://github.com/remkop/picocli/tree/master/picocli-codegen[`picocli-codegen` README] for more details.
== Options and Parameters
Command line arguments can be separated into _options_ and _positional parameters_.
Options have a name, positional parameters are usually the values that follow the options,
but they may be mixed.
image:OptionsAndParameters2.png[Example command with annotated @Option and @Parameters]
Picocli has separate annotations for options and positional parameters.
=== Options
An option must have one or more `names`.
Picocli lets you use any option name you want.
TIP: You may be interested in this http://catb.org/~esr/writings/taoup/html/ch10s05.html#id2948149[list of common option names]. Following these conventions may make your application more intuitive to use for experienced users.
The below example shows options with one or more names, options that take an option parameter, and a <<Help Options,help>> option.
[source,java]
----
class Tar {
@Option(names = "-c", description = "create a new archive")
boolean create;
@Option(names = { "-f", "--file" }, paramLabel = "ARCHIVE", description = "the archive file")
File archive;
@Parameters(paramLabel = "FILE", description = "one ore more files to archive")
File[] files;
@Option(names = { "-h", "--help" }, usageHelp = true, description = "display a help message")
private boolean helpRequested = false;
}
----
Picocli matches the option names to set the field values.
[source,java]
----
String[] args = { "-c", "--file", "result.tar", "file1.txt", "file2.txt" };
Tar tar = new Tar();
new CommandLine(tar).parseArgs(args);
assert !tar.helpRequested;
assert tar.create;
assert tar.archive.equals(new File("result.tar"));
assert Arrays.equals(tar.files, new File[] {new File("file1.txt"), new File("file2.txt")});
----
=== Interactive (Password) Options
Picocli 3.5 introduced password support: for options and positional parameters marked as `interactive`, the user is prompted to enter a value on the console.
When running on Java 6 or higher, picocli will use the https://docs.oracle.com/javase/8/docs/api/java/io/Console.html#readPassword-java.lang.String-java.lang.Object...-[`Console.readPassword`] API so that user input is not echoed to the console.
CAUTION: Interactive _positional parameters_ have a limitation: they must be followed by a non-interactive positional parameter.
Commands where the _last_ positional parameter is `interactive` are currently not supported.
==== Example
The example below demonstrates how an interactive option can be used to specify a password.
From picocli 3.9.6, interactive options can use type `char[]` instead of String, to allow applications to null out the array after use so that sensitive information is no longer resident in memory.
Example usage:
[source,java]
----
class Login implements Callable<Integer> {
@Option(names = {"-u", "--user"}, description = "User name")
String user;
@Option(names = {"-p", "--password"}, description = "Passphrase", interactive = true)
char[] password;
public Integer call() throws Exception {
byte[] bytes = new byte[password.length];
for (int i = 0; i < bytes.length; i++) { bytes[i] = (byte) password[i]; }
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes);
System.out.printf("Hi %s, your password is hashed to %s.%n", user, base64(md.digest()));
// null out the arrays when done
Arrays.fill(bytes, (byte) 0);
Arrays.fill(password, ' ');
return 0;
}
private String base64(byte[] arr) { /* ... */ }
}
----
When this command is invoked like this:
[source,java]
----
new CommandLine(new Login()).execute("-u", "user123", "-p");
----
Then the user will be prompted to enter a value:
[source]
----
Enter value for --password (Passphrase):
----
When running on Java 6 or higher, the user input is not echoed to the console.
After the user enters a password value and presses enter, the `call()` method is invoked, which prints something like the following:
[source]
----
Hi user123, your passphrase is hashed to 75K3eLr+dx6JJFuJ7LwIpEpOFmwGZZkRiB84PURz6U8=.
----
==== Optionally Interactive
Interactive options by default cause the application to wait for input on stdin. For commands that need to be run interactively as well as in batch mode, it is useful if the option can optionally consume an argument from the command line.
The default <<Arity,arity>> for interactive options is zero, meaning that the option takes no parameters. From picocli 3.9.6, interactive options can also take a value from the command line if configured with `arity = "0..1"`.
For example, if an application has these options:
```java
@Option(names = "--user")
String user;
@Option(names = "--password", arity = "0..1", interactive = true)
char[] password;
```
With the following input, the `password` field will be initialized to `"123"` without prompting the user for input:
```
--password 123 --user Joe
```
However, if the password is not specified, the user will be prompted to enter a value. In the following example, the password option has no parameter, so the user will be prompted to type in a value on the console:
```
--password --user Joe
```
[TIP]
.Providing Passwords to Batch Scripts Securely
====
Note that specifying a password in plain text on the command line or in scripts is not secure. There are alternatives that are more secure.
One idea is to add a separate different option (that could be named `--password:file`) that takes a `File` or `Path` parameter, where the application reads the password from the specified file.
Another idea is to add a separate different option (that could be named `--password:env`) that takes an environment variable name parameter, where the application gets the password from the users environment variables.
A command that combines either of these with an interactive `--password` option (with the default `arity = "0"`) allows end users to provide a password without specifying it in plain text on the command line. Such a command can be executed both interactively and in batch mode.
The `picocli-examples` module has https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/interactive/PasswordDemo.java[an example].
====
[CAUTION]
.Interactive options and shell applications with JLine 2
====
Interactive options do not work in conjuction with JLine 2's `ConsoleReader`. Either implement a <<Custom Parameter Processing,`IParameterConsumer`>> which uses JLine2's `ConsoleReader` directly or use `picocli-shell-jline3`.
====
=== Short (POSIX) Options
Picocli supports http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02[POSIX clustered short options]:
one or more single-character options without option-arguments, followed by at most one option with an option-argument, can be grouped behind one '-' delimiter.
For example, given this annotated class:
[source,java]
----
class ClusteredShortOptions {
@Option(names = "-a") boolean aaa;
@Option(names = "-b") boolean bbb;
@Option(names = "-c") boolean ccc;
@Option(names = "-f") String file;
}
----
The following command line arguments are all equivalent and parsing them will give the same result:
[source,java]
----
<command> -abcfInputFile.txt
<command> -abcf=InputFile.txt
<command> -abc -f=InputFile.txt
<command> -ab -cf=InputFile.txt
<command> -a -b -c -fInputFile.txt
<command> -a -b -c -f InputFile.txt
<command> -a -b -c -f=InputFile.txt
...
----
=== Boolean Options
Boolean options usually don't need a parameter: it is enough to specify the option name on the command line.
[source,java]
----
class BooleanOptions {
@Option(names = "-x") boolean x;
}
----
The value of `x` is `false` by default, and is set to `true` (the opposite of the default) if the `-x` option is specified on the command line.
If the `-x` option is specified multiple times on the command line, the value of `x` remains `true`. (Prior to picocli 4.0, the value of `x` would "toggle" (flip to its opposite) for every `-x` option on the command line. This can still be <<Toggle Boolean Flags,configured>> if required.)
This is enough in most cases, but picocli offers alternatives for applications that need to get the value from something other than the default value. When the option is specified on the command line, the annotated field (or <<option-parameters-methods,method>>) is assigned a value, as follows:
* If the parser is configured to <<Toggle Boolean Flags,toggle boolean options>>, the opposite of the _current value_ is assigned. (This was the default prior to picocli 4.0.)
* If a <<fallbackValue-annotation, fallback value>> is defined, the fallback value is assigned.
* If the option is defined with a non-zero <<Arity,arity>>, and an option parameter was specified on the command line, this option <<Boolean Options with Parameters,parameter value is assigned>>.
* Otherwise, the value assigned is the logical opposite of the _default value_.
=== Negatable Options
From picocli 4.0, options can be `negatable`.
```java
@Command(name = "negatable-options-demo")
class NegatableOptionsDemo {
@Option(names = "--verbose", negatable = true) boolean verbose;
@Option(names = "-XX:+PrintGCDetails", negatable = true) boolean printGCDetails;
@Option(names = "-XX:-UseG1GC", negatable = true) boolean useG1GC = true;
}
```
When an option is negatable, picocli will recognize negative aliases of the option on the command line.
The usage help for the above example looks like this:
----
Usage: negatable-options-demo [--[no-]verbose] [-XX:(+|-)PrintGCDetails]
[-XX:(+|-)UseG1GC]
--[no-]verbose Show verbose output
-XX:(+|-)PrintGCDetails
Prints GC details
-XX:(+|-)UseG1GC Use G1 algorithm for GC
----
For *nix-style long options, aliases have the prefix `no-` to the given names, for example `--no-verbose`.
For Java JVM-style options like `-XX:+PrintGCDetails`, the `:+` is turned into `:-` and vice versa.
Short option names are not given a negative alias by default. (This is <<Customizing Negatable Options,customizable>>.)
If the negated form of the option is found, for example `--no-verbose`, the value is set to the provided default. Otherwise, with a regular call, for example `--verbose`, it is set to the opposite of the default.
[TIP]
.Negatable options that are `true` by default
====
When a negatable option is `true` by default, give it the negative name. For example:
[source,java]
----
@Option(names = "--no-backup", negatable = true,
description = "Make a backup. True by default.")
boolean backup = true;
----
When end users specify `--no-backup` on the command line, the value is set to `false`.
The negated form of this option is `--backup`, and if that is specified, the default value is applied.
====
=== Positional Parameters
Any command line arguments that are not subcommands or options (or option parameters) are interpreted as positional parameters.
Positional parameters generally follow the options but from picocli v2.0, positional parameters can be mixed with options on the command line.
Use the (zero-based) `index` attribute to specify exactly which parameters to capture.
Omitting the `index` attribute means the field captures _all_ positional parameters.
Array or collection fields can capture multiple values.
The `index` attribute accepts _range_ values, so an annotation like `@Parameters(index="2..4")` captures the arguments at index 2, 3 and 4. Range values can be _open-ended_. For example, `@Parameters(index="3..*")` captures all arguments from index 3 and up.
For example:
[source,java]
----
class PositionalParameters {
@Parameters(hidden = true) // "hidden": don't show this parameter in usage help message
List<String> allParameters; // no "index" attribute: captures _all_ arguments (as Strings)
@Parameters(index = "0") InetAddress host;
@Parameters(index = "1") int port;
@Parameters(index = "2..*") File[] files;
}
----
Picocli initializes fields with the values at the specified index in the arguments array.
[source,java]
----
String[] args = { "localhost", "12345", "file1.txt", "file2.txt" };
PositionalParameters params = CommandLine.populateCommand(new PositionalParameters(), args);
assert params.host.getHostName().equals("localhost");
assert params.port == 12345;
assert Arrays.equals(params.files, new File[] {new File("file1.txt"), new File("file2.txt")});
assert params.allParameters.equals(Arrays.asList("localhost", "12345", "file1.txt", "file2.txt"));
----
See <<Strongly Typed Everything>> for which types are supported out of the box and how to add custom types.
=== Mixing Options and Positional Parameters
From picocli v2.0, positional parameters can be mixed with options on the command line.
For example:
[source,java]
----
class Mixed {
@Parameters
List<String> positional;
@Option(names = "-o")
List<String> options;
}
----
Any command line argument that is not an option or subcommand is interpreted as a positional parameter.
[source,java]
----
String[] args = { "param0", "-o", "AAA", "param1", "param2", "-o", "BBB", "param3" };
Mixed mixed = new Mixed();
new CommandLine(mixed).parseArgs(args);
assert mixed.positional.equals(Arrays.asList("param0", "param1", "param2", "param3");
assert mixed.options.equals (Arrays.asList("AAA", "BBB"));
----
=== Double dash (`--`)
When one of the command line arguments is just two dashes without any characters attached (`--`),
picocli interprets all following arguments as positional parameters, even arguments that match an option name.
[source,java]
----
class DoubleDashDemo {
@Option(names = "-v") boolean verbose;
@Option(names = "-files") List<String> files;
@Parameters List<String> params;
}
----
The `--` end-of-options delimiter clarifies which of the arguments are positional parameters:
[source,java]
----
String[] args = { "-v", "--", "-files", "file1", "file2" };
DoubleDashDemo demo = new DoubleDashDemo();
new CommandLine(demo).parseArgs(args);
assert demo.verbose;
assert demo.files == null;
assert demo.params.equals(Arrays.asList("-files", "file1", "file2"));
----
A custom delimiter can be configured with `CommandLine.setEndOfOptionsDelimiter(String)`.
[[AtFiles]]
=== @-files
==== Argument Files for Long Command Lines
Users sometimes run into system limitations on the length of a command line when creating a
command line with lots of options or with long arguments for options.
Starting from v2.1.0, picocli supports "argument files" or "@-files".
Argument files are files that themselves contain arguments to the command.
When picocli encounters an argument beginning with the character `@',
it expands the contents of that file into the argument list.
An argument file can include options and positional parameters in any combination.
The arguments within a file can be space-separated or newline-separated.
If an argument contains embedded whitespace, put the whole argument in double or single quotes.
Within quoted values, backslashes need to be escaped with another backslash.
For example, it is possible to have a path with a space,
such as `c:\Program Files` that can be specified as either `"c:\\Program Files"` or,
to avoid an escape, `c:\Program" "Files`.
Lines starting with `#` are comments and are ignored.
The comment character can be configured with `CommandLine.setAtFileCommentChar(Character)`,
and comments can be switched off by setting the comment character to `null`.
The file may itself contain additional @-file arguments; any such arguments will be processed recursively.
If the file does not exist, or cannot be read, then the argument will be treated literally, and not removed.
Multiple @-files may be specified on the command line. The specified path may be relative (to the current directory) or absolute.
For example, suppose a file with arguments exists at `/home/foo/args`, with these contents:
----
# This line is a comment and is ignored.
ABC -option=123
'X Y Z'
----
A command may be invoked with the @file argument, like this:
[source,bash]
----
java MyCommand @/home/foo/args
----
The above will be expanded to the contents of the file:
[source,bash]
----
java MyCommand ABC -option=123 "X Y Z"
----
@-file expansion can be switched off by calling `CommandLine::setExpandAtFiles` with `false`.
If turned on, you can still pass a real parameter with an initial '@' character by escaping it
with an additional '@' symbol, e.g. '@@somearg' will become '@somearg' and not be subject to expansion.
This feature is similar to the 'Command Line Argument File' processing supported by gcc, javadoc and javac.
The documentation for these tools shows further examples.
==== Simplified Format
From picocli 3.8.1, a simpler argument file format is also supported where every line (except empty lines and comment lines)
is interpreted as a single argument. Arguments containing whitespace do not need to be quoted,
but it is not possible to have arguments with embedded newlines or to have empty string arguments without quotes.
From picocli 3.9, this simpler argument format is fully compatible with http://jcommander.org/#__syntax[JCommander]'s `@-file` argument file format.
You can tell picocli to use the simplified argument file format programmatically with `CommandLine.setUseSimplifiedAtFiles(true)`,
or by setting system property `picocli.useSimplifiedAtFiles` without a value or with value `"true"`
(case-insensitive). The system property is useful to allow end users control over the format.
== Strongly Typed Everything
When command line options and positional parameters are mapped to the annotated fields,
the text value is converted to the type of the annotated field.
=== Built-in Types
Out of the box, picocli can convert command line argument strings to a number of common data types.
Most of the built-in types work with Java 5, but picocli also has some default converters for Java 7 types like `Path` and Java 8 types like `Duration`, etc. These converters are loaded using reflection and are only available when running on a Java version that supports them. See the below list for details.
* any Java primitive type or their wrapper
* any `enum`
* `String`, `StringBuilder`, `CharSequence`
* `java.math.BigDecimal`, `java.math.BigInteger`
* `java.nio.Charset`
* `java.io.File`
* `java.net.InetAddress`
* `java.util.regex.Pattern`
* `java.util.Date` (for values in `"yyyy-MM-dd"` format)
* `java.net.URL`, `java.net.URI`
* `java.util.UUID`
* `java.lang.Class` (from picocli 2.2, for the fully qualified class name)
* `java.nio.ByteOrder` (from picocli 2.2, for the Strings `"BIG_ENDIAN"` or `"LITTLE_ENDIAN"`)
* `java.util.Currency` (from picocli 2.2, for the ISO 4217 code of the currency)
* `java.net.NetworkInterface` (from picocli 2.2, for the InetAddress or name of the network interface)
* `java.util.TimeZoneConverter` (from picocli 2.2, for the ID for a TimeZone)
Converters loaded using reflection:
* `java.nio.file.Path` (from picocli 2.2, requires Java 7 or higher)
* `java.time` value objects: `Duration`, `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `MonthDay`, `OffsetDateTime`, `OffsetTime`, `Period`, `Year`, `YearMonth`, `ZonedDateTime`, `ZoneId`, `ZoneOffset` (from picocli 2.2, requires Java 8 or higher, invokes the `parse` method of these classes)
* `java.sql.Time` (for values in any of the `"HH:mm"`, `"HH:mm:ss"`, `"HH:mm:ss.SSS"`, or `"HH:mm:ss,SSS"` formats)
* `java.sql.Timestamp` (from picocli 2.2, for values in the `"yyyy-MM-dd HH:mm:ss"` or `"yyyy-MM-dd HH:mm:ss.fffffffff"` formats)
* `java.sql.Connection` (from picocli 2.2, for a database url of the form `jdbc:subprotocol:subname`)
* `java.sql.Driver` (from picocli 2.2, for a database URL of the form `jdbc:subprotocol:subname`)
TIP: Sometimes loading converters with reflection is not desirable.
Use system property `picocli.converters.excludes` to specify a comma-separated list of fully qualified class names for which the converter should not be loaded.
Regular expressions are supported.
For example, invoking the program with `-Dpicocli.converters.excludes=java.sql.Ti.*` will not load type converters for `java.sql.Time` and `java.sql.Timestamp`.
=== Custom Type Converters
Register a custom type converter to handle data types other than the above built-in ones.
Custom converters need to implement the `picocli.CommandLine.ITypeConverter` interface:
[source,java]
----
public interface ITypeConverter<K> {
/**
* Converts the specified command line argument value to some domain object.
* @param value the command line argument String value
* @return the resulting domain object
* @throws Exception an exception detailing what went wrong during the conversion
*/
K convert(String value) throws Exception;
}
----
Custom type converters can be registered with the `CommandLine.registerConverter(Class<K> cls, ITypeConverter<K> converter)` method. All options and positional parameters with the specified type will be converted by the specified converter.
NOTE: Java 8 lambdas make it easy to register custom converters:
[source,java]
----
CommandLine cl = new CommandLine(app)
cl.registerConverter(Locale.class, s -> new Locale.Builder().setLanguageTag(s).build());
cl.registerConverter(Cipher.class, s -> Cipher.getInstance(s));
----
After registering custom converters, call the `execute(String...)` or parseArgs(String...)` method on the `CommandLine` instance where the converters are registered. (The static `populateCommand` method cannot be used.) For example:
[source,java]
----
class App {
@Parameters java.util.Locale locale;
@Option(names = "-a") javax.crypto.Cipher cipher;
}
----
[source,java]
----
App app = new App();
CommandLine commandLine = new CommandLine(app)
.registerConverter(Locale.class, s -> new Locale.Builder().setLanguageTag(s).build())
.registerConverter(Cipher.class, s -> Cipher.getInstance(s));
commandLine.parseArgs("-a", "AES/CBC/NoPadding", "en-GB");
assert app.locale.toLanguageTag().equals("en-GB");
assert app.cipher.getAlgorithm().equals("AES/CBC/NoPadding");
----
CAUTION: _Note on subcommands:_ the specified converter will be registered with the `CommandLine` object
and all subcommands (and nested sub-subcommands) that were added _before_ the converter was registered.
Subcommands added later will not have the converter added automatically.
To ensure a custom type converter is available to all subcommands, register the type converter last, after adding subcommands.
=== Option-specific Type Converters
Picocli 2.2 added a `converter` attribute to the `@Option` and `@Parameter` annotations. This allows a specific option or positional parameter to use a different converter than would be used by default based on the type of the field.
For example, for a specific field you may want to use a converter that maps the constant names defined in https://docs.oracle.com/javase/9/docs/api/java/sql/Types.html[`java.sql.Types`] to the `int` value of these constants, but any other `int` fields should not be affected by this and should continue to use the standard int converter that parses numeric values.
Example usage:
[source,java]
----
class App {
@Option(names = "--sqlType", converter = SqlTypeConverter.class)
int sqlType;
}
----
Example implementation:
[source,java]
----
class SqlTypeConverter implements ITypeConverter<Integer> {
public Integer convert(String value) throws Exception {
switch (value) {
case "ARRAY" : return Types.ARRAY;
case "BIGINT" : return Types.BIGINT;
case "BINARY" : return Types.BINARY;
case "BIT" : return Types.BIT;
case "BLOB" : return Types.BLOB;
...
}
}
}
----
This may also be useful for applications that need a custom type converter but want to use the static convenience methods (`populateCommand`, `run`, `call`, `invoke`). The `converter` annotation does not require a `CommandLine` instance so it can be used with the static convenience methods.
Type converters declared with the `converter` attribute need to have a public no-argument constructor to be instantiated, unless a <<Custom Factory>> is installed to instantiate classes.
=== Arrays, Collections, Maps
NOTE: Starting from picocli v2.0, the `type` attribute is no longer necessary for `Collection` and `Map` fields:
picocli will infer the collection element type from the generic type.
(The `type` attribute still works as before, it is just optional in most cases.)
==== Arrays and Collections
Multiple parameters can be captured together in a single array or `Collection` field.
The array or collection elements can be any type for which a <<Strongly Typed Everything,converter>> is registered.
For example:
[source,java]
----
import java.util.regex.Pattern;
import java.io.File;
class Convert {
@Option(names = "-patterns", description = "the regex patterns to use")
Pattern[] patterns;
@Parameters(/* type = File.class, */ description = "the files to convert")
List<File> files; // picocli infers type from the generic type
}
----
[source,java]
----
String[] args = { "-patterns", "a*b", "-patterns", "[a-e][i-u]", "file1.txt", "file2.txt" };
Convert convert = CommandLine.populateCommand(new Convert(), args);
// convert.patterns now has two Pattern objects
// convert.files now has two File objects
----
NOTE: If a collection is returned from a type converter, the _contents_ of the collection are added to the field or method parameter, not the collection itself.
If the field or method parameter is `null`, picocli will instantiate it when the option or positional parameter is successfully matched.
If the `Collection` type is not a concrete class, picocli will make a best effort to instantiate it based on the field type:
`List -> ArrayList`, `OrderedSet -> TreeSet`, `Set -> LinkedHashSet`, `Queue -> LinkedList`, otherwise, `ArrayList`.
Multi-value options and positional parameters can be defined with a `split` regular expression to allow end users to specify multiple values in a single parameter.
See the <<Split Regex>> section for details.
==== Maps
Picocli v1.0 introduced support for `Map` fields similar to Java's system properties `-Dkey=value` or Gradle's project properties `-Pmyprop=myvalue`.
`Map` fields may have any type for their key and value
as long as a <<Strongly Typed Everything,converter>> is registered for both the key and the value type.
Key and value types are inferred from the map's generic type parameters.
For example:
[source,java]
----
import java.net.InetAddress;
import java.net.Proxy.Type;
import java.util.concurrent.TimeUnit;
class MapDemo {
@Option(names = {"-p", "--proxyHost"});
Map<Proxy.Type, InetAddress> proxies;
@Option(names = {"-u", "--timeUnit"});
Map<TimeUnit, Long> timeout;
}
----
Map options may be specified multiple times with different key-value pairs. (See <<Multiple Values>>.)
[source,bash]
----
<command> -p HTTP=123.123.123.123 --proxyHost SOCKS=212.212.212.212
<command> -uDAYS=3 -u HOURS=23 -u=MINUTES=59 --timeUnit=SECONDS=13
----
If the field is `null`, picocli will instantiate it when the option or positional parameter is matched.
If the type is not a concrete class, picocli will instantiate a `LinkedHashMap` to preserve the input ordering.
NOTE: On the command line, the key and the value must be separated by a `=` character.
Map options and positional parameters can be defined with a `split` regular expression to allow end users to specify multiple values in a single parameter.
See the <<Split Regex>> section for details.
=== Abstract Field Types
The field's type can be an interface or an abstract class.
The `type` attribute can be used to control for each field what concrete class the string value should be converted to.
For example:
[source,java]
----
class App {
@Option(names = "--big", type = BigDecimal.class) // concrete Number subclass
Number[] big; // array type with abstract component class
@Option(names = "--small", type = Short.class) // other Number subclass
Number[] small;
@Parameters(type = StringBuilder.class) // StringBuilder implements CharSequence
CharSequence address; // interface type
}
----
==== Maps and Collections with Abstract Elements
For raw maps and collections, or when using generics with unbounded wildcards like `Map<?, ?>`, or when the type parameters are themselves abstract classes like `List<CharSequence>` or `Map<? extends Number, ? super Number>`, there is not enough information to convert to a stronger type. By default, the raw String values are added as is to such collections.
The `type` attribute can be specified to convert to a stronger type than String. For example:
[source,java]
----
class TypeDemo {
@Option(names = "-x"); // not enough information to convert
Map<?, ?> weaklyTyped; // String keys and values are added as is
@Option(names = "-y", type = {Short.class, BigDecimal.class});
Map<? extends Number, ? super Number> stronglyTyped;
@Option(names = "-s", type = CharBuffer.class);
List<CharSequence> text;
}
----
=== Enum Types
It is encouraged to use `enum` types for options or positional parameters with a limited set of valid values.
Not only will picocli validate the input, it allows you to <<Show Default Values,show all values>> in the usage help message with `@Option(description = "Valid values: ${COMPLETION-CANDIDATES}")`. It also allows command line completion to suggest completion candidates for the values of this option.
Enum value matching is case-sensitive by default, but from 3.4 this can be controlled with `CommandLine::setCaseInsensitiveEnumValuesAllowed` and `CommandSpec::caseInsensitiveEnumValuesAllowed`.
== Default Values
It is possible to define a default value for an option or positional parameter, that is assigned when the user did not specify this option or positional parameter on the command line.
[#defaultValue-annotation]
=== `defaultValue` Annotation
The recommended way to give an option or positional parameter a default value is to use the `defaultValue` annotation attribute. This works correctly with argument groups, `@Option` and `@Parameters`-annotated methods, and allows annotation processors to detect and use default values.
For <<option-parameters-methods,@Option and @Parameters-annotated methods>> and <<command-methods,@Command-annotated methods>>, there is no alternative but to use the `defaultValue` annotation attribute. For example, for an annotated interface:
[source,java]
----
interface Spec {
@Option(names = "-c", defaultValue = "123", description = "... ${DEFAULT-VALUE} ...")
int count();
}
----
Example of using the `defaultValue` attribute in the option of a command method:
[source,java]
----
class CommandMethod {
@Command(description = "Do something.")
void doit(@Option(names = "-c", defaultValue = "123") int count) {
// ...
}
}
----
Note that you can use the `${DEFAULT-VALUE}` <<Predefined Variables,variable>> in the `description` of the option or positional parameter and picocli will <<Show Default Values,show>> the actual default value.
=== Field Values
For annotated fields, it is possible to declare the field with a value:
[source,java]
----
@Option(names = "-c", description = "The count (default: ${DEFAULT-VALUE})")
int count = 123; // default value is 123
----
[WARNING]
====
Defining a default value by assigning a value at the field declaration has limitations:
* when the option is used in a argument group, the usage help <<Default Values in Argument Groups,cannot show the default value>>
* picocli's annotation processors can only detect default values in annotations, not in the field declaration. Your application may not work correctly with future features like documentation generated from the annotations.
====
=== Default Provider
Finally, you can specify a default provider in the `@Command` annotation:
[source,java]
----
@Command(defaultValueProvider = MyDefaultProvider.class)
class MyCommand // ...
----
The default provider allows you to get default values from a configuration file or some other central place.
Default providers need to implement the `picocli.CommandLine.IDefaultValueProvider` interface:
[source,java]
----
public interface IDefaultValueProvider {
/**
* Returns the default value for an option or positional parameter or {@code null}.
* The returned value is converted to the type of the option/positional parameter
* via the same type converter used when populating this option/positional
* parameter from a command line argument.
*
* @param argSpec the option or positional parameter, never {@code null}
* @return the default value for the option or positional parameter, or {@code null} if
* this provider has no default value for the specified option or positional parameter
* @throws Exception when there was a problem obtaining the default value
*/
String defaultValue(ArgSpec argSpec) throws Exception;
}
----
See the
https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/defaultprovider/[default provider examples]
for example implementations.
=== PropertiesDefaultProvider
From picocli 4.1, applications can use the built-in `PropertiesDefaultProvider`
implementation that loads default values from a properties file.
By default, this implementation tries to find a properties file named `.${COMMAND-NAME}.properties` in the user home directory, where `${COMMAND-NAME}` is the name of the command. If a command has aliases in addition to its name, these aliases are also used to try to find the properties file. For example:
[source,java]
----
import picocli.CommandLine.PropertiesDefaultProvider;
// ...
@Command(name = "git", defaultValueProvider = PropertiesDefaultProvider.class)
class Git { }
----
The above will try to load default values from `new File(System.getProperty("user.home"), ".git.properties")`.
The location of the properties file can also be controlled with system property `"picocli.defaults.${COMMAND-NAME}.path"` (`"picocli.defaults.git.path"` in this example), in which case the value of the property must be the path to the file containing the default values.
The location of the properties file may also be specified programmatically. For example:
[source,java]
----
CommandLine cmd = new CommandLine(new MyCommand());
File defaultsFile = new File("path/to/config/mycommand.properties");
cmd.setDefaultValueProvider(new PropertiesDefaultProvider(defaultsFile));
cmd.execute(args);
----
==== PropertiesDefaultProvider Format
The `PropertiesDefaultProvider` expects the properties file to be in the standard java `.properties` https://en.wikipedia.org/wiki/.properties[format].
For options, the key is either the https://picocli.info/apidocs/picocli/CommandLine.Option.html#descriptionKey--[descriptionKey],
or the option's https://picocli.info/apidocs/picocli/CommandLine.Model.OptionSpec.html#longestName--[longest name], without the prefix. So, for an option `--verbose`, the key would be `verbose`, and for an option `/F`, the key would be `F`.
For positional parameters, the key is either the https://picocli.info/apidocs/picocli/CommandLine.Parameters.html#descriptionKey--[descriptionKey],
or the positional parameter's https://picocli.info/apidocs/picocli/CommandLine.Parameters.html#paramLabel--[param label].
End users may not know what the `descriptionKey` of your options and positional parameters are, so be sure to document that with your application.
==== Subcommands Default Values
The default values for options and positional parameters of subcommands can be included in the
properties file for the top-level command, so that end users need to maintain only a single file.
This can be achieved by prefixing the keys for the options and positional parameters
with their command's qualified name.
For example, to give the `git commit` command's `--cleanup` option a
default value of `strip`, define a key of `git.commit.cleanup` and assign
it a default value:
[source]
----
# /home/remko/.git.properties
git.commit.cleanup = strip
----
[#fallbackValue-annotation]
=== `fallbackValue` Annotation
If an option is defined with `arity = "0..1"`, it may or not have a parameter value.
If such an option is specified without a value on the command line, it is assigned the fallback value.
The `fallbackValue` annotation attribute was introduced in picocli 4.0; prior to this, (from picocli 2.3) an empty String was assigned.
This is different from the `defaultValue`, which is assigned if the option is not specified at all on the command line.
For example:
[source, java]
----
class FallbackValueDemo implements Runnable {
@Option(names = "-x", arity = "0..1",
defaultValue = "-1", fallbackValue = "-2",
description = "Option with optional parameter. Default: ${DEFAULT-VALUE}, " +
"if specified without parameter: ${FALLBACK-VALUE}")
int x;
public void run() { System.out.printf("x = %s%n", x); }
public static void main(String... args) {
new CommandLine(new FallbackValueDemo()).execute(args);
}
}
----
Gives the following results:
[source, bash]
----
java FallbackValueDemo -x 100
x = 100
java FallbackValueDemo -x
x = -2
java FallbackValueDemo
x = -1
----
Any String value is converted to the type of the option before it is assigned to the option. Options and positional parameters may define a <<Custom Type Converters,custom type converter>> if necessary.
Note that the option description may contain the `${FALLBACK-VALUE}` <<Predefined Variables,variable>> which will be replaced with the actual fallback value when the usage help is shown.
<<Boolean Options,Boolean options>> can also define a `fallbackValue` to specify the value that should be set when the option is matched on the command line, regardless of the default value. This can be useful when the default is configurable by the end user, for example.
== Multiple Values
Multi-valued options and positional parameters are annotated fields that can capture multiple values from the command line.
=== Multiple Occurrences
==== Repeated Options
The simplest way to create a multi-valued option is to declare an annotated field whose type is an array, collection or a map.
[source,java]
----
@Option(names = "-option")
int[] values;
----
Users may specify the same option multiple times. For example:
----
<command> -option 111 -option 222 -option 333
----
Each value is appended to the array or collection.
==== Multiple Positional Parameters
Similarly for multi-valued positional parameters:
[source,java]
----
@Parameters
List<TimeUnit> units;
----
Users may specify multiple positional parameters. For example:
----
<command> SECONDS HOURS DAYS
----
Again, each value is appended to the array or collection.
==== Repeated Boolean Options
Boolean options with multiple values are supported from picocli v2.1.0.
[source,java]
----
@Option(names = "-v", description = { "Specify multiple -v options to increase verbosity.",
"For example, `-v -v -v` or `-vvv`"})
boolean[] verbosity;
----
Users may specify multiple boolean flag options without parameters. For example:
----
<command> -v -v -v -vvv
----
The above example results in six `true` values being added to the `verbosity` array.
=== Split Regex
Options and parameters may also specify a `split` regular expression used to split each option parameter into smaller substrings.
Each of these substrings is converted to the type of the collection or array. See <<Arrays and Collections>>.
[source,java]
----
@Option(names = "-option", split = ",")
int[] values;
----
A single command line argument like the following will be split up and three `int` values are added to the array:
----
-option 111,222,333
----
Similarly for <<Maps>>:
[source,java]
----
@Option(names = "-fix", split = "\\|")
Map<Integer, String> message;
----
With the above option, command line arguments like the following are interpreted as a set of key-value pairs instead of a single string:
----
-fix 8=FIX.4.4|9=69|35=A|49=MBT|56=TargetCompID|34=9|52=20130625-04:05:32.682|98=0|108=30|10=052
----
The above input results in the `message` field being assigned a `LinkedHashMap` with the following key-value pairs:
----
{8=FIX.4.4, 9=69, 35=A, 49=MBT, 56=TargetCompID, 34=9, 52=20130625-04:05:32.682, 98=0, 108=30, 10=052}
----
See <<Quoted Values>> for details on handling more complex cases.
=== Arity
Sometimes you want to define an option that requires more than one option parameter _for each option occurrence_ on the command line.
The `arity` attribute lets you control exactly how many parameters to consume for each option occurrence.
The `arity` attribute can specify an exact number of required parameters, or a _range_ with a minimum and a maximum number of parameters.
The maximum can be an exact upper bound, or it can be `"*"` to denote _any number_ of parameters. For example:
[source, java]
----
class ArityDemo {
@Parameters(arity = "1..3", description = "one to three Files")
File[] files;
@Option(names = "-f", arity = "2", description = "exactly two floating point numbers")
double[] doubles;
@Option(names = "-s", arity = "1..*", description = "at least one string")
String[] strings;
}
----
A `MissingParameterException` is thrown when fewer than the minimum number of parameters is specified on the command line.
Once the minimum number of parameters is consumed, picocli will check each subsequent command line argument to see whether it is an additional parameter, or a new option. For example:
----
ArityDemo -s A B C -f 1.0 2.0 /file1 /file2
----
Option `-s` has arity `"1..*"` but instead of consuming all parameters,
the `-f` argument is recognized as a separate option.
=== Default Arity
If no `arity` is specified, the number of parameters depends on the field's type.
==== Option Arity
.Default `arity` for `@Option` fields
[grid=cols,cols="30,5,65",options="header"]
|===
| @Option Field Type | Default Arity | Notes
| boolean | 0 |Boolean options by default don't require an option parameter. The field is set to the opposite of its default value when the option name is recognized. (This can be <<Toggle Boolean Flags,configured>>.)
| Single-valued type (e.g., `int`, `String`, `File`) | 1 | The option name must be followed by a value.
| Multi-valued type (arrays, collections or maps) | 1 | The option name must be followed by a value.
|===
CAUTION: Prior to picocli v2.0, multi-valued options used to greedily consume as many arguments as possible until
encountering another option or subcommand.
If your application relies on the previous behaviour, you need to explicitly specify an option arity of `0..*` when migrating to picocli v2.0.
==== Positional Parameter Arity
.Default `arity` for `@Parameters` fields
[grid=cols,cols="30,5,65",options="header"]
|===
| @Parameters Field Type | Default Arity | Notes
| boolean | 1 |Positional parameters of type `boolean` or `Boolean` require a value. Only `true` or `false` (case insensitive) are valid values.
| Single-valued type (e.g., `int`, `String`, `File`) | 1 | One parameter required for each position.
| Multi-valued type (arrays, collections or maps) | 0..1 | For multi-valued positional parameters (arrays, collections or maps), values are optional, not required.
|===
`@Parameters` fields are applied to a command line argument if their index matches the argument's position.
The default index is `\*`, meaning all positions.
A `@Parameters` field with `index = "*"` is applied multiple times: once for each positional parameter on the command line.
When a `@Parameters` field is applied (because its index matches the index of the positional parameter), the field may consume zero, one or more arguments, depending on its arity.
=== Optional Values
If an option is defined with `arity = "0..1"`, it may or not have a parameter value.
If such an option is specified without a value on the command line, it is assigned the <<fallbackValue-annotation,fallback value>>.
== Required Arguments
=== Required Options
Options can be marked `required` to make it mandatory for the user to specify them on the command line. When a required option is not specified, a `MissingParameterException` is thrown from the `parse` method. For example:
[source, java]
----
class MandatoryOption {
@Option(names = "-n", required = true, description = "mandatory number")
int number;
@Parameters
File[] files;
}
----
The following command line arguments would result in an exception complaining that `number` is missing:
----
// invalid: missing option -n
<command> file1 file2 file3
----
The following command line arguments would be accepted:
----
// valid: required option -n has a value
<command> -n 123 file1 file2 file3
----
=== Required Parameters
Use the `arity` attribute to make `@Parameters` mandatory:
[source, java]
----
class BothOptionAndParametersMandatory {
@Parameters(arity = "1..*", description = "at least one File")
File[] files;
@Option(names = "-n", required = true, description = "mandatory number")
int number;
}
----
The following command line arguments would result in an exception complaining that `files` are missing:
----
// invalid: missing file parameters
<command> -n 123
----
The following command line arguments would be accepted:
----
// valid: both required fields have a value
<command> -n 123 file1
----
== Argument Groups
Picocli 4.0 introduces a new `@ArgGroup` annotation and its `ArgGroupSpec` programmatic equivalent.
Argument Groups can be used to define:
* mutually exclusive options
* options that must co-occur (dependent options)
* option sections in the usage help message
* repeating composite arguments
To create a group using the annotations API, annotate a field or method with `@ArgGroup`.
The field's type refers to the class containing the options and positional parameters in the group.
(For annotated interface methods this would be the return type, for annotated setter methods in a concrete class this would be the setter's parameter type.)
Picocli will instantiate this class when needed to capture command line argument values in the `@Option` and `@Parameters`-annotated fields and methods of this class.
=== Mutually Exclusive Options
Annotate a field or method with `@ArgGroup(exclusive = true)` to create a group of mutually exclusive options and positional parameters. For example:
[source, java]
----
@Command(name = "exclusivedemo")
public class MutuallyExclusiveOptionsDemo {
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
static class Exclusive {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
----
The above example defines a command with mutually exclusive options `-a`, `-b` and `-c`.
The group itself has a `multiplicity` attribute that defines how many times the group may be specified within the command.
The default is `multiplicity = "0..1"`, meaning that by default a group may be omitted or specified once.
In this example the group has `multiplicity = "1"`, so the group must occur once: one of the exclusive options must occur on the command line.
The synopsis of this command is:
----
Usage: exclusivedemo (-a=<a> | -b=<b> | -c=<c>)
----
When one of the options in the group is matched, picocli creates an instance of the `Exclusive` class and assigns it to the `@ArgGroup`-annotated `exclusive` field.
Note that the options are defined as `required = true`; this means required _within the group_, not required within the command.
Picocli will validate the arguments and throw a `MutuallyExclusiveArgsException` if multiple mutually exclusive arguments were specified. For example:
[source, java]
----
MutuallyExclusiveOptionsDemo example = new MutuallyExclusiveOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MutuallyExclusiveArgsException ex) {
assert "Error: -a=<a>, -b=<b> are mutually exclusive (specify only one)"
.equals(ex.getMessage());
}
----
For the above group, only one of the options can be specified. Any other combination of options, or the absence of options, is invalid.
CAUTION: Picocli will not initialize the `@ArgGroup`-annotated field
if none of the group options is specified on the command line.
For optional groups (groups with `multiplicity = "0..1"` - the default) this means that the `@ArgGroup`-annotated field may remain `null`.
=== Mutually Dependent Options
Annotate a field or method with `@ArgGroup(exclusive = false)` to create a group of dependent options and positional parameters that must co-occur. For example:
[source, java]
----
@Command(name = "co-occur")
public class DependentOptionsDemo {
@ArgGroup(exclusive = false)
Dependent dependent;
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
}
----
The above example defines a command with dependent options `-a`, `-b` and `-c` that must co-occur.
The group itself has a `multiplicity` attribute that defines how many times the group may be specified within the command.
In this example the group uses the default multiplicity, `multiplicity = "0..1"`, meaning that the group may be omitted or specified once.
The synopsis of this command is:
----
Usage: co-occur [-a=<a> -b=<b> -c=<c>]
----
When the first option in the group is matched, picocli creates an instance of the `Dependent` class and assigns it to the `@ArgGroup`-annotated `dependent` field.
Note that the options are defined as `required = true`; this means required _within the group_, not required within the command.
Picocli will validate the arguments and throw a `MissingParameterException` if not all dependent arguments were specified. For example:
[source, java]
----
DependentOptionsDemo example = new DependentOptionsDemo();
CommandLine cmd = new CommandLine(example);
try {
cmd.parseArgs("-a=1", "-b=2");
} catch (MissingParameterException ex) {
assert "Error: Missing required argument(s): -c=<c>".equals(ex.getMessage());
}
----
CAUTION: Picocli will not initialize the `@ArgGroup`-annotated field
if none of the group options is specified on the command line.
For optional groups (groups with `multiplicity = "0..1"` - the default) this means that the `@ArgGroup`-annotated field may remain `null`.
=== Option Sections in Usage Help
==== Use Heading to Enable Option Sections
The example below uses groups to define options sections in the usage help.
When a group has a non-null `heading` (or `headingKey`), the options in the group are given the specified heading in the usage help message.
The `headingKey` attribute can be used to get the heading text from the command's resource bundle.
This works for mutually exclusive or co-occurring groups, but it is also possible to define a group that does no validation but only creates an option section in the usage help.
Annotate a field or method with `@ArgGroup(validate = false)` to create a group for display purposes only. For example:
[source, java]
----
@Command(name = "sectiondemo", description = "Section demo")
public class OptionSectionDemo {
@ArgGroup(validate = false, heading = "This is the first section%n")
Section1 section1;
static class Section1 {
@Option(names = "-a", description = "Option A") int a;
@Option(names = "-b", description = "Option B") int b;
@Option(names = "-c", description = "Option C") int c;
}
@ArgGroup(validate = false, heading = "This is the second section%n")
Section2 section2;
static class Section2 {
@Option(names = "-x", description = "Option X") int x;
@Option(names = "-y", description = "Option Y") int y;
@Option(names = "-z", description = "Option X") int z;
}
public static void main(String[] args) {
new CommandLine(new OptionSectionDemo()).usage(System.out);
}
}
----
This prints the following usage help message:
----
Usage: sectiondemo [-a=<a>] [-b=<b>] [-c=<c>] [-x=<x>] [-y=<y>] [-z=<z>]
Section demo
This is the first section
-a=<a> Option A
-b=<b> Option B
-c=<c> Option C
This is the second section
-x=<x> Option X
-y=<y> Option Y
-z=<z> Option X
----
Note that the heading text must end with `%n` to insert a newline between the heading text and the first option.
This is for consistency with other headings in the usage help, like `@Command(headerHeading = "Usage:%n", optionListHeading = "%nOptions:%n")`.
CAUTION: Picocli will not initialize the `@ArgGroup`-annotated field
if none of the group options is specified on the command line.
For optional groups (groups with `multiplicity = "0..1"` - the default) this means that the `@ArgGroup`-annotated field may remain `null`.
==== Option Section Order
Options that are not in any argument group are always displayed before the option sections.
The ordering of option sections can be controlled with the `order` attribute. For example:
[source, java]
----
@ArgGroup(heading = "First%n", order = 1) Section1 section1;
@ArgGroup(heading = "Next%n", order = 2) Section2 section2;
@ArgGroup(heading = "Last%n", order = 3) Section3 section3;
----
=== Repeating Composite Argument Groups
The below example shows how groups can be composed of other groups, and how arrays and collections can be used to capture repeating groups (with a `multiplicity` greater than one):
[source, java]
----
@Command(name = "repeating-composite-demo")
public class CompositeGroupDemo {
@ArgGroup(exclusive = false, multiplicity = "1..*")
List<Composite> composites;
static class Composite {
@ArgGroup(exclusive = false, multiplicity = "0..1")
Dependent dependent;
@ArgGroup(exclusive = true, multiplicity = "1")
Exclusive exclusive;
}
static class Dependent {
@Option(names = "-a", required = true) int a;
@Option(names = "-b", required = true) int b;
@Option(names = "-c", required = true) int c;
}
static class Exclusive {
@Option(names = "-x", required = true) boolean x;
@Option(names = "-y", required = true) boolean y;
@Option(names = "-z", required = true) boolean z;
}
}
----
In the above example, the annotated `composites` field defines a composite group that must be specified at least once, and may be specified many times (`multiplicity = "1..*"`), on the command line. Notice that for multi-value groups the type of the `@ArgGroup`-annotated field must be a collection or an array to capture the multiple `Composite` instances that hold the values that were matched on the command line.
The synopsis of this command is:
----
Usage: repeating-composite-demo ([-a=<a> -b=<b> -c=<c>] (-x | -y | -z))...
----
Each time the group is matched, picocli creates an instance of the `Composite` class and adds it to the `composites` list.
The `Composite` class itself contains two groups: an optional (`multiplicity = "0..1"`) group of dependent options that must co-occur, and another group of mutually exclusive options, which is mandatory (`multiplicity = "1"`).
The below example illustrates:
[source, java]
----
CompositeGroupDemo example = new CompositeGroupDemo();
CommandLine cmd = new CommandLine(example);
cmd.parseArgs("-x", "-a=1", "-b=1", "-c=1", "-a=2", "-b=2", "-c=2", "-y");
assert example.composites.size() == 2;
Composite c1 = example.composites.get(0);
assert c1.exclusive.x;
assert c1.dependent.a == 1;
assert c1.dependent.b == 1;
assert c1.dependent.c == 1;
Composite c2 = example.composites.get(1);
assert c2.exclusive.y;
assert c2.dependent.a == 2;
assert c2.dependent.b == 2;
assert c2.dependent.c == 2;
----
[CAUTION]
====
Picocli will not initialize the `@ArgGroup`-annotated field
if none of the group options is specified on the command line.
For optional groups (groups with `multiplicity = "0..1"` - the default) this means that the `@ArgGroup`-annotated field may remain `null`.
If the application assigned a non-`null` Collection in the field declaration (e.g., `@ArgGroup List<Composite> composites = new ArrayList<>();`), then the collection will remain empty if none of the group options is specified on the command line.
====
=== Default Values in Argument Groups
The <<Default Values,default values>> of options in an argument group are applied when at least one option in the group is matched on the command line and picocli instantiates the user object of the group.
Picocli will not initialize the `@ArgGroup`-annotated field (and so no default values are applied) if none of the group options is specified on the command line.
==== Default Values in Group Usage Help
When options are used in argument groups, they can only define default values via the `@Option(defaultValue = "...")` annotation (not in the field declaration).
When defined this way, the `${DEFAULT-VALUE}` variable can be used to <<Show Default Values,show the default value>> in the description of options in an argument group. For example:
.This works correctly: usage help will show the default value.
[source,java]
----
class GoodGroup {
@Option(names = "-x", defaultValue = "123", description = "Default: ${DEFAULT-VALUE}")
int x;
}
@Command(name = "good", description = "usage help shows the default value")
class GoodExample {
@ArgGroup GoodGroup goodGroup;
public static void main(String[] args) {
new CommandLine(new GoodExample()).usage(System.out);
}
}
----
When the default value is defined in the annotation, the usage help shows the correct default value:
----
Usage: good [[-x=<x>]]
usage help shows the default value
-x=<x> Default: 123
----
[WARNING]
====
Picocli will not be able to retrieve the default values that are defined by assigning a value in the declaration of an `@Option`-annotated field in a group. For example:
.This does not work correctly: usage help shows `null` as the default value.
[source,java]
----
class BadGroup {
@Option(names = "-x", description = "Default: ${DEFAULT-VALUE}")
int x = 123; // picocli cannot find this value until `BadGroup` is instantiated
}
@Command(name = "bad", description = "usage help shows the wrong default value")
class BadExample {
@ArgGroup BadGroup badGroup;
public static void main(String[] args) {
new CommandLine(new BadExample()).usage(System.out);
}
}
----
When the default value is defined in the field declaration and not in the annotation, usage help for the options in the group incorrectly shows `null` as the default value:
----
Usage: bad [[-x=<x>]]
usage help shows the wrong default value
-x=<x> Default: null
----
====
=== Positional Parameters
When a `@Parameters` positional parameter is part of a group, its `index` is the index _within the group_, not within the command.
=== Argument Group Limitations
* Options with the same name cannot be defined in multiple groups. Similarly, it is not possible to define an option outside of a group with the same name as a different option that is part of a group.
* Positional parameters in a single group work fine, but take care (or avoid) defining positional parameters in multiple groups or positional parameters in a group as well as outside a group. Positional parameters are matched by index, and while the index of a group is reset when a new group multiple is encountered, the index of positional parameters outside a group only increases and is never reset.
[#less-boilerplate]
[#execute]
== Executing Commands
Parsing the command line arguments is the first step. A robust real-world application needs to handle a number of scenarios:
. User input was invalid
. User requested usage help (potentially for a subcommand)
. User requested version help (potentially for a subcommand)
. None of the above: we can run the business logic (potentially for a subcommand)
. The business logic may throw an exception
Picocli 4.0 introduces an `execute` method for handling all of the above scenarios in a single line of code. For example:
```java
new CommandLine(new MyApp()).execute(args);
```
With the `execute` method, application code can be *extremely compact*:
[source,java,linenumbers]
----
@Command(name = "myapp", mixinStandardHelpOptions = true, version = "1.0")
class MyApp implements Callable<Integer> {
@Option(names = "-x") int x;
@Override
public Integer call() { // business logic
System.out.printf("x=%s%n", x);
return 123; // exit code
}
public static void main(String... args) { // bootstrap the application
System.exit(new CommandLine(new MyApp()).execute(args));
}
}
----
Despite being only 15 lines long, this is a full-fledged application, with <<Mixin Standard Help Options,`--help` and `--version`>> options in addition to the `-x` option.
The `execute` method will show the usage help or version information if requested by the user, and invalid user input will result
in a helpful <<Handling Errors,error message>>. If the user input was valid, the business logic is invoked.
Finally, the `execute` method returns an <<Exit Code,exit status code>> that can be used to call `System.exit` if desired.
IMPORTANT: A command is executable if its user object implements `Runnable` or `Callable`, or is a `@Command`-annotated `Method`. Examples follow below.
NOTE: The `execute` method replaces the older `run`, `call`, `invoke` and `parseWithHandlers` methods.
The <<DIY Command Execution>> section shows an example of the boilerplate code that can be omitted with the `execute` method.
=== Exit Code
Many command line applications return an https://en.wikipedia.org/wiki/Exit_status[exit code] to signify success or failure. Zero often means success, a non-zero exit code is often used for errors, but other than that, meanings differ per application.
The `CommandLine.execute` method introduced in picocli 4.0 returns an `int`, and applications can use this return value to call `System.exit` if desired. For example:
```java
public static void main(String... args) {
int exitCode = new CommandLine(new MyApp()).execute(args);
System.exit(exitCode);
}
```
CAUTION: Older versions of picocli had some limited exit code support where picocli would call `System.exit`, but this is now deprecated.
=== Generating an Exit Code
`@Command`-annotated classes that implement `Callable` and `@Command`-<<command-methods,annotated methods>> can simply return an `int` or `Integer`, and this value will be returned from `CommandLine.execute`. For example:
```java
@Command(name = "greet")
class Greet implements Callable<Integer> {
public Integer call() {
System.out.println("hi");
return 1;
}
// define a "shout" subcommand with a @Command-annotated method
@Command
int shout() {
System.out.println("HI!");
return 2;
}
}
assert 1 == new CommandLine(new Greet()).execute();
assert 2 == new CommandLine(new Greet()).execute("shout");
```
Commands with a user object that implements `Runnable` can implement the `IExitCodeGenerator` interface to generate an exit code. For example:
```java
@Command(name = "wave")
class Gesture implements Runnable, IExitCodeGenerator {
@Override public void run() {
System.out.println("wave");
}
@Override public int getExitCode() {
return 3;
}
}
assert 3 == new CommandLine(new Gesture()).execute();
```
=== Exception Exit Codes
By default, the `execute` method returns `CommandLine.ExitCode.OK` (`0`) on success, `CommandLine.ExitCode.SOFTWARE` (`1`) when an exception occurred in the Runnable, Callable or command method, and `CommandLine.ExitCode.USAGE` (`2`) for invalid input. (These are common values according to https://stackoverflow.com/questions/1101957/are-there-any-standard-exit-status-codes-in-linux/40484670#40484670[this StackOverflow answer]). This can be customized with the `@Command` annotation. For example:
```java
@Command(exitCodeOnInvalidInput = 123,
exitCodeOnExecutionException = 456)
```
Additionally, applications can configure a `IExitCodeExceptionMapper` to map a specific exception to an exit code:
```java
class MyMapper implements IExitCodeExceptionMapper {
@Override
public int getExitCode(Throwable t) {
if (t instanceof FileNotFoundException) {
return 74;
}
return 1;
}
}
```
When the end user specified invalid input, the `execute` method prints an error message followed by the usage help message of the command, and returns an exit code. This can be <<Invalid User Input,customized>> by configuring a `IParameterExceptionHandler`.
If the business logic of the command throws an exception, the `execute` method prints the stack trace of the exception and returns an exit code. This can be customized by configuring a `IExecutionExceptionHandler`.
=== Usage Help Exit Code Section
By default, the usage help message does not include exit code information.
Applications that call `System.exit` need to configure the usage help message to show exit code details,
either with the `exitCodeListHeading` and `exitCodeList` annotation attributes,
or programmatically by calling `UsageMessageSpec.exitCodeListHeading` and `UsageMessageSpec.exitCodeList`.
See <<Exit Code List>> for details.
=== Execution Configuration
The following methods can be used to configure the behaviour of the `execute` method:
* get/setOut
* get/setErr
* get/setColorScheme
* get/setExecutionStrategy
* get/setParameterExceptionHandler
* get/setExecutionExceptionHandler
* get/setExitCodeExceptionMapper
CAUTION: The above methods are not applicable with (and ignored by) other entry points like `parse`, `parseArgs`, `populateCommand`, `run`, `call`, `invoke`, `parseWithHandler` and `parseWithHandlers`.
=== Migration
Older versions of picocli supported `run`, `call`, `invoke` and `parseWithHandlers` convenience methods that were similar to `execute` but had limited support for parser configuration and and limited support for exit codes.
These methods are deprecated from picocli 4.0.
The sections below show some common usages and how the same can be achieved with the `execute` API.
==== Customizing Output Streams and ANSI settings
.Before:
```java
PrintStream out = // output stream for user-requested help
PrintStream err = // output stream for error messages
Ansi ansi = // to use ANSI colors and styles or not
CommandLine.run(new MyRunnable(), out, err, ansi, args);
```
.After:
```java
PrintWriter out = // output stream for user-requested help
PrintWriter err = // output stream for error messages
Ansi ansi = // to use ANSI colors and styles or not
CommandLine cmd = new CommandLine(new MyRunnable())
.setOut(out);
.setErr(err);
.setColorScheme(Help.defaultColorScheme(ansi));
int exitCode = cmd.execute(args);
```
==== Return Value from Callable or Method
.Before:
```java
class MyCallable implements Callable<MyResult> {
public MyResult call() { ... }
}
MyResult result = CommandLine.call(new MyCallable(), args);
```
.After:
```java
CommandLine cmd = new CommandLine(new MyCallable());
int exitCode = cmd.execute(args);
MyResult result = cmd.getExecutionResult();
```
==== Invoking Command Methods
.Before:
```java
class MyCommand {
@Command
public MyResult doit(@Option(names = "-x") int x) { ... }
}
MyResult result = CommandLine.invoke("doit", MyCommand.class, args);
```
.After:
```java
Method doit = CommandLine.getCommandMethods(MyCommand.class, "doit").get(0);
CommandLine cmd = new CommandLine(doit);
int exitCode = cmd.execute(args);
MyResult result = cmd.getExecutionResult();
```
==== Executing Commands with Subcommands
The `IParseResultHandler2` interface has been deprecated in picocli 4.0 in favor of `IExecutionStrategy`. The existing built-in handlers `RunLast`, `RunAll` and `RunFirst` implement the `IExecutionStrategy` interface and can still be used:
* the `RunLast` handler prints help if requested, and otherwise gets the _last specified_ command or subcommand and tries to execute it as a `Runnable`, `Callable` or `Method`. This is the default execution strategy.
* the `RunFirst` handler prints help if requested, and otherwise executes the _top-level_ command as a `Runnable`, `Callable` or `Method`
* the `RunAll` handler prints help if requested, and otherwise executes _all_ commands and subcommands that the user specified on the command line as `Runnable`, `Callable` or `Method` tasks
.Before
[source,java]
----
CommandLine cmd = new CommandLine(MyTopLevelCommand())
.addSubcommand("status", new GitStatus())
.addSubcommand("commit", new GitCommit())
.addSubcommand("add", new GitAdd());
List<Object> result = cmd.parseWithHandler(new RunAll(), args);
----
.After
[source,java]
----
CommandLine cmd = new CommandLine(MyTopLevelCommand())
.addSubcommand("status", new GitStatus())
.addSubcommand("commit", new GitCommit())
.addSubcommand("add", new GitAdd());
// the default is RunLast, this can be customized:
cmd.setExecutionStrategy(new RunAll());
int exitCode = cmd.execute(args);
----
The `ParseResult` can be used to get the return value from a Callable or Method subcommand:
[source,java]
----
// getting return value from Callable or Method command
Object topResult = cmd.getExecutionResult();
// getting return value from Callable or Method subcommand
ParseResult parseResult = cmd.getParseResult();
if (parseResult.subcommand() != null) {
CommandLine sub = parseResult.subcommand().commandSpec().commandLine();
Object subResult = sub.getExecutionResult();
}
----
=== DIY Command Execution
Alternatively, applications may want to use the `parseArgs` method directly and write their own "Do It Yourself" command execution logic.
The example below covers the following common scenarios:
. Handle invalid user input, and report any problems to the user (potentially suggesting alternative options and subcommands for simple typos if we want to get fancy).
. Check if the user requested usage help, and print this help and abort processing if this was the case.
. Check if the user requested version information, and print this information and abort processing if this was the case.
. If none of the above, run the business logic of the application.
. Handle any errors that occurred in the business logic.
[source,java]
----
Callable<Object> callable = new MyCallable();
CommandLine cmd = new CommandLine(callable);
try {
ParseResult parseResult = cmd.parseArgs(args);
// Did user request usage help (--help)?
if (cmd.isUsageHelpRequested()) {
cmd.usage(cmd.getOut());
return cmd.getCommandSpec().exitCodeOnUsageHelp();
// Did user request version help (--version)?
} else if (cmd.isVersionHelpRequested()) {
cmd.printVersionHelp(cmd.getOut());
return cmd.getCommandSpec().exitCodeOnVersionHelp();
}
// invoke the business logic
Object result = callable.call();
cmd.setExecutionResult(result);
return cmd.getCommandSpec().exitCodeOnSuccess();
// invalid user input: print error message and usage help
} catch (ParameterException ex) {
cmd.getErr().println(ex.getMessage());
if (!UnmatchedArgumentException.printSuggestions(ex, cmd.getErr())) {
ex.getCommandLine().usage(cmd.getErr());
}
return cmd.getCommandSpec().exitCodeOnInvalidInput();
// exception occurred in business logic
} catch (Exception ex) {
ex.printStackTrace(cmd.getErr());
return cmd.getCommandSpec().exitCodeOnExecutionException();
}
----
The `CommandLine.execute` method is equivalent to the above, and additionally handles subcommands correctly.
=== Handling Errors
Internally, the `execute` method parses the specified user input and populates the options and positional parameters defined by the annotations.
When the user specified invalid input, this is handled by the `IParameterExceptionHandler`.
After parsing the user input, the business logic of the command is invoked: the `run`, `call` or `@Command`-annotated method.
When an exception is thrown by the business logic, this is handled by the `IExecutionExceptionHandler`.
In most cases, the default handlers are sufficient, but the sections below show how they can be customized.
==== Invalid User Input
When the user specified invalid input, the parser throws a `ParameterException`.
In the `execute` method, such exceptions are caught and passed to the `IParameterExceptionHandler`.
The default parameter exception handler prints an error message describing the problem,
followed by either https://picocli.info/apidocs/picocli/CommandLine.UnmatchedArgumentException.html#printSuggestions-picocli.CommandLine.ParameterException-java.io.PrintWriter-[suggested alternatives]
for mistyped options, or the full usage help message of the problematic command.
Finally, the handler returns an <<Exception Exit Codes,exit code>>.
This is sufficient for most applications.
Sometimes you want to display a shorter message. For example, the `grep` utility does not not show the full usage help when it gets an invalid argument:
----
$ grep -d recurese "ERROR" logs/*
Error: invalid argument recurese for --directories
Valid arguments are:
- read
- recurse
- skip
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
----
You can customize how your application handles invalid user input by setting a custom `IParameterExceptionHandler`:
[source,java]
----
new CommandLine(new MyApp())
.setParameterExceptionHandler(new ShortErrorMessageHandler())
.execute(args);
----
Where the `IParameterExceptionHandler` implementation could be something like this:
[source,java]
----
class ShortErrorMessageHandler implements IParameterExceptionHandler {
public int handleParseException(ParameterException ex, String[] args) {
CommandLine cmd = ex.getCommandLine();
PrintWriter writer = cmd.getErr();
writer.println(ex.getMessage());
UnmatchedArgumentException.printSuggestions(ex, writer);
writer.print(cmd.getHelp().fullSynopsis()); // since 4.1
CommandSpec spec = cmd.getCommandSpec();
writer.printf("Try '%s --help' for more information.%n", spec.qualifiedName());
return cmd.getExitCodeExceptionMapper() != null
? cmd.getExitCodeExceptionMapper().getExitCode(ex)
: spec.exitCodeOnInvalidInput();
}
}
----
==== Business Logic Exceptions
When the business logic throws an exception, this exception is caught and passed to the `IExecutionExceptionHandler`.
The default execution exception handling results in the stack trace of the exception being printed and an <<Exception Exit Codes,exit code>> being returned.
This is sufficient for most applications.
If you have designed your business logic to throw exceptions with user-facing error messages, you want to print this error message instead of the stack trace.
This can be accomplished by installing a custom `IExecutionException`, like this:
[source,java]
----
new CommandLine(new MyApp())
.setExecutionExceptionHandler(new PrintExceptionMessageHandler())
.execute(args);
----
Where the `IExecutionException` implementation could look something like this:
[source,java]
----
class PrintExceptionMessageHandler implements IExecutionExceptionHandler() {
public int handleExecutionException(Exception ex,
CommandLine commandLine,
ParseResult parseResult) {
commandLine.getErr().println(ex.getMessage());
return cmd.getExitCodeExceptionMapper() != null
? cmd.getExitCodeExceptionMapper().getExitCode(ex)
: cmd.getCommandSpec().exitCodeOnExecutionException();
}
}
----
== Parser Configuration
=== Overwriting Single Options
When a single-value option is specified multiple times on the command line, the default parser behaviour is
to throw an `OverwrittenOptionException`. For example:
[source,java]
----
@Option(name = "-p") int port;
----
The following input results in an `OverwrittenOptionException`:
----
<command> -p 80 -p 8080
----
Applications can change this by calling `CommandLine.setOverwrittenOptionsAllowed(true)` before parsing the input.
When overwritten options are allowed, the last specified value takes effect (the above input will set the `port` field to `8080`)
and a WARN level message is printed to the console. (See <<Tracing>> for how to switch off the warnings.)
=== Stop At Positional
By default, positional parameters can be mixed with options on the command line, but this is not always desirable.
From picocli 2.3, applications can call `CommandLine.setStopAtPositional(true)`
to force the parser to treat all values following the first positional parameter as positional parameters.
When this flag is set, the first positional parameter effectively serves as an "<<Double dash (`--`),end of options>>" marker.
=== Unmatched Input
By default, an `UnmatchedArgumentException` is thrown when a command line argument cannot be assigned to
an option or positional parameter. For example:
[source,java]
----
class OnlyThree {
@Parameters(arity = "3") String[] values;
}
----
The command has only one annotated field, `values`, and it expects exactly three arguments,
so the following input results in an `UnmatchedArgumentException`:
----
java OnlyThree 1 2 3 4 5
----
Applications can change this by calling `CommandLine.setUnmatchedArgumentsAllowed(true)` before parsing the input.
When unmatched arguments are allowed, the above input will be accepted and a WARN level message is printed to the console.
(See <<Tracing>> for how to switch off the warnings.)
The unmatched argument values can be obtained with the `CommandLine.getUnmatchedArguments()` method.
=== `@Unmatched` annotation [[unmatched-annotation]]
From picocli 3.0, fields annotated with `@Unmatched` will be populated with the unmatched arguments.
The field must be of type `String[]` or `List<String>`.
If picocli finds a field annotated with `@Unmatched`, it automatically sets `unmatchedArgumentsAllowed` to `true`
so no `UnmatchedArgumentException` is thrown when a command line argument cannot be assigned to an option or positional parameter.
If no unmatched arguments are found, the value of the field annotated with `@Unmatched` is unchanged.
=== Unknown Options
A special case of unmatched input are arguments that resemble options but don't match any of the defined options.
For example:
[source,java]
----
@Option(names = "-a") String alpha;
@Option(names = "-b") String beta;
@Parameters String[] remainder;
----
The above defines options `-a` and `-b`, but what should the parser do with input like this?
----
<command> -x -a AAA
----
The `-x` argument "looks like" an option but there is no `-x` option defined...
One possibility is to silently accept such values as positional parameters but this is often not desirable.
From version 1.0, picocli determines if the unmatched argument "resembles an option"
by comparing its leading characters to the prefix characters of the known options.
When the unmatched value is similar to the known options, picocli throws an `UnmatchedArgumentException`
rather than treating it as a positional parameter.
As usual, `CommandLine.setUnmatchedArgumentsAllowed(true)` will accept unmatched input and
display a WARN-level message on the console.
Arguments that are not considered similar to the known options are interpreted as positional parameters:
----
<command> x -a AAA
----
The above input is treated by the parser as one positional parameter (`x`) followed by the `-a` option and its value.
Picocli 3.0 introduced a `CommandLine.setUnmatchedOptionsArePositionalParams(boolean)` method that can be used to
force the parser to treat arguments resembling an option as positional parameters. For example:
----
<command> -x -a AAA
----
When `unmatchedOptionsArePositionalParams` is set to `true`, the unknown option `-x` is treated as a positional parameter.
The next argument `-a` is recognized and processed as a known option like you would expect.
=== Stop At Unmatched
From picocli 2.3, applications can call `CommandLine.setStopAtUnmatched(true)` to force the parser to stop interpreting
options and positional parameters as soon as it encounters an unmatched argument.
When this flag is set, the first unmatched argument and all subsequent command line arguments are added to the
unmatched arguments list returned by `CommandLine.getUnmatchedArguments()`.
=== Toggle Boolean Flags
When a flag option is specified on the command line picocli will set its value to the opposite of its _default_ value.
Prior to 4.0, the default was to "toggle" boolean flags to the opposite of their _current_ value:
if the previous value was `true` it is set to `false`, and when the value was `false` it is set to `true`.
Applications can call `CommandLine.setToggleBooleanFlags(true)` to enable toggling.
Note that when toggling is enabled, specifying a flag option twice on the command line will have no effect because they cancel each other out.
=== POSIX Clustered Short Options
By default, the picocli parser allows POSIX clustered short options, so short options like `-x -v -f SomeFile` can be clustered together like `-xvfSomeFile`.
From picocli 3.0, applications can call `CommandLine.setPosixClusteredShortOptionsAllowed(false)` to enforce that options must be separated with whitespace on the command line.
(This also means that option parameters must be separated from the option name by whitespace or the `=` <<Option-Parameter Separators,separator>> character, so `-D key=value` and `-D=key=value` will be recognized but `-Dkey=value` will not.)
=== Lenient Mode (Incubating)
From picocli 3.2, the parser can be configured to continue parsing invalid input to the end.
When `collectErrors` is set to `true`, and a problem occurs during parsing, an `Exception` is added to the `ParseResult.errors()` list and parsing continues. The default behaviour (when `collectErrors` is `false`) is to abort parsing by throwing the `Exception`.
This is useful when generating completion candidates on partial input, and is also useful when using picocli in
languages like Clojure where idiomatic error handling does not involve throwing and catching exceptions.
When using this feature, applications are responsible for actively verifying that no errors occurred before executing the business logic. Use with care!
=== Quoted Values
==== Trimming Quotes
From picocli 3.7, quotes around command line parameters are preserved by default (previously they were removed). This can be configured with `CommandLine::setTrimQuotes`, or the parser configuration `trimQuotes`. From picocli 4.0, quoted arguments can contain nested quoted substrings, to give end users fine-grained control over how values are split.
If `CommandLine::setTrimQuotes`, or the parser configuration `trimQuotes` is set to `true`, picocli will remove quotes from the command line arguments, as follows:
* As each command line argument is processed, the below <<Smart Unquote,smart unquote>> procedure is used to trim the outermost quotes.
* Next, if the option or positional parameter has a `split` regex defined, the parameter value is split while respecting quotes: the `split` regex is not matched if it occurs in a quoted substring of the parameter value. Each of the parts found by the splitting process will have its quotes removed using the below "smart unquote" procedure.
See the <<Splitting Quoted Parameters>> section below for examples.
===== Smart Unquote
* If the command line argument contains just the leading and trailing quote, these quotes are removed.
* If the command line argument contains unescaped quotes, other than the leading and trailing quote, the argument is unchanged (the leading and trailing quotes remain).
* If a quoted command line argument contains backslash-escaped quotes, the leading and trailing quotes are removed, backslash-escaped quotes are converted to unescaped quotes, and backslash-escaped backslashes are converted to unescaped backslashes.
For example:
[cols=3*,options="header"]
|===
|Command Line Argument|After Trimming Quotes|Note
|`"-x=abc"`|`-x=abc`| quotes removed
|`"a,b","x,y"` |`"a,b","x,y"`|left unchanged
|`"-x=a,b,\"c,d,e\",f"`|`-x=a,b,"c,d,e",f`|Splitting will find 4 values: `a`; `b`; `c,d,e`; and `f`
|`"-x=\"a,b,\\"c,d,e\\",f\""`|`-x="a,b,\"c,d,e\",f"`|Splitting will find 1 value: `a,b,"c,d,e",f`
|===
==== Splitting Quoted Parameters
By default, if the option or positional parameter has a <<Split Regex,`split`>> regex defined, parameter values are split into parts while respecting quotes: the `split` regular expression is not matched inside a quoted region.
Example:
```
@Option(names = "-x", split = ",")
String[] parts;
```
Given input like below:
```
<command> -x "-Dvalues=a,b,c","-Dother=1,2"
```
This results in the `parts` array having the following values, assuming the parser configuration `trimQuotes` is `false` (the default):
```
"-Dvalues=a,b,c"
"-Dother=1,2"
```
If the parser configuration `trimQuotes` is `true`, the above example would be split into the following values (with quotes trimmed from the resulting parts):
```
-Dvalues=a,b,c
-Dother=1,2
```
Given input like below:
```
<command> -x a,b,"c,d,e",f,"xxx,yyy"
```
This results in the `parts` array having the following values:
```
a
b
"c,d,e"
f
"xxx,yyy"
```
Or, if the parser configuration `trimQuotes` is `true`:
```
a
b
c,d,e
f
xxx,yyy
```
To preserve quotes when `trimQuotes` is `true`, specify additional nested quotes on the command line. For example:
```
<command> "-x=\"a,b,\\"c,d,e\\",f\"" "x,y,z" "\"1,2,3\"" "\\"1,2,3\\""
```
With parser configuration `trimQuotes` set to `true`, the above input gives the following values:
```
a,b,"c,d,e",f
x
y
z
1,2,3
"1,2,3"
```
This "smart splitting" (respecting quotes) can be switched off with `CommandLine::setSplitQuotedStrings`:
setting the `splitQuotedStrings` parser attribute to `true` switches off smart splitting,
and the `split` regex is applied to the parameter value regardless of quotes.
[WARNING]
====
`splitQuotedStrings` is mostly for backwards compatibility, for applications that want the pre-3.7 behaviour of simply splitting regardless of quotes.
Most applications should leave this setting to the default (`false`).
When this setting is `true`, the above input is parsed as:
```
a
b
"c
d
e"
f
"xxx
yyy"
```
====
=== Customizing Negatable Options
<<Negatable Options,Negatable options>> can be customized via the `INegatableOptionTransformer` interface:
```java
interface INegatableOptionTransformer {
/**
* Returns the negative form of the specified option name for the parser to recognize
* when parsing command line arguments.
* @param optionName the option name to create a negative form for,
* for example {@code --force}
* @param cmd the command that the option is part of
* @return the negative form of the specified option name, for example {@code --no-force}
*/
String makeNegative(String optionName, CommandSpec cmd);
/**
* Returns the documentation string to show in the synopsis and usage help message for
* the specified option. The returned value should be concise and clearly suggest that
* both the positive and the negative form are valid option names.
* @param optionName the option name to create a documentation string for,
* for example {@code --force}, or {@code -XX:+<option>}
* @param cmd the command that the option is part of
* @return the documentation string for the negatable option,
* for example {@code --[no-]force}, or {@code -XX:(+|-)<option>}
*/
String makeSynopsis(String optionName, CommandSpec cmd);
}
```
This allows you to control:
* which option names should have a negative form
* the negative form recognized by the parser while parsing the command line
* the documentation string showing both the positive and the negative form in the usage help message
By default, a set of https://picocli.info/apidocs/picocli/CommandLine.RegexTransformer.html#createDefault--[regular expressions] is used to control the above.
Use `CommandLine.setNegatableOptionTransformer` to replace the https://picocli.info/apidocs/picocli/CommandLine.INegatableOptionTransformer[`INegatableOptionTransformer`] with a custom version.
See the javadoc for details.
=== Custom Parameter Processing
Options or positional parameters can be assigned a `IParameterConsumer` that implements
custom logic to process the parameters for this option or this position.
When an option or positional parameter with a custom `IParameterConsumer`
is matched on the command line, picocli's internal parser is temporarily suspended,
and the custom parameter consumer becomes responsible for consuming and processing as many
command line arguments as needed.
This can be useful when passing options through to another command.
For example, the unix https://en.wikipedia.org/wiki/Find_(Unix)[`find`] command
has a https://en.wikipedia.org/wiki/Find_(Unix)#Execute_an_action[`-exec`]
option to execute some action for each file found.
Any arguments following the `-exec` option until a `;` or `+` argument are not
options for the `find` command itself, but are interpreted as a separate command and its options.
The example below demonstrates how to implement `find -exec` using this API:
```java
@Command(name = "find")
class Find {
@Option(names = "-exec", parameterConsumer = ExecParameterConsumer.class)
List<String> list = new ArrayList<String>();
}
class ExecParameterConsumer implements IParameterConsumer {
public void consumeParameters(Stack<String> args, ArgSpec argSpec, CommandSpec commandSpec) {
List<String> list = argSpec.getValue();
while (!args.isEmpty()) {
String arg = args.pop();
list.add(arg);
// `find -exec` semantics: stop processing after a ';' or '+' argument
if (";".equals(arg) || "+".equals(arg)) {
break;
}
}
}
}
```
== Help
=== Help Options
Applications can define help options by setting attribute `versionHelp = true`, `usageHelp = true` or `help = true`.
If one of the arguments specified on the command line is a "help" option, picocli will not throw a `MissingParameterException` when required options are missing.
For example:
[source,java]
----
@Option(names = {"-V", "--version"}, versionHelp = true, description = "display version info")
boolean versionInfoRequested;
@Option(names = {"-h", "--help"}, usageHelp = true, description = "display this help message")
boolean usageHelpRequested;
----
Use these attributes for options that request the usage help message or version information to be shown on the console.
[source,java]
----
App app = CommandLine.populateCommand(new App(), args);
if (app.usageHelpRequested) {
CommandLine.usage(new App(), System.out);
return;
}
----
The `CommandLine` class offers two methods that allow external components to detect whether
usage help or version information was requested (without inspecting the annotated domain object):
* `CommandLine.isUsageHelpRequested()` returns `true` if the parser matched an option annotated with `usageHelp=true`
* `CommandLine.isVersionHelpRequested()` returns `true` if the parser matched an option annotated with `versionHelp=true`
[source,java]
----
CommandLine commandLine = new CommandLine(new App());
commandLine.parseArgs(args);
if (commandLine.isUsageHelpRequested()) {
commandLine.usage(System.out);
return;
} else if (commandLine.isVersionHelpRequested()) {
commandLine.printVersionHelp(System.out);
return;
}
// ... run App's business logic
----
See also <<Printing Help Automatically>>.
=== Mixin Standard Help Options
Picocli 3.0 introduced the `mixinStandardHelpOptions` command attribute. When this attribute is set to `true`, picocli adds a <<Mixins,mixin>> to the
command that adds <<Help Options,`usageHelp`>> and <<Help Options,`versionHelp`>> options to the command. For example:
[source,java]
----
@Command(mixinStandardHelpOptions = true, version = "auto help demo - picocli 3.0")
class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
@Override public void run() { ... }
}
----
Commands with `mixinStandardHelpOptions` do not need to explicitly declare fields annotated with `@Option(usageHelp = true)` and `@Option(versionHelp = true)` any more.
The usage help message for the above example looks like this:
----
Usage: <main class> [-hV] [--option=<option>]
--option=<option> Some option.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
----
=== Built-in Help Subcommand
From 3.0, picocli provides a `help` subcommand (`picocli.CommandLine.HelpCommand`) that can be installed as a subcommand
on any application command. It prints usage help for the parent command or sibling subcommands. For example:
[source,java]
----
import picocli.CommandLine.HelpCommand;
@Command(name = "myapp", subcommands = {HelpCommand.class, Subcommand.class})
class MyCommand implements Runnable {
// ...
}
----
For example, the following command prints usage help for a subcommand:
[source,bash]
----
myapp help subcommand
----
To print usage help for the main command:
[source,bash]
----
myapp help
----
=== Custom Help Subcommands
Custom help subcommands should mark themselves as a <<Help Subcommands,help command>> to tell picocli not to throw a `MissingParameterException` when required options are missing.
[source,java]
----
@Command(helpCommand = true)
----
Picocli 4.0 introduced a new interface `picocli.CommandLine.IHelpCommandInitializable2` that provides custom help
commands with access to the parent command and sibling commands, whether to use Ansi colors or not, and the streams to print the usage help message to.
The `IHelpCommandInitializable2` interface replaces the `IHelpCommandInitializable` interface which was introduced in picocli 3.0.
[source,java]
----
public interface IHelpCommandInitializable2 {
/**
* Initializes this object with the information needed to implement a help command that
* provides usage help for other commands.
*
* @param helpCommandLine the {@code CommandLine} object associated with this help command.
* Implementors can use this to walk the command hierarchy and
* get access to the help command's parent and sibling commands.
* @param colorScheme the color scheme to use when printing help, including whether
* to use Ansi colors or not
* @param outWriter the output writer to print the usage help message to
* @param errWriter the error writer to print any diagnostic messages to,
* in addition to the output from the exception handler
*/
void init(CommandLine helpCommandLine,
Help.ColorScheme colorScheme,
PrintWriter outWriter,
PrintWriter errWriter);
}
----
=== Printing Help Automatically
From picocli v2.0, the <<Executing Commands,convenience methods>> will automatically print usage help and version information
when a help option was specified on the command line (options annotated with the `versionHelp` or `usageHelp` attribute - but not the `help` attribute).
The same holds for the `mixinStandardHelpOptions` attribute, the built-in `HelpCommand` and any custom help subcommands marked as a <<Help Subcommands,help command>>.
The following <<Executing Commands,convenience methods>> automatically print help:
* `CommandLine::execute`
* `CommandLine::call`
* `CommandLine::run`
* `CommandLine::invoke`
* `CommandLine::parseWithHandler` (with the built-in `Run...` handlers)
* `CommandLine::parseWithHandlers` (with the built-in `Run...` handlers)
The following methods *do not* automatically print help:
* `CommandLine::parse`
* `CommandLine::parseArgs`
* `CommandLine::populateCommand`
When using the last three methods, applications need to query the parse result to detect whether usage help or version help
was requested, and invoke `CommandLine::usage` or `CommandLine::printVersionHelp` to actually print the requested help message.
== Version Help
=== Static Version Information
==== Command `version` Attribute
Since v0.9.8, applications can specify version information in the `version` attribute of the `@Command` annotation.
[source,java]
----
@Command(version = "1.0")
class VersionedCommand {
@Option(names = { "-V", "--version" }, versionHelp = true,
description = "print version information and exit")
boolean versionRequested;
...
----
The `CommandLine.printVersionHelp(PrintStream)` method extracts the version information from this
annotation and prints it to the specified `PrintStream`.
[source,java]
----
CommandLine commandLine = new CommandLine(new VersionedCommand());
commandLine.parseArgs(args);
if (commandLine.isVersionHelpRequested()) {
commandLine.printVersionHelp(System.out);
return;
}
----
==== Multi-line Version Info
The `version` may specify multiple Strings. Each will be printed on a separate line.
[source,java]
----
@Command(version = { "Versioned Command 1.0", "Build 12345", "(c) 2017" })
class VersionedCommand { ... }
----
The `CommandLine.printVersionHelp(PrintStream)` method will print the above as:
----
Versioned Command 1.0
Build 12345
(c) 2017
----
==== Version Info With Variables
Since 4.0, the version strings may contain <<Variable Interpolation,system properties and environment variables>>. For example:
[source,java]
----
@Command(version = {
"Versioned Command 1.0",
"Picocli " + picocli.CommandLine.VERSION,
"JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})",
"OS: ${os.name} ${os.version} ${os.arch}"})
class VersionedCommand { ... }
----
Depending on your environment, that may print something like:
----
Versioned Command 1.0
Picocli 4.0.0
JVM: 1.8.0_202 (Oracle Corporation Substrate VM GraalVM 1.0.0-rc15 CE)
OS: Linux 4.4.0-17134-Microsoft amd64
----
==== Version Info With Colors
The version strings may contain <<Usage Help with Styles and Colors,markup>> to show ANSI styles and colors. For example:
[source,java]
----
@Command(version = {
"@|yellow Versioned Command 1.0|@",
"@|blue Build 12345|@",
"@|red,bg(white) (c) 2017|@" })
class VersionedCommand { ... }
----
The markup will be rendered as ANSI escape codes on supported systems.
image:VersionInfoWithColors.png[Screenshot of version information containing markup with Ansi styles and colors]
==== Version Info With Format Specifiers
From picocli v1.0, the `version` may contain <<Format Specifiers,format specifiers>>:
[source,java]
----
@Command(version = {
"Versioned Command 1.0",
"Build %1$s",
"(c) 2017, licensed to %2$s" })
class VersionedCommand { ... }
----
Format argument values can be passed to the `printVersionHelp` method:
[source,java]
----
String[] args = {"1234", System.getProperty("user.name")};
new CommandLine(new VersionedCommand())
.printVersionHelp(System.out, Help.Ansi.AUTO, args);
----
=== Dynamic Version Information
==== Command `versionProvider` Attribute
From picocli 2.2, the `@Command` annotation supports a `versionProvider` attribute.
Applications may specify a `IVersionProvider` implementation in this attribute, and picocli will instantiate this class
and invoke it to collect version information.
[source,java]
----
@Command(versionProvider = com.my.custom.ManifestVersionProvider.class)
class App { ... }
----
This is useful when the version of an application should be detected dynamically at runtime.
For example, an implementation may return version information obtained from the JAR manifest, a properties file or some other source.
==== `IVersionProvider` Interface
Custom version providers need to implement the `picocli.CommandLine.IVersionProvider` interface:
[source,java]
----
public interface IVersionProvider {
/**
* Returns version information for a command.
* @return version information (each string in the array is displayed on a separate line)
* @throws Exception an exception detailing what went wrong when obtaining version information
*/
String[] getVersion() throws Exception;
}
----
Version providers declared with the `versionProvider` attribute need to have a public no-argument constructor to be instantiated, unless a <<Custom Factory>> is installed to instantiate classes.
The GitHub project has a manifest file-based
https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/VersionProviderDemo2.java[example]
and a build-generated version properties file-based
https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/VersionProviderDemo1.java[example] version provider implementation.
==== Dynamic Version Info with Variables
The version strings returned from the `IVersionProvider` may contain <<Variable Interpolation,system properties and environment variables>>.
== Usage Help
=== Compact Example
A default picocli usage help message looks like this:
----
Usage: cat [-AbeEnstTuv] [--help] [--version] [FILE...]
Concatenate FILE(s), or standard input, to standard output.
FILE Files whose contents to display
-A, --show-all equivalent to -vET
-b, --number-nonblank number nonempty output lines, overrides -n
-e equivalent to -vET
-E, --show-ends display $ at end of each line
-n, --number number all output lines
-s, --squeeze-blank suppress repeated empty output lines
-t equivalent to -vT
-T, --show-tabs display TAB characters as ^I
-u (ignored)
-v, --show-nonprinting use ^ and M- notation, except for LDF and TAB
--help display this help and exit
--version output version information and exit
Copyright(c) 2017
----
The usage help message is generated from annotation attributes, like below:
[source,java]
----
@Command(name = "cat", footer = "Copyright(c) 2017",
description = "Concatenate FILE(s), or standard input, to standard output.")
class Cat {
@Parameters(paramLabel = "FILE", description = "Files whose contents to display")
List<File> files;
@Option(names = "--help", usageHelp = true, description = "display this help and exit")
boolean help;
@Option(names = "-t", description = "equivalent to -vT") boolean t;
@Option(names = "-e", description = "equivalent to -vET") boolean e;
@Option(names = {"-A", "--show-all"}, description = "equivalent to -vET") boolean all;
// ...
}
----
=== Command Name
In the above example, the program name is taken from the `name` attribute of the `Command` annotation:
[source,java]
----
@Command(name = "cat")
----
Without a `name` attribute, picocli will show a generic `<main class>` in the synopsis:
----
Usage: <main class> [-AbeEnstTuv] [--help] [--version] [FILE...]
----
=== Parameter Labels
Non-boolean options require a value. The usage help should explain this, and picocli shows the option parameter
in the synopsis and in the option list. By default, the field name is shown in `<` and `>` fish brackets.
Use the `paramLabel` attribute to display a different name. For example:
----
Usage: <main class> [-f=FILE] [-n=<number>] NUM <host>
NUM number param
host the host parameter
-f= FILE a file
-n= <number> a number option
----
Some annotated fields in the below example class have a `paramLabel` attribute and others don't:
[source,java]
----
@Command()
class ParamLabels {
@Option(names = "-f", description = "a file", paramLabel = "FILE") File f;
@Option(names = "-n", description = "a number option") int number;
@Parameters(index = "0", description = "number param", paramLabel = "NUM") int n;
@Parameters(index = "1", description = "the host parameter") InetAddress host;
}
----
NOTE: For demonstration purposes the above example mixes the all-uppercase (e.g., `NUM`) style label and the fish bracket (e.g., `<number>`) style labels. For real applications, mixing these label styles should be avoided. An application should consistently use only one style.
=== Unsorted Option List
By default the options list displays options in alphabetical order. Use the `sortOptions = false` attribute to display options in the order they are declared in your class.
[source,java]
----
@Command(sortOptions = false)
----
=== Reordering Options
When mixing `@Option` methods and `@Option` fields, options do not reliably appear in declaration order.
The `@Option(order = <int>)` attribute can be used to explicitly control the position in the usage help message at which the option should be shown.
Options with a lower number are shown before options with a higher number.
=== Abbreviated Synopsis
If a command is very complex and has many options, it is sometimes desirable to suppress details from the synopsis with the `abbreviateSynopsis` attribute. For example:
----
Usage: <main class> [OPTIONS] [<files>...]
----
Note that the positional parameters are not abbreviated.
[source,java]
----
@Command(abbreviateSynopsis = true)
class App {
@Parameters File[] files;
@Option(names = {"--count", "-c"}) int count;
....
}
----
=== Custom Synopsis
For even more control of the synopsis, use the `customSynopsis` attribute to specify one ore more synopsis lines. For example:
----
Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
or: ln [OPTION]... TARGET (2nd form)
or: ln [OPTION]... TARGET... DIRECTORY (3rd form)
or: ln [OPTION]... -t DIRECTORY TARGET... (4th form)
----
To produce a synopsis like the above, specify the literal text in the `customSynopsis` attribute:
[source,java]
----
@Command(synopsisHeading = "", customSynopsis = {
"Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form)",
" or: ln [OPTION]... TARGET (2nd form)",
" or: ln [OPTION]... TARGET... DIRECTORY (3rd form)",
" or: ln [OPTION]... -t DIRECTORY TARGET... (4th form)",
})
class Ln { ... }
----
=== Synopsis Subcommand Label
For commands with <<Usage Help for Subcommands,subcommands>>, the string `[COMMAND]` is appended to the end of the synopsis (whether the synopsis is <<Abbreviated Synopsis,abbreviated>> or not). This looks something like this:
----
Usage: <cmd> [OPTIONS] FILES [COMMAND]
----
From picocli 4.0, this can be customized with the `synopsisSubcommandLabel` attribute.
For example, to clarify that a <<Required Subcommands,subcommand is mandatory>>, an application may specify `COMMAND`, without the `[` and `]` brackets:
[source,java]
----
@Command(name = "git", synopsisSubcommandLabel = "COMMAND")
class Git { ... }
----
An application with a limited number of subcommands may want to show them all in the synopsis, for example:
[source,java]
----
@Command(name = "fs", synopsisSubcommandLabel = "(list | add | delete)",
subcommands = {List.class, Add.class, Delete.class}, mixinStandardHelpOptions = true)
class Fs { ... }
----
This will show the following synopsis:
----
Usage: fs [-hV] (list | add | delete)
----
=== Header and Footer
The `header` will be shown at the top of the usage help message (before the synopsis). The first header line is also the line shown in the subcommand list if your command has subcommands (see <<Usage Help for Subcommands>>).
Use the `footer` attribute to specify one or more lines to show below the generated usage help message.
Each element of the attribute String array is displayed on a separate line.
=== Exit Code List
By default, the usage help message does not display <<Generating an Exit Code,exit code>> information.
Applications that call `System.exit` need to configure the `exitCodeListHeading` and `exitCodeList` annotation attributes.
For example:
```java
@Command(mixinStandardHelpOptions = true,
exitCodeListHeading = "Exit Codes:%n",
exitCodeList = {
" 0:Successful program execution",
"64:Usage error: user input for the command was incorrect, " +
"e.g., the wrong number of arguments, a bad flag, " +
"a bad syntax in a parameter, etc.",
"70:Internal software error: an exception occurred when invoking " +
"the business logic of this command."})
class App {}
new CommandLine(new App()).usage(System.out);
```
This will print the following usage help message to the console:
```
Usage: <main class>
Exit Codes:
0 Successful program execution
64 Usage error: user input for the command was incorrect, e.g., the wrong
number of arguments, a bad flag, a bad syntax in a parameter, etc.
70 Internal software error: an exception occurred when invoking the
business logic of this command.
```
=== Format Specifiers
All usage help message elements can have embedded line separator (`%n`) format specifiers.
These are converted to the platform-specific line separator when the usage help message is printed.
<<Static Version Information,Version help>> may have format specifiers that format additional arguments passed to the `printVersionHelp` method.
See the https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html[java.util.Formatter javadoc] for details.
IMPORTANT: Note that to show percent `'%'` characters in the usage help message, they need to be escaped with another `%`. For example: `@Parameters(description = "%%-age of the total")` is rendered as `%-age of the total`.
An alternative way to control the layout of the usage help message is that some sections (`header`, `footer`, and `description`) can be specified as an array of Strings,
where each element of the array is displayed on a separate line in the usage help message.
=== Section Headings
Section headers can be used to make usage message layout appear more spacious. The example below demonstrates the use of embedded line separator (`%n`) format specifiers:
[source,java]
----
@Command(name = "commit",
sortOptions = false,
headerHeading = "Usage:%n%n",
synopsisHeading = "%n",
descriptionHeading = "%nDescription:%n%n",
parameterListHeading = "%nParameters:%n",
optionListHeading = "%nOptions:%n",
header = "Record changes to the repository.",
description = "Stores the current contents of the index in a new commit " +
"along with a log message from the user describing the changes.")
class GitCommit { ... }
----
The usage help message generated from this class is shown below in <<Expanded Example>>.
=== Expanded Example
The below example demonstrates what a customized usage message can look like.
Note how section headings with line separators can create a more spacious usage message,
and also that options are listed in declaration order (instead of in alphabetic order).
----
Usage:
Record changes to the repository.
git commit [-ap] [--fixup=<commit>] [--squash=<commit>] [-c=<commit>]
[-C=<commit>] [-F=<file>] [-m[=<msg>...]] [<files>...]
Description:
Stores the current contents of the index in a new commit along with a log
message from the user describing the changes.
Parameters:
<files> the files to commit
Options:
-a, --all Tell the command to automatically stage files
that have been modified and deleted, but new
files you have not told Git about are not
affected.
-p, --patch Use the interactive patch selection interface to
chose which changes to commit
-C, --reuse-message=<commit>
Take an existing commit object, and reuse the log
message and the authorship information
(including the timestamp) when creating the
commit.
-c, --reedit-message=<commit>
Like -C, but with -c the editor is invoked, so
that the user can further edit the commit
message.
--fixup=<commit> Construct a commit message for use with rebase
--autosquash.
--squash=<commit> Construct a commit message for use with rebase
--autosquash. The commit message subject line is
taken from the specified commit with a prefix
of "squash! ". Can be used with additional
commit message options (-m/-c/-C/-F).
-F, --file=<file> Take the commit message from the given file. Use
- to read the message from the standard input.
-m, --message[=<msg>...] Use the given <msg> as the commit message. If
multiple -m options are given, their values are
concatenated as separate paragraphs.
----
The annotated class that this usage help message is generated from is shown in <<Section Headings>>.
=== Option-Parameter Separators
The separator displayed between options and option parameters (`=` by default)
in the synopsis and the option list can be configured with the `separator` attribute.
[source,java]
----
@Command(separator = " ")
----
NOTE: the `@Command(separator = " ")` annotation also affects how picocli parses the command line. See also <<Custom Separators>>.
=== Hidden Options and Parameters
Options and Parameters with the `hidden` attribute set to `true` will not be shown in the usage help message.
This is useful for example when a parameter at some index is captured into multiple fields:
by default each of these fields would be shown in the usage message, which would be confusing for users.
For example, the `all` field below is annotated as `hidden = true`:
[source,java]
----
@Command()
class App {
@Parameters(index = "0", description = "destination host") InetAddress host;
@Parameters(index = "1", description = "destination port") int port;
@Parameters(index = "2..*", description = "files to transfer") String[] files;
@Parameters(hidden = true) String[] all;
}
----
The above will generate the following usage help message, where the `all` field is not shown:
----
Usage: <main class> <host> <port> [<files>...]
host destination host
port destination port
files files to transfer
----
=== Show Default Values
==== `${DEFAULT-VALUE}` Variable
From picocli 3.2, it is possible to embed the <<Default Values,default values>> in the description for an option or positional parameter by
specifying the <<Variable Interpolation,variable>> `${DEFAULT-VALUE}` in the description text.
Picocli uses reflection to get the default values from the annotated fields.
The <<Variable Interpolation,variable>> is replaced with the default value regardless of the `@Command(showDefaultValues)` attribute
and regardless of the `@Option(showDefaultValues)` or `@Parameters(showDefaultValues)` attribute.
[source,java]
----
class DefaultValues {
@Option(names = {"-f", "--file"}, defaultValue = "config.xml",
description = "the file to use (default: ${DEFAULT-VALUE})")
File file;
}
CommandLine.usage(new DefaultValues(), System.out);
----
This produces the following usage help:
----
Usage: <main class> -f=<file>
-f, --file=<file> the file to use (default: config.xml)
----
==== `${COMPLETION-CANDIDATES}` Variable
Similarly, it is possible to embed the completion candidates in the description for an option or positional parameter by
specifying the <<Variable Interpolation,variable>> `${COMPLETION-CANDIDATES}` in the description text.
This works for java `enum` classes and for options or positional parameters of non-enum types for which completion candidates are specified.
[source,java]
----
enum Lang { java, groovy, kotlin, javascript, frege, clojure }
static class MyAbcCandidates extends ArrayList<String> {
MyAbcCandidates() { super(Arrays.asList("A", "B", "C")); }
}
class ValidValuesDemo {
@Option(names = "-l", description = "Enum values: ${COMPLETION-CANDIDATES}")
Lang lang = null;
@Option(names = "-o", completionCandidates = MyAbcCandidates.class,
description = "Candidates: ${COMPLETION-CANDIDATES}")
String option;
}
CommandLine.usage(new ValidValuesDemo(), System.out);
----
This produces the following usage help:
----
Usage: <main class> [-l=<lang>] [-o=<option>]
-l=<lang> Enum values: java, groovy, kotlin, javascript, frege, clojure
-o=<option> Candidates: A, B, C
----
==== Legacy Configuration for Displaying Default Values
Prior to picocli 3.2, you need to use the `@Command(showDefaultValues = true)` attribute to append the default value of
all non-`null` options and positional parameters to the description column.
Additionally, picocli 3.0 introduced a `showDefaultValue` attribute to the `@Option` and `@Parameters` annotation.
This allows you to specify for each individual option and positional parameter whether its default value should be shown in the usage help.
This attribute accepts three values:
* `ALWAYS` - always display the default value of this option or positional parameter, even `null` values, regardless what value of `showDefaultValues` was specified on the command
* `NEVER` - don't show the default value for this option or positional parameter, regardless what value of `showDefaultValues` was specified on the command
* `ON_DEMAND` - (this is the default) only show the default value for this option or positional parameter if `showDefaultValues` was specified on the command
These legacy mechanisms still work but for maximum flexibility use the variables explained above.
=== Required-Option Marker
Required options can be marked in the option list by the character specified with the `requiredOptionMarker` attribute. By default options are not marked because the synopsis shows users which options are required and which are optional. This feature may be useful in combination with `abbreviatedSynopsis`. For example:
[source,java]
----
@Command(requiredOptionMarker = '*', abbreviateSynopsis = true)
class Example {
@Option(names = {"-a", "--alpha"}, description = "optional alpha") String alpha;
@Option(names = {"-b", "--beta"}, required = true, description = "mandatory beta") String beta;
}
----
Produces the following usage help message:
----
Usage: <main class> [OPTIONS]
-a, --alpha=<alpha> optional alpha
* -b, --beta=<beta> mandatory beta
----
=== Usage Width
The default width of the usage help message is 80 characters.
Commands defined with `@Command(usageHelpWidth = NUMBER)` in the annotations will use the specified width.
Picocli 3.0 also introduced programmatic API for this via the `CommandLine::setUsageHelpWidth` and `UsageMessageSpec::width` methods.
End users can use system property `picocli.usage.width` to specify a custom width that overrides the programmatically set value.
The minimum width that can be configured is 55 characters.
=== Auto (Terminal) Width
From 4.0, commands defined with `@Command(usageHelpAutoWidth = true)` will try to adjust the usage message help layout to the terminal width.
There is also programmatic API to control this via the `CommandLine::setUsageHelpAutoWidth` and `UsageMessageSpec::autoWidth` methods.
End users may enable this by setting system property `picocli.usage.width` to `AUTO`, and may disable this by setting this system property to a numeric value.
This feature requires Java 7.
== ANSI Colors and Styles
=== Colorized Example
Below shows the same usage help message as shown in <<Expanded Example>>, with ANSI escape codes enabled.
image:UsageHelpWithStyle.png[Screenshot of usage help with Ansi codes enabled]
=== Usage Help with Styles and Colors
You can use colors and styles in the descriptions, header and footer
of the usage help message.
Picocli supports a custom markup notation for mixing colors and styles in text,
following a convention introduced by https://github.com/fusesource/jansi[Jansi], where
`@|` starts a styled section, and `|@` ends it.
Immediately following the `@|` is a comma-separated list of colors and styles, so `@|STYLE1[,STYLE2]... text|@`.
For example:
[source,java]
----
@Command(description = "Custom @|bold,underline styles|@ and @|fg(red) colors|@.")
----
image:DescriptionWithColors.png[Description with Ansi styles and colors]
.Pre-defined styles and colors that can be used in descriptions and headers using the `@|STYLE1[,STYLE2]... text|@` notation
[grid=cols,cols=2*,options="header"]
|===
|Pre-defined Styles | Pre-defined Colors
| bold | black
| faint | red
| underline | green
| italic | yellow
| blink | blue
| reverse | magenta
| reset | cyan
| | white
|===
Colors are applied as _foreground_ colors by default.
You can set _background_ colors by specifying `bg(<color>)`.
For example, `@|bg(red) text with red background|@`.
Similarly, `fg(<color>)` explicitly sets the foreground color.
The example below shows how this markup can be used to add colors and styles to the headings and descriptions of a usage help message:
[source,java]
----
@Command(name = "commit",
sortOptions = false,
headerHeading = "@|bold,underline Usage|@:%n%n",
synopsisHeading = "%n",
descriptionHeading = "%n@|bold,underline Description|@:%n%n",
parameterListHeading = "%n@|bold,underline Parameters|@:%n",
optionListHeading = "%n@|bold,underline Options|@:%n",
header = "Record changes to the repository.",
description = "Stores the current contents of the index in a new commit " +
"along with a log message from the user describing the changes.")
class GitCommit { ... }
----
CAUTION: Markup styles cannot be nested, for example: `@|bold this @|underline that|@|@` will not work. You can achieve the same by combining styles, for example: `@|bold this|@ @|bold,underline that|@` will work fine.
=== Styles and Colors in Application Output
The use of ANSI colors and styles is not limited to the <<Usage Help with Styles and Colors,usage help>>
and <<Static Version Information,version information>>.
Applications can use the picocli `Ansi` class directly to create colored output.
By using the `Ansi.AUTO` enum value, picocli will <<Heuristics for Enabling ANSI,auto-detect>> whether it can emit ANSI escape codes or only the plain text.
.Using the picocli `Ansi` API to generate colored output.
[source,java]
----
// import picocli.CommandLine.Help.Ansi;
String str = Ansi.AUTO.string("@|bold,green,underline Hello, colored world!|@");
System.out.println(str);
----
=== More Colors
Most terminals support a https://en.wikipedia.org/wiki/ANSI_escape_code#Colors[256 color indexed palette]:
----
0x00-0x07: standard colors (the named colors)
0x08-0x0F: high intensity colors (often similar to named colors + bold style)
0x10-0xE7: 6 × 6 × 6 cube (216 colors): 16 + 36 × r + 6 × g + b (0 ≤ r, g, b ≤ 5)
0xE8-0xFF: grayscale from black to white in 24 steps
----
Colors from the 256 color palette can be specified by their index values or by their RGB components.
RGB components must be separated by a semicolon `;` and each component must be between `0` and `5`, inclusive.
For example, `@|bg(0;5;0) text with red=0, green=5, blue=0 background|@`,
or `@|fg(46) the same color by index, as foreground color|@`.
image:256colors.png[256 color indexed palette]
=== Configuring Fixed Elements
==== Color Scheme
Picocli uses a default color scheme for options, parameters and commands.
There are no annotations to modify this color scheme, but it can be changed programmatically.
The below code snippet shows how a custom color scheme can be specified to configure the usage help message style:
[source,java]
----
// see also CommandLine.Help.defaultColorScheme()
ColorScheme colorScheme = new ColorScheme()
.commands (Style.bold, Style.underline) // combine multiple styles
.options (Style.fg_yellow) // yellow foreground color
.parameters (Style.fg_yellow)
.optionParams(Style.italic);
CommandLine.usage(annotatedObject, System.out, colorScheme);
...
----
When using the <<Executing Commands,`execute`>> API, you can configure a `ColorScheme` like this:
[source,java]
----
public static void main(String[] args) {
ColorScheme colorScheme = createColorScheme();
new CommandLine(new MyApp())
.setColorScheme(colorScheme) // use this color scheme in the usage help message
.execute(args);
}
----
==== Color Scheme Overrides
The following system properties override the color scheme styles. This allows end users to adjust for their individual terminal color setup.
.System Properties to Override the Color Scheme
----
picocli.color.commands
picocli.color.options
picocli.color.parameters
picocli.color.optionParams
----
For example:
```
java -Dpicocli.color.options=blink,blue -Dpicocli.color.parameters=reverse com.app.Main
```
System property values may specify multiple comma separated styles.
=== Supported Platforms
Picocli will only emit ANSI escape codes on supported platforms.
For details, see <<Heuristics for Enabling ANSI>>.
==== Unix and Linux
Most Unix and Linux platforms support ANSI colors natively.
On Windows, when picocli detects it is running under a Unix variant like Cygwin or MSYS(2) on Windows
it will display ANSI colors and styles, otherwise it will not emit ANSI codes.
==== Windows
Displaying colors on Windows Command Console and PowerShell requires a bit of extra work.
The easiest way to accomplish this is to use the http://fusesource.github.io/jansi/[Jansi] library in your application.
NOTE: None of the below is mandatory. If not supported, picocli will simply not emit ANSI escape codes, and everything will work without colors.
===== Jansi
To use Jansi, you need to enable it in your application. For example:
[source,java]
----
import org.fusesource.jansi.AnsiConsole;
...
public static void main(String[] args) {
AnsiConsole.systemInstall(); // enable colors on Windows
new CommandLine(new WindowsJansiDemo()).execute(args);
AnsiConsole.systemUninstall(); // cleanup when done
}
----
===== Jansi in GraalVM Native Images
In Java applications compiled to GraalVM native images for Windows, Jansi by itself is https://github.com/fusesource/jansi/issues/162[insufficient] to show colors.
This is partly because GraalVM requires configuration and partly because Jansi internally depends on non-standard system properties, without a graceful fallback if these properties are absent (as is the case in GraalVM).
Users may be interested in combining Jansi with https://github.com/remkop/picocli-jansi-graalvm[picocli-jansi-graalvm] until this issue is fixed. Example usage:
[source,java]
----
import picocli.jansi.graalvm.AnsiConsole; // not org.fusesource.jansi.AnsiConsole
...
public static void main(String[] args) {
int exitCode;
try (AnsiConsole ansi = AnsiConsole.windowsInstall()) {
exitCode = new CommandLine(new MyApp()).execute(args);
}
System.exit(exitCode);
}
----
===== For Reference: Without Jansi on Windows 10 Command Console and PowerShell
NOTE: As of this writing, the practical way to get colors in Command Console and PowerShell is to use Jansi. The below is just for reference.
Starting from Windows 10, the Windows Console https://msdn.microsoft.com/en-us/library/windows/desktop/mt638032(v=vs.85).aspx[supports ANSI escape sequences],
but https://github.com/Microsoft/WSL/issues/1173#issuecomment-254250445[it's not enabled by default].
Unless the specific software you're using (e.g. java) enables ANSI processing by calling the https://docs.microsoft.com/en-us/windows/console/setconsolemode[SetConsoleMode] API with the `ENABLE_VIRTUAL_TERMINAL_PROCESSING` (`0x0400`) flag (java doesn't), you won't see colors or get ANSI processing for that application.
Note that there is a registry setting to https://superuser.com/questions/413073/windows-console-with-ansi-colors-handling/1300251#1300251[change the global default] from _opt in_ to _opt out_.
This https://stackoverflow.com/a/51681675/1446916[Stack Overflow answer] has more details.
CAUTION: Note that picocli's <<Heuristics for Enabling ANSI,heuristics for enabling ANSI>> currently do not include detecting whether support for Virtual Terminal / ANSI escape sequences has been turned on or off via `SetConsoleMode` or a registry change.
So just making these changes is not sufficient to let a picocli-based application show colors.
Applications that enabled colors via `SetConsoleMode` may want to set system property `picocli.ansi` to `tty`.
Environments that enabled colors via a Windows Registry change may want to set environment variable `CLICOLOR=1`.
===== For Reference: Windows Subsystem for Linux (WSL)
You may want to recommend your users to try https://docs.microsoft.com/en-us/windows/wsl/install-win10[getting] https://docs.microsoft.com/en-us/windows/wsl/about[Windows Subsystem for Linux] (WSL).
This lets them run a GNU/Linux environment -- including most command-line tools, utilities, and applications -- directly on Windows, unmodified, without the overhead of a virtual machine.
Picocli-based applications will show ANSI colors in WSL by default.
===== For Reference: 3rd Party Software
In Windows version prior to 10, the Windows command console doesn't support output coloring by default.
One option is for end users to install either http://cmder.net/[Cmder], http://sourceforge.net/projects/conemu/[ConEmu], https://github.com/adoxa/ansicon/[ANSICON] or https://mintty.github.io/[Mintty] (used by default in GitBash and Cygwin) to add coloring support to their Windows command console.
=== Forcing ANSI On/Off
You can force picocli to either always use ANSI codes or never use ANSI codes regardless of the platform:
* Setting system property `picocli.ansi` to `true` forces picocli to use ANSI codes; setting `picocli.ansi` to `false` forces picocli to *not* use ANSI codes. It may be useful for your users to mention this system property in the documentation for your command line application.
* Setting system property `picocli.ansi` to `tty` (case-insensitive) forces picocli to use ANSI codes only if picocli guesses that the process is using an interactive console: either `System.console() != null` or picocli guesses the application is running in a pseudo-terminal pty on a Linux emulator in Windows. Otherwise the <<Heuristics for Enabling ANSI,below heuristics>> are used to determine whether to output ANSI escape codes.
* You can decide to force disable or force enable ANSI escape codes programmatically by specifying `Ansi.ON` or `Ansi.OFF` when invoking `CommandLine.usage`.
This overrides the value of system property `picocli.ansi`. For example:
[source,java]
----
import picocli.CommandLine.Help.Ansi;
// print usage help message to STDOUT without ANSI escape codes
CommandLine.usage(new App(), System.out, Ansi.OFF);
----
=== Heuristics for Enabling ANSI
Below is the exact sequence of steps picocli uses to determine whether or not to emit ANSI escape codes.
. If `Ansi.ON` or `Ansi.OFF` is <<Forcing ANSI On/Off,explicitly specified>>, either via system property `picocli.ansi` or programmatically, this value is used.
. ANSI is disabled when environment variable https://no-color.org/[`NO_COLOR`] is defined (regardless of its value).
. ANSI is enabled when environment variable https://bixense.com/clicolors/[`CLICOLOR_FORCE`] is defined and has any value other than `0` (zero).
. ANSI is enabled when system property `os.name` starts with `"Windows"` and JAnsi Console is https://github.com/fusesource/jansi[installed].
. ANSI is disabled when environment variable https://bixense.com/clicolors/[`CLICOLOR == 0`].
. ANSI is disabled when environment variable https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable[`ConEmuANSI == OFF`].
. ANSI is disabled when Picocli https://stackoverflow.com/questions/1403772/how-can-i-check-if-a-java-programs-input-output-streams-are-connected-to-a-term[_guesses_] the program's output stream is not connected to a terminal: when `System.console()` returns `null`. This check is omitted if picocli _guesses_ the program is running in a Windows https://www.cygwin.com/[Cygwin] or http://www.mingw.org/wiki/MSYS[MSYS] environment: when system property `os.name` starts with `"Windows"` and either environment variable `TERM` starts with `xterm` or environment variable `OSTYPE` is defined.
. ANSI is enabled when environment variable https://github.com/adoxa/ansicon/blob/master/readme.txt[`ANSICON`] is defined.
. ANSI is enabled when environment variable https://bixense.com/clicolors/[`CLICOLOR == 1`].
. ANSI is enabled when environment variable https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable[`ConEmuANSI == ON`].
. ANSI is enabled when picocli detects the program is running in a non-Windows OS (system property `os.name` does not start with `"Windows"`).
. ANSI is enabled when picocli _guesses_ the program is running in a https://www.cygwin.com/[Cygwin] or http://www.mingw.org/wiki/MSYS[MSYS] environment (either environment variable `TERM` starts with `xterm` or environment variable `OSTYPE` is defined).
ANSI escape codes are not emitted if none of the above apply.
== Usage Help API
For further customization of the usage help message, picocli has a Help API.
The `Help` class provides a number of high-level operations, and a set of components like `Layout`, `TextTable`, `IOptionRenderer`, etc., that can be used to build custom help messages.
Details of the Help API are out of scope for this document, but the following sections give some idea of what is possible.
=== Reordering Sections
One thing you may want to do is reorder sections of the usage message or add custom sections.
Picocli 3.9 introduces new API to facilitate customizing the usage help message:
`IHelpFactory` allows applications to plug in `Help` subclasses, and
`IHelpSectionRenderer` allows applications to add custom sections to the usage help message, or redefine existing sections.
The usage help message is no longer hard-coded, but is now constructed from the section renderers defined in `CommandLine::getHelpSectionMap` (or `UsageMessageSpec::sectionMap` for a single `CommandSpec`).
By default this map contains the predefined section renderers:
[source,java]
----
// The default section renderers delegate to methods in Help for their implementation
// (using Java 8 lambda notation for brevity):
Map<String, IHelpSectionRenderer> map = new HashMap<>();
map.put(SECTION_KEY_HEADER_HEADING, help -> help.headerHeading());
map.put(SECTION_KEY_HEADER, help -> help.header());
//e.g. Usage:
map.put(SECTION_KEY_SYNOPSIS_HEADING, help -> help.synopsisHeading());
//e.g. <cmd> [OPTIONS] <subcmd> [COMMAND-OPTIONS] [ARGUMENTS]
map.put(SECTION_KEY_SYNOPSIS, help -> help.synopsis(help.synopsisHeadingLength()));
//e.g. %nDescription:%n%n
map.put(SECTION_KEY_DESCRIPTION_HEADING, help -> help.descriptionHeading());
//e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
map.put(SECTION_KEY_DESCRIPTION, help -> help.description());
//e.g. %nPositional parameters:%n%n
map.put(SECTION_KEY_PARAMETER_LIST_HEADING, help -> help.parameterListHeading());
//e.g. [FILE...] the files to convert
map.put(SECTION_KEY_PARAMETER_LIST, help -> help.parameterList());
//e.g. %nOptions:%n%n
map.put(SECTION_KEY_OPTION_LIST_HEADING, help -> help.optionListHeading());
//e.g. -h, --help displays this help and exits
map.put(SECTION_KEY_OPTION_LIST, help -> help.optionList());
//e.g. %nCommands:%n%n
map.put(SECTION_KEY_COMMAND_LIST_HEADING, help -> help.commandListHeading());
//e.g. add this command adds the frup to the frooble
map.put(SECTION_KEY_COMMAND_LIST, help -> help.commandList());
map.put(SECTION_KEY_EXIT_CODE_LIST_HEADING, help -> help.exitCodeListHeading());
map.put(SECTION_KEY_EXIT_CODE_LIST, help -> help.exitCodeList());
map.put(SECTION_KEY_FOOTER_HEADING, help -> help.footerHeading());
map.put(SECTION_KEY_FOOTER, help -> help.footer());
----
Applications can add, remove or replace sections in this map. The `CommandLine::getHelpSectionKeys` method (or `UsageMessageSpec::sectionKeys` for a single `CommandSpec`) returns the section keys in the order that the usage help message should render the sections. The default keys are (in order):
[start=0]
. SECTION_KEY_HEADER_HEADING
. SECTION_KEY_HEADER
. SECTION_KEY_SYNOPSIS_HEADING
. SECTION_KEY_SYNOPSIS
. SECTION_KEY_DESCRIPTION_HEADING
. SECTION_KEY_DESCRIPTION
. SECTION_KEY_PARAMETER_LIST_HEADING
. SECTION_KEY_PARAMETER_LIST
. SECTION_KEY_OPTION_LIST_HEADING
. SECTION_KEY_OPTION_LIST
. SECTION_KEY_COMMAND_LIST_HEADING
. SECTION_KEY_COMMAND_LIST
. SECTION_KEY_EXIT_CODE_LIST_HEADING
. SECTION_KEY_EXIT_CODE_LIST
. SECTION_KEY_FOOTER_HEADING
. SECTION_KEY_FOOTER
This ordering may be modified with the `CommandLine::setHelpSectionKeys` setter method (or `UsageMessageSpec::sectionKeys(List)` for a single `CommandSpec`).
==== Custom Help Section Example
The below example shows how to add a custom Environment Variables section to the usage help message.
.Adding a custom Environment Variables section
[source,java]
----
// help section keys
static final String SECTION_KEY_ENV_HEADING = "environmentVariablesHeading";
static final String SECTION_KEY_ENV_DETAILS = "environmentVariables";
// ...
// the data to display
Map<String, String> env = new LinkedHashMap<>();
env.put("FOO", "explanation of foo");
env.put("BAR", "explanation of bar");
env.put("XYZ", "xxxx yyyy zzz");
// register the custom section renderers
CommandLine cmd = new CommandLine(new MyApp());
cmd.getHelpSectionMap().put(SECTION_KEY_ENV_HEADING,
help -> help.createHeading("Environment Variables:%n"));
cmd.getHelpSectionMap().put(SECTION_KEY_ENV_DETAILS,
help -> help.createTextTable(env).toString());
// specify the location of the new sections
List<String> keys = new ArrayList<>(cmd.getHelpSectionKeys());
int index = keys.indexOf(CommandLine.Model.UsageMessageSpec.SECTION_KEY_FOOTER_HEADING);
keys.add(index, SECTION_KEY_ENV_HEADING);
keys.add(index + 1, SECTION_KEY_ENV_DETAILS);
cmd.setHelpSectionKeys(keys);
----
More examples for customizing the usage help message are https://github.com/remkop/picocli/tree/master/picocli-examples/src/main/java/picocli/examples/customhelp[here].
=== Custom Layout
Picocli also supports unconventional option list layouts. An example of an unconventional layout is the `zip` application, which shows multiple options per row:
[source,java]
----
CommandLine.usage(new ZipHelpDemo(), System.out);
----
----
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
Zip 3.0 (July 5th 2008). Command:
zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]
The default action is to add or replace zipfile entries from list, which
can include the special name - to compress standard input.
If zipfile and list are omitted, zip compresses stdin to stdout.
-f freshen: only changed files -u update: only changed or new files
-d delete entries in zipfile -m move into zipfile (delete OS files)
-r recurse into directories -j junk (don't record) directory names
-0 store only -l convert LF to CR LF (-ll CR LF to LF)
-1 compress faster -9 compress better
-q quiet operation -v verbose operation/print version info
-c add one-line comments -z add zipfile comment
-@ read names from stdin -o make zipfile as old as latest entry
-x exclude the following names -i include only the following names
-F fix zipfile (-FF try harder) -D do not add directory entries
-A adjust self-extracting exe -J junk zipfile prefix (unzipsfx)
-T test zipfile integrity -X eXclude eXtra file attributes
-y store symbolic links as the link instead of the referenced file
-e encrypt -n don't compress these suffixes
-h2 show more help
----
This can be achieved in picocli by subclassing the Help.Layout class.
See the https://github.com/remkop/picocli/blob/master/src/test/java/picocli/CustomLayoutDemo.java[CustomLayoutDemo] class in the picocli tests for how to achieve this.
== Subcommands
=== Registering Subcommands Declaratively
From v0.9.8, picocli supports registering subcommands declaratively with the `@Command` annotation's `subcommands` attribute.
[source,java]
----
@Command(subcommands = {
GitStatus.class,
GitCommit.class,
GitAdd.class,
GitBranch.class,
GitCheckout.class,
GitClone.class,
GitDiff.class,
GitMerge.class,
GitPush.class,
GitRebase.class,
GitTag.class
})
public class Git { ... }
----
The declared subcommands are automatically instantiated and added when the `new CommandLine(new Git())` instance is constructed. The result is the same as if subcommands were added <<Registering Subcommands Programmatically,programmatically>>.
Subcommands referenced in a `subcommands` attribute _must_ have a `@Command` annotation with a `name` attribute, or an exception is thrown from the `CommandLine` constructor. This name will be used both for generating usage help and for recognizing subcommands when parsing the command line.
Custom type converters registered on a `CommandLine` instance will apply to all subcommands that were declared on the main command with the `subcommands` annotation.
Subcommands referenced in a `subcommands` attribute need to have a public no-argument constructor to be instantiated, unless a <<Custom Factory>> is installed to instantiate classes.
=== Registering Subcommands Programmatically
Subcommands can be registered with the `CommandLine.addSubcommand` method.
You pass in the name of the command and the annotated object to populate with the subcommand options.
The specified name is used by the parser to recognize subcommands in the command line arguments.
[source,java]
----
CommandLine commandLine = new CommandLine(new Git())
.addSubcommand("status", new GitStatus())
.addSubcommand("commit", new GitCommit())
.addSubcommand("add", new GitAdd())
.addSubcommand("branch", new GitBranch())
.addSubcommand("checkout", new GitCheckout())
.addSubcommand("clone", new GitClone())
.addSubcommand("diff", new GitDiff())
.addSubcommand("merge", new GitMerge())
.addSubcommand("push", new GitPush())
.addSubcommand("rebase", new GitRebase())
.addSubcommand("tag", new GitTag());
----
It is strongly recommended that subcommands have a `@Command` annotation with `name` and `description` attributes.
From picocli 3.1, the usage help synopsis of the subcommand shows not only the subcommand name but also the parent command name.
For example, if the `git` command has a `commit` subcommand, the usage help for the `commit` subcommand shows `Usage: git commit <options>`.
CAUTION: _Note on custom type converters:_ custom type converters are registered only with the subcommands and nested
sub-subcommands that were added _before_ the custom type was registered.
To ensure a custom type converter is available to all subcommands, register the type converter last, after
adding subcommands.
=== Subcommand Aliases
Commands may optionally define an `aliases` attribute to provide alternate names for commands that will be recognized by the parser. Aliases are displayed in the default help output. For example:
[source,java]
----
@Command(name = "status", aliases = {"st"}, description = "Show the working tree status.")
class GitStatus { ... }
----
Would result in this help fragment:
----
status, st Show the working tree status.
----
=== Subcommands as Methods
From picocli 3.6 it is possible to register subcommands in a very compact manner by having a `@Command` class with `@Command`-annotated methods. The methods are automatically <<Subcommand Methods, registered as subcommands>> of the `@Command` class.
=== Executing Subcommands
The easiest way to design an application with subcommands is to let each command and subcommand either be a class that implements `Runnable` or `Callable`, or a `@Command`-annotated method.
This will allow you to parse the command line, deal with requests for help and requests for version information, deal with invalid user input, and invoke the business logic of the user-specified subcommand - all of that - in one line of code: the <<Executing Commands,`execute`>> method.
For example:
[source,java]
----
@Command(name = "foo", subcommands = Bar.class)
class Foo implements Callable<Integer> {
@Option(names = "-x") int x;
@Override public Integer call() {
System.out.printf("hi from foo, x=%d%n", x);
boolean ok = true;
return ok ? 0 : 1; // exit code
}
public static void main(String... args) {
int exitCode = new CommandLine(new Foo()).execute(args);
System.exit(exitCode);
}
}
@Command(name = "bar", description = "I'm a subcommand of `foo`")
class Bar implements Callable<Integer> {
@Option(names = "-y") int y;
@Override public Integer call() {
System.out.printf("hi from bar, y=%d%n", y);
return 23;
}
@Command(name = "baz", description = "I'm a subcommand of `bar`")
int baz(@Option(names = "-z") int z) {
System.out.printf("hi from baz, z=%d%n", z);
return 45;
}
}
----
To test our example on Linux, we created an alias `foo` that invokes our Java application. This could also be a script or a function that calls our Java program:
[source,bash]
----
alias foo='java Foo'
----
Next, we call our top-level command with an option like this:
[source,bash]
----
$ foo -x 123
hi from foo, x=123
#check the exit code
$ echo $?
0
----
We can also specify a subcommand:
[source,bash]
----
$ foo -x 123 bar -y=456
hi from bar, y=456
#check the exit code
$ echo $?
23
----
And finally, we can also specify a sub-subcommand:
[source,bash]
----
$ foo bar baz -z=789
hi from baz, z=789
#check the exit code
$ echo $?
45
----
As you can see, the _last specified_ command or subcommand is executed and its exit code is returned.
See also <<Executing Commands with Subcommands>> for details on configuring this.
=== Manually Parsing Subcommands
For the following example, we assume we created an alias `git` that invokes our Java application. This could also be a script or a function that calls our Java program:
[source,bash]
----
alias git='java picocli.Demo$Git'
----
Next, we call our command with some arguments like this:
[source,bash]
----
git --git-dir=/home/rpopma/picocli status -sb -uno
----
Where `git` (actually `java picocli.Demo$Git`) is the top-level command, followed by a global option and a subcommand `status` with its own options.
Setting up the parser and parsing the command line could look like this:
[source,java]
----
public static void main(String... args) {
// Set up the parser
CommandLine commandLine = new CommandLine(new Git());
// add subcommands programmatically (not necessary if the parent command
// declaratively registers the subcommands via annotation)
commandLine.addSubcommand("status", new GitStatus())
.addSubcommand("commit", new GitCommit())
...
// Invoke the parseArgs method to parse the arguments
ParseResult parsed = commandLine.parseArgs(args);
handleParseResult(parsed);
}
----
The `CommandLine.parseArgs` method returns a `ParseResult` that can be queried to get information about
the top-level command (the Java class invoked by `git` in this example).
The `ParseResult.subcommand()` method returns a nested `ParseResult` if the parser found a subcommand.
This can be recursively queried until the last nested subcommand was found and the `ParseResult.subcommand()` method returns `null`.
[source,java]
----
private void handleParseResult(ParseResult parsed) {
assert parsed.subcommand() != null : "at least 1 command and 1 subcommand found"
ParseResult sub = parsed.subcommand();
assert parsed.commandSpec().userObject().getClass() == Git.class : "main command"
assert sub.commandSpec().userObject().getClass() == GitStatus.class : "subcommand"
Git git = (Git) parsed.commandSpec().userObject();
assert git.gitDir.equals(new File("/home/rpopma/picocli"));
GitStatus gitstatus = (GitStatus) sub.commandSpec().userObject();
assert gitstatus.shortFormat : "git status -s"
assert gitstatus.branchInfo : "git status -b"
assert !gitstatus.showIgnored : "git status --showIgnored not specified"
assert gitstatus.mode == GitStatusMode.no : "git status -u=no"
}
----
You may be interested in the <<Executing Commands,execute method>> to reduce error handling and other boilerplate code in your application.
See also the previous section, <<Executing Subcommands>>.
=== `@ParentCommand` Annotation
In command line applications with subcommands, options of the top level command are often intended as "global" options that apply to all the subcommands. Prior to picocli 2.2, subcommands had no easy way to access their parent command options unless the parent command made these values available in a global variable.
The `@ParentCommand` annotation introduced in picocli 2.2 makes it easy for subcommands to access their parent command options: subcommand fields annotated with `@ParentCommand` are initialized with a reference to the parent command. For example:
[source,java]
----
@Command(name = "fileutils", subcommands = List.class)
class FileUtils {
@Option(names = {"-d", "--directory"},
description = "this option applies to all subcommands")
File baseDirectory;
}
----
The above top-level command has a `--directory` option that applies to its subcommands.
The `List` subcommand can use the `@ParentCommand` annotation to get a reference to the parent command, so it can easily access the parent command options.
[source,java]
----
@Command(name = "list")
class List implements Runnable {
@ParentCommand
private FileUtils parent; // picocli injects reference to parent command
@Option(names = {"-r", "--recursive"},
description = "Recursively list subdirectories")
private boolean recursive;
@Override
public void run() {
list(new File(parent.baseDirectory, "."));
}
private void list(File dir) {
System.out.println(dir.getAbsolutePath());
if (dir.isDirectory()) {
for (File f : dir.listFiles()) {
if (f.isDirectory() && recursive) {
list(f);
} else {
System.out.println(f.getAbsolutePath());
}
}
}
}
}
----
=== Usage Help for Subcommands
After registering subcommands, calling the `commandLine.usage` method will show a usage help message that includes all registered subcommands. For example:
[source,java]
----
CommandLine commandLine = new CommandLine(new Git());
// add subcommands programmatically (not necessary if the parent command
// declaratively registers the subcommands via annotation)
commandLine.addSubcommand("status", new GitStatus());
commandLine.addSubcommand("commit", new GitCommit());
...
commandLine.usage(System.out);
----
The usage help message shows the commands in the order they were registered:
[#subcommand-help]
----
Usage: git [-hV] [--git-dir=<gitDir>] [COMMAND]
Git is a fast, scalable, distributed revision control system with an unusually
rich command set that provides both high-level operations and full access to
internals.
--git-dir=<gitDir> Set the path to the repository.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
Commands:
The most commonly used git commands are:
help Displays help information about the specified command
status Show the working tree status.
commit Record changes to the repository.
add Add file contents to the index.
branch List, create, or delete branches.
checkout Checkout a branch or paths to the working tree.
clone Clone a repository into a new directory.
diff Show changes between commits, commit and working tree, etc.
merge Join two or more development histories together.
push Update remote refs along with associated objects.
rebase Forward-port local commits to the updated upstream head.
tag Create, list, delete or verify a tag object signed with GPG.
----
The description of each subcommand in the command list is taken from the subcommand's first `header` line, or the first `description` line if it does not have a `header` defined.
The above usage help message is produced from the annotations on the class below:
[source,java]
----
@Command(name = "git", mixinStandardHelpOptions = true,
version = "subcommand demo - picocli 3.0",
subcommands = HelpCommand.class,
description = "Git is a fast, scalable, distributed revision control " +
"system with an unusually rich command set that provides both " +
"high-level operations and full access to internals.",
commandListHeading = "%nCommands:%n%nThe most commonly used git commands are:%n")
class Git {
@Option(names = "--git-dir", description = "Set the path to the repository.")
private File gitDir;
}
----
The above example uses the <<Mixin Standard Help Options,mixinStandardHelpOptions>> attribute to mix in
<<Help Options,`usageHelp`>> and <<Help Options,`versionHelp`>> options and registers the `help` subcommand.
TIP: Use the `@Spec` annotation for subcommands that need to show the usage help message explicitly.
From picocli 3.1, the usage help synopsis of the subcommand shows not only the subcommand name but also the parent command name.
For example, if the `git` command has a `commit` subcommand, the usage help for the `commit` subcommand shows `Usage: git commit <options>`.
If a subcommand explicitly wants to show the usage help message, the `@Spec` annotation may be useful.
The injected `CommandSpec` has its parent command initialized correctly, so the usage help can show the fully qualified name of the subcommand.
[source,java]
----
@Command(name = "commit", description = "...")
class Commit implements Runnable {
@Spec CommandSpec spec;
public void run() {
if (shouldShowHelp()) {
spec.commandLine().usage(System.out);
}
}
}
----
For example, see <<Section Headings>> for an example subcommand (`git commit`), which produces the help message shown
in <<Expanded Example>>.
=== Hidden Subcommands
Commands with the `hidden` attribute set to `true` will not be shown in the usage help message of their parent command.
For example, the `bar` subcommand below is annotated as `hidden = true`:
[source,java]
----
@Command(name = "foo", description = "This is a visible subcommand")
class Foo { }
@Command(name = "bar", description = "This is a hidden subcommand", hidden = true)
class Bar { }
@Command(name = "app", subcommands = {Foo.class, Bar.class})
class App { }
----
The usage help message for `App` looks like the below. Note that the `bar` subcommand is not shown:
----
Usage: app
Commands:
foo This is a visible subcommand
----
=== Help Subcommands
Commands with the `helpCommand` attribute set to `true` are treated as help commands.
When picocli encounters a help command on the command line, required options and required positional parameters of the parent command
are not validated (similar to <<Help Options,help options>>).
See <<Custom Help Subcommands>> for more details on creating help subcommands.
[source,java]
----
@Command(helpCommand = true)
----
=== Nested sub-Subcommands
The specified object can be an annotated object or a
`CommandLine` instance with its own nested subcommands. For example:
[source,java]
----
CommandLine commandLine = new CommandLine(new MainCommand())
.addSubcommand("cmd1", new ChildCommand1())
.addSubcommand("cmd2", new ChildCommand2())
.addSubcommand("cmd3", new CommandLine(new ChildCommand3())
.addSubcommand("cmd3sub1", new GrandChild3Command1())
.addSubcommand("cmd3sub2", new GrandChild3Command2())
.addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3())
.addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
.addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
)
);
----
Declaratively, subcommands can be nested by specifying the `subcommands` attribute on subcommand classes:
[source,java]
----
@Command(name = "main", subcommands = {
ChildCommand1.class,
ChildCommand2.class,
ChildCommand3.class })
class MainCommand { }
@Command(name = "cmd3", subcommands = {
GrandChild3Command1.class,
GrandChild3Command2.class,
GrandChild3Command3.class })
class ChildCommand3 { }
@Command(name = "cmd3sub3", subcommands = {
GreatGrandChild3Command3_1.class,
GreatGrandChild3Command3_2.class })
class GrandChild3Command3 { }
...
----
By default, the usage help message only shows the subcommands of the specified command,
and not the nested sub-subcommands. This can be customized by specifying your own <<Reordering Sections,`IHelpSectionRenderer`>> for the command list section.
The `picocli-examples` module has an https://github.com/remkop/picocli/blob/master/picocli-examples/src/main/java/picocli/examples/customhelp/ShowCommandHierarchy.java[example] that shows how to accomplish this.
=== Required Subcommands
For some command suites, it does not make sense to invoke the top-level command by itself, and the user is required to specify a subcommand.
Picocli does not offer direct support for making a subcommand required, but it does provide the tools to:
* display a synopsis that indicates that subcommands are mandatory
* respond appropriately when the user input is invalid
By default, the synopsis of a command with subcommands shows `[COMMAND]`, indicating that a subcommand can optionally be specified.
To show that the subcommand is mandatory, set the `synopsisSubcommandLabel` attribute to `COMMAND`, without the `[` and `]` brackets.
If the end user invokes the top-level command without specifying a subcommand, one way to respond is to show an error message followed by the usage help of the top-level command.
This can be accomplished by letting the top-level command throw a `ParameterException`. For example:
[source,java]
----
@Command(name = "git", synopsisSubcommandLabel = "COMMAND", subcommands = { ... })
class Git implements Runnable {
@Spec CommandSpec spec;
public void run() {
throw new ParameterException(spec.commandLine(), "Missing required subcommand");
}
public static void main(String... args) {
System.exit(new CommandLine(new Git()).execute(args));
}
}
----
== Reuse
You may find yourself defining the same options, parameters or command attributes in many command line applications.
To reduce duplication, picocli supports both subclassing and mixins as ways to reuse such options and attributes.
For both mechanisms, the first step is to extract these options, parameters and command attributes into a separate class. Below is an example class, `ReusableOptions`, that we will use in example scenarios in this chapter:
[source,java]
----
@Command(synopsisHeading = "%nUsage:%n%n",
descriptionHeading = "%nDescription:%n%n",
parameterListHeading = "%nParameters:%n%n",
optionListHeading = "%nOptions:%n%n",
commandListHeading = "%nCommands:%n%n")
public class ReusableOptions {
@Option(names = { "-v", "--verbose" }, description = {
"Specify multiple -v options to increase verbosity.",
"For example, `-v -v -v` or `-vvv`" })
protected boolean[] verbosity = new boolean[0];
}
----
This defines some usage help attributes that give a spacious layout, and a `verbosity` option that makes the operation more talkative.
=== Subclassing
One way to reuse the above option and attributes is to extend the class. Picocli will walk the class hierarchy to check for annotations, so `@Options`, `@Parameters` and `@Command` attributes declared on a superclass are available in all subclasses.
For example, all commands that extend the <<Reuse,above sample>> `ReusableOptions` class will inherit the `--verbose` option, and generate a usage help message in the same spacious style. Example code:
[source,java]
----
@Command(name = "zip", description = "Example reuse by subclassing")
public class MyCommand extends ReusableOptions { ... }
----
=== Mixins
Picocli 3.0 introduces the concept of "mixins". Mixins are a convenient alternative to subclassing:
picocli annotations from _any_ class can be added to ("mixed in" with) another command.
This includes options, positional parameters, subcommands and command attributes.
Picocli <<Mixin Standard Help Options,mixinStandardHelpOptions>> internally uses a mixin.
A mixin is a separate class with options, positional parameters, subcommands and command attributes
that you want to reuse in other commands.
Mixins can be installed by calling the `CommandLine.addMixin` method with an object of this class, or annotating a field in your command with `@Mixin`.
==== Adding Mixins Programmatically
The below example shows how a mixin can be added programmatically with the `CommandLine.addMixin` method.
We use the sample `ReusableOptions` class <<Reuse,defined above>> as the mixin:
[source,java]
----
CommandLine commandLine = new CommandLine(new MyCommand());
ReusableOptions mixin = new ReusableOptions();
commandline.addMixin("myMixin", mixin);
----
Programmatically added mixins can be accessed via the map returned by `CommandLine.getMixins`. Continuing from the previous example:
[source,java]
----
commandLine.parseArgs("-vvv");
// the options defined in ReusableOptions have been added to the zip command
assert mixin == commandLine.getMixins().get("myMixin");
assert mixin.verbosity.length == 3;
----
==== `@Mixin` Annotation
A command can also include a mixin by annotating a field with `@Mixin`. All picocli annotations found in the mixin class
are added to the command that has a field annotated with `@Mixin`. For example, again using the sample `ReusableOptions` class <<Reuse,defined above>>:
[source,java]
----
@Command(name = "zip", description = "Example reuse with @Mixin annotation.")
public class MyCommand {
// adds the options defined in ReusableOptions to this command
@Mixin
private ReusableOptions myMixin;
...
}
----
In addition to adding the options, subcommands and command attributes of the mixed-in object to the command,
the mixed-in object is also injected into the field annotated with `@Mixin`, making it trivial for the command to reference the mixed-in object if necessary.
[source,java]
----
MyCommand zip = new MyCommand();
CommandLine commandLine = new CommandLine(zip);
commandLine.parseArgs("-vvv");
// the options defined in ReusableOptions have been added to the zip command
assert zip.myMixin.verbosity.length == 3;
----
Mixins added with the `@Mixin` annotation can also be accessed via the map returned by `CommandLine.getMixins`.
The GitHub project has a https://github.com/remkop/picocli/tree/master/picocli-examples/src/main/java/picocli/examples/mixin[full working example].
=== Reuse Combinations
The above mechanisms can be combined in any way. Mixins can be nested, and there is no limitation to how deeply mixins can be nested. A mixin may also inherit options, positional parameters and command attributes from a super class.
An option with the same name should not be defined multiple times or a `DuplicateOptionAnnotationsException` is thrown during initialization. Positional parameters for the same position may be defined multiple times, they can co-exist.
Command attributes may be defined multiple times, but only one value is preserved. In case a command attribute is defined multiple times, the definition earlier in the following list takes priority over later in the list:
. @Command attributes of the command itself
. Attributes on the @Mixin commands
. Attributes on a @Mixin nested in a @Mixin of the command
. Attributes on superclass of nested @Mixin
. Attributes on superclass of @Mixin
. Attributes on superclass of the command
. Attributes on programmatically added mixins
== Internationalization
From version 3.6, usage help message sections and the description for options and positional parameters can be specified in a resource bundle.
A resource bundle can be set via annotations and programmatically.
=== Configuration
Annotation example:
[source,java]
----
@Command(name = "i18n-demo", resourceBundle = "my.org.I18nDemo_Messages")
class I18nDemo {}
----
Programmatic example:
[source,java]
----
@Command class I18nDemo2 {}
CommandLine cmd = new CommandLine(new I18nDemo2());
cmd.setResourceBundle(ResourceBundle.getBundle("my.org.I18nDemo2_Messages"));
----
=== Example Resource Bundle
Example properties resource bundle:
[source]
----
# Usage Help Message Sections
# ---------------------------
# Numbered resource keys can be used to create multi-line sections.
usage.headerHeading = This is my app. It does stuff. Good stuff.%n
usage.header = header first line
usage.header.0 = header second line
usage.descriptionHeading = Description:%n
usage.description.0 = first line
usage.description.1 = second line
usage.description.2 = third line
usage.synopsisHeading = Usage:\u0020
# Leading whitespace is removed by default.
# Start with \u0020 to keep the leading whitespace.
usage.customSynopsis.0 = Usage: ln [OPTION]... [-T] TARGET LINK_NAME (1st form)
usage.customSynopsis.1 = \u0020 or: ln [OPTION]... TARGET (2nd form)
usage.customSynopsis.2 = \u0020 or: ln [OPTION]... TARGET... DIRECTORY (3rd form)
# Headings can contain the %n character to create multi-line values.
usage.parameterListHeading = %nPositional parameters:%n
usage.optionListHeading = %nOptions:%n
usage.commandListHeading = %nCommands:%n
usage.footerHeading = Powered by picocli%n
usage.footer = footer
# Option Descriptions
# -------------------
# Use numbered keys to create multi-line descriptions.
# Example description for an option `@Option(names = "-x")`
x = This is the description for the -x option
# Example multi-line description for an option `@Option(names = "-y")`
y.0 = This is the first line of the description for the -y option
y.1 = This is the second line of the description for the -y option
# Example descriptions for the standard help mixin options:
help = Show this help message and exit.
version = Print version information and exit.
# Exit Code Description
usage.exitCodeListHeading = Exit Codes:%n
usage.exitCodeList.0 = \u00200:Successful program execution. (notice leading space '\u0020')
usage.exitCodeList.1 = 64:Usage error: user input for the command was incorrect.
usage.exitCodeList.2 = 70:An exception occurred when invoking the business logic of this command.
----
For options and positional parameters, the optional annotation attribute `descriptionKey` can be used to localize the description. For example:
```java
@Option(names = "-x", descriptionKey = "xoption") int x;
```
The matching entry in the resource bundle could look like this:
```
xoption = This is the description for the -x option.
```
When the `descriptionKey` is omitted, the https://picocli.info/apidocs/picocli/CommandLine.Option.html#descriptionKey--[fallback for options] is any option name without the leading dashes, for example:
```java
@Option(names = {"-v", "--verbose") boolean[] verbose;
```
The matching entry in the resource bundle could look like this:
----
verbose = Show more detail during execution. \
May be specified multiple times for increasing verbosity.
----
For https://picocli.info/apidocs/picocli/CommandLine.Parameters.html#descriptionKey--[positional parameters] the fallback key is the `paramLabel + [ index ]`, for example:
[source,java]
----
@Parameters(index = "0..*", paramLabel="FILES") File[];
----
The matching entry in the resource bundle could look like this:
----
FILES[0..*] = The files to process.
----
For argument groups, use the `headingKey` to specify a resource bundle key. For example:
```java
@ArgGroup(headingKey = "myBundleKey") MyArgGroup myGroup;
```
The matching entry in the resource bundle could look like this:
----
myBundleKey = The localized heading for this argument group%n
----
Note that the heading text should end with `%n` or the first option in the group will be on the same line.
This is to be consistent with other <<Section Headings,section headings>> in the usage help.
=== Shared Resource Bundles
Resources for multiple commands can be specified in a single ResourceBundle. Keys and their value can be
shared by multiple commands (so you don't need to repeat them for every command), but alternatively, keys can be prefixed with
`command name + "."` to specify different values for different commands.
The most specific key wins. For example:
[source]
----
jfrog.rt.usage.header = Artifactory commands
jfrog.rt.config.usage.header = Configure Artifactory details.
jfrog.rt.upload.usage.header = Upload files.
# shared between all commands
usage.footerHeading = Environment Variables:
usage.footer.0 = footer line 0
usage.footer.1 = footer line 1
----
=== Localizing the Built-In Help
The built-in `picocli.CommandLine.HelpCommand` can be localized as follows:
* `help.usage.header` controls the help command summary in the subcommand list
* `helpCommand.help` is the resource bundle key for the `--help` option of the help subcommand
* `helpCommand.command` is the resource bundle key for the `COMMAND` positional parameter of the help subcommand
[source]
----
# for a specific subcommand, e.g., `parent help`
parent.help.usage.header=This is the `help` subcommand of the `parent` command
parent.help.helpCommand.help = Specialized description of --help option of help subcommand for parent command
parent.help.helpCommand.command = Specialized description of COMMAND parameter of help subcommand for parent command
# or have one global entry for the `help` subcommand (for any and all commands)
help.usage.header=This is the `help` subcommand
helpCommand.help = Shared description of --help option of built-in help subcommand
helpCommand.command = Shared description of COMMAND parameter of built-in help subcommand
----
=== Localizing Default Values
Options with a <<Default Values,default value>> can use the `${DEFAULT-VALUE}` variable in the localized option description in the resource bundle:
[source]
----
userName=Specify the user name. The default is ${DEFAULT-VALUE}.
----
== Variable Interpolation
From 4.0, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API.
=== Variable Interpolation Example
```java
@Command(name = "status",
description = "This command logs the ${COMMAND-NAME} for ${PARENT-COMMAND-NAME}.",
version = {
"Versioned Command 1.0",
"Picocli " + picocli.CommandLine.VERSION,
"JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})",
"OS: ${os.name} ${os.version} ${os.arch}"})
class Status {
// -d or --directories
@Option(names = {"${dirOptionName1:--d}", "${dirOptionName2:---directories}"},
description = {"Specify one or more directories, " +
"separated by '${sys:path.separator}'.",
"The default is the user home directory (${DEFAULT-VALUE})."},
arity = "${sys:dirOptionArity:-1..*}",
defaultValue = "${sys:user.home}",
split = "${sys:path.separator}")
String[] directories;
}
```
=== Predefined Variables
The following variables are predefined:
[grid=cols,cols=".<3,.^1,.<3,.<3",options="header"]
|===
|Variable | Since | Use in | Meaning
|`${DEFAULT-VALUE}`| 3.2 | the description for an option or positional parameter|replaced with the <<defaultValue-annotation,default value>> for that option or positional parameter
|`${FALLBACK-VALUE}`| 4.0 | the description for an option with optional parameter|replaced with the <<fallbackValue-annotation,fallback value>> for that option or positional parameter
|`${COMPLETION-CANDIDATES}`| 3.2 | the description for an option or positional parameter| replaced with the completion candidates for that option or positional parameter
|`${COMMAND-NAME}`| 4.0 | any section of the usage help message for a command|replaced with the name of the command
|`${COMMAND-FULL-NAME}`| 4.0 | any section of the usage help message for a command| replaced with the fully qualified name of the command (that is, preceded by its parent fully qualified name)
|`${PARENT-COMMAND-NAME}`| 4.0 | any section of the usage help message for a command| replaced with the name of its parent command
|`${PARENT-COMMAND-FULL-NAME}`| 4.0 | any section of the usage help message for a command| replaced with the fully qualified name of its parent command (that is, preceded by the name(s) of the parent command's ancestor commands)
|===
=== Custom Variables
In addition, you can define your own variables. Currently the following syntaxes are supported:
* `${sys:key}`: system property lookup, replaced by the value of `System.getProperty("key")`
* `${env:key}`: environment variable lookup, replaced by the value of `System.getEnv("key")`
* `${bundle:key}`: look up the value of `key` in the resource bundle of the command
* `${key}`: search all of the above, first system properties, then environment variables, and finally the resource bundle of the command
=== Default Values for Custom Variables
You can specify a default value to use when no value is found for a custom variable. The syntax for specifying a default is `${a:-b}`, where `a` is the variable name and `b` is the default value to use if `a` is not found.
So, for the individual lookups, this looks like this:
```
${key:-defaultValue}
${sys:key:-defaultValue}
${env:key:-defaultValue}
${bundle:key:-defaultValue}
```
The default value may contain other custom variables. For example:
```
${bundle:a:-${env:b:-${sys:c:-X}}}
```
The above variable is expanded as follows. First, try to find key `a` in the command's resource bundle. If `a` is not found in the resource bundle, get the value of environment variable `b`. If no environment variable `b` exists, get the value of system property `c`. Finally, no system property `c` exists, the value of the expression becomes `X`.
=== Escaping Variables
Sometimes you want to show a string like `"${VAR}"` in a description.
A `$` character can be escaped with another `$` character. Therefore, `$${VAR}` will not be interpreted as a `VAR` variable, but will be replaced by `${VAR}` instead.
=== Switching Off Variable Interpolation
Variable interpolation can be switched off for the full command hierarchy by calling `CommandLine.setInterpolateVariables(false)`, or for a particular command by calling `CommandSpec.interpolateVariables(false)`.
=== Limitations of Variable Interpolation
Some attribute values need to be resolved early, when the model is constructed from the annotation values.
Specifically:
* command names and aliases, option names, mixin names
* `arity` (for options and positional parameters)
* `index` (for positional parameters)
* `separator` (for commands)
It is possible for these attributes to contain variables, but be aware of the limitations.
If these attributes have variables, and the variables get a different value after the model is constructed, the change will not be reflected in the model.
//Also, the annotation processor will not be able to resolve these variables at compile time and will not be able to construct a model.
== Tips & Tricks
[#option-parameters-methods]
=== `@Option` and `@Parameters` Methods
From version 3.2, `@Option` and `@Parameters` annotations can be added to methods as well as fields of a class.
For concrete classes, annotate "setter" methods (methods that accept a parameter) and when the option is specified on the command line, picocli will invoke the method with the value specified on the command line, converted to the type of the method parameter.
Alternatively, you may annotate "getter-like" methods (methods that return a value) on an interface, and picocli will create an instance of the interface that returns the values specified on the command line, converted to the method return type.
==== Annotating Methods of an Interface
The `@Option` and `@Parameters` annotations can be used on methods of an interface that return a value. For example:
[source,java]
----
interface Counter {
@Option(names = "--count")
int getCount();
}
----
You use it by specifying the class of the interface:
[source,java]
----
CommandLine cmd = new CommandLine(Counter.class); // specify a class
String[] args = new String[] {"--count", "3"};
cmd.parseArgs(args);
Counter counter = cmd.getCommand(); // picocli created an instance
assert counter.getCount() == 3; // method returns command line value
----
==== Annotating Methods of a Concrete Class
The `@Option` and `@Parameters` annotations can be used on methods of a class that accept a parameter. For example:
[source,java]
----
class Counter {
int count;
@Option(names = "--count")
void setCount(int count) {
this.count = count;
}
}
----
You use it by passing an instance of the class:
[source,java]
----
Counter counter = new Counter(); // the instance to populate
CommandLine cmd = new CommandLine(counter);
String[] args = new String[] {"--count", "3"};
cmd.parseArgs(args);
assert counter.count == 3; // method was invoked with command line value
----
Methods annotated with `@Option` and `@Parameters` can do simple input validation by throwing a `ParameterException` when invalid values are specified on the command line.
[source,java]
----
class ValidationExample {
private Map<String, String> properties = new LinkedHashMap<>();
@Spec private CommandSpec spec; // injected by picocli
@Option(names = {"-D", "--property"}, paramLabel = "KEY=VALUE")
public void setProperty(Map<String, String> map) {
for (String key : map.keySet()) {
String newValue = map.get(key);
validateUnique(key, newValue);
properties.put(key, newValue);
}
}
private void validateUnique(String key, String newValue) {
String existing = properties.get(key);
if (existing != null && !existing.equals(newValue)) {
throw new ParameterException(spec.commandLine(),
String.format("Duplicate key '%s' for values '%s' and '%s'.",
key, existing, newValue));
}
}
// ...
}
----
[#command-methods]
=== `@Command` Methods
From picocli 3.6, methods can be annotated with `@Command`.
The method parameters provide the command options and parameters. For example:
[source,java]
----
class Cat {
public static void main(String[] args) {
CommandLine.invoke("cat", Cat.class, args);
}
@Command(description = "Concatenate FILE(s) to standard output.",
mixinStandardHelpOptions = true, version = "3.6.0")
void cat(@Option(names = {"-E", "--show-ends"}) boolean showEnds,
@Option(names = {"-n", "--number"}) boolean number,
@Option(names = {"-T", "--show-tabs"}) boolean showTabs,
@Option(names = {"-v", "--show-nonprinting"}) boolean showNonPrinting,
@Parameters(paramLabel = "FILE") File[] files) {
// process files
}
}
----
The usage help of the above command looks like this:
----
Usage: cat [-EhnTvV] [FILE...]
Concatenate FILE(s) to standard output.
[FILE...]
-E, --show-ends
-h, --help Show this help message and exit.
-n, --number
-T, --show-tabs
-v, --show-nonprinting
-V, --version Print version information and exit.
----
See below for an example that uses a <<Internationalization,resource bundle>> to define usage help descriptions outside the code.
For positional parameters, the `@Parameters` annotation may be omitted on method parameters.
TIP: If compiled with the `-parameters` flag on Java 8 or higher, the `paramLabel` of positional parameters is obtained from the method parameter name using reflection instead of the generic arg0, arg1, etc.
==== Subcommand Methods
If the enclosing class is annotated with `@Command`, method commands are automatically added as subcommands to the class command, unless the class command has attribute `@Command(addMethodSubcommands = false)`.
For example:
[source,java]
----
@Command(name = "git", mixinStandardHelpOptions = true,
resourceBundle = "Git_Messages", version = "picocli-3.6.0")
class Git {
@Option(names = "--git-dir", descriptionKey = "GITDIR")
Path path;
@Command
void commit(@Option(names = {"-m", "--message"}) String commitMessage,
@Option(names = "--squash", paramLabel = "<commit>") String squash,
@Parameters(paramLabel = "<file>") File[] files) {
// ... implement business logic
}
}
----
Use `@Command(addMethodSubcommands = false)` on the class `@Command` annotation if the `@Command`-annotated methods in this class should not be added as subcommands.
==== Description Text in ResourceBundle
The usage help of the above `git commit` example command is very minimal:
----
Usage: git commit [--squash=<commit>] [-m=<arg0>] [<file>...]
[<file>...]
--squash=<commit>
-m, --message=<arg0>
----
You can use a <<Internationalization,resource bundle>> to move the descriptions out of the code:
----
# shared between all commands
help = Show this help message and exit.
version = Print version information and exit.
# command-specific strings
git.usage.description = Version control system
git.GITDIR = Set the path to the repository
git.commit.usage.description = Record changes to the repository
git.commit.message = Use the given <msg> as the commit message.
git.commit.squash = Construct a commit message for use with rebase --autosquash.
git.commit.<file>[0..*] = The files to commit.
----
With this resource bundle, the usage help for the `git commit` command looks like this:
----
Usage: git commit [--squash=<commit>] [-m=<arg0>] [<file>...]
Record changes to the repository
[<file>...] The files to commit.
--squash=<commit> Construct a commit message for use with rebase
--autosquash.
-m, --message=<arg0> Use the given <msg> as the commit message.
----
==== Mixin Support in `@Command` Methods
From picocli 3.8, `@Command` methods accept `@Mixin` parameters.
All options and positional parameters defined in the mixin class are added to the command.
Example:
```java
class CommonParams {
@Option(names = "-x") int x;
@Option(names = "-y") int y;
}
class App {
@Command
public void doit(@Mixin CommonParams params, @Option(names = "-z") int z) {}
}
```
In the above example, the `-x` and `-y` options are added to the other options of the `doit` command.
=== `@Spec` Annotation
Picocli 3.2 introduces a `@Spec` annotation for injecting the `CommandSpec` model of the command into a command field.
This is useful when a command needs to use the picocli API, for example to walk the command hierarchy and iterate over its sibling commands.
This complements the `@ParentCommand` annotation; the `@ParentCommand` annotation injects a user-defined command object, whereas this annotation injects a picocli class.
[source,java]
----
class InjectSpecExample implements Runnable {
@Spec CommandSpec commandSpec;
//...
public void run() {
// do something with the injected spec
}
}
----
=== Improved Support for Chinese, Japanese and Korean
Picocli will align the usage help message to fit within some user-defined width (80 columns by default).
A number of characters in Chinese, Japanese and Korean (CJK) are wider than others.
If those characters are treated to have the same width as other characters, the usage help message may extend past the right margin.
From 4.0, picocli will use 2 columns for these wide characters when calculating where to put line breaks, resulting in better usage help message text.
This can be switched off with `CommandLine.setAdjustLineBreaksForWideCJKCharacters(false)`.
=== Custom Factory
Declaratively registered <<Registering Subcommands Declaratively,subcommands>>, <<Option-specific Type Converters,type converters>> and <<Dynamic Version Information,version providers>> must be instantiated somehow. From picocli 2.2, a custom factory can be specified when constructing a `CommandLine` instance. This allows full control over object creation and opens possibilities for Inversion of Control and Dependency Injection (see <<Dependency Injection,next section>>). For example:
[source,java]
----
IFactory myFactory = getCustomFactory();
CommandLine cmdLine = new CommandLine(new Git(), myFactory);
----
Custom factories need to implement the `picocli.CommandLine.IFactory` interface:
[source,java]
----
public interface IFactory {
/**
* Creates and returns an instance of the specified class.
* @param clazz the class to instantiate
* @param <K> the type to instantiate
* @return the new instance
* @throws Exception an exception detailing what went wrong when creating the instance
*/
<K> K create(Class<K> clazz) throws Exception;
}
----
If no factory is specified, a default factory is used. The default factory requires that the classes to instantiate have a public no-argument constructor: it instantiates the class by calling first calling `clazz.newInstance()`, and if that fails, `clazz.getDeclaredConstructor().newInstance()`.
From version 4.0, picocli delegates all object creation to the factory, including creating `Collection` instances to capture <<Arrays and Collections,multi-value>> `@Option` values.
Previously, `Collection` objects were instantiated separately without involving the factory.
It is recommended that custom factories should fall back to the default factory. Something like this:
```java
@Override
public <K> K create(Class<K> clazz) throws Exception {
try {
return doCreate(clazz); // custom factory lookup or instantiation
} catch (Exception e) {
return CommandLine.defaultFactory().create(clazz); // fallback if missing
}
}
```
=== Boolean Options with Parameters
By default the value of a boolean field is set to the logical negative of its default value when the option is specified on the command line.
It is possible to let end users explicitly specify "true" or "false" as a parameter for a boolean option by defining an explicit <<Arity>> attribute. A boolean option with `arity = "0..1"` accepts zero to one parameters, `arity = "1"` means the option _must_ have one parameter. For example:
[source, java]
----
class BooleanOptionWithParameters {
@Option(names = "-x", arity = "1", description = "1 mandatory parameter")
boolean x;
@Option(names = "-y", arity = "0..1", description = "min 0 and max 1 parameter")
boolean y;
}
----
The following ways to invoke the program will be accepted (values are not case sensitive):
----
<command> -x true
<command> -x FALSE
<command> -x TRUE -y
<command> -x True -y False
----
But trying to specify the `-x` option without a parameter, or with a value other than "true" or "false" (case insensitive) will result in a `ParameterException`.
=== Hexadecimal Values
Numeric values are interpreted as decimal numbers by default. If you want picocli to be more flexible, you can
register a custom type converter that delegates to the https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#decode-java.lang.String-[decode] method to convert strings to numbers.
NOTE: The `decode` method looks at the prefix to determine the radix, so numbers
starting with `0x`, `0X` or `#` are interpreted as hexadecimal numbers, numbers starting with `0` are interpreted
as octal numbers, and otherwise the number is interpreted as a decimal number.
Java 8-style lambdas:
[source,java]
----
new CommandLine(obj)
.registerConverter(Byte.class, s -> Byte::decode)
.registerConverter(Byte.TYPE, s -> Byte::decode)
.registerConverter(Short.class, s -> Short::decode)
.registerConverter(Short.TYPE, s -> Short::decode)
.registerConverter(Integer.class, s -> Integer::decode)
.registerConverter(Integer.TYPE, s -> Integer::decode)
.registerConverter(Long.class, s -> Long::decode)
.registerConverter(Long.TYPE, s -> Long::decode);
----
In Java 5:
[source,java]
----
ITypeConverter<Integer> intConverter = new ITypeConverter<Integer>() {
public Integer convert(String s) {
return Integer.decode(s);
}
};
commandLine.registerConverter(Integer.class, intConverter);
commandLine.registerConverter(Integer.TYPE, intConverter);
...
----
=== Option-Parameter Separators
==== Default Separators
Options may take an _option parameter_ (also called _option-argument_).
For POSIX-style short options (like `-f` or `-c`), the option parameter may be attached to the option,
or it may be separated by a space or the _separator string_ (`=` by default).
That is, all of the below are equivalent:
[source,java]
----
<command> -foutput.txt
<command> -f output.txt
<command> -f=output.txt
----
Long option names (like `--file`) must be separated from their option parameter by a space or the
_separator string_ (`=` by default). That is, the first two below examples are valid but the last example is invalid:
[source,java]
----
// valid (separator between --file and its parameter)
<command> --file output.txt
<command> --file=output.txt
// invalid (picocli will not recognize the --file option when attached to its parameter)
<command> --fileoutput.txt
----
==== Custom Separators
The separator string can be customized programmatically or declaratively.
Use the `separator` attribute of the `@Command` annotation to declaratively set a separator string:
[source,java]
----
@Command(separator = ":") // declaratively set a separator
class OptionArg {
@Option(names = { "-f", "--file" }) String file;
}
----
[source,java]
----
OptionArg optionArg = CommandLine.populateCommand(new OptionArg(), "-f:output.txt");
assert optionArg.file.equals("output.txt");
----
Alternatively, the separator string can be changed programmatically with the `CommandLine.setSeparator(String separator)` method.
For example:
[source,java]
----
OptionArg optionArg = new OptionArg();
CommandLine commandLine = new CommandLine(optionArg);
commandLine.setSeparator(":"); // programmatically set a separator
commandLine.parseArgs("-f:output.txt");
assert optionArg.file.equals("output.txt");
----
=== Best Practices for Command Line Interfaces
When designing your command line application,
the https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html#Command_002dLine-Interfaces[GNU recommendations] for command line interfaces and http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html#tag_12_02[POSIX Utility Guidelines] may be useful.
Generally, many applications use options for optional values and parameters for mandatory values.
However, picocli lets you make options required if you want to, see <<Required Arguments>>.
== Dependency Injection
=== Guice Example
image:https://picocli.info/images/225px-Guice.jpg[Guice logo]
The below example shows how to create a <<Custom Factory,custom `IFactory`>> implementation with a Guice `Injector`:
[source,java]
----
import com.google.inject.*;
import picocli.CommandLine.IFactory;
public class GuiceFactory implements IFactory {
private final Injector injector = Guice.createInjector(new DemoModule());
@Override
public <K> K create(Class<K> aClass) throws Exception {
try {
return injector.getInstance(aClass);
} catch (ConfigurationException ex) { // no implementation found in Guice configuration
return CommandLine.defaultFactory().create(clazz); // fallback if missing
}
}
static class DemoModule extends AbstractModule {
@Override
protected void configure() {
bind(java.util.List.class).to(java.util.LinkedList.class);
bind(Runnable.class).to(InjectionDemo.class);
}
}
}
----
Use the custom factory when creating a `CommandLine` instance, or when invoking the `run` or `call` convenience methods:
[source,java]
----
import javax.inject.Inject;
@Command(name = "di-demo")
public class InjectionDemo implements Runnable {
@Inject java.util.List list;
@Option(names = "-x") int x;
public static void main(String[] args) {
new CommandLine(Runnable.class, new GuiceFactory()).execute(args);
}
@Override
public void run() {
assert list instanceof java.util.LinkedList;
}
}
----
=== Spring Boot Example
image:https://picocli.info/images/spring-boot.png[Spring Boot Logo,width=350,height=167]
From 4.0, picocli provides a custom factory in the `picocli-spring-boot-starter` module.
To use this custom factory, add the following dependency:
Maven:
```xml
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli-spring-boot-starter</artifactId>
<version>4.0.1</version>
</dependency>
```
Gradle:
```
dependencies {
compile "info.picocli:picocli-spring-boot-starter:4.0.1"
}
```
This will bring in the `info.picocli:picocli` and `org.springframework.boot:spring-boot-starter` dependencies.
The below example shows how to use picocli with Spring Boot:
[source,java]
----
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.Bean;
import picocli.CommandLine;
import picocli.CommandLine.IFactory;
@SpringBootApplication
public class MySpringApp implements CommandLineRunner, ExitCodeGenerator {
private IFactory factory; // auto-configured to inject PicocliSpringFactory
private MyCommand myCommand; // your @picocli.CommandLine.Command-annotated class
private int exitCode;
// constructor injection
MySpringApp(IFactory factory, MyCommand myCommand) {
this.factory = factory;
this.myCommand = myCommand;
}
@Override
public void run(String... args) {
// let picocli parse command line args and run the business logic
exitCode = new CommandLine(myCommand, factory).execute(args);
}
@Override
public int getExitCode() {
return exitCode;
}
public static void main(String[] args) {
// let Spring instantiate and inject dependencies
System.exit(SpringApplication.exit(SpringApplication.run(MySpringApp.class, args)));
}
}
----
See the https://github.com/remkop/picocli/tree/master/picocli-spring-boot-starter[picocli-spring-boot-starter README] for another example.
[TIP]
====
It may be a good idea to define an option `--spring.config.location` in your command.
Spring Boot allows end users to specify the `spring.config.location` Spring environment property as a command line option to specify an alternative location for the `application.properties` file.
Defining this option prevents picocli from throwing an `UnmatchedArgumentException` ("Unknown option") when it sees an option it cannot match.
You can make it a `hidden` option so it is not shown in the usage help message, or add a description that explains its meaning.
Alternatively, you can define an <<unmatched-annotation,unmatched>> field to capture _all_ unknown options (and positional parameters):
[source,java]
----
@Unmatched List<String> unmatched;
----
====
When your command is annotated with `@org.springframework.stereotype.Component` Spring can autodetect it for dependency injection.
The business logic of your command looks like any other picocli command with options and parameters.
[source,java]
----
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import java.util.concurrent.Callable;
@Component
@Command(name = "myCommand")
public class MyCommand implements Callable<Integer> {
@Autowired
private SomeService someService;
// Prevent "Unknown option" error when users use
// the Spring Boot parameter 'spring.config.location' to specify
// an alternative location for the application.properties file.
@Option(names = "--spring.config.location", hidden = true)
private String springConfigLocation;
@Option(names = { "-x", "--option" }, description = "example option")
private boolean flag;
public Integer call() throws Exception {
// business logic here
return 0;
}
}
----
=== Micronaut Example
image:https://micronaut.io/images/micronaut_mini_copy_tm.svg[Micronaut Logo,width=350]
The Micronaut microservices framework provides https://docs.micronaut.io/latest/guide/index.html#picocli[built-in support] for picocli with its `PicocliRunner` class.
[source,java]
----
import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.http.annotation.*;
import io.micronaut.http.client.*;
import javax.inject.Inject;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "myMicronautApp")
public class MyMicronautApp implements Runnable {
@Client("https://api.github.com")
@Inject RxHttpClient client;
@Option(names = {"-x", "--option"}, description = "example option")
boolean flag;
public static void main(String[] args) throws Exception {
// let Micronaut instantiate and inject services
PicocliRunner.run(MyMicronautApp.class, args);
}
public void run() {
// business logic here
}
}
----
== Tracing
Picocli v1.0 introduced support for parser tracing to facilitate troubleshooting.
System property `picocli.trace` controls the trace level. Supported levels are `OFF`, `WARN`, `INFO`, and `DEBUG`. The default trace level is `WARN`.
Specifying system property `-Dpicocli.trace` without a value will set the trace level to `INFO`.
* DEBUG: Shows details of the decisions made by the parser during command line parsing.
* INFO: Shows a high-level overview of what happens during command line parsing.
* WARN: The default. Shows warnings instead of errors when lenient parsing is enabled:
when single-value options were specified multiple times (and `CommandLine.overwrittenOptionsAllowed` is `true`),
or when command line arguments could not be matched as an option or positional parameter
(and `CommandLine.unmatchedArgumentsAllowed` is `true`).
* OFF: Suppresses all tracing including warnings.
Example:
[source,bash]
----
# create a custom 'git' command that invokes picocli.Demo$Git with tracing switched on
alias git='java -Dpicocli.trace -cp picocli-all.jar picocli.Demo$Git'
# invoke our command with some parameters
git --git-dir=/home/rpopma/picocli commit -m "Fixed typos" -- src1.java src2.java src3.java
# remove our 'git' pseudonym from the current shell environment
unalias git
----
Output:
----
[picocli INFO] Parsing 8 command line args [--git-dir=/home/rpopma/picocli, commit, -m, "Fixed typos", --, src1.java, src2.java, src3.java]
[picocli INFO] Setting File field 'Git.gitDir' to '\home\rpopma\picocli' for option --git-dir
[picocli INFO] Adding [Fixed typos] to List<String> field 'GitCommit.message' for option -m
[picocli INFO] Found end-of-options delimiter '--'. Treating remainder as positional parameters.
[picocli INFO] Adding [src1.java] to List<String> field 'GitCommit.files' for args[0..*]
[picocli INFO] Adding [src2.java] to List<String> field 'GitCommit.files' for args[0..*]
[picocli INFO] Adding [src3.java] to List<String> field 'GitCommit.files' for args[0..*]
----
== TAB Autocomplete
Picocli-based applications can now have command line completion in Bash or Zsh Unix shells.
See the link:autocomplete.html[Autocomplete for Java Command Line Applications] manual for how to generate an autocompletion script tailored to your application.
== Java 9 JPMS Modules
The main `picocli-${version}.jar` is a JPMS module named `info.picocli`.
Starting from picocli 4.0, this jar will be an explicit module instead of an automatic module,
so the https://docs.oracle.com/en/java/javase/12/tools/jlink.html[`jlink` tool] can be used to provide a trimmed binary image that has only the required modules.
(Note that https://medium.com/azulsystems/using-jlink-to-build-java-runtimes-for-non-modular-applications-9568c5e70ef4[there are ways] to use jlink with non-modular applications.)
Typically, a modular jar includes the `module-info.class` file in its root directory.
This causes problems for some older tools, which incorrectly process the module descriptor as if it were a normal Java class.
To provide the best backward compatibility, the main picocli artifact is a https://openjdk.java.net/jeps/238#Modular-multi-release-JAR-files[modular multi-release jar] with the `module-info.class` file located in `META-INF/versions/9`.
=== Module Configuration
Applications that use Java 9's modules need to configure their module to allow picocli reflective access to the annotated classes and fields.
Often applications want the annotated classes and fields to be **private**; there should be no need to make them part of the exported API of your module just to allow picocli to access them. The below settings make this possible.
Example `module-info.java`:
```
module com.yourorg.yourapp {
requires info.picocli;
// Open this package for reflection to external frameworks.
opens your.package.using.picocli;
// or: limit access to picocli only
opens other.package.using.picocli to info.picocli;
}
```
Note that neither package is `exported`, so other modules cannot accidentally compile against types in these packages.
Alternatively:
```
// open all packages in the module to reflective access
open module com.yourorg.yourapp {
requires info.picocli;
}
```
== OSGi Bundle
image:https://www.osgi.org/wp-content/uploads/OSGi-website-header-logo.png[OSGi logo]
From 4.0, the picocli JAR is an OSGi bundle with `Bundle-Name: picocli` and other appropriate metadata in the manifest.
== Packaging Your Application
You finished your application. Congratulations! Now, how do you package it and distribute it to your users? Here are some ideas.
=== GraalVM Native Image
image:exe-picocli-on-graalvm.png[Turn your picocli-based application into a native image,width=265,height=150]
https://www.graalvm.org/docs/reference-manual/aot-compilation/[GraalVM Native Image] allows you to
ahead-of-time compile Java code to a standalone executable, called a native image.
The resulting executable includes the application, the libraries, and the JDK and does not require a separate Java VM to be installed.
The generated native image has faster startup time and lower runtime memory overhead compared to a Java VM.
GraalVM native images have some limitations and require some extra https://github.com/oracle/graal/blob/master/substratevm/CONFIGURE.md[configuration]
to be able to use features like https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md[reflection], https://github.com/oracle/graal/blob/master/substratevm/RESOURCES.md[resources] (including resource bundles) and https://github.com/oracle/graal/blob/master/substratevm/DYNAMIC_PROXY.md[dynamic proxies].
The `picocli-codegen` module contains an annotation processor that generates the necessary configuration files
under `META-INF/native-image/picocli-generated/$project` during compilation,
to be included in the application jar. The <<Annotation Processor>> section of the manual has details on configuring the annotation processor, and further information can be found in the https://github.com/remkop/picocli/tree/master/picocli-codegen[picocli-codegen README]
file.
By embedding these configuration files, your jar is instantly Graal-enabled: the
https://www.graalvm.org/docs/reference-manual/aot-compilation/#install-native-image[`native-image` tool]
used to generate the native executable is able to get the configuration from the jar.
In most cases no further configuration is needed when generating a native image.
GraalVM includes a https://medium.com/graalvm/simplifying-native-image-generation-with-maven-plugin-and-embeddable-configuration-d5b283b92f57[Maven plugin]
to generate a native image during the build.
Gradle users may be interested in the https://github.com/palantir/gradle-graal[gradle-graal] plugin by Palantir.
(Documentation for both of these seems sparse at time of this writing.)
This https://picocli.info/picocli-on-graalvm.html[older article], "Picocli on GraalVM: Blazingly Fast Command Line Apps", may still be useful.
=== Build Tool Plugins
Both https://www.mojohaus.org/appassembler/[Application Assembler Maven Plugin] and https://docs.gradle.org/current/userguide/application_plugin.html[Gradle Application plugin] create a distribution zip or tar file with launcher scripts. Both require a JRE to be installed on the target machine.
=== launch4j
http://launch4j.sourceforge.net/docs.html[launch4j] can create a native launcher executable. It can bundle a JRE (~200MB) or use a pre-installed one.
=== javapackager (Java 8)
JDK 8 https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javapackager.html[javapackager] can create a native launcher executable. It can bundle a JRE (~200MB) or use a pre-installed one.
=== jlink (Java 9+)
With the JPMS module system introduced in Java 9 it became possible to use https://docs.oracle.com/javase/9/tools/jlink.htm#JSWOR-GUID-CECAC52B-CFEE-46CB-8166-F17A8E9280E9[jlink] to create a custom light-weight JRE with only the necessary modules.
This JRE may be as small as 30-40MB.
Use `jlink` with the `--launcher` option to generate launcher scripts for your application.
See https://medium.com/azulsystems/using-jlink-to-build-java-runtimes-for-non-modular-applications-9568c5e70ef4[this article] for using jlink for non-modular applications.
=== jpackage (Early Access)
https://jdk.java.net/jpackage/[jpackage] is an early access build of https://openjdk.java.net/jeps/343[JEP 343: Packaging Tool].
JPackage can take the custom light-weight JRE produced by `jlink` and create an installer and a native application launcher.
The result is a Java "application image" that is a single directory in the filesystem containing
the native application launcher, resources and configuration files,
and the custom light-weight JRE runtime image (including the application modules) produced by `jlink`.
This https://www.infoq.com/news/2019/03/jep-343-jpackage/[InfoQ article] has more details.
Gradle users may like these plugins: https://badass-runtime-plugin.beryx.org/releases/latest/[org.beryx Badass Runtime Plugin]
and https://badass-jlink-plugin.beryx.org/releases/latest/[org.beryx Badass JLink Plugin].
== Picocli in Other Languages
Picocli may be used in other JVM languages that support annotations.
=== Groovy
In Groovy, use `[` and `]` to surround array values, instead of the `{` and `}` used in Java.
[source,groovy]
----
@Command(name = "MyApp", version = "Groovy picocli v4.0 demo",
mixinStandardHelpOptions = true, // add --help and --version options
description = "@|bold Groovy|@ @|underline picocli|@ example")
class MyApp implements Runnable {
@Option(names = ["-c", "--count"], description = "number of repetitions")
int count = 1
void run() {
count.times {
println("hello world $it...")
}
}
static void main(String[] args) {
System.exit(new CommandLine(new MayApp()).execute(args))
}
}
----
Picocli 2.0 introduced special support for Groovy scripts. (From picocli 4.0 this was moved into a separate module, `picocli-groovy`.)
Scripts annotated with `@picocli.groovy.PicocliScript` are automatically transformed to use
`picocli.groovy.PicocliBaseScript` as their base class and can also use the `@Command` annotation to
customize parts of the usage message like command name, description, headers, footers etc.
Before the script body is executed, the `PicocliBaseScript` base class parses the command line and initializes
`@Field` variables annotated with `@Option` or `@Parameters`.
The script body is executed if the user input was valid and did not request usage help or version information.
[source,groovy]
----
@Grab('info.picocli:picocli-groovy:4.1.2-SNAPSHOT')
@Command(name = "myScript",
mixinStandardHelpOptions = true, // add --help and --version options
description = "@|bold Groovy script|@ @|underline picocli|@ example")
@picocli.groovy.PicocliScript
import groovy.transform.Field
import static picocli.CommandLine.*
@Option(names = ["-c", "--count"], description = "number of repetitions")
@Field int count = 1;
// PicocliBaseScript prints usage help or version if requested by the user
count.times {
println "hi"
}
// the CommandLine that parsed the args is available as a property
assert this.commandLine.commandName == "myScript"
----
WARNING: When upgrading scripts to picocli 4.0, just changing the version number is not enough!
Scripts should use `@Grab('info.picocli:picocli-groovy:4.1.2-SNAPSHOT')`. The old artifact id `@Grab('info.picocli:picocli:4.1.2-SNAPSHOT')` will not work,
because the `@picocli.groovy.PicocliScript` annotation class and supporting classes have been moved into a separate module, `picocli-groovy`.
NOTE: When using a Groovy version older than 2.4.7, use this workaround for the https://issues.apache.org/jira/browse/GROOVY-7613[Grape bug] that causes this error:
`java.lang.ClassNotFoundException: # Licensed to the Apache Software Foundation (ASF) under one or more`.
[source,groovy]
----
@Grab('info.picocli:picocli-groovy:4.1.2-SNAPSHOT')
@GrabExclude('org.codehaus.groovy:groovy-all') // work around GROOVY-7613
...
----
=== Kotlin
Kotlin 1.2 (released Nov 28, 2017) officially supports http://kotlinlang.org/docs/reference/whatsnew12.html#array-literals-in-annotations[array literals in annotations], allowing a more compact notation:
[source,kotlin]
----
@Command(name = "MyApp", version = ["Kotlin picocli v4.0 demo"],
mixinStandardHelpOptions = true, // add --help and --version options
description = ["@|bold Kotlin|@ @|underline picocli|@ example"])
class MyApp : Callable<Int> {
@Option(names = ["-c", "--count"], paramLabel = "COUNT",
description = ["the count"])
private var count: Int = 1
override fun call(): Int {
for (i in 0 until count) {
println("hello world $i...")
}
return 0
}
}
fun main(args: Array<String>) = System.exit(CommandLine(MyApp()).execute(*args))
----
When specify a class as an argument of an annotation, use a Kotlin class (https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html[KClass]).
The Kotlin compiler will automatically convert it to a Java class, so that the Java code will be able to see the annotations and arguments normally.
[source,kotlin]
----
@Command(name = "top", // ...
subcommands = [SubCmd::class, picocli.CommandLine.HelpCommand::class])
class TopCmd { // ...
}
@Command(name = "sub", /* ... */)
class SubCmd { // ...
}
----
Kotlin versions prior to 1.2 did not allow the https://kotlinlang.org/docs/reference/annotations.html[array literal syntax in annotations], so with older versions of Kotlin you will have to write `arrayOf(...)` for the `names`, `description` and `type` attributes.
[source,kotlin]
----
@Command(name = "MyApp", version = arrayOf("picocli demo for Kotlin v1.0 and Kotlin v1.1"),
mixinStandardHelpOptions = true, // add --help and --version options
description = arrayOf("@|bold Kotlin|@ @|underline picocli|@ example"))
class MyApp : Callable<Int> {
@Option(names = arrayOf("-c", "--count"),
description = arrayOf("number of repetitions"))
private var count: Int = 1
override fun call(): Int {
for (i in 0 until count) {
println("hello world $i...")
}
return 0
}
}
fun main(args: Array<String>) = System.exit(CommandLine(MyApp()).execute(*args))
----
=== Scala
Scala does not allow specifying array annotation attribute as a single value,
so be aware that you will have to write `Array(...)` for the `names`, `description` and `type` attributes.
[source,scala]
----
@Command(name = "MyApp", version = Array("Scala picocli demo v4.0"),
mixinStandardHelpOptions = true, // add --help and --version options
description = Array("@|bold Scala|@ @|underline picocli|@ example"))
class MyApp extends Callable[Int] {
@Option(names = Array("-c", "--count"), paramLabel = "COUNT",
description = Array("the count"))
private var count: Int = 1
def call() : Int = {
for (i <- 0 until count) {
println(s"hello world $i...")
}
0
}
}
object MyApp {
def main(args: Array[String]) {
System.exit(new CommandLine(new MyApp()).execute(args: _*))
}
}
----
== API Javadoc
Picocli API Javadoc can be found link:apidocs/[here].
See also: https://remkop.github.io/picocli/apidocs[latest version], https://picocli.info/man/3.x/apidocs[picocli 3.x javadoc].
== GitHub Project
The https://github.com/remkop/picocli[GitHub project] has the source code, tests, build scripts, etc.
Star icon:star-o[] and/or fork icon:code-fork[] this project on GitHub if you like it!
++++
<iframe src="https://ghbtns.com/github-btn.html?user=remkop&repo=picocli&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=remkop&repo=picocli&type=fork&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe>
<iframe src="https://ghbtns.com/github-btn.html?user=remkop&type=follow&count=true" frameborder="0" scrolling="0" width="170px" height="20px"></iframe>
++++
== Issue Tracker
The GitHub https://github.com/remkop/picocli/issues[Issue Tracker] can be used to report bugs or request features. There is also a <<Mailing List>>, and for questions where the user community may know the answer, https://stackoverflow.com/questions/tagged/picocli[StackOverflow] is both a good resource and a great way to build an online knowledge base.
== Mailing List
Join the https://groups.google.com/d/forum/picocli[picocli Google group] if you are interested in discussing anything picocli-related and receiving announcements on new releases.
== License
Picocli is licensed under the https://github.com/remkop/picocli/blob/master/LICENSE[Apache License 2.0].
== Releases
Previous versions are available from the GitHub project https://github.com/remkop/picocli/releases[Releases].
== Download
You can add picocli as an external dependency to your project, or you can include it as source.
See the <<Source,source code>> below. Copy and paste it into a file called `CommandLine.java`, add it to your project, and enjoy!
=== Gradle
----
compile 'info.picocli:picocli:4.1.2-SNAPSHOT'
----
=== Maven
----
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.1.2-SNAPSHOT</version>
</dependency>
----
=== Scala SBT
----
libraryDependencies += "info.picocli" % "picocli" % "4.1.2-SNAPSHOT"
----
=== Ivy
----
<dependency org="info.picocli" name="picocli" rev="4.1.2-SNAPSHOT" />
----
=== Source
Picocli has only one source file: link:https://github.com/remkop/picocli/blob/master/src/main/java/picocli/CommandLine.java[CommandLine.java].
This facilitates including it in your project in source form to avoid having an external dependency on picocli.