picocli 2.0
Picocli 2.0
The picocli community is pleased to announce picocli 2.0.
First, picocli now provides tight integration for Groovy scripts. The new @picocli.groovy.PicocliScript
annotation allows Groovy scripts to use the @Command
annotation, and turns a Groovy script into a picocli-based command line application. When the script is run, @Field
variables annotated with @Option
or @Parameters
are initialized from the command line arguments before the script body is executed.
Applications with subcommands will also benefit from upgrading to picocli 2.0. The CommandLine.run
and CommandLine.call
methods now work for subcommands, and if more flexibility is needed, take a look at the new parseWithHandler
methods. Error handling for subcommands has been improved in this release with the new ParseException.getCommandLine
method.
Improved ease of use: Usage help is now printed automatically from the CommandLine.run
and CommandLine.call
methods and from the built-in handlers used with the parseWithHandler
method.
The parser has been improved and users can now mix positional arguments with options on the command line. Previously, positional parameter had to follow the options. Important notice: To make this feature possible, the default parsing behaviour of multi-value options and parameters changed to be non-greedy by default.
Finally, this release includes many bug fixes.
This is the twelfth public release.
Picocli follows semantic versioning.
Table of Contents
New and noteworthy
Groovy Script Support
Picocli 2.0 introduces special support for Groovy scripts.
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.
// exampleScript.groovy
@Grab('info.picocli:picocli:2.0.0')
@Command(name = "myCommand", description = "does something special")
@PicocliScript
import picocli.groovy.PicocliScript
import picocli.CommandLine.Command
import picocli.CommandLine.Option
import groovy.transform.Field
@Option(names = "-x", description = "number of repetitions")
@Field int count;
@Option(names = ["-h", "--help"], usageHelp = true, description = "print this help message and exit")
@Field boolean helpRequested;
//if (helpRequested) { // not necessary: PicocliBaseScript takes care of this
// CommandLine.usage(this, System.err); return 0;
//}
count.times {
println "hi"
}
// the CommandLine that parsed the args is available as a property
assert this.commandLine.commandName == "myCommand"
Better Subcommand Support
New methods CommandLine::parseWithHandler
were added. These methods intend to offer the same ease of use as the run
and call
methods, but with more flexibility and better support for nested subcommands.
The CommandLine::call
and CommandLine::run
now support subcommands and will execute the last subcommand specified by the user. (Previously subcommands were ignored and only the top-level command was executed.)
From this release, picocli exceptions provide a getCommandLine
method that returns the command or subcommand where parsing or execution failed. Previously, if the user provided invalid input for applications with subcommands, it was difficult to pinpoint exactly which subcommand failed to parse the input.
Easier To Use
The convenience methods will automatically print usage help and version information when the user specifies options annotated with the versionHelp
or usageHelp
attributes.
Methods that automatically print help:
- CommandLine::call
- CommandLine::run
- CommandLine::parseWithHandler (with the built-in Run… handlers)
- CommandLine::parseWithHandlers (with the built-in Run… handlers)
Methods that do not automatically print help:
- CommandLine::parse
- CommandLine::populateCommand
Also notable: Collection and Map fields no longer require the type
annotation attribute: picocli now infers the conversion target type from the generic type parameters where possible.
Parser Improvements
Positional parameters can now be mixed with options on the command line. Previously, positional parameter had to follow the options.
To make this feature possible, the default parsing behaviour of multi-value options and parameters changed to be non-greedy by default.
Usage Help Format Improvements
This release contains various bugfixes related to improving the usage help format for multi-value options and collections. For example, for Maps that don't have a paramLabel
, picocli now shows key type and value type instead of the internal Java field name.
Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
The following are the features that have been promoted in this picocli release.
- Autocomplete - as of picocli 2.0, autocompletion is no longer beta.
Fixed issues
- [#207] API Change: Provide ability to find which subcommand threw a ParameterException API enhancement. Thanks to velit and AshwinJay.
- [#179] API Change to remove full JRE dependency and require only Compact Profile. Replace use of
java.awt.Point
withpicocli.CommandLine.Help.TextTable.Cell
. Thanks to webfolderio. - [#205] API Change:
CommandLine::getCommand
now returns a generic type instead of Object so client code can avoid type casting. - [#196] API Change:
Option::type()
andParameters::type()
now return empty array by default (was{String.class}
). - [#210] API Change: Deprecated the option
help
attribute in favour of theusageHelp
andversionHelp
attributes. - [#115] New feature: Added new
CommandLine::parseWithHandler
convenience methods for commands with subcommands. - [#130] New feature: Options and positional parameters can now be mixed on the command line.
- [#196] New feature: Infer type from collections and maps when
type
annotation not specified. Thanks to ddimtirov for the suggestion. - [#197] New feature: Use
type
attribute to determine conversion target type instead of field type. This allows fields to be declared as interfaces or abstract types (or arrays/collections/maps of these) and via thetype
attribute picocli will be able to convert String arguments to concrete implementation objects. - [#187] New feature: Added methods to programmatically get and set the command name.
- [#192] Bugfix: Default arity should be 1, not *, for array and collection options. Thanks to RobertZenz.
- [#193] Bugfix: Splitting an argument should not cause max arity to be exceeded.
- [#191] Bugfix: Arity should not limit the total number of values put in an array or collection. Thanks to RobertZenz.
- [#186] Bugfix: Confusing usage message for collection options. Thanks to AlexFalappa.
- [#181] Bugfix: Incorrect help message was displayed for short options with paramLabel when arity > 1.
- [#184] Bugfix/Enhancement: Programmatically setting the separator is now reflected in the usage help message. Thanks to defnull.
- [#200] Bugfix: Prevent NPE when command name is set to empty string or spaces. Thanks to jansohn.
- [#203] Bugfix: Empty string parameter parsed incorrectly. Thanks to AshwinJay.
- [#194] Enhancement: Usage help should show split regex for option/parameters.
- [#198] Enhancement: Usage help parameter list details should indicate arity for positional parameters.
- [#195] Enhancement: Usage help should show Map types if paramLabel not specified.
- [#183] Enhancement: Add examples to user manual for using picocli in other JVM languages. Thanks to binkley for pointing out that Kotlin may support array literals in annotations from 1.2.
- [#185] Enhancement: Exception message text for missing options should not use field names but be more descriptive and consistent with usage help. Thanks to AlexFalappa.
- [#201] Enhancement: Usage help should not show
null
default values. Thanks to jansohn. - [#202] Enhancement: Java 9: add
Automatic-Module-Name: info.picocli
to MANIFEST.MF to make picocli play nice in the Java 9 module system. - [#204] Enhancement: instantiate
LinkedHashSet
instead ofHashSet
forSet
fields to preserve input ordering. - [#208] Enhancement: Remove pom.xml, which was not being maintained. Picocli can only be built with gradle going forward.
- [#212] Enhancement: Improve javadoc for picocli.AutoComplete.
Deprecations
The help
attribute for options is now deprecated. Please change to use usageHelp
and versionHelp
attributes instead. From picocli v2.0, the convenience methods will automatically print usage help and version information when requested with the versionHelp
and usageHelp
option attributes (but not for the help
attribute).
Potential breaking changes
This release has a number of incompatible changes:
- Multi-value options (array, list and map fields) are not greedy by default any more.
- Arity is not max values: end users may specify multi-value options (array, list and map fields) an unlimited number of times.
- A single argument that is split into parts with a regex now counts as a single argument (so
arity="1"
won't prevent all parts from being added to the field) - API change: replaced
java.awt.Point
with customCell
class as return value type for public methodHelp.TextTable.putValue()
. - API change:
@Option.type()
and@Parameters.type()
now return an empty array by default (was{String.class}
). - API change:
ParameterException
and all subclasses now require aCommandLine
object indicating the command or subcommand that the user provided invalid input for. - The
CommandLine::call
andCommandLine::run
now support subcommands and will execute the last subcommand specified by the user. Previously subcommands were ignored and the top-level command was executed unconditionally.
I am not happy about the disruption these changes may cause, but I felt they were needed for three reasons: the old picocli v1.0 behaviour caused ambiguity in common use cases, was inconsistent with most Unix tools, and prevented supporting mixing options with positional arguments on the command line.
To illustrate the new non-greedy behaviour, consider this example program:
class MixDemo {
@Option(names="-o") List<String> options;
@Parameters List<String> positionalParams;
public void run() {
System.out.println("positional: " + positionalParams);
System.out.println("options : " + options);
}
public static void main(String[] args) {
CommandLine.run(new MixDemo(), System.err, args);
}
}
We run this program as below, where the option is followed by multiple values:
$ java MixDemo -o 1 2 3
Previously, the arguments following -o
would all end up in the options
list. Running the above command with picocli 1.0 would print out the following:
# (Previously, in picocli-1.0.1)
$ java MixDemo -o 1 2 3
positional: null
options : [1, 2, 3]
From picocli 2.0, only the first argument following -o
is added to the options
list, the remainder is parsed as positional parameters:
# (Currently, in picocli-2.0)
$ java MixDemo -o 1 2 3
positional: [2, 3]
options : [1]
To put multiple values in the options list in picocli 2.0, users can specify the -o
option multiple times:
$ java MixDemo -o 1 -o 2 -o 3
positional: null
options : [1, 2, 3]
Alternatively, application authors can make a multi-value option greedy in picocli v2.0 by explicitly setting a variable arity:
class Args {
@Option(names = "-o", arity = "1..*") List<String> options;
}
(... "greedy" means consume until the next option, so not necessarily all remaining command line arguments.)