diff --git a/README.md b/README.md
index c9772ae9f..8cef55b34 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ The user manual has examples of integrating with [Guice](https://picocli.info/#_
### Releases
* [All Releases](https://github.com/remkop/picocli/releases)
-* Latest: 4.6.1 [Release Notes](https://github.com/remkop/picocli/releases/tag/v4.6.1)
+* Latest: 4.6.2 [Release Notes](https://github.com/remkop/picocli/releases/tag/v4.6.2)
* Older: Picocli 4.0 [Release Notes](https://github.com/remkop/picocli/releases/tag/v4.0.0)
* Older: Picocli 3.0 [Release Notes](https://github.com/remkop/picocli/releases/tag/v3.0.0)
* Older: Picocli 2.0 [Release Notes](https://github.com/remkop/picocli/releases/tag/v2.0.0)
@@ -246,9 +246,9 @@ If you like picocli, there are a few things you can do to help:
* Upvote my [Quora answer](https://www.quora.com/What-is-the-best-way-to-parse-command-line-arguments-with-Java/answer/Remko-Popma) to "What is the best way to parse command-line arguments with Java?"
* Upvote my [StackOverflow answer](https://stackoverflow.com/a/43780433/1446916) to "How do I parse command line arguments in Java?"
-If you like picocli and your project is on GitHub, consider adding this badge to your README.md: [![picocli](https://img.shields.io/badge/picocli-4.6.1-green.svg)](https://github.com/remkop/picocli)
+If you like picocli and your project is on GitHub, consider adding this badge to your README.md: [![picocli](https://img.shields.io/badge/picocli-4.6.2-green.svg)](https://github.com/remkop/picocli)
```
-[![picocli](https://img.shields.io/badge/picocli-4.6.1-green.svg)](https://github.com/remkop/picocli)
+[![picocli](https://img.shields.io/badge/picocli-4.6.2-green.svg)](https://github.com/remkop/picocli)
```
@@ -336,41 +336,41 @@ See the [source code](https://github.com/remkop/picocli/blob/master/src/main/jav
### Gradle
```
-implementation 'info.picocli:picocli:4.6.1'
+implementation 'info.picocli:picocli:4.6.2'
```
### Maven
```
@Grab('info.picocli:picocli-groovy:4.6.1')
+@Grab('info.picocli:picocli-groovy:4.6.2')
import picocli.CommandLine
import static picocli.CommandLine.*
@@ -2325,7 +2254,7 @@
Groovy script
-@Grab('info.picocli:picocli-groovy:4.6.1')
+@Grab('info.picocli:picocli-groovy:4.6.2')
import static picocli.CommandLine.*
import groovy.transform.Field
import java.security.MessageDigest
@@ -2396,7 +2325,7 @@ class Checksum extends Callable[Int] {
@Parameters(index = "0", description = Array("The file whose checksum to calculate."))
- private var file: File = null
+ private var file: File = null
@Option(names = Array("-a", "--algorithm"), description = Array("MD5, SHA-1, SHA-256, ..."))
private var algorithm = "MD5"
@@ -2470,7 +2399,7 @@ Gradle
dependencies {
- implementation 'info.picocli:picocli:4.6.1'
+ implementation 'info.picocli:picocli:4.6.2'
}
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
- <version>4.6.1</version>
+ <version>4.6.2</version>
</dependency>
dependencies {
- implementation 'info.picocli:picocli:4.6.1'
- annotationProcessor 'info.picocli:picocli-codegen:4.6.1'
+ implementation 'info.picocli:picocli:4.6.2'
+ annotationProcessor 'info.picocli:picocli-codegen:4.6.2'
}
@@ -2559,7 +2488,7 @@ Usi
<path>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
- <version>4.6.1</version>
+ <version>4.6.2</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
@@ -2584,7 +2513,7 @@ apply plugin: 'kotlin-kapt' // required
dependencies {
// ...
- kapt 'info.picocli:picocli-codegen:4.6.1'
+ kapt 'info.picocli:picocli-codegen:4.6.2'
}
java -cp "picocli-4.6.1.jar:checksum.jar" CheckSum --algorithm SHA-1 hello.txt
+java -cp "picocli-4.6.2.jar:checksum.jar" CheckSum --algorithm SHA-1 hello.txt
+ + | +
+ POSIX short options and usability
+
+
+Applications can give a subtle hint to end users that an option is common and encouraged by providing both a short and a long name for an option. +Conversely, the absence of a short option can signal that the option is unusual or perhaps should be used with care. + |
+
static
, or picocli will not be able to instantiate them without a Custom Factory.
+Make sure any nested classes are static
, or picocli will not be able to instantiate them.
static
, or picocli will not be able to instantiate your nested converter class without a Custom Factory.
+If your type converter is declared as nested class, make sure you mark this class as static
, or picocli will not be able to instantiate your nested converter class.
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
.
List → ArrayList
, SortedSet → 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.
@@ -5133,7 +5078,7 @@
boolean
0
0..1
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 configured.)
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 this StackOverflow answer). This can be customized with the @Command
annotation. For example:
@Command(exitCodeOnInvalidInput = 123,
exitCodeOnExecutionException = 456)
@@ -8413,7 +8357,7 @@ static
, or picocli will not be able to instantiate them without a Custom Factory.
+Make sure any nested classes are static
, or picocli will not be able to instantiate them.
static
, or picocli will not be able to instantiate them without a Custom Factory.
+Make sure any nested classes are static
, or picocli will not be able to instantiate them.
Custom help subcommands should mark themselves as a help command to tell picocli not to throw a MissingParameterException
when required options are missing.
@Command(helpCommand = true)
In the above example, the program name is taken from the name
attribute of the Command
annotation:
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.
@Command(sortOptions = false)
Options and parameters may have a split
attribute to split each parameter into smaller substrings.
-Regular expressions may contain literal text, but may also contain special characters.
-The regular expression in the split
attribute may be quite different from what end users need to type.
The example below uses the plus (+
) character as a separator.
-The regular expression in the split
attribute uses backslash (\
) characters to make sure that the plus character is treated as a literal.
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 the abbreviateSynopsis
attribute. For example:
@Parameters(split = "\\+", splitSynopsisLabel = "+", paramLabel = "VALUE")
-List<String> values;
+@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;
+}
@Parameters(split = "\\+", splitSynopsisLabel = "+", paramLabel = "VALUE")
-lateinit var values: List<String>
+@Command(requiredOptionMarker = '*', abbreviateSynopsis = true)
+class Example {
+ @Option(names = ["-a", "--alpha"], description = ["optional alpha"])
+ lateinit var alpha: String
+
+ @Option(names = ["-b", "--beta"], required = true, description = ["mandatory beta"])
+ lateinit var beta: String
+}
However, end users can type simply A+B+C
(using the plus character separator), not A\+B\+C
.
-We want the usage help message to show this.
Produces the following usage help message:
+Usage: <main class> [OPTIONS] + -a, --alpha=<alpha> optional alpha +* -b, --beta=<beta> mandatory beta+
The splitSynopsisLabel
attribute, introduced in picocli 4.3, controls what is shown in the synopsis of the usage help message.
The default layout shows short options and long options in separate columns, followed by the description column.
With the example above, the synopsis of the usage help looks like this:
+Only POSIX short options are shown in the first column, that is, options that start with a single -
dash and are one character long.
Usage: cmd [VALUE[+VALUE...]...]+
+ + | ++Options with two characters are not considered short options and are shown in the long option column. + | +
This is a common layout for Unix utilities, and can enhance usability: +applications can give a subtle hint to end users that an option is common and encouraged by providing both a short and a long name for the option. +Conversely, the absence of a short option can signal that the option is unusual or perhaps should be used with care.
++ + | +
+It is possible to left-align all options by using a custom layout.
+See LeftAlignOptions.java in the picocli-examples module for an example.
+ |
+
The default layout shows short options and long options in separate columns, followed by the description column. +The width of the long options column shrinks automatically if all long options are very short, +but by default this column does not grow larger than 20 characters.
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:
If the long option with its option parameter is longer than 20 characters
+(for example: --output=<outputFolder>
), the long option overflows into the description column, and the option description is shown on the next line.
This (the default) looks like this:
Usage: <main class> [OPTIONS] [<files>...]+
Usage: myapp [-hV] [-o=<outputFolder>] + -h, --help Show this help message and exit. + -o, --output=<outputFolder> + Output location full path. + -V, --version Print version information and exit.
Note that the positional parameters are not abbreviated.
+As of picocli 4.2, there is programmatic API to change this via the CommandLine::setUsageHelpLongOptionsMaxWidth
and UsageMessageSpec::longOptionsMaxWidth
methods.
In the above example, if we call commandLine.setUsageHelpLongOptionsMaxWidth(23)
before printing the usage help, we get this result:
@Command(abbreviateSynopsis = true)
-class App {
- @Parameters File[] files;
- @Option(names = {"--count", "-c"}) int count;
- // ...
-}
+Usage: myapp [-hV] [-o=<outputFolder>] + -h, --help Show this help message and exit. + -o, --output=<outputFolder> Output location full path. + -V, --version Print version information and exit.
@Command(abbreviateSynopsis = true)
-class App {
- @Parameters lateinit var files: Array<File>
- @Option(names = ["--count", "-c"]) var count = 0
- // ...
-}
+The minimum value that can be specified for longOptionsMaxWidth
is 20, the maximum value is the usage width minus 20
.
For even more control of the synopsis, use the customSynopsis
attribute to specify one ore more synopsis lines. For example:
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.
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)+
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.
To produce a synopsis like the above, specify the literal text in the customSynopsis
attribute:
The minimum width that can be configured is 55 characters.
+As of picocli 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.
+Options and parameters may have a split
attribute to split each parameter into smaller substrings.
+Regular expressions may contain literal text, but may also contain special characters.
+The regular expression in the split
attribute may be quite different from what end users need to type.
The example below uses the plus (+
) character as a separator.
+The regular expression in the split
attribute uses backslash (\
) characters to make sure that the plus character is treated as a literal.
@Parameters(split = "\\+", splitSynopsisLabel = "+", paramLabel = "VALUE")
+List<String> values;
+@Parameters(split = "\\+", splitSynopsisLabel = "+", paramLabel = "VALUE")
+lateinit var values: List<String>
+However, end users can type simply A+B+C
(using the plus character separator), not A\+B\+C
.
+We want the usage help message to show this.
The splitSynopsisLabel
attribute, introduced in picocli 4.3, controls what is shown in the synopsis of the usage help message.
With the example above, the synopsis of the usage help looks like this:
+Usage: cmd [VALUE[+VALUE...]...]+
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.
+@Command(abbreviateSynopsis = true)
+class App {
+ @Parameters File[] files;
+ @Option(names = {"--count", "-c"}) int count;
+ // ...
+}
+@Command(abbreviateSynopsis = true)
+class App {
+ @Parameters lateinit var files: Array<File>
+ @Option(names = ["--count", "-c"]) var count = 0
+ // ...
+}
+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:
For commands with subcommands, the string [COMMAND]
is appended to the end of the synopsis (whether the synopsis is abbreviated or not). This looks something like this:
For example, to clarify that a subcommand is mandatory, an application may specify COMMAND
, without the [
and ]
brackets:
@Command(name = "git", synopsisSubcommandLabel = "COMMAND")
class Git { /* ... */ }
@@ -9575,7 +9666,7 @@ 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).
By default, the usage help message does not display exit code information.
Applications that call System.exit
need to configure the exitCodeListHeading
and exitCodeList
annotation attributes.
@@ -9641,7 +9732,7 @@
The separator displayed between options and option parameters (=
by default)
in the synopsis and the option list can be configured with the separator
attribute.
@Command(separator = " ")
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:
@@ -9846,12 +9936,12 @@
As of picocli 4.2, an entry for @<filename>
can be shown in the options and parameters list of the usage help message of a command with the @Command(showAtFileInUsageHelp = true)
annotation.
By default, the @<filename>
entry is shown before the positional parameters in the synopsis as well as in the parameters list.
Both the label and the description of the @<filename>
entry have been defined with custom variables, to allow applications to change the text. The variables are:
For example, if we define these system properties:
System.setProperty("picocli.atfile.label", "my@@@@file");
System.setProperty("picocli.atfile.description", "@files rock!");
@@ -10016,12 +10105,12 @@ As of picocli 4.3, an entry for the --
End of Options delimiter can be shown in the options list of the usage help message of a command with the @Command(showEndOfOptionsDelimiterInUsageHelp = true)
annotation.
By default, the --
End of Options entry is shown between the options and the positional parameters in the synopsis, and at the end of the options list.
The description of the --
End of Options delimiter entry has been defined with a custom variable, to allow applications to change the text. The variable is:
For example, if we define this system property:
System.setProperty("picocli.endofoptions.description", "End of options. Remainder are positional parameters.");
${DEFAULT-VALUE}
Variable${DEFAULT-VALUE}
VariableFrom picocli 3.2, it is possible to embed the default values in the description for an option or positional parameter by
specifying the variable ${DEFAULT-VALUE}
in the description text.
@@ -10233,7 +10321,7 @@
${COMPLETION-CANDIDATES}
Variable${COMPLETION-CANDIDATES}
VariableSimilarly, it is possible to embed the completion candidates in the description for an option or positional parameter by
specifying the variable ${COMPLETION-CANDIDATES}
in the description text.
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 the abbreviateSynopsis
attribute. For example:
@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;
-}
-@Command(requiredOptionMarker = '*', abbreviateSynopsis = true)
-class Example {
- @Option(names = ["-a", "--alpha"], description = ["optional alpha"])
- lateinit var alpha: String
-
- @Option(names = ["-b", "--beta"], required = true, description = ["mandatory beta"])
- lateinit var beta: String
-}
-Produces the following usage help message:
-Usage: <main class> [OPTIONS] - -a, --alpha=<alpha> optional alpha -* -b, --beta=<beta> mandatory beta-
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.
-As of picocli 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.
-The default layout shows short options and long options in separate columns, followed by the description column. -The width of the long options column shrinks automatically if all long options are very short, -but by default this column does not grow larger than 20 characters.
-If the long option with its option parameter is longer than 20 characters
-(for example: --output=<outputFolder>
), the long option overflows into the description column, and the option description is shown on the next line.
This (the default) looks like this:
-Usage: myapp [-hV] [-o=<outputFolder>] - -h, --help Show this help message and exit. - -o, --output=<outputFolder> - Output location full path. - -V, --version Print version information and exit.-
As of picocli 4.2, there is programmatic API to change this via the CommandLine::setUsageHelpLongOptionsMaxWidth
and UsageMessageSpec::longOptionsMaxWidth
methods.
In the above example, if we call commandLine.setUsageHelpLongOptionsMaxWidth(23)
before printing the usage help, we get this result:
Usage: myapp [-hV] [-o=<outputFolder>] - -h, --help Show this help message and exit. - -o, --output=<outputFolder> Output location full path. - -V, --version Print version information and exit.-
The minimum value that can be specified for longOptionsMaxWidth
is 20, the maximum value is the usage width minus 20
.
There are some scenarios where picocli can not parse an option with a default value which is the same as a subcommand name. To work around this, you can parse the option yourself using IParameterConsumer
. A simple implementation is shown below. See this issue for more details.
class MyParameterConsumer : CommandLine.IParameterConsumer {
+ override fun consumeParameters(
+ args: Stack<String>,
+ argSpec: CommandLine.Model.ArgSpec,
+ commandSpec: CommandLine.Model.CommandSpec
+ ) {
+ if (args.isEmpty()) {
+ throw CommandLine.ParameterException(
+ commandSpec.commandLine(),
+ "Missing required parameter for option " +
+ (argSpec as CommandLine.Model.OptionSpec).longestName()
+ )
+ }
+ argSpec.setValue(args.pop());
+ }
+}
+Annotation example:
@Command(name = "i18n-demo", resourceBundle = "my.org.I18nDemo_Messages")
class I18nDemo {}
@@ -14020,37 +14025,178 @@ As of version 4.0, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API.
+In your localized application, it may be desirable to specify the locale in order to determine the language of message texts and help output.
+One way of controlling the locale is to give -Duser.language=desiredLocale
as VM argument when running the app.
+A more accessible and user-friendly approach is to to implement a command line parameter (e. g. --locale
) inside your app which can be used to change the locale.
+The latter technique requires a two-phase approach to parsing in your application in order to get a valid load order.
+The minimal example below demonstrates how to implement this two phase approach:
@Command(name = "status", mixinStandardHelpOptions = true,
- 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;
-}
+class InitLocale {
+ @Option(names = { "-l", "--locale" }, description = "locale for message texts (phase 1)")
+ void setLocale(String locale) {
+ Locale.setDefault(new Locale(locale));
+ }
+
+ @Unmatched
+ List<String> remainder; // ignore any other parameters and options in the first parsing phase
+}
+
+@Command(name = "GreetingApp", resourceBundle = "mybundle", mixinStandardHelpOptions = true)
+public class GreetingApp implements Runnable {
+ @Option(names = { "-l", "--locale" }, paramLabel = "<locale>")
+ private String ignored;
+
+ @Parameters(arity = "1..", paramLabel = "<name1> <name2>")
+ private String[] names;
+
+ ResourceBundle bundle = ResourceBundle.getBundle("mybundle");
+
+ public void run() { // business logic here
+ for (String name : names) {
+ System.out.println(MessageFormat.format(bundle.getString("Hello"), name));
+ }
+ }
+
+ public static void main(String[] args) {
+ // first phase: configure locale
+ new CommandLine(new InitLocale()).parseArgs(args);
+
+ // second phase: parse all args (ignoring --locale) and run the app
+ new CommandLine(new GreetingApp()).execute(args);
+ }
+}
+class InitLocale {
+ @Option(names = ["-l", "--locale"], description = ["locale for message texts (phase 1)"])
+ fun setLocale(locale: String?) {
+ Locale.setDefault(Locale(locale))
+ }
+
+ @Unmatched
+ lateinit var others : List<String> // ignore other parameters/options in first parsing phase
+}
+
+@Command(name = "GreetingApp", resourceBundle = "mybundle", mixinStandardHelpOptions = true)
+class GreetingApp : Runnable {
+ @Option(names = ["-l", "--locale"], paramLabel = "<locale>")
+ lateinit var ignored: String
+
+ @Parameters(arity = "1..", paramLabel = "<name1> <name2>")
+ lateinit var names: Array<String>
+
+ private var bundle = ResourceBundle.getBundle("mybundle")
+
+ override fun run() { // business logic here
+ names.onEach {
+ println(MessageFormat.format(bundle.getString("Hello"), it))
+ }
+ }
+}
+
+fun main(args: Array<String>) {
+ // first phase: configure locale
+ CommandLine(picocli.examples.kotlin.i18n.localecontrol.InitLocale()).parseArgs(*args)
+
+ // second phase: parse all args (ignoring --locale) and run the app
+ exitProcess(CommandLine(GreetingApp()).execute(*args))
+}
+Now put the default properties file (mybundle.properties
, in English) and the Spanish language variant (mybundle_es.properties
) in place:
Hello = Hello {0}!+
Hello = ¡Hola {0}!+
Eventually, we are ready to run our application:
+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp Sarah Lea
+With no command line parameter --locale
given, the message texts are printed in the default language (here: English):
Hello Sarah! +Hello Lea!+
In order to control the locale choosen for our output, we have to make use of the command line parameter --locale
:
java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp --locale=es Sarah Lea
+Now our message texts are printed in Spanish:
+¡Hola Sarah! +¡Hola Lea!+
Using the command line parameter --locale
, one can also determine the language of the help output of your application.
+The picocli-examples
module has examples with fully implemented, localized help output, coded both in Java and Kotlin.
As of version 4.0, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API.
+@Command(name = "status", mixinStandardHelpOptions = true,
+ 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;
+}
+ + | +
+In Kotlin, the dollar sign ($) has to be escaped with a backslash (\) in order to prevent Kotlin string interpolation to occur: \${DEFAULT-VALUE} .
+ |
+
static
, or picocli will not be able to instantiate your transformer class without a Custom Factory.
+If your model transformer is declared as nested class, make sure you mark this class as static
, or picocli will not be able to instantiate your transformer class.
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli-spring-boot-starter</artifactId>
- <version>4.6.1</version>
+ <version>4.6.2</version>
</dependency>
dependencies {
- implementation 'info.picocli:picocli-spring-boot-starter:4.6.1'
+ implementation 'info.picocli:picocli-spring-boot-starter:4.6.2'
}
dependencies {
- implementation("info.picocli:picocli-spring-boot-starter:4.6.1")
+ implementation("info.picocli:picocli-spring-boot-starter:4.6.2")
}
Finally we have to configure our mail service. This can be done inside a file application properties
, which we put in a config
subdirectory of your project:
Finally we have to configure our mail service. This can be done inside a file application.properties
, which we put in a config
subdirectory of your project:
For example:
MyApp app = new MyApp();
CommandLine cmd = new CommandLine(app);
@@ -16666,14 +16825,31 @@ assertEquals("expectedValue2", app.getState2());
val app = MyApp()
+val cmd = CommandLine(app)
+
+val sw = StringWriter()
+cmd.out = PrintWriter(sw)
+
+// black box testing
+val exitCode = cmd.execute("-x", "-y=123")
+assertEquals(0, exitCode)
+assertEquals("Your output is abc...", sw.toString())
+
+// white box testing
+assertEquals("expectedValue1", app.state1)
+assertEquals("expectedValue2", app.state2)
+This assumes that the application uses the PrintWriter
provided by CommandLine.getOut
or CommandLine.getErr
.
Applications can get these writers via the @Spec
annotation:
@Command
+class MyApp : Runnable {
+ @Spec lateinit var spec: CommandSpec
+
+ override fun run() {
+ // make testing easier by printing to the Err and Out streams provided by picocli
+ spec.commandLine().out.println("Your output is abc...")
+ }
+}
+Applications that print to System.out
or System.err
directly, or use a version of picocli lower than 4.0, can be tested by capturing the standard output and error streams.
+There are various options for doing this, some of which are shown below.
Applications that use JUnit 5 or Java 8+ can use Stephan Birkner’s System-Lambda project for capturing output. +This library has facilities for capturing the standard output and standard error streams separately or mixed together, and for normalizing line breaks.
+Applications that use a version of picocli older than 4.0, or applications that print to System.out
or System.err
directly can be tested by capturing the standard output and error streams like this:
Example usage:
+import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemErr;
+import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemOutNormalized;
+// ...
+
+class MyTest {
+ @Test
+ void testMyApp() throws Exception {
+ String errText = tapSystemErr(() -> {
+ String outText = tapSystemOutNormalized(() -> {
+ new CommandLine(new MyApp()).execute("--option=value", "arg0", "arg1");
+ });
+ assertEquals("--option='value'\n" +
+ "position[0]='arg0'\n" +
+ "position[1]='arg1'\n", outText);
+ });
+ assertEquals("", errText);
+ }
+}
+Applications that use JUnit 4 can use Stephan Birkner’s System-Rules project for capturing output.
+Example usage:
+import org.junit.contrib.java.lang.system.SystemErrRule;
+import org.junit.contrib.java.lang.system.SystemOutRule;
+// ...
+
+class MyTest {
+ @Rule
+ SystemErrRule systemErrRule = new SystemErrRule().enableLog().muteForSuccessfulTests();
+
+ @Rule
+ SystemOutRule systemOutRule = new SystemOutRule().enableLog().muteForSuccessfulTests();
+
+ @Test
+ void testMyApp() throws Exception {
+ new CommandLine(new MyApp()).execute("--option=value", "arg0", "arg1");
+ String expected = String.format("--option='value'%n" +
+ "position[0]='arg0'%n" +
+ "position[1]='arg1'%n");
+ assertEquals(expected, systemOutRule.getLog());
+ assertEquals("", systemErrRule.getLog());
+ }
+}
+It is also possible to capture output in the tests yourself without using a library.
+For example:
If you’re testing with JUnit 4, you can do the setup in a @org.junit.Before
-annotated method and teardown in an @org.junit.After
-annotated method.
+
This looks verbose, but can be simplified a lot by letting the test framework do the setup and cleanup.
+JUnit 4 lets you do setup in a @org.junit.Before
-annotated method and teardown in an @org.junit.After
-annotated method.
The JUnit 5 equivalent annotations are @org.junit.jupiter.api.BeforeEach
and @org.junit.jupiter.api.AfterEach
, respectively.
For example:
Testing the exit code of applications that call System.exit
can be tricky but is not impossible.
Testing the exit code of applications that call System.exit
can be tricky but is not impossible.
+Depending on your programming language, your environment and your testing framework, you have several options:
Java 8: You can use Stephan Birkner’s System-Lambda project for testing the exit code
+Java/Kotlin + Junit 5: You can use Todd Ginsberg’s System.exit() extension for Junit 5. The project README mentions common use cases.
+Java + Junit 4: You can use Stephan Birkner’s System-Rules project for testing the exit code.
+Kotlin + Kotest: Kotlin coders you may use the Kotest test framework which comes with System Exit extensions that allow you to test the exit code.
+Applications that use JUnit 4 can use Stephan Birkner’s System-Rules project for testing the exit code. -(This library has many other nice features, including capturing the standard output and standard error streams, and more.) -For example:
+The listing below provides code samples for all of the four options mentioned above:
import static com.github.stefanbirkner.systemlambda.SystemLambda.catchSystemExit;
+// ...
+
+class MyTest {
+ @Command
+ static class MyApp implements Callable<Integer> {
+ public Integer call() {
+ System.out.println("Hi");
+ return 42;
+ }
+ public static void main(String[] args) {
+ System.exit(new CommandLine(new MyApp()).execute(args));
+ }
+ }
+
+ @Test
+ void testMyAppExit() throws Exception {
+ int exitCode = catchSystemExit(() -> {
+ MyApp.main();
+ });
+ assertEquals(42, exitCode);
+ }
+}
+import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
+import org.junit.jupiter.api.Test;
+// ...
+
+class MyTest {
+ @Command
+ static class MyApp implements Callable<Integer> {
+ @Override
+ public Integer call() throws Exception {
+ System.out.println("Hi");
+ return 42;
+ }
+ public static void main (String[] args) {
+ System.exit(new CommandLine(new MyApp()).execute(args));
+ }
+ }
+
+ @Test
+ @ExpectSystemExitWithStatus(42)
+ void testMyAppExit() {
+ MyApp.main(new String[] {});
+ }
+}
+import org.junit.Rule;
import org.junit.Test;
@@ -16772,79 +17116,177 @@ class MyTest {
@Rule public final ExpectedSystemExit exit = ExpectedSystemExit.none();
+ @Command
+ static class MyApp implements Callable<Integer> {
+ public Integer call() {
+ System.out.println("Hi");
+ return 42;
+ }
+ public static void main(String[] args) {
+ System.exit(new CommandLine(new MyApp()).execute(args));
+ }
+ }
+
@Test
public void testExitCode() {
- @Command class App implements Runnable {
- public void run() {
- System.exit(23);
- }
- }
- exit.expectSystemExitWithStatus(23);
- new CommandLine(new App()).execute();
+ exit.expectSystemExitWithStatus(42);
+ MyApp.main();
}
}
JUnit 5 users may be interested in Todd Ginsberg’s blog post Testing System.exit() with JUnit5.
+import io.kotest.assertions.throwables.shouldThrow
+import io.kotest.core.spec.style.StringSpec
+import io.kotest.extensions.system.*
+import io.kotest.matchers.shouldBe
+// ...
+
+class SystemExitTest : StringSpec() {
+
+ override fun listeners() = listOf(SpecSystemExitListener)
+
+ init {
+ "Picocli app should exit process with return code 42" {
+ shouldThrow<SystemExitException> {
+ main(arrayOf())
+ }.exitCode shouldBe 42
+ }
+ }
+}
+
+@Command
+class PicocliApp : Callable<Int> {
+ override fun call(): Int {
+ return 42
+ }
+}
+
+fun main(args: Array<String>) : Unit = exitProcess(CommandLine(PicocliApp()).execute(*args))
+Since picocli offers support for using environment variables in the annotations, you may want to test this.
-Applications that use JUnit 4 can use Stephan Birkner’s System-Rules project for testing environment variables.
-JUnit 5 does not appear to provide an equivalent extension for testing environment variables.
-JUnit 5 users can use Stephan Birkner’s @Rule EnvironmentVariables …
for testing environment variables, but there are some things to be aware of.
Since picocli offers support for using environment variables in the annotations, you may want to test this. +Depending on your programming language, your environment and your testing framework, you have several options:
Use com.github.stefanbirkner:system-rules
version 1.17.2: the latest version, 1.18, has an issue that means the Environment Variables rule will not work in JUnit 5.
Java 8: You can use Stephan Birkner’s System-Lambda project for testing environment variables
Apparently the JUnit 5 @EnableRuleMigrationSupport
annotation is not sufficient to reliably use @Rule EnvironmentVariables
in a JUnit 5 test.
Java + Junit 4: You can use Stephan Birkner’s System-Rules project for testing the environment variables.
Instead, I recommend creating a separate JUnit 4 test class for the environment variable tests.
+Kotlin + Kotest: Kotlin coders you may use the Kotest test framework which comes with System Environment extension that allow you to test environment variables.
In Gradle, use the following dependencies:
+The listing below provides code samples for the three options mentioned above:
dependencies {
- implementation "info.picocli:picocli:${picocliVersion}"
- annotationProcessor "info.picocli:picocli-codegen:${picocliVersion}"
+import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
+// ...
- testImplementation("com.github.stefanbirkner:system-rules:1.17.2") {
- exclude group:"junit"
- }
- testImplementation "junit:junit:${junit4Version}"
- testImplementation "org.junit.jupiter:junit-jupiter-api:${junit5Version}"
+@Test
+void testEnvVar() throws Exception {
+ class MyApp {
+ @Option(names = "--option", defaultValue = "${env:MYVAR}",
+ description = "Some option. Default: ${DEFAULT-VALUE}")
+ String option;
+ }
+ String actual = withEnvironmentVariable("MYVAR", "some-value")
+ .and("OTHER_VAR", "second value")
+ .execute(() -> new CommandLine(new MyApp())
+ .getUsageMessage(CommandLine.Help.Ansi.OFF));
+
+ String expected = String.format("" +
+ "Usage: <main class> [--option=<option>]%n" +
+ " --option=<option> Some option. Default: some-value%n");
+ assertEquals(expected, actual);
+}
+
import org.junit.contrib.java.lang.system.EnvironmentVariables;
+// ...
+
+class MyTest {
+ @Rule
+ public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
- testRuntimeOnly "org.junit.platform:junit-platform-launcher:1.6.0"
- testRuntimeOnly "org.junit.vintage:junit-vintage-engine:${junit5Version}"
- testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junit5Version}"
+ @Test
+ public void testEnvVar() {
+ class MyApp {
+ @Option(names = "--option", defaultValue = "${env:MYVAR}",
+ description = "Some option. Default: ${DEFAULT-VALUE}")
+ String option;
+ }
+ environmentVariables.clear("MYVAR", "OTHER_VAR", "THIRD_VAR");
+ environmentVariables.set("MYVAR", "some-value");
+ environmentVariables.set("OTHER_VAR", "second value");
- // ...
-}
+ String actual = new CommandLine(new MyApp())
+ .getUsageMessage(CommandLine.Help.Ansi.OFF);
-test {
- useJUnitPlatform {
- includeEngines 'junit-jupiter', 'junit-vintage'
- }
-}
+ String expected = String.format("" +
+ "Usage: <main class> [--option=<option>]%n" +
+ " --option=<option> Some option. Default: some-value%n");
+ assertEquals(expected, actual);
+ }
+}
For more details, see the sample project provided by David M. Carr.
+import io.kotest.core.spec.style.StringSpec
+import io.kotest.extensions.system.withEnvironment
+import io.kotest.matchers.shouldBe
+import picocli.CommandLine
+import picocli.CommandLine.Command
+
+class EnvironmentVarTest : StringSpec() {
+ init {
+ "env var" {
+ withEnvironment(mapOf("MYVAR" to "some-value", "OTHER_VAR" to "second value")) {
+ CommandLine(MyApp()).getUsageMessage(CommandLine.Help.Ansi.OFF) shouldBe
+ "Usage: <main class> [--option=<option>]" + System.lineSeparator() +
+ " --option=<option> Some option. Default: some-value" + System.lineSeparator()
+ }
+ }
+ }
+}
+
+@Command
+class MyApp {
+ @CommandLine.Option(names = ["--option"], defaultValue = "\${env:MYVAR}",
+ description = ["Some option. Default: \${DEFAULT-VALUE}"])
+ lateinit var option: String
+}
++ + | +
+The latest versions of com.github.stefanbirkner:system-rules , 1.18 and 1.19, have an issue that means the Environment Variables rule will not work in JUnit 5. Use System Rules version 1.17.2 instead when combining with JUnit 5.
+ |
+
java -cp "picocli-4.6.1.jar;myapp.jar" org.myorg.MyMainClass --option=value arg0 arg1
+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.MyMainClass --option=value arg0 arg1
alias mycommand='java -cp "/path/to/picocli-4.6.1.jar:/path/to/myapp.jar" org.myorg.MainClass'
+alias mycommand='java -cp "/path/to/picocli-4.6.2.jar:/path/to/myapp.jar" org.myorg.MainClass'
path/to/native-image -cp picocli-4.6.1.jar --static -jar myapp.jar+
path/to/native-image -cp picocli-4.6.2.jar --static -jar myapp.jar
JReleaser enables several packaging options such as Homebrew, Chocolatey, +Snapcraft, Scoop, jbang, Docker, among others. +Currently two different distribution types are supported: jlink, and standard zip/tar distributions. The latter can be generated with a +combination of the appassembler-maven-plugin and +maven-assembly-plugin plugins if using Maven, or the +application plugin if using Gradle.
+@Grab('info.picocli:picocli-groovy:4.6.1')
+@Grab('info.picocli:picocli-groovy:4.6.2')
@GrabConfig(systemClassLoader=true)
@Command(name = "myScript",
mixinStandardHelpOptions = true, // add --help and --version options
@@ -17257,7 +17710,7 @@ 30.1.2. G
When upgrading scripts from picocli versions older than 4.0, just changing the version number is not enough!
-Scripts should use @Grab('info.picocli:picocli-groovy:4.6.1')
. The old artifact id @Grab('info.picocli:picocli:4.6.1')
will not work,
+Scripts should use @Grab('info.picocli:picocli-groovy:4.6.2')
. The old artifact id @Grab('info.picocli:picocli:4.6.2')
will not work,
because the @picocli.groovy.PicocliScript
annotation class and supporting classes have been moved into a separate module, picocli-groovy
.
@@ -17352,7 +17805,7 @@
-@Grab('info.picocli:picocli-groovy:4.6.1')
+@Grab('info.picocli:picocli-groovy:4.6.2')
@GrabExclude('org.codehaus.groovy:groovy-all') // work around GROOVY-7613
...
@@ -17543,14 +17996,14 @@ 37.1. Build too
Gradle
-implementation 'info.picocli:picocli:4.6.1'
+implementation 'info.picocli:picocli:4.6.2'
Gradle (Kotlin)
dependencies {
- implementation("info.picocli:picocli:4.6.1")
+ implementation("info.picocli:picocli:4.6.2")
}
@@ -17560,46 +18013,46 @@ 37.1. Build too
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
- <version>4.6.1</version>
+ <version>4.6.2</version>
</dependency>
libraryDependencies += "info.picocli" % "picocli" % "4.6.1"
+libraryDependencies += "info.picocli" % "picocli" % "4.6.2"
<dependency org="info.picocli" name="picocli" rev="4.6.1" />
+<dependency org="info.picocli" name="picocli" rev="4.6.2" />
@Grapes(
- @Grab(group='info.picocli', module='picocli', version='4.6.1')
+ @Grab(group='info.picocli', module='picocli', version='4.6.2')
)
[info.picocli/picocli "4.6.1"]
+[info.picocli/picocli "4.6.2"]
'info.picocli:picocli:jar:4.6.1'
+'info.picocli:picocli:jar:4.6.2'
//DEPS info.picocli:picocli:4.6.1
+//DEPS info.picocli:picocli:4.6.2
java -Duser.language=de -cp "myapp.jar;picocli-4.6.1.jar;picocli-codegen-4.6.1.jar" picocli.codegen.docgen.manpage.ManPageGenerator my.pkg.MyClass+
java -Duser.language=de -cp "myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar" picocli.codegen.docgen.manpage.ManPageGenerator my.pkg.MyClass
java -cp "myapp.jar;picocli-4.6.1.jar;picocli-codegen-4.6.1.jar" picocli.codegen.aot.graalvm.DynamicProxyConfigGenerator my.pkg.MyClass+
java -cp "myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar" picocli.codegen.aot.graalvm.DynamicProxyConfigGenerator my.pkg.MyClass
java -cp "myapp.jar;picocli-4.6.1.jar" \ +java -cp "myapp.jar;picocli-4.6.2.jar" \ picocli.AutoComplete my.pkg.MyClass
$ java -cp "myapp.jar;picocli-4.6.1.jar" ASCIIArt --font-size=9 Hello picocli +$ java -cp "myapp.jar;picocli-4.6.2.jar" ASCIIArt --font-size=9 Hello picocli # # # # # # # # # # # # # # *** # # **** #*** # **# **** **# # # @@ -2048,7 +2052,7 @@
Resolving two letter language codes-$ java -cp "myapp.jar;picocli-4.6.1.jar" ISOCodeResolver language de cs en sd se +$ java -cp "myapp.jar;picocli-4.6.2.jar" ISOCodeResolver language de cs en sd se de: German cs: Czech en: English @@ -2059,7 +2063,7 @@
Resolving two letter country codes-diff --git a/docs/zh/picocli-2.0-do-more-with-less.html b/docs/zh/picocli-2.0-do-more-with-less.html index d1c5c6ad8..bf9260d1c 100644 --- a/docs/zh/picocli-2.0-do-more-with-less.html +++ b/docs/zh/picocli-2.0-do-more-with-less.html @@ -527,88 +527,88 @@ .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} - - - + + +$ java -cp "myapp.jar;picocli-4.6.1.jar" ISOCodeResolver country cn fr th ro no +$ java -cp "myapp.jar;picocli-4.6.2.jar" ISOCodeResolver country cn fr th ro no CN: China FR: France TH: Thailand @@ -3797,8 +3801,8 @@17. More
Picocli 2.0: 以少求多
-version 4.6.1 +version 4.6.2@@ -1004,7 +1004,7 @@diff --git a/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html b/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html index d995fa4be..0a17b6af2 100644 --- a/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html +++ b/docs/zh/picocli-2.0-groovy-scripts-on-steroids.html @@ -527,88 +527,88 @@ .CodeRay .change .change{color:#66f} .CodeRay .head .head{color:#f4f} - - - + + +结论
Picocli 2.0: Steroids上的Groovy脚本
-version 4.6.1 +version 4.6.2@@ -876,7 +876,7 @@diff --git a/gradle.properties b/gradle.properties index 5e876a238..3be9f5530 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,10 +18,10 @@ springBootVersion = 2.5.6 # projectPreviousPublishedVersion is non-SNAPSHOT, only published releases projectPreviousPublishedVersion = 4\\.6\\.1 # projectPreviousVersionRegex may be a SNAPSHOT -projectPreviousVersionRegex = 4\\.6\\.1 -projectVersion = 4.6.2-SNAPSHOT +projectPreviousVersionRegex = 4\\.6\\.2-SNAPSHOT +projectVersion = 4.6.2 -releaseDate = 2021-01-03 +releaseDate = 2021-11-05 releaseDatePreviousRegex = 2021\\-01\\-03 systemRulesVersion = 1.17.1 diff --git a/gradle/release-tasks.gradle b/gradle/release-tasks.gradle index 0d212c2ee..1a357022e 100644 --- a/gradle/release-tasks.gradle +++ b/gradle/release-tasks.gradle @@ -112,19 +112,19 @@ task copyDocs(type: Copy) { /* Release procedure: 1. edit version numbers: remove -SNAPSHOT classifier; edit releaseDate -2. gradlew bumpVersion +2. ./gradlew bumpVersion 3. check modified files -4. gradlew clean build -5. gradlew copyDocs +4. ./gradlew clean build +5. ./gradlew copyDocs 6. update RELEASE-NOTES.md -7. gradlew bumpReadmeVersion +7. ./gradlew bumpReadmeVersion 7a update README.md (latest version, release notes) 8. commit -m "Release picocli version ..." 9. tag v$version -10. gradlew bintrayUpload - to publish to bintray.com +10. ./gradlew publishReleasePublicationToSonatypeRepository - creates staging repository, and uploads artifacts 11. edit version numbers: increase minor version and add -SNAPSHOT classifier -12. gradlew bumpVersion +12. ./gradlew bumpVersion 13. check modified files 14. commit -m "Prepare for next development cycle" 15. push (make sure that Push Tags is checked) @@ -133,12 +133,8 @@ Release procedure: 17. Click the new tag, click Edit button, update title and release notes (copy from RELEASE-NOTES.md) 18. Upload picocli-$version.jar and picocli-all$version.zip to GitHub -19. Log in to Bintray -20. Navigate to the page for the new version -21. Edit version: Publication Date, Description, VCS tag, GitHub release notes file (RELEASE-NOTES.md) -22. On the version page, Release Notes tab, select GitHub File -23. Publish artifacts to JCenter -24. On the version page, Maven Central tab, sync to Maven (takes several minutes) +19. Log in to https://oss.sonatype.org/ . In the menu on the left, select Staging repositories. + (When releasing from branch) 25. Switch to master diff --git a/picocli-codegen/README.adoc b/picocli-codegen/README.adoc index 5ea8a1b38..8c5b09c07 100644 --- a/picocli-codegen/README.adoc +++ b/picocli-codegen/README.adoc @@ -1,6 +1,6 @@ = Picocli Code Generation -:revnumber: 4.6.1 -:revdate: 2021-01-03 +:revnumber: 4.6.2 +:revdate: 2021-11-05 :toc: left :numbered: :toclevels: 4 @@ -76,7 +76,7 @@ This requires `maven-compiler-plugin` plugin version 3.5 or higher.总结
@@ -89,13 +89,13 @@ An alternative that works with older versions of the `maven-compiler-plugin` is info.picocli picocli-codegen -4.6.1 +4.6.2 info.picocli picocli -4.6.1 +4.6.2 ``` @@ -108,16 +108,16 @@ See < info.picocli picocli-codegen -4.6.1 +4.6.2 provided > below. Use the `annotationProcessor` path in Gradle https://docs.gradle.org/4.6/release-notes.html#convenient-declaration-of-annotation-processor-dependencies[4.6 and higher]: ```groovy dependencies { - implementation 'info.picocli:picocli:4.6.1' - annotationProcessor 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + annotationProcessor 'info.picocli:picocli-codegen:4.6.2' } ``` For Gradle versions prior to 4.6, use `compileOnly`, to prevent the `picocli-codegen` jar from being a transitive dependency included in the artifact the module produces. ```groovy dependencies { - implementation 'info.picocli:picocli:4.6.1' - compileOnly 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + compileOnly 'info.picocli:picocli-codegen:4.6.2' } ``` @@ -145,7 +145,7 @@ Add an execution of the `kapt` goal from `kotlin-maven-plugin` before `compile`: @@ -168,7 +168,7 @@ then replace `annotationProcessor` with `kapt`: apply plugin: 'kotlin-kapt' // required dependencies { // ... - kapt 'info.picocli:picocli-codegen:4.6.1' + kapt 'info.picocli:picocli-codegen:4.6.2' } ``` @@ -352,7 +352,7 @@ Note that the `picocli-codegen` module is only added as a dependency for the `ex info.picocli picocli-codegen -4.6.1 +4.6.2 @@ -373,8 +373,8 @@ configurations { generateConfig } dependencies { - implementation 'info.picocli:picocli:4.6.1' - generateConfig 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + generateConfig 'info.picocli:picocli-codegen:4.6.2' } ---- @@ -463,7 +463,7 @@ Note that the `picocli-codegen` module is only added as a dependency for the `ex info.picocli picocli-codegen -4.6.1 +4.6.2 jar @@ -483,8 +483,8 @@ configurations { generateConfig } dependencies { - implementation 'info.picocli:picocli:4.6.1' - generateConfig 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + generateConfig 'info.picocli:picocli-codegen:4.6.2' } ---- @@ -570,7 +570,7 @@ Note that the `picocli-codegen` module is only added as a dependency for the `ex info.picocli picocli-codegen -4.6.1 +4.6.2 jar @@ -590,8 +590,8 @@ configurations { generateConfig } dependencies { - implementation 'info.picocli:picocli:4.6.1' - generateConfig 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + generateConfig 'info.picocli:picocli-codegen:4.6.2' } ---- @@ -625,8 +625,8 @@ You will also need the https://asciidoctor.org/docs/asciidoctor-gradle-plugin/[A [source,groovy] ---- dependencies { - implementation "info.picocli:picocli:4.6.1" - annotationProcessor "info.picocli:picocli-codegen:4.6.1" + implementation "info.picocli:picocli:4.6.2" + annotationProcessor "info.picocli:picocli-codegen:4.6.2" } mainClassName = "my.pkg.MyCommand" @@ -700,7 +700,7 @@ Note that the `picocli-codegen` module is only added as a dependency for the `ex info.picocli picocli-codegen -4.6.1 +4.6.2 jar diff --git a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/DynamicProxyConfigGenerator.java b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/DynamicProxyConfigGenerator.java index 34ed47fcf..67e0e6091 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/DynamicProxyConfigGenerator.java +++ b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/DynamicProxyConfigGenerator.java @@ -58,7 +58,7 @@ public class DynamicProxyConfigGenerator { }, footerHeading = "%nExample%n", footer = { - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar;picocli-codegen-4.6.2-SNAPSHOT.jar\" " + + " java -cp \"myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar\" " + "picocli.codegen.aot.graalvm.DynamicProxyConfigGenerator my.pkg.MyClass" }, mixinStandardHelpOptions = true, version = "picocli-codegen gen-proxy-config " + CommandLine.VERSION) diff --git a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/JniConfigGenerator.java b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/JniConfigGenerator.java index 205b8d370..417c32745 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/JniConfigGenerator.java +++ b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/JniConfigGenerator.java @@ -31,7 +31,7 @@ public class JniConfigGenerator { }, footerHeading = "%nExample%n", footer = { - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar;picocli-codegen-4.6.2-SNAPSHOT.jar\" " + + " java -cp \"myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar\" " + "picocli.codegen.aot.graalvm.JniConfigGenerator my.pkg.MyClass" }, mixinStandardHelpOptions = true, sortOptions = false, diff --git a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ReflectionConfigGenerator.java b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ReflectionConfigGenerator.java index 5ac4b8f06..298800789 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ReflectionConfigGenerator.java +++ b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ReflectionConfigGenerator.java @@ -95,7 +95,7 @@ public class ReflectionConfigGenerator { }, footerHeading = "%nExample%n", footer = { - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar;picocli-codegen-4.6.2-SNAPSHOT.jar\" " + + " java -cp \"myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar\" " + "picocli.codegen.aot.graalvm.ReflectionConfigGenerator my.pkg.MyClass" }, mixinStandardHelpOptions = true, sortOptions = false, diff --git a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ResourceConfigGenerator.java b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ResourceConfigGenerator.java index 9c16f41cb..b60027379 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ResourceConfigGenerator.java +++ b/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ResourceConfigGenerator.java @@ -54,7 +54,7 @@ public class ResourceConfigGenerator { }, footerHeading = "%nExample%n", footer = { - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar;picocli-codegen-4.6.2-SNAPSHOT.jar\" " + + " java -cp \"myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar\" " + "picocli.codegen.aot.graalvm.ResourceConfigGenerator my.pkg.MyClass" }, mixinStandardHelpOptions = true, version = "picocli-codegen gen-resource-config " + CommandLine.VERSION) diff --git a/picocli-codegen/src/main/java/picocli/codegen/docgen/manpage/ManPageGenerator.java b/picocli-codegen/src/main/java/picocli/codegen/docgen/manpage/ManPageGenerator.java index 18fbd5b5f..23ae9e208 100644 --- a/picocli-codegen/src/main/java/picocli/codegen/docgen/manpage/ManPageGenerator.java +++ b/picocli-codegen/src/main/java/picocli/codegen/docgen/manpage/ManPageGenerator.java @@ -190,7 +190,7 @@ private void verboseDetailed(String message, Object... params) { "", "Example", "-------", - " java -Duser.language=de -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar;picocli-codegen-4.6.2-SNAPSHOT.jar\" " + + " java -Duser.language=de -cp \"myapp.jar;picocli-4.6.2.jar;picocli-codegen-4.6.2.jar\" " + "picocli.codegen.docgen.manpage.ManPageGenerator my.pkg.MyClass" } ) diff --git a/picocli-examples/annotation-processing/example-gradle-project-kotlin-graal-nativeimage/build.gradle b/picocli-examples/annotation-processing/example-gradle-project-kotlin-graal-nativeimage/build.gradle index 989a69229..55357f54d 100644 --- a/picocli-examples/annotation-processing/example-gradle-project-kotlin-graal-nativeimage/build.gradle +++ b/picocli-examples/annotation-processing/example-gradle-project-kotlin-graal-nativeimage/build.gradle @@ -76,8 +76,8 @@ configurations { generateConfig } dependencies { - implementation 'info.picocli:picocli:4.6.1' - generateConfig 'info.picocli:picocli-codegen:4.6.1' + implementation 'info.picocli:picocli:4.6.2' + generateConfig 'info.picocli:picocli-codegen:4.6.2' } task(generateGraalReflectionConfig, dependsOn: 'classes', type: JavaExec) { diff --git a/picocli-examples/annotation-processing/example-gradle-project/build.gradle b/picocli-examples/annotation-processing/example-gradle-project/build.gradle index 2a7dd2a01..c05dfd037 100644 --- a/picocli-examples/annotation-processing/example-gradle-project/build.gradle +++ b/picocli-examples/annotation-processing/example-gradle-project/build.gradle @@ -17,9 +17,9 @@ dependencies { testImplementation group: 'junit', name: 'junit', version: '4.13.1' } dependencies { - implementation 'info.picocli:picocli:4.6.1' - annotationProcessor 'info.picocli:picocli-codegen:4.6.1' - //compileOnly 'info.picocli:picocli-codegen:4.6.1' // in pre-Gradle 4.6 + implementation 'info.picocli:picocli:4.6.2' + annotationProcessor 'info.picocli:picocli-codegen:4.6.2' + //compileOnly 'info.picocli:picocli-codegen:4.6.2' // in pre-Gradle 4.6 } compileJava { // minimum 1.6 diff --git a/picocli-examples/annotation-processing/example-maven-project-shading/pom.xml b/picocli-examples/annotation-processing/example-maven-project-shading/pom.xml index d41731e43..ceef015d7 100644 --- a/picocli-examples/annotation-processing/example-maven-project-shading/pom.xml +++ b/picocli-examples/annotation-processing/example-maven-project-shading/pom.xml @@ -22,7 +22,7 @@ info.picocli picocli-codegen -4.6.1 +4.6.2 jar info.picocli picocli-codegen -4.6.1 +4.6.2 @@ -80,7 +80,7 @@ diff --git a/picocli-examples/annotation-processing/example-maven-project-simple/pom.xml b/picocli-examples/annotation-processing/example-maven-project-simple/pom.xml index 5df11b30d..e656e57a2 100644 --- a/picocli-examples/annotation-processing/example-maven-project-simple/pom.xml +++ b/picocli-examples/annotation-processing/example-maven-project-simple/pom.xml @@ -56,12 +56,12 @@ info.picocli picocli -4.6.1 +4.6.2 info.picocli picocli -4.6.1 +4.6.2 diff --git a/picocli-examples/generate-man-pages/example-gradle-project/build.gradle b/picocli-examples/generate-man-pages/example-gradle-project/build.gradle index 9d4b10266..9a7473149 100644 --- a/picocli-examples/generate-man-pages/example-gradle-project/build.gradle +++ b/picocli-examples/generate-man-pages/example-gradle-project/build.gradle @@ -33,8 +33,8 @@ dependencies { testImplementation group: 'junit', name: 'junit', version: '4.13.1' } dependencies { - implementation "info.picocli:picocli:4.6.1" - annotationProcessor "info.picocli:picocli-codegen:4.6.1" + implementation "info.picocli:picocli:4.6.2" + annotationProcessor "info.picocli:picocli-codegen:4.6.2" } project.ext { diff --git a/picocli-examples/generate-man-pages/example-maven-project/pom.xml b/picocli-examples/generate-man-pages/example-maven-project/pom.xml index a6d75815d..5da51b388 100644 --- a/picocli-examples/generate-man-pages/example-maven-project/pom.xml +++ b/picocli-examples/generate-man-pages/example-maven-project/pom.xml @@ -59,7 +59,7 @@ info.picocli picocli-codegen -4.6.1 +4.6.2 provided @@ -117,12 +117,12 @@ info.picocli picocli-codegen -4.6.1 +4.6.2 jar info.picocli picocli -4.6.1 +4.6.2 diff --git a/picocli-groovy/README.md b/picocli-groovy/README.md index 684101d2b..cc1d52e9f 100644 --- a/picocli-groovy/README.md +++ b/picocli-groovy/README.md @@ -12,7 +12,7 @@ This module was introduced in picocli 4.0; in previous versions these classes we ## Example ```groovy -@Grab('info.picocli:picocli-groovy:4.6.1') +@Grab('info.picocli:picocli-groovy:4.6.2') @Command(description = "Print a checksum of each specified FILE.", mixinStandardHelpOptions = true, version = 'checksum v1.2.3', diff --git a/picocli-shell-jline2/README.md b/picocli-shell-jline2/README.md index d68d7f85c..3edb7840b 100644 --- a/picocli-shell-jline2/README.md +++ b/picocli-shell-jline2/README.md @@ -37,7 +37,7 @@ get command line TAB auto-completion for a picocli-based application running in info.picocli picocli-codegen -4.6.1 +4.6.2 provided ``` diff --git a/picocli-shell-jline3/README.md b/picocli-shell-jline3/README.md index 236a066cb..359fba432 100644 --- a/picocli-shell-jline3/README.md +++ b/picocli-shell-jline3/README.md @@ -75,7 +75,7 @@ JLine [Wiki](https://github.com/jline/jline3/wiki) and some more [Demos](https:/ info.picocli picocli-shell-jline2 -4.6.1 +4.6.2 ``` diff --git a/picocli-spring-boot-starter/README.md b/picocli-spring-boot-starter/README.md index 77cfeee50..af618a7b3 100644 --- a/picocli-spring-boot-starter/README.md +++ b/picocli-spring-boot-starter/README.md @@ -22,14 +22,14 @@ Maven: info.picocli picocli-shell-jline3 -4.6.1 +4.6.2 ``` Gradle: ``` dependencies { - implementation "info.picocli:picocli-spring-boot-starter:4.6.1" + implementation "info.picocli:picocli-spring-boot-starter:4.6.2" } ``` diff --git a/src/main/java/picocli/AutoComplete.java b/src/main/java/picocli/AutoComplete.java index a2d22703c..95c91b7d0 100644 --- a/src/main/java/picocli/AutoComplete.java +++ b/src/main/java/picocli/AutoComplete.java @@ -108,7 +108,7 @@ private static boolean syspropDefinedAndNotFalse(String key) { "", "Example", "-------", - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar\" \\", + " java -cp \"myapp.jar;picocli-4.6.2.jar\" \\", " picocli.AutoComplete my.pkg.MyClass" }, exitCodeListHeading = "%nExit Codes:%n", diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java index c845408ff..a0acda4c7 100644 --- a/src/main/java/picocli/CommandLine.java +++ b/src/main/java/picocli/CommandLine.java @@ -145,7 +145,7 @@ public class CommandLine { /** This is picocli version {@value}. */ - public static final String VERSION = "4.6.2-SNAPSHOT"; + public static final String VERSION = "4.6.2"; private final Tracer tracer = new Tracer(); private CommandSpec commandSpec; @@ -8787,7 +8787,7 @@ private String[] expandVariables(String[] desc) { /** Returns the root option or positional parameter (on the parent command), if this option or positional parameter was inherited; * or {@code null} if it was not. * @see Option#scope() - * @since 4.6.2-SNAPSHOT */ + * @since 4.6.2 */ public ArgSpec root() { return root; } /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. @@ -9425,7 +9425,7 @@ private static String inferLabel(String label, String fieldName, ITypeInfo typeI /** Returns the root option or positional parameter (on the parent command), if this option or positional parameter was inherited; * or {@code null} if it was not. * @see Option#scope() - * @since 4.6.2-SNAPSHOT */ + * @since 4.6.2 */ public ArgSpec root() { return root; } /** Returns the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value. @@ -9568,7 +9568,7 @@ private static String inferLabel(String label, String fieldName, ITypeInfo typeI /** * Sets the root object for this inherited option, and returns this builder. - * @since 4.6.2-SNAPSHOT */ + * @since 4.6.2 */ public T root(ArgSpec root) { this.root = root ; return self(); } /** Sets the type to convert the option or positional parameter to before {@linkplain #setValue(Object) setting} the value, and returns this builder. diff --git a/src/test/java/picocli/AutoCompleteTest.java b/src/test/java/picocli/AutoCompleteTest.java index 46a618289..d33cb0b40 100644 --- a/src/test/java/picocli/AutoCompleteTest.java +++ b/src/test/java/picocli/AutoCompleteTest.java @@ -303,7 +303,7 @@ private static String toString(Object obj) { "%n" + "Example%n" + "-------%n" + - " java -cp \"myapp.jar;picocli-4.6.2-SNAPSHOT.jar\" \\%n" + + " java -cp \"myapp.jar;picocli-4.6.2.jar\" \\%n" + " picocli.AutoComplete my.pkg.MyClass%n"); @Test diff --git a/src/test/java/picocli/CommandLineTest.java b/src/test/java/picocli/CommandLineTest.java index 0ca111fbc..814cdd12b 100644 --- a/src/test/java/picocli/CommandLineTest.java +++ b/src/test/java/picocli/CommandLineTest.java @@ -138,7 +138,7 @@ class App { } @Test public void testVersion() { - assertEquals("4.6.2-SNAPSHOT", CommandLine.VERSION); + assertEquals("4.6.2", CommandLine.VERSION); } @Test public void testArrayPositionalParametersAreReplacedNotAppendedTo() { info.picocli picocli-spring-boot-starter -4.6.1 +4.6.2