From 03541f6d411e2bd511915ab18fdc262d4a03a8b2 Mon Sep 17 00:00:00 2001
From: Remko Popma 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. If the field or method parameter is Multi-value options and positional parameters can be defined with a 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 Custom help subcommands should mark themselves as a help command to tell picocli not to throw a In the above example, the program name is taken from the By default the options list displays options in alphabetical order. Use the Options and parameters may have a The example below uses the plus ( Required options can be marked in the option list by the character specified with the However, end users can type simply Produces the following usage help message: The 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 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. 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 If the long option with its option parameter is longer than 20 characters
+(for example: This (the default) looks like this: Note that the positional parameters are not abbreviated. As of picocli 4.2, there is programmatic API to change this via the In the above example, if we call The minimum value that can be specified for For even more control of the synopsis, use the The default width of the usage help message is 80 characters.
+Commands defined with Picocli 3.0 also introduced programmatic API for this via the End users can use system property To produce a synopsis like the above, specify the literal text in the The minimum width that can be configured is 55 characters. As of picocli 4.0, commands defined with End users may enable this by setting system property This feature requires Java 7. Options and parameters may have a The example below uses the plus ( However, end users can type simply The With the example above, the synopsis of the usage help looks like this: If a command is very complex and has many options, it is sometimes desirable to suppress details from the synopsis with the Note that the positional parameters are not abbreviated. For even more control of the synopsis, use the To produce a synopsis like the above, specify the literal text in the For commands with subcommands, the string For example, to clarify that a subcommand is mandatory, an application may specify The By default, the usage help message does not display exit code information.
Applications that call The separator displayed between options and option parameters ( Options and Parameters with the As of picocli 4.2, an entry for By default, the Both the label and the description of the For example, if we define these system properties: As of picocli 4.3, an entry for the By default, the The description of the For example, if we define this system property: From picocli 3.2, it is possible to embed the default values in the description for an option or positional parameter by
specifying the variable Similarly, it is possible to embed the completion candidates in the description for an option or positional parameter by
specifying the variable Required options can be marked in the option list by the character specified with the Produces the following usage help message: The default width of the usage help message is 80 characters.
-Commands defined with Picocli 3.0 also introduced programmatic API for this via the End users can use system property The minimum width that can be configured is 55 characters. As of picocli 4.0, commands defined with End users may enable this by setting system property 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: This (the default) looks like this: As of picocli 4.2, there is programmatic API to change this via the In the above example, if we call The minimum value that can be specified for 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 Annotation example: 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 Now put the default properties file ( Eventually, we are ready to run our application: With no command line parameter In order to control the locale choosen for our output, we have to make use of the command line parameter Now our message texts are printed in Spanish: Using the command line parameter As of version 4.0, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API. Finally we have to configure our mail service. This can be done inside a file Finally we have to configure our mail service. This can be done inside a file For example: This assumes that the application uses the Applications that print to 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 Example usage: Applications that use JUnit 4 can use Stephan Birkner’s System-Rules project for capturing output. Example usage: 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 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 Testing the exit code of applications that call Testing the exit code of applications that call 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: JUnit 5 users may be interested in Todd Ginsberg’s blog post Testing System.exit() with JUnit5. 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 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 Java 8: You can use Stephan Birkner’s System-Lambda project for testing environment variables Apparently the JUnit 5 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: For more details, see the sample project provided by David M. Carr. 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.A Whirlwind Tour of Picocli
-version 4.6.1
+version 4.6.2
A CheckSum Utility
@Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
private String algorithm = "MD5";
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
// CheckSum implements Callable, so parsing, error handling and handling user
// requests for usage help or version help can be done with one line of code.
CommandLine.call(new CheckSum(), args);
@@ -2928,7 +2928,7 @@ Micronaut
@Option(names = {"-x", "--option"}, description = "example option")
boolean flag;
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
// let Micronaut instantiate and inject services
PicocliRunner.run(MyMicronautApp.class, args);
}
@@ -3086,8 +3086,8 @@ Conclusion
Announcing picocli 1.0 - a mighty tiny command line interface
-version 4.6.1,
+version 4.6.2,
2017-09-10
Feedback Welcome
diff --git a/docs/apidocs/allclasses-frame.html b/docs/apidocs/allclasses-frame.html
index 0a3f62f40..be9e90390 100644
--- a/docs/apidocs/allclasses-frame.html
+++ b/docs/apidocs/allclasses-frame.html
@@ -3,7 +3,7 @@
-Autocomplete for Java Command Line Applications
12. Releases
Build great native CLI apps in Java with GraalVM and Picocli
Conclusion
Groovy 2.5 CliBuilder Renewal (Part 1)
Wait, There’s More…
diff --git a/docs/groovy-2.5-clibuilder-renewal-part2.html b/docs/groovy-2.5-clibuilder-renewal-part2.html
index 46a082ab2..b33e9cb9e 100644
--- a/docs/groovy-2.5-clibuilder-renewal-part2.html
+++ b/docs/groovy-2.5-clibuilder-renewal-part2.html
@@ -527,88 +527,88 @@
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
-
-
-
+
+
+
Groovy 2.5 CliBuilder Renewal (Part 2)
Conclusion
diff --git a/docs/groovy-2.5-clibuilder-renewal.html b/docs/groovy-2.5-clibuilder-renewal.html
index abe93c9c6..44a9fdf9a 100644
--- a/docs/groovy-2.5-clibuilder-renewal.html
+++ b/docs/groovy-2.5-clibuilder-renewal.html
@@ -527,88 +527,88 @@
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
-
-
-
+
+
+
Groovy 2.5 CliBuilder Renewal
Conclusion
diff --git a/docs/index.adoc b/docs/index.adoc
index 7fb802826..70ab3999b 100644
--- a/docs/index.adoc
+++ b/docs/index.adoc
@@ -1,8 +1,8 @@
= picocli - a mighty tiny command line interface
//:author: Remko Popma
//:email: rpopma@apache.org
-:revnumber: 4.6.2-SNAPSHOT
-:revdate: 2021-01-03
+:revnumber: 4.6.2
+:revdate: 2021-11-05
:toc: left
:numbered:
:toclevels: 2
@@ -120,7 +120,7 @@ class CheckSum implements Callablepicocli - a mighty tiny command line interface
picocli - a mighty tiny command line interface
picocli - a mighty tiny command line interface
picocli - a mighty tiny command line interface
picocli - a mighty tiny command line interface
@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 @@
@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>
Usi
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
+
+
+
+
+
+
+
+
+3.4. Boolean Options
@@ -3850,7 +3795,7 @@
-Make sure any nested classes are
@@ -4005,7 +3950,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.
-If your type converter is declared as nested class, make sure you mark this class as
@@ -4100,7 +4045,7 @@ 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.
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
.
split
regular expression to allow end users to specify multiple values in a single parameter.
@@ -5133,7 +5078,7 @@ 6.5.1. Option
-
+
@@ -6541,8 +6486,7 @@
@@ -8534,7 +8478,7 @@ <
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:
@@ -8413,7 +8357,7 @@ @Command(exitCodeOnInvalidInput = 123,
exitCodeOnExecutionException = 456)
-Make sure any nested classes are
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.
Examp
-Make sure any nested classes are
@@ -8796,8 +8740,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.
MissingParameterException
when required options are missing.@Command(helpCommand = true)
14.2. Command
name
attribute of the Command
annotation:14.4. Unsorted Option List
+14.4. Option List
+14.4.1. Unsorted Option List
sortOptions = false
attribute to display options in the order they are declared in your class.@Command(sortOptions = false)
14.6. Split Synopsis Label
-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.14.4.3. Required-Option Marker
+
) 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.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
+}
A+B+C
(using the plus character separator), not A\+B\+C
.
-We want the usage help message to show this.Usage: <main class> [OPTIONS]
+ -a, --alpha=<alpha> optional alpha
+* -b, --beta=<beta> mandatory beta
+14.4.4. Short and Long Option Columns
splitSynopsisLabel
attribute, introduced in picocli 4.3, controls what is shown in the synopsis of the usage help message.-
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.
+
+
+
+
+
+
+
+
+It is possible to left-align all options by using a custom layout.
+See LeftAlignOptions.java in the
+picocli-examples
module for an example.
+14.4.5. Long Option Column Width
+14.7. Abbreviated Synopsis
abbreviateSynopsis
attribute. For example:--output=<outputFolder>
), the long option overflows into the description column, and the option description is shown on the next line.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.
CommandLine::setUsageHelpLongOptionsMaxWidth
and UsageMessageSpec::longOptionsMaxWidth
methods.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
- // ...
-}
longOptionsMaxWidth
is 20, the maximum value is the usage width minus 20
.14.8. Custom Synopsis
+14.5. Usage Width
customSynopsis
attribute to specify one ore more synopsis lines. For example:@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)
+CommandLine::setUsageHelpWidth
and UsageMessageSpec::width
methods.picocli.usage.width
to specify a custom width that overrides the programmatically set value.customSynopsis
attribute:14.6. Auto (Terminal) Width
+@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.picocli.usage.width
to AUTO
, and may disable this by setting this system property to a numeric value.14.7. Split Synopsis Label
+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.+
) 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>
A+B+C
(using the plus character separator), not A\+B\+C
.
+We want the usage help message to show this.splitSynopsisLabel
attribute, introduced in picocli 4.3, controls what is shown in the synopsis of the usage help message.Usage: cmd [VALUE[+VALUE...]...]
+14.8. Abbreviated Synopsis
+abbreviateSynopsis
attribute. For example:Usage: <main class> [OPTIONS] [<files>...]
+
+@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
+ // ...
+}
14.9. Custom Synopsis
+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)
+customSynopsis
attribute:14.9. Synopsis Subcommand Label
+14.10. Synopsis Subcommand Label
[COMMAND]
is appended to the end of the synopsis (whether the synopsis is abbreviated or not). This looks something like this:
COMMAND
, without the [
and ]
brackets:
@@ -9575,7 +9666,7 @@ @Command(name = "git", synopsisSubcommandLabel = "COMMAND")
class Git { /* ... */ }
-
14.10. Header and Footer
+14.11. Header and Footer
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).14.
14.11. Exit Code List
+14.12. Exit Code List
System.exit
need to configure the exitCodeListHeading
and exitCodeList
annotation attributes.
@@ -9641,7 +9732,7 @@ 14.11. Ex
14.15. Option-Parameter Separators
+14.16. Option-Parameter Separators
=
by default)
in the synopsis and the option list can be configured with the separator
attribute.@Command(separator = " ")
-
14.16. Hidden Options and Parameters
+14.17. Hidden Options and Parameters
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 @@
-
14.17. Show At Files
+14.18. Show At Files
@<filename>
can be shown in the options and parameters list of the usage help message of a command with the @Command(showAtFileInUsageHelp = true)
annotation.14.17.2. Changing the At File Entry Location
+14.18.2. Changing the At File Entry Location
@<filename>
entry is shown before the positional parameters in the synopsis as well as in the parameters list.
-
14.17.3. Changing the At File Entry Text
+14.18.3. Changing the At File Entry Text
@<filename>
entry have been defined with custom variables, to allow applications to change the text. The variables are:
@@ -10016,12 +10105,12 @@ System.setProperty("picocli.atfile.label", "my@@@@file");
System.setProperty("picocli.atfile.description", "@files rock!");
-
14.18. Show End of Options
+14.19. Show End of Options
--
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.14.18.2. Changing the End of Options Entry Location
+14.19.2. Changing the End of Options Entry Location
--
End of Options entry is shown between the options and the positional parameters in the synopsis, and at the end of the options list.
-
14.18.3. Changing the End of Options Entry Text
+14.19.3. Changing the End of Options Entry Text
--
End of Options delimiter entry has been defined with a custom variable, to allow applications to change the text. The variable is:
System.setProperty("picocli.endofoptions.description", "End of options. Remainder are positional parameters.");
-
14.19. Show Default Values
+14.20. Show Default Values
14.19.1.
+${DEFAULT-VALUE}
Variable14.20.1.
${DEFAULT-VALUE}
Variable${DEFAULT-VALUE}
in the description text.
@@ -10233,7 +10321,7 @@
-
14.19.2.
+${COMPLETION-CANDIDATES}
Variable14.20.2.
${COMPLETION-CANDIDATES}
Variable${COMPLETION-CANDIDATES}
in the description text.
-
14.19.3. Legacy Configuration for Displaying Default Values
+14.20.3. Legacy Configuration for Displaying Default Values
14.20. Required-Option Marker
-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
-}
Usage: <main class> [OPTIONS]
- -a, --alpha=<alpha> optional alpha
-* -b, --beta=<beta> mandatory beta
-14.21. Usage Width
-@Command(usageHelpWidth = NUMBER)
in the annotations will use the specified width.CommandLine::setUsageHelpWidth
and UsageMessageSpec::width
methods.picocli.usage.width
to specify a custom width that overrides the programmatically set value.14.22. Auto (Terminal) Width
-@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.picocli.usage.width
to AUTO
, and may disable this by setting this system property to a numeric value.14.23. Long Option Column Width
---output=<outputFolder>
), the long option overflows into the description column, and the option description is shown on the next line.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.
-CommandLine::setUsageHelpLongOptionsMaxWidth
and UsageMessageSpec::longOptionsMaxWidth
methods.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.
-longOptionsMaxWidth
is 20, the maximum value is the usage width minus 20
.17.18. Subcommands and default values
+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());
+ }
+}
19.1. Confi
@@ -14020,37 +14025,178 @@ @Command(name = "i18n-demo", resourceBundle = "my.org.I18nDemo_Messages")
class I18nDemo {}
-
20. Variable Interpolation
-19.6. Controlling the locale
-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:20.1. Variable Interpolation Example
+@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))
+}
mybundle.properties
, in English) and the Spanish language variant (mybundle_es.properties
) in place:Hello = Hello {0}!
+Hello = ¡Hola {0}!
+
+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp Sarah Lea
--locale
given, the message texts are printed in the default language (here: English):Hello Sarah!
+Hello Lea!
+--locale
:
+java -cp "picocli-4.6.2.jar;myapp.jar" org.myorg.GreetingApp --locale=es Sarah Lea
¡Hola Sarah!
+¡Hola Lea!
+--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.20. Variable Interpolation
+20.1. Variable Interpolation Example
+@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}
.
+20.2. Predefined Variables
@@ -14883,7 +15041,7 @@
-If your model transformer is declared as nested class, make sure you mark this class as
@@ -15561,7 +15719,7 @@ 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>
Gradle (Groovy)
dependencies {
- implementation 'info.picocli:picocli-spring-boot-starter:4.6.1'
+ implementation 'info.picocli:picocli-spring-boot-starter:4.6.2'
}
Gradle (Kotlin)
dependencies {
- implementation("info.picocli:picocli-spring-boot-starter:4.6.1")
+ implementation("info.picocli:picocli-spring-boot-starter:4.6.2")
}
application properties
, which we put in a config
subdirectory of your project:application.properties
, which we put in a config
subdirectory of your project:22.
defaultValue = "remkop/picocli")
String slug;
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) {
PicocliRunner.execute(GitStarsCommand.class, args);
}
@@ -16648,7 +16806,8 @@
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)
28.2. Testing the Output
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...")
+ }
+}
28.2. Testing the Output
+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.28.2.1. Java 8+ with System-Lambda
+System.out
or System.err
directly can be tested by capturing the standard output and error streams like this:
+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);
+ }
+}
28.2.2. JUnit 4 with System-Rules
+
+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());
+ }
+}
28.2.3. DIY Output Capturing
+@org.junit.Before
-annotated method and teardown in an @org.junit.After
-annotated method.
+@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:2
28.3. Testing the Exit Code
System.exit
can be tricky but is not impossible.System.exit
can be tricky but is not impossible.
+Depending on your programming language, your environment and your testing framework, you have several options:
+
+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();
}
}
+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))
28.4. Testing Environment Variables
@Rule EnvironmentVariables …
for testing environment variables, but there are some things to be aware of.
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.@EnableRuleMigrationSupport
annotation is not sufficient to reliably use @Rule EnvironmentVariables
in a JUnit 5 test.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);
+}
+ 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'
- }
-}
+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
29.9. jbang
This asciinema presentation shows what is possible.
29.10. JReleaser
+@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
@@ -17352,7 +17805,7 @@ @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
.
@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
...
37.1. Build too
+implementation 'info.picocli:picocli:4.6.1'
implementation 'info.picocli:picocli:4.6.2'
dependencies {
- implementation("info.picocli:picocli:4.6.1")
+ implementation("info.picocli:picocli:4.6.2")
}
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
37.2. Source
Example
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
Example
Example
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
Example
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