pax_global_header 0000666 0000000 0000000 00000000064 13457642030 0014516 g ustar 00root root 0000000 0000000 52 comment=a7443993152cf042525687c7085a63d167991f90
picocli-3.9.6/ 0000775 0000000 0000000 00000000000 13457642030 0013157 5 ustar 00root root 0000000 0000000 picocli-3.9.6/.gitattributes 0000664 0000000 0000000 00000001647 13457642030 0016062 0 ustar 00root root 0000000 0000000 # Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
#
# The above will handle all files NOT found below
#
# These files are text and should be normalized (Convert crlf => lf)
*.adoc text
*.css text
*.gradle text
*.groovy text
*.html text
*.java text
*.js text
*.md text
*.properties text
*.txt text
*.yml text
# These files are text and must be normalized to lf
gradlew text eol=lf
*.sh text eol=lf
*.bash text eol=lf
# These files are text and must be normalized to crlf
*.bat text eol=crlf
# These files are binary and should be left untouched
# (binary is a macro for -text -diff)
*.gif binary
*.ico binary
*.jar binary
*.jpg binary
*.jpeg binary
*.png binary
picocli-3.9.6/.gitignore 0000664 0000000 0000000 00000000101 13457642030 0015137 0 ustar 00root root 0000000 0000000 .gradle/
.idea/
build/
local.properties
target/
tmp/
picocli.iml
picocli-3.9.6/.travis.yml 0000664 0000000 0000000 00000002202 13457642030 0015264 0 ustar 00root root 0000000 0000000 env:
global:
# for CodeClimate
- CC_TEST_REPORTER_ID=83a2e05f875e3a67f60a1969f20a558a3de03a7592052c8bf52807d0e317f01a
language: java
jdk:
- oraclejdk8
- oraclejdk11
- oraclejdk-ea
- openjdk8
- openjdk9
- openjdk10
- openjdk11
- openjdk-ea
# - openjdk7 # Disabled to avoid error java.security.NoSuchProviderException: no such provider: SunEC...
# - oraclejdk7
# $ jdk_switcher use oraclejdk7
# Switching to Oracle JDK7 (java-7-oracle), JAVA_HOME will be set to /usr/lib/jvm/java-7-oracle
# update-java-alternatives: directory does not exist: /usr/lib/jvm/java-7-oracle
# ...
# ERROR: JAVA_HOME is set to an invalid directory: /usr/lib/jvm/java-7-oracle
#
# - openjdk6 # gradle 3.1 requires java 7
matrix:
allow_failures:
- jdk: oraclejdk-ea
before_script:
- chmod +x gradlew
# for CodeClimate
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
- chmod +x ./cc-test-reporter
- ./cc-test-reporter before-build
script:
- ./gradlew check --info
after_success:
- bash <(curl -s https://codecov.io/bash)
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
picocli-3.9.6/LICENSE 0000664 0000000 0000000 00000026135 13457642030 0014173 0 ustar 00root root 0000000 0000000 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
picocli-3.9.6/README.md 0000664 0000000 0000000 00000033573 13457642030 0014451 0 ustar 00root root 0000000 0000000
[](https://github.com/remkop/picocli/releases)
[](https://travis-ci.org/remkop/picocli)
[](https://codecov.io/gh/remkop/picocli)
[](https://twitter.com/intent/follow?screen_name=remkopopma)
[](https://twitter.com/intent/follow?screen_name=picocli)
# picocli - a mighty tiny command line interface
Java command line parser with both an annotations API and a programmatic API, featuring usage help with ANSI colors, autocomplete and nested subcommands.
In a single file, so you can include it _in source form_.
This lets users run picocli-based applications without requiring picocli as an external dependency.
How it works: annotate your class and picocli initializes it from the command line arguments,
converting the input to strongly typed data. Supports git-like [subcommands](https://picocli.info/#_subcommands)
(and nested [sub-subcommands](https://picocli.info/#_nested_sub_subcommands)),
any option prefix style, POSIX-style [grouped short options](https://picocli.info/#_short_options),
custom [type converters](https://picocli.info/#_custom_type_converters),
[password options](http://picocli.info/#_interactive_password_options) and more.
Parser [tracing](https://picocli.info/#_tracing) facilitates troubleshooting.
Command-line [argument files](https://picocli.info/#AtFiles) (@-files) allow applications to handle very long command lines.
Distinguishes between [named options](https://picocli.info/#_options) and
[positional parameters](https://picocli.info/#_positional_parameters) and allows _both_ to be
[strongly typed](https://picocli.info/#_strongly_typed_everything).
[Multi-valued fields](https://picocli.info/#_multiple_values) can specify
an exact number of parameters or a [range](https://picocli.info/#_arity) (e.g., `0..*`, `1..2`).
Supports [Map options](https://picocli.info/#_maps) like `-Dkey1=val1 -Dkey2=val2`, where both key and value can be strongly typed.
Generates polished and easily tailored [usage help](https://picocli.info/#_usage_help)
and [version help](https://picocli.info/#_version_help),
using [ANSI colors](https://picocli.info/#_ansi_colors_and_styles) where possible.
Works with Java 5 or higher (but is designed to facilitate the use of Java 8 lambdas).
Picocli-based command line applications can have [TAB autocompletion](https://picocli.info/autocomplete.html),
interactively showing users what options and subcommands are available.
When an option has [`completionCandidates`](https://picocli.info/#__code_completion_candidates_code_variable) or has an `enum` type, autocompletion can also suggest option values.
Picocli can generate completion scripts for bash and zsh, and offers [`picocli-shell-jline2`](picocli-shell-jline2/README.md) and [`picocli-shell-jline3`](picocli-shell-jline3/README.md) modules with JLine `Completer` implementations for building interactive shell applications.
Picocli-based applications can easily [integrate](https://picocli.info/#_dependency_injection) with Dependency Injection containers.

### Releases
* [Releases](https://github.com/remkop/picocli/releases) - Latest: 3.9.6 [Release Notes](https://github.com/remkop/picocli/releases/tag/v3.9.6)
* Older: Picocli 3.0.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)
### Documentation
* [3.x User manual: https://picocli.info](https://picocli.info)
* [3.x Quick Guide](https://picocli.info/quick-guide.html)
* [2.x User manual](https://picocli.info/man/2.x)
* [Command line autocompletion](https://picocli.info/autocomplete.html)
* [API Javadoc](https://picocli.info/apidocs/)
* [3.0 Programmatic API](https://picocli.info/picocli-3.0-programmatic-api.html)
* [FAQ](https://github.com/remkop/picocli/wiki/FAQ)
* [GraalVM AOT Compilation to Native Image](https://picocli.info/picocli-on-graalvm.html)
### Articles
* [Migrating from Commons CLI to picocli](https://picocli.info/migrating-from-commons-cli.html). You won't regret it! :-) (also on: [DZone](https://dzone.com/articles/migrating-from-commons-cli-to-picocli) and [Java Code Geeks](https://www.javacodegeeks.com/2018/11/migrating-commons-cli-picocli.html)).
* [Groovy 2.5 CliBuilder Renewal](https://picocli.info/groovy-2.5-clibuilder-renewal.html) (also on [blogs.apache.org](https://blogs.apache.org/logging/entry/groovy-2-5-clibuilder-renewal)). In two parts: [Part 1](https://picocli.info/groovy-2.5-clibuilder-renewal-part1.html) (also on: [DZone](https://dzone.com/articles/groovy-25-clibuilder-renewal), [Java Code Geeks](https://www.javacodegeeks.com/2018/06/groovy-clibuilder-renewal-part-1.html)), [Part 2](https://picocli.info/groovy-2.5-clibuilder-renewal-part2.html) (also on: [DZone](https://dzone.com/articles/groovy-25-clibuilder-renewal-part-2), [Java Code Geeks](https://www.javacodegeeks.com/2018/06/groovy-clibuilder-renewal-part-2.html)).
* Micronaut user manual for running microservices [standalone with picocli](https://docs.micronaut.io/snapshot/guide/index.html#commandLineApps).
* [Java Command-Line Interfaces (Part 30): Observations](http://marxsoftware.blogspot.jp/2017/11/java-cmd-line-observations.html) by Dustin Marx about picocli 2.0.1 (also on: [DZone](https://dzone.com/articles/java-command-line-interfaces-part-30-finale-observations), [Java Code Geeks](https://www.javacodegeeks.com/2017/11/java-command-line-interfaces-part-30-observations.html))
* [Java Command-Line Interfaces (Part 10): Picocli](http://marxsoftware.blogspot.jp/2017/08/picocli.html) by Dustin Marx about picocli 0.9.7 (also on: [DZone](https://dzone.com/articles/java-command-line-interfaces-part-10-picocli), [Java Code Geeks](https://www.javacodegeeks.com/2017/08/java-command-line-interfaces-part-10-picocli.html))
* [Picocli 2.0: Groovy Scripts on Steroids](https://picocli.info/picocli-2.0-groovy-scripts-on-steroids.html) (also on: [DZone](https://dzone.com/articles/picocli-v2-groovy-scripts-on-steroids), [Java Code Geeks](https://www.javacodegeeks.com/2018/01/picocli-2-0-groovy-scripts-steroids.html))
* [Picocli 2.0: Do More With Less](https://picocli.info/picocli-2.0-do-more-with-less.html) (also on: [DZone](https://dzone.com/articles/whats-new-in-picocli-20), [Java Code Geeks](https://www.javacodegeeks.com/2018/01/picocli-2-0-less.html))
* [Announcing picocli 1.0](https://picocli.info/announcing-picocli-1.0.html) (also on: [DZone](https://dzone.com/articles/announcing-picocli-10))
### 中文
* [Picocli 2.0: Steroids上的Groovy脚本](https://picocli.info/zh/picocli-2.0-groovy-scripts-on-steroids.html)
* [Picocli 2.0: 以少求多](https://picocli.info/zh/picocli-2.0-do-more-with-less.html)
### Mailing List
Join the [picocli Google group](https://groups.google.com/d/forum/picocli) if you are interested in discussing anything picocli-related and receiving announcements on new releases.
### Related
* Check out Thibaud Lepretre's [picocli Spring boot starter](https://github.com/kakawait/picocli-spring-boot-starter)!
### Credit
[Reallinfo](https://github.com/reallinfo) designed the new picocli logo! Many thanks!
## Adoption
* Picocli is now part of Groovy. From Groovy 2.5, all Groovy command line tools are picocli-based, and picocli is the underlying parser for Groovy's [CliBuilder DSL](http://groovy-lang.org/dsls.html#_clibuilder).
* Picocli is now part of Micronaut. The Micronaut CLI has been rewritten with picocli, and Micronaut has dedicated support for running microservices [standalone with picocli](https://docs.micronaut.io/snapshot/guide/index.html#commandLineApps).
* Picocli is now part of JUnit 5. JUnit 5.3 migrated its `ConsoleLauncher` from jopt-simple to picocli to support @-files (argument files); this helps users who need to specify many tests on the command line and run into system limitations.
* Debian now offers a [libpicocli-java package](https://tracker.debian.org/pkg/picocli). Thanks to [Miroslav Kravec](https://udd.debian.org/dmd/?kravec.miroslav%40gmail.com).
* Picocli is used in the Intuit [Karate](https://github.com/intuit/karate) standalone JAR / executable.
* Picocli is part of [Ballerina](https://ballerina.io/). Ballerina uses picocli for all its command line utilities.
* Picocli is used in the [CheckStyle](https://checkstyle.org/cmdline.html) standalone JAR / executable from Checkstyle 8.15.
* Picocli is included in the [OpenJDK Quality Outreach](https://wiki.openjdk.java.net/display/quality/Quality+Outreach) list of Free Open Source Software (FOSS) projects that actively test against OpenJDK builds.
Glad to see more people are using picocli. We must be doing something right. :-)
## Example
Annotate fields with the command line parameter names and description. Optionally implement `Runnable` or `Callable` to delegate error handling and requests for usage help or version help to picocli. For example:
```java
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
@Command(name = "example", mixinStandardHelpOptions = true, version = "Picocli example 3.0")
public class Example implements Runnable {
@Option(names = { "-v", "--verbose" }, description = "Verbose mode. Helpful for troubleshooting. " +
"Multiple -v options increase the verbosity.")
private boolean[] verbose = new boolean[0];
@Parameters(arity = "1..*", paramLabel = "FILE", description = "File(s) to process.")
private File[] inputFiles;
public void run() {
if (verbose.length > 0) {
System.out.println(inputFiles.length + " files to process...");
}
if (verbose.length > 1) {
for (File f : inputFiles) {
System.out.println(f.getAbsolutePath());
}
}
}
public static void main(String[] args) {
CommandLine.run(new Example(), args);
}
}
```
If your command implements `Runnable`, all that is necessary to parse the command line and execute the command is a call to `CommandLine.run` with the command line parameters and the `Runnable` command. When the program is run on the command line, the command line arguments are converted to Java objects and assigned to the annotated fields. After the arguments are successfully parsed, picocli calls the command's `run` method.
```bash
$ java Example -v inputFile1 inputFile2
2 files to process...
```
The `CommandLine.run` convenience method automatically prints the usage help message if the user requested help or when the input was invalid.

If you want more control, you may be interested in the `CommandLine.parse` or `CommandLine.parseWithHandlers` methods. See the user manual for details.
## Usage Help with ANSI Colors and Styles
Colors, styles, headers, footers and section headings are easily customized with annotations.
For example:

See the [source code](https://github.com/remkop/picocli/blob/v0.9.4/src/test/java/picocli/Demo.java#L337).
## Usage Help API
Picocli annotations offer many ways to customize the usage help message.
If annotations are not sufficient, you can use picocli's [Help API](https://picocli.info/#_usage_help_api) to customize even further.
For example, your application can generate help like this with a custom layout:

See the [source code](https://github.com/remkop/picocli/blob/master/src/test/java/picocli/CustomLayoutDemo.java#L61).
## Download
You can add picocli as an external dependency to your project, or you can include it as source.
See the [source code](https://github.com/remkop/picocli/blob/master/src/main/java/picocli/CommandLine.java). Copy and paste it into a file called `CommandLine.java`, add it to your project, and enjoy!
### Gradle
```
compile 'info.picocli:picocli:3.9.6'
```
### Maven
```
info.picocli
picocli
3.9.6
```
### Scala SBT
```
libraryDependencies += "info.picocli" % "picocli" % "3.9.6"
```
### Ivy
```
```
### Grape
```groovy
@Grapes(
@Grab(group='info.picocli', module='picocli', version='3.9.6')
)
```
### Leiningen
```
[info.picocli/picocli "3.9.6"]
```
### Buildr
```
'info.picocli:picocli:jar:3.9.6'
```
picocli-3.9.6/RELEASE-NOTES.md 0000664 0000000 0000000 00000632276 13457642030 0015467 0 ustar 00root root 0000000 0000000 # picocli Release Notes
# Picocli 3.9.6
The picocli community is pleased to announce picocli 3.9.6.
This release improves support for interactive (password) options:
* interactive options can now use type `char[]` instead of String, to allow applications to null out the array after use so that sensitive information is no longer resident in memory
* interactive options can be optionally interactive if configured with `arity = "0..1"`
This is the fifty-second public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.6-new)
* [Fixed issues](#3.9.6-fixes)
* [Deprecations](#3.9.6-deprecated)
* [Potential breaking changes](#3.9.6-breaking-changes)
## New and Noteworthy
This release improves support for interactive (password) options:
* interactive options can now use type `char[]` instead of String, to allow applications to null out the array after use so that sensitive information is no longer resident in memory
* interactive options can be optionally interactive if configured with `arity = "0..1"`
For example, if an application has these options:
```java
@Option(names = "--user")
String user;
@Option(names = "--password", arity = "0..1", interactive = true)
char[] password;
```
With the following input, the `password` field will be initialized to `"123"` without prompting the user for input:
```
--password 123 --user Joe
```
However, if the password is not specified, the user will be prompted to enter a value. In the following example, the password option has no parameter, so the user will be prompted to type in a value on the console:
```
--password --user Joe
```
## Fixed issues
* [#657] Support type `char[]` for interactive options. Thanks to [Lukáš Petrovický](https://github.com/triceo) for raising this issue.
* [#536] Support optionally interactive options. Thanks to [Lukas Heumos](https://github.com/Zethson) for raising this issue.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.9.5
The picocli community is pleased to announce picocli 3.9.5.
This release contains a critical workaround to protect against JVM crashes when running on RedHat Linux 3.10.0-327.44.2.el7.x86_64.
Picocli 3.9.0 introduced a change in the heuristics for emitting ANSI escape characters. As part of this change, picocli may load the `org.fusesource.jansi.AnsiConsole` class from the JAnsi library when not running on Windows. This may crash the JVM (see [fusesource/jansi-native#17](https://github.com/fusesource/jansi-native/issues/17)).
The workaround in this release is to only load the `AnsiConsole` class when running on Windows.
Users using 3.9.0 and higher are strongly recommended to upgrade to 3.9.5 or later.
This is the fiftieth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.5-new)
* [Fixed issues](#3.9.5-fixes)
* [Deprecations](#3.9.5-deprecated)
* [Potential breaking changes](#3.9.5-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#630] Avoid loading `org.fusesource.jansi.AnsiConsole` when not running on Windows to avoid JVM crashes on non-Windows platforms.
- [#632] ReflectionConfigGenerator now specifies the `allowWrite = true` attribute for final fields.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.9.4
The picocli community is pleased to announce picocli 3.9.4.
This release contains bugfixes and enhancements.
From this release, `enum`-typed options and positional parameters that are multi-value can be stored in `EnumSet` collections (in addition to other Collections, arrays and Maps).
Also, a better error message is now shown when unknown options are encountered while processing clustered short options. The new error message includes both the failing part and the original command line argument.
Bugfixes:
* `ReflectionConfigGenerator` incorrectly listed superclass fields as fields of the concrete subclass, causing "GraalVM error: Error parsing reflection configuration in json" when creating a native image.
* Method subcommands in commands that subclass another command caused `InitializationException`.
This is the forty-nineth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.4-new)
* [Fixed issues](#3.9.4-fixes)
* [Deprecations](#3.9.4-deprecated)
* [Potential breaking changes](#3.9.4-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#628] Add support for collecting `enum` multi-value options and positional parameters in `EnumSet<>` collections. Thanks to [Lee Atkinson](https://github.com/leeatkinson) for raising this.
- [#619] Bugfix: Method subcommands in commands that subclass another command caused `InitializationException`: "Another subcommand named 'method' already exists...". Thanks to [PorygonZRocks](https://github.com/PorygonZRocks) for the bug report.
- [#622] Bugfix: `ReflectionConfigGenerator` incorrectly listed superclass fields as fields of the concrete subclass, causing "GraalVM error: Error parsing reflection configuration in json". Thanks to [Sebastian Thomschke](https://github.com/sebthom) for the bug report.
- [#623] `ReflectionConfigGenerator` now generates json in alphabetic order.
- [#627] Improve error message for unknown options when processing clustered short options.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.9.3
The picocli community is pleased to announce picocli 3.9.3.
This release contains bugfixes and enhancements.
This is the forty-eight public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.3-new)
* [Fixed issues](#3.9.3-fixes)
* [Deprecations](#3.9.3-deprecated)
* [Potential breaking changes](#3.9.3-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#613] Enhancement: Improve picocli heuristics for unmatched options: single-character arguments that don't exactly match options (like `-`) should be considered positional parameters. Thanks to [Oliver Weiler](https://github.com/helpermethod) for the bug report.
- [#615] Bugfix: Opaque stacktrace for "%" in Option description. Thanks to [petermr](https://github.com/petermr) for the bug report.
- [#616] Bugfix: showDefaultValues=true with defaultValueProvider did not render defaultValues in usage help. Thanks to [Sebastian Thomschke](https://github.com/sebthom) for the bug report.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.9.2
The picocli community is pleased to announce picocli 3.9.2.
This release contains bugfixes and enhancements.
Picocli now has a mailing list `picocli at googlegroups dot com`. Alternatively visit the [picocli Google group](https://groups.google.com/d/forum/picocli) web interface.
The user manual has improved documentation for internationalization and localization, and the section on Dependency Injection now has a Spring Boot example and link to the Micronaut user manual.
Bugfixes: `AutoComplete` now uses the specified `IFactory` correctly for `CommandLine`; defaulting `usageHelp` or `versionHelp` options no longer prevents validation of required options; and usage help for booleans options with `arity = "1"` now correctly show the option parameter in the synopsis.
Many thanks to the many members of the picocli community who contributed pull requests, bug reports and participated in discussions!
This is the forty-seventh public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.2-new)
* [Fixed issues](#3.9.2-fixes)
* [Deprecations](#3.9.2-deprecated)
* [Potential breaking changes](#3.9.2-breaking-changes)
## New and Noteworthy
Picocli now has a mailing list `picocli at googlegroups dot com`. Alternatively visit the [picocli Google group](https://groups.google.com/d/forum/picocli) web interface.
The user manual has improved documentation for internationalization and localization. Dependency Injection is now a top-level section and now has a Spring Boot example and link to the Micronaut user manual.
## Fixed issues
- [#602] Make `CommandLine` in `AutoComplete` use correct `IFactory` implementation. Thanks to [Mikołaj Krzyżanowski](https://github.com/MikolajK) for the pull request.
- [#608] Bugfix: defaulting `usageHelp` or `versionHelp` options incorrectly prevented validation of required options and positional parameters. Thanks to [Pietro Braione](https://github.com/pietrobraione) for the bug report.
- [#612] Bugfix: Usage help for booleans options with `arity = "1"` now correctly show the option parameter in synopsis. Thanks to [prewersk](https://github.com/prewersk) for the bug report.
- [#606] Doc: Added subcommand example. Thanks to [Andreas Deininger](https://github.com/deining) for the pull request.
- [#605] Doc: Improved documentation for internationalization and localization. Thanks to [Andreas Deininger](https://github.com/deining) for raising this.
- [#604] Doc: Improve user manual section on Dependency Injection: add Spring Boot example. Thanks to [Alistair Rutherford](https://github.com/alistairrutherford) for the example code.
- [#610] Build: add JDKs to Travis CI build.
- [#609] Created mailing list `picocli at googlegroups dot com`: [picocli Google group](https://groups.google.com/d/forum/picocli).
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.9.1
The picocli community is pleased to announce picocli 3.9.1.
The `picocli.AutoComplete` application no longer calls `System.exit()` unless requested by setting system property `picocli.autocomplete.systemExitOnError` or `picocli.autocomplete.systemExitOnSuccess` to any value other than `false`. Applications that rely on the exit codes introduced in picocli 3.9.0 need to set these system properties.
This release adds support for quoted map keys with embedded '=' characters.
This release contains bugfixes and enhancements.
This is the forty-sixth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.1-new)
* [Fixed issues](#3.9.1-fixes)
* [Deprecations](#3.9.1-deprecated)
* [Potential breaking changes](#3.9.1-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#592] Error message now shows `enum` constant names, not `toString()` values, after value mismatch. Thanks to [startewho](https://github.com/startewho) for the bug report.
- [#591] Replace some String concatenation in `picocli.AutoComplete` with StringBuilder. Thanks to [Sergio Escalante](https://github.com/sergioescala) for the pull request.
- [#594] Add support for quoted map keys with embedded '=' characters. Thanks to [Pubudu Fernando](https://github.com/pubudu91) for the suggestion.
- [#596] `picocli.AutoComplete` should not call `System.exit()` unless requested. Thanks to [Markus Heiden](https://github.com/markusheiden), [Bob Tiernay](https://github.com/bobtiernay-okta) and [RobertZenz](https://github.com/RobertZenz) for analysis and ideas contributing to the solution.
- [#593] Use Gradle Bintray Plugin to publish artifacts to Bintray.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
The `picocli.AutoComplete` application no longer calls `System.exit()` unless requested by setting system property `picocli.autocomplete.systemExitOnError` or `picocli.autocomplete.systemExitOnSuccess` to any value other than `false`.
Applications that rely on the exit codes introduced in picocli 3.9.0 need to set these system properties.
The new support for quoted map keys with embedded '=' characters [#594] may inpact some existing applications.
If `CommandLine::setTrimQuotes()` is set to `true`, quotes are now removed from map keys and map values. This did not use to be the case.
For example:
```java
class App {
@Option(names = "-p") Map map;
}
```
When `CommandLine::setTrimQuotes()` was set to `true`, given input like the below:
```
-p AppOptions="-Da=b -Dx=y"
```
The above used to result in a map with key `AppOptions` and value `"-Da=b -Dx=y"` (including the quotes), but the same program and input now results in a map with key `AppOptions` and value `-Da=b -Dx=y` (without quotes).
Also, when `CommandLine::setTrimQuotes()` is `false` (the default), input like the below will now cause a `ParameterException` ("value should be in KEY=VALUE format"):
```
-p "AppOptions=-Da=b -Dx=y"
```
Prior to this release, the above was silently ignored (no errors but also no key-value pairs in the resulting map).
# Picocli 3.9.0
The picocli community is pleased to announce picocli 3.9.0.
This release contains bugfixes and enhancements in the main picocli module, and adds a new module: `picocli-shell-jline3`.
The new module Picocli Shell JLine3 (`picocli-shell-jline3`) contains components and documentation for building
interactive shell command line applications with JLine 3 and picocli.
This release contains API enhancements to allow customization of the usage help message:
* help section renderers can be added, replaced or removed
* help section keys to reorder sections in the usage help message
* help factory to create custom `Help` instances
* option order attribute to reorder options in the usage help message option list
This release also has improved heuristics to decide whether ANSI escape codes should be emitted or not.
The simplified @-file (argument file) format is now fully compatible with JCommander: empty lines are ignored and comments may start with leading whitespace.
The `picocli.Autocompletion` application now accepts a parameter specifying a custom factory, and returns a non-zero exit code on error, to facilitate incorporating it into the build.
Bug fixes in this release:
* `@Command` method options and positional parameter values are now cleared correctly when reusing a `CommandLine` instance
* the default exception handler now correctly respects the exit code for all exceptions
Finally, this release improves internal quality and robustness by increasing the test code coverage. About 300 tests were added to bring the total to 1300+ tests. This improved line coverage to 98% (was 88%) and complexity coverage to 98% (was 82%).
This is the forty-fifth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.9.0-new)
* [Fixed issues](#3.9.0-fixes)
* [Deprecations](#3.9.0-deprecated)
* [Potential breaking changes](#3.9.0-breaking-changes)
## New and Noteworthy
### Help Section Renderer API
This release introduces new API to facilitate customizing the usage help message: `IHelpFactory` allows applications to plug in `Help` subclasses, and `IHelpSectionRenderer` allows applications to add custom sections to the usage help message, or redefine existing sections.
The usage help message is no longer hard-coded, but is now constructed from the section renderers defined in `CommandLine::getHelpSectionMap` (or `UsageMessageSpec::sectionMap` for a single `CommandSpec`).
By default this map contains the predefined section renderers:
```java
// The default section renderers delegate to methods in Help for their implementation
// (using Java 8 lambda notation for brevity):
Map map = new HashMap<>();
map.put(SECTION_KEY_HEADER_HEADING, help -> help.headerHeading());
map.put(SECTION_KEY_HEADER, help -> help.header());
//e.g. Usage:
map.put(SECTION_KEY_SYNOPSIS_HEADING, help -> help.synopsisHeading());
//e.g. [OPTIONS] [COMMAND-OPTIONS] [ARGUMENTS]
map.put(SECTION_KEY_SYNOPSIS, help -> help.synopsis(help.synopsisHeadingLength()));
//e.g. %nDescription:%n%n
map.put(SECTION_KEY_DESCRIPTION_HEADING, help -> help.descriptionHeading());
//e.g. {"Converts foos to bars.", "Use options to control conversion mode."}
map.put(SECTION_KEY_DESCRIPTION, help -> help.description());
//e.g. %nPositional parameters:%n%n
map.put(SECTION_KEY_PARAMETER_LIST_HEADING, help -> help.parameterListHeading());
//e.g. [FILE...] the files to convert
map.put(SECTION_KEY_PARAMETER_LIST, help -> help.parameterList());
//e.g. %nOptions:%n%n
map.put(SECTION_KEY_OPTION_LIST_HEADING, help -> help.optionListHeading());
//e.g. -h, --help displays this help and exits
map.put(SECTION_KEY_OPTION_LIST, help -> help.optionList());
//e.g. %nCommands:%n%n
map.put(SECTION_KEY_COMMAND_LIST_HEADING, help -> help.commandListHeading());
//e.g. add adds the frup to the frooble
map.put(SECTION_KEY_COMMAND_LIST, help -> help.commandList());
map.put(SECTION_KEY_FOOTER_HEADING, help -> help.footerHeading());
map.put(SECTION_KEY_FOOTER, help -> help.footer());
```
Applications can add, remove or replace sections in this map. The `CommandLine::getHelpSectionKeys` method (or `UsageMessageSpec::sectionKeys` for a single `CommandSpec`) returns the section keys in the order that the usage help message should render the sections. The default keys are (in order):
1. SECTION_KEY_HEADER_HEADING
1. SECTION_KEY_HEADER
1. SECTION_KEY_SYNOPSIS_HEADING
1. SECTION_KEY_SYNOPSIS
1. SECTION_KEY_DESCRIPTION_HEADING
1. SECTION_KEY_DESCRIPTION
1. SECTION_KEY_PARAMETER_LIST_HEADING
1. SECTION_KEY_PARAMETER_LIST
1. SECTION_KEY_OPTION_LIST_HEADING
1. SECTION_KEY_OPTION_LIST
1. SECTION_KEY_COMMAND_LIST_HEADING
1. SECTION_KEY_COMMAND_LIST
1. SECTION_KEY_FOOTER_HEADING
1. SECTION_KEY_FOOTER
This ordering may be modified with the `CommandLine::setHelpSectionKeys` setter method (or `UsageMessageSpec::sectionKeys(List)` for a single `CommandSpec`).
### Option `order` Attribute
Options are sorted alphabetically by default, but this can be switched off by specifying `@Command(sortOptions = false)` on the command declaration. This displays options in the order they are declared.
However, when mixing `@Option` methods and `@Option` fields, options do not reliably appear in declaration order.
The `@Option(order = )` attribute can be used to explicitly control the position in the usage help message at which the option should be shown. Options with a lower number are shown before options with a higher number.
### New Module `picocli-shell-jline3`
Picocli Shell JLine3 contains components and documentation for building interactive shell command line applications with JLine 3 and picocli.
This release contains the `picocli.shell.jline3.PicocliJLineCompleter` class.
`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to get command line TAB auto-completion for a picocli-based application running in a JLine 3 shell.
It is similar to the class with the same name in the `picocli.shell.jline2` package in the `picocli-shell-jline2` module.
See the module's [README](https://github.com/remkop/picocli/blob/master/picocli-shell-jline3/README.md) for more details.
### Improved ANSI Heuristics
This release has improved heuristics to decide whether ANSI escape codes should be emitted or not.
Support was added for the following environment variables to control enabling ANSI:
* [`NO_COLOR`](https://no-color.org/)
* [`CLICOLOR_FORCE`](https://bixense.com/clicolors/)
* [`CLICOLOR`](https://bixense.com/clicolors/)
* [`ConEmuANSI`](https://conemu.github.io/en/AnsiEscapeCodes.html#Environment_variable)
* [`ANSICON`](https://github.com/adoxa/ansicon/blob/master/readme.txt)
## Fixed issues
- [#574] Add `picocli-shell-jline3` module. Thanks to [mattirn](https://github.com/mattirn) for the pull request.
- [#587] Enhance `picocli-shell-jline3` example by using JLine's `DefaultParser` to split lines into arguments. Thanks to [mattirn](https://github.com/mattirn) for the pull request.
- [#567] Usage message customization API initial implementation. Thanks to [Christian Helmer](https://github.com/SysLord) for the pull request.
- [#530] Added API for easily customizing the usage help message. Thanks to [stechio](https://github.com/stechio) for raising the request and productive discussions.
- [#569] Facilitate customization of the synopsis: split `Help.detailedSynopsis()` into protected methods.
- [#508] Annotation API: added `@Option(order = )` attribute to allow explicit control of option ordering in the usage help message; useful when mixing methods and fields with `@Option` annotation.
- [#588] Added method `CommandSpec.names` returning both `name` and `aliases`.
- [#578] Add API for simplified @files argument files.
- [#573] Make simplified @files JCommander-compatible: ignore empty lines and comments starting with whitespace. Thanks to [Lukáš Petrovický](https://github.com/triceo) for the pull request with test to reproduce the issue.
- [#572] `CommandSpec.addMethodSubcommands` now throws `picocli.CommandLine.InitializationException` instead of `java.lang.UnsupportedOperationException` when the user object of the parent command is a `java.lang.reflect.Method`.
- [#581] Added support for ConEmu, ANSICON and other environment variables to improve the ANSI heuristics. Documented the heuristics in the user manual.
- [#579] Improved `AutoComplete` error message when not overwriting existing files.
- [#585] `picocli.AutoComplete` now accepts a parameter specifying a custom `IFactory` implementation. Thanks to [Bob Tiernay](https://github.com/bobtiernay-okta) for the suggestion.
- [#582] `picocli.AutoComplete` now returns a non-zero return code on error. Thanks to [Bob Tiernay](https://github.com/bobtiernay-okta) for the suggestion.
- [#570] Bugfix: Command method options and positional parameter Object values are now cleared correctly when reusing CommandLine. Thanks to [Christian Helmer](https://github.com/SysLord) for the pull request.
- [#576] Bugfix: fixed StringIndexOutOfBoundsException in shell-jline2 completion when cursor was before `=` when option parameter was attached to option name.
- [#583] Bugfix: Default exception handler now exits on exception if exitCode was set, regardless of exception type.
- [#584] Add documentation for generating autocompletion script during a Maven build. Thanks to [Bob Tiernay](https://github.com/bobtiernay-okta).
- [#586] Replace Ansi.Text.clone() with copy constructor.
- [#571] Improve test code coverage. Added ~300 tests to bring the total to 1300+ tests. Improved line coverage to 98% (was 88%) and complexity coverage to 98% (was 82%).
- [#590] Fail the build if test coverage falls below minimum threshold.
- [#589] Fix index.adoc to eliminate warnings; suppress javadoc warnings.
- [#566] Add example showing how to customize the usage help message to show the full command tree including nested subcommands. Thanks to [lgawron](https://github.com/lgawron) for the request.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
`CommandSpec.addMethodSubcommands` now throws `InitializationException` instead of `java.lang.UnsupportedOperationException` when the user object of the parent command is a `java.lang.reflect.Method`.
AutoComplete application now prints different error message when not overwriting existing script files. This may break tests that verify the console output.
# Picocli 3.8.2
The picocli community is pleased to announce picocli 3.8.2.
This release contains bugfixes only.
When running a native image with Graal, ANSI colors are now shown correctly.
This is the forty-forth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.8.2-new)
* [Fixed issues](#3.8.2-fixes)
* [Deprecations](#3.8.2-deprecated)
* [Potential breaking changes](#3.8.2-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#557] Bugfix: No colors are shown when compiling to a native image with Graal on MacOS. Thanks to [Oliver Weiler](https://github.com/helpermethod) for the bug report.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This is a patch release and has no breaking changes.
# Picocli 3.8.1
The picocli community is pleased to announce picocli 3.8.1.
This release contains bugfixes and minor enhancements.
Command methods explicitly throwing a `ParametersException` is now correctly handled by picocli, showing the error message and the usage help message.
This release adds support for JCommander-style argument files (one argument per line, no quoting) and better tracing.
Many thanks to the many members of the picocli community who contributed!
This is the forty-third public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.8.1-new)
* [Fixed issues](#3.8.1-fixes)
* [Deprecations](#3.8.1-deprecated)
* [Potential breaking changes](#3.8.1-breaking-changes)
## New and Noteworthy
### Simplified Argument Files
In this argument file format every line (except comment lines) is interpreted as a single argument. Arguments containing whitespace do not need to be quoted, but it is not possible to have arguments with embedded newlines.
Set system property `picocli.useSimplifiedAtFiles` without a value or with value `"true"` (case-insensitive) to enable this simpler argument file format.
This format is similar to the way JCommander processes argument files, which makes it easier for command line applications to migrate from JCommander to picocli.
### Improved Tracing
The following information has been added to the tracing output in this release:
* Version information (picocli version, java version, os version), logged at INFO level
* ANSI enabled status, logged at DEBUG level
* Log at DEBUG level when a Map or Collection binding for an option or positional parameter is initialized with a new instance
* Log at DEBUG level when parameters are being split (into how many parts, show resulting parts)
## Fixed issues
- [#551] Enhancement: Add support for JCommander-style argument files (one argument per line, no quoting). Thanks to [Lukáš Petrovický](https://github.com/triceo) for the bug report and unit tests.
- [#562] Enhancement: Allow for enabling quote trimming via system property `picocli.trimQuotes`. Thanks to [Lukáš Petrovický](https://github.com/triceo) for the pull request.
- [#560] Enhancement: Better tracing.
- [#554] Bugfix: Convenience method error handling was broken for command methods that explicitly throw an ParameterException: InvocationTargetException hides the ParameterException. Thanks to [SysLord](https://github.com/SysLord) for the bug report.
- [#553] Doc: Fix broken link to CommandLine.java source code. Thanks to [Simon Legner](https://github.com/simon04) for the pull request.
- [#563] Doc: Improve documentation for explicitly showing usage help from subcommands. Thanks to [Steve Johnson](https://github.com/Blatwurst) for raising this issue.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This is a patch release and has no breaking changes.
# Picocli 3.8.0
The picocli community is pleased to announce picocli 3.8.0.
This release contains bugfixes and minor enhancements.
`@Command` methods now support `@Mixin` parameters. `OverwrittenOptionException` now has an accessor for the `ArgSpec` that was overwritten.
The `ReflectionConfigGenerator` tool in the `picocli-codegen` module now correctly generates configuration for `@Mixin` fields.
Many thanks to the many members of the picocli community who contributed!
This is the forty-second public release.
Picocli follows [semantic versioning](http://semver.org/). (This release could have been called 3.7.1 except that it has a minor additional API change, which means it cannot be called a patch release by semver rules.)
## Table of Contents
* [New and noteworthy](#3.8.0-new)
* [Fixed issues](#3.8.0-fixes)
* [Deprecations](#3.8.0-deprecated)
* [Potential breaking changes](#3.8.0-breaking-changes)
## New and Noteworthy
### Mixin Support in `@Command` Methods
`@Command` methods now accept `@Mixin` parameters. All options and positional parameters defined in the mixin class are added to the command.
Example:
```java
class CommonParams {
@Option(names = "-x") int x;
@Option(names = "-y") int y;
}
class App {
@Command
public void doit(@Mixin CommonParams params, @Option(names = "-z") int z) {}
}
```
In the above example, the `-x` and `-y` options are added to the other options of the `doit` command.
## Fixed issues
- [#525] Enhancement: Allow `@Mixin` parameters in `@Command` methods. Thanks to [Paul Horn](https://github.com/knutwalker) for the pull request.
- [#532] Enhancement: `OverwrittenOptionException` now has an accessor for the `ArgSpec` that was overwritten. Thanks to [Steven Fontaine](https://github.com/acid1103) for the pull request.
- [#524] Enhancement/Bugfix: `ReflectionConfigGenerator` in `picocli-codegen` should generate configuration for `@Mixin` fields. Thanks to [Paul Horn](https://github.com/knutwalker) for the pull request.
- [#301] Enhancement/Bugfix: The subcommand listing now correctly renders `%n` as line breaks in the brief description for each subcommand. Thanks to [Vlad Topala](https://github.com/topalavlad) for the pull request.
- [#523] Bugfix: Array should be initialized before calling setter method. Thanks to [Paul Horn](https://github.com/knutwalker) for the pull request.
- [#527] Bugfix: Quoting logic did not work for some Unicode code points.
- [#531] Bugfix: Usage help should not show space between short option name and parameter (for options that only have a short name).
- [#538] Bugfix: Command methods and interface methods should pass `null` for unmatched primitive wrapper options.
- [#547] Bugfix: Fix infinite loop when print help. Thanks to [Patrick Kuo](https://github.com/patrickkuo) for the pull request.
- [#528] Doc: Javadoc for xxxHandler API referred to non-existant prototypeReturnValue.
- [#545] Doc: Include mention of command methods for options using collections. Thanks to [Bob Tiernay](https://github.com/bobtiernay-okta) for the pull request.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
### Help Layout
The usage help no longer shows a space between short option names and the parameter (for options that only have a short name).
This may break tests that rely on the exact output format.
Before:
```
Usage: times [-l=] [-r=]
-l=
-r=
```
After:
```
Usage: times [-l=] [-r=]
-l=
-r=
```
### Unmatched Primitive Wrapper Type Options
Another behavioral change is that command methods now pass in `null` for primitive wrapper options that were not matched on the command line.
This impacts methods annotated with `@Command`, and interface methods annotated with `@Option`. Classes annotated with `@Command` already behaved like this and this has not changed.
This behaviour is now consistent for all annotation-based and programmatic ways of defining commands.
# Picocli 3.7.0
The picocli community is pleased to announce picocli 3.7.0.
This release contains bugfixes and enhancements in the main picocli module, and adds two new modules:
`picocli-codegen` and `picocli-shell-jline2`.
Picocli Code Generation (`picocli-codegen`) contains tools for generating source code, documentation and configuration files
for picocli-based applications.
Picocli Shell JLine2 (`picocli-shell-jline2`) contains components and documentation for building
interactive shell command line applications with JLine 2 and picocli.
Many thanks to the many members of the picocli community who contributed!
This is the forty-first public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.7.0-new)
* [Fixed issues](#3.7.0-fixes)
* [Deprecations](#3.7.0-deprecated)
* [Potential breaking changes](#3.7.0-breaking-changes)
## New and Noteworthy
### Improved Parsing of Quoted Values
This release improves parser behaviour of quoted arguments:
* Quotes around command line parameters are now preserved by default (previously they were removed). This can be configured with `CommandLine::setTrimQuotes`.
* When [splitting](https://picocli.info/#_split_regex) parameters, quoted strings are no longer split. This can be configured with `CommandLine::setSplitQuotedStrings`.
Example:
```
@Option(names = "-x", split = ",")
String[] parts;
```
Given input like below:
```
-x a,b,"c,d,e",f,"xxx,yyy"
```
This results in the `parts` array having the following values:
```
a
b
"c,d,e"
f
"xxx,yyy"
```
### New Module `picocli-codegen`
Picocli Code Generation contains tools for generating source code, documentation and configuration files
for picocli-based applications.
This release contains the `ReflectionConfigGenerator` class.
`ReflectionConfigGenerator` generates a JSON String with the program elements that will be accessed reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native executable with GraalVM.
The output of `ReflectionConfigGenerator` is intended to be passed to the `-H:ReflectionConfigurationFiles=/path/to/reflectconfig` option of the `native-image` GraalVM utility. This allows picocli-based applications to be compiled to a native image.
See [Picocli on GraalVM: Blazingly Fast Command Line Apps](https://github.com/remkop/picocli/wiki/Picocli-on-GraalVM:-Blazingly-Fast-Command-Line-Apps) for details.
The module's [README](https://github.com/remkop/picocli/blob/master/picocli-codegen/README.md) explains how to configure your build to generate the configuration file automatically as part of your build.
### New Module `picocli-shell-jline2`
Picocli Shell JLine2 contains components and documentation for building
interactive shell command line applications with JLine 2 and picocli.
This release contains the `PicocliJLineCompleter` class.
`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to
get command line TAB auto-completion for a picocli-based application running in a JLine 2 shell.
See the module's [README](https://github.com/remkop/picocli/blob/master/picocli-shell-jline2/README.md) for more details.
## Fixed issues
- [#503] Build: Upgrade to gradle 4.10.2.
- [#497] add module `picocli-shell-jline2` for components and documentation for building interactive shell command line applications with JLine 2 and picocli.
- [#499] add module `picocli-codegen` for tools to generate documentation, configuration, source code and other files from a picocli model
- [#410] add `ReflectionConfigGenerator` class for GraalVM `native-image`
- [#513] Enhancement: Simplify AutoCompletion script generator code.
- [#481] Enhancement: Add `@Command(usageHelpWidth = )` annotation attribute.
- [#379] Option with split property should not split quoted strings. Thanks to [Markus Kramer](https://github.com/MarkusKramer) for the feature request.
- [#514] Bugfix/Enhancement: picocli no longer removes opening and closing quotes around arguments by default. This is configurable with `CommandLine::setTrimQuotes`. Thanks to [mshatalov](https://github.com/mshatalov) for the bug report.
- [#509] Bugfix: Long boolean options with arity 0 should not allow parameters. Thanks to [Adam Zegelin](https://github.com/zegelin) for the bug report.
- [#510] Documentation: Fix broken link for moved example files. Thanks to [Anthony Keenan](https://github.com/anthonykeenan) for the pull request.
- [#24] Documentation: Added Chinese translations of "Picocli 2.0 Do More With Less" and "Picocli 2.0 Groovy Scripts on Steroids".
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
From this release, picocli no longer removes opening and closing quotes around arguments by default.
This is configurable with `CommandLine::setTrimQuotes`.
# Picocli 3.6.1
The picocli community is pleased to announce picocli 3.6.1.
This release contains bugfixes, minor enhancements and documentation improvements.
ANSI is automatically enabled on Windows if Jansi's `AnsiConsole` has been installed.
It is now possible to selectively avoid loading type converters with reflection.
Bugfix: Enum values were not rendered in `${COMPLETION-CANDIDATES}` for collection type options.
Many thanks to the many members of the picocli community who contributed!
This is the fortieth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.6.1-new)
* [Fixed issues](#3.6.1-fixes)
* [Deprecations](#3.6.1-deprecated)
* [Potential breaking changes](#3.6.1-breaking-changes)
## New and Noteworthy
## Fixed issues
- [#487] Enhancement: Auto-completion script should return from `generateOptionsSwitch` immediately if there is nothing to generate. Thanks to [David Walluck](https://github.com/dwalluck) for the pull request.
- [#483][#486] Enhancement: Improve `Help.Ansi.AUTO`: automatically enable ANSI on Windows if Jansi's `AnsiConsole` has been installed. Thanks to [Philippe Charles](https://github.com/charphi) for the pull request.
- [#491] Enhancement: Improve `Help.Ansi.AUTO` cygwin/msys detection on Windows.
- [#451] Enhancement: Selectively disable reflective type converter registration. Thanks to [Paolo Di Tommaso](https://github.com/pditommaso) for the suggestion.
- [#488] Doc: Clarify in user manual that `CommandLine.setPosixClusteredShortOptionsAllowed(false)` means that option parameters cannot be attached to the option name. Thanks to [Maryam Ziyad](https://github.com/MaryamZi) for raising this.
- [#492][#493] Doc: Add section on `@Command(aliases)` attribute to user manual. Thanks to [marinier](https://github.com/marinier) for the pull request.
- [#494] Bugfix: Enum values were not rendered in `${COMPLETION-CANDIDATES}` for collection type options.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.6.0
The picocli community is pleased to announce picocli 3.6.0.
This release contains new features, bugfixes and enhancements.
New interface: `IDefaultProvider` allows you to get default values from a configuration file or some other central place.
`@Command` Methods: From this release, methods can be annotated with `@Command`. The method parameters provide the command options and parameters.
Internationalization: from this release, usage help message sections and the description for options and positional parameters can be specified in a resource bundle. A resource bundle can be set via annotations and programmatically.
The error message on invalid user input has been improved.
This release also contains various improvements the the bash/zsh completion script generation to be more consistent with standard completion on these shells.
Many thanks to the many members of the picocli community who raised issues and contributed solutions!
This is the thirty-nineth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.6.0-new)
* [Fixed issues](#3.6.0-fixes)
* [Deprecations](#3.6.0-deprecated)
* [Potential breaking changes](#3.6.0-breaking-changes)
## New and Noteworthy
### Default Provider
This release allows you to specify a default provider in the `@Command` annotation:
```java
@Command(defaultValueProvider = MyDefaultProvider.class)
class MyCommand // ...
```
The default provider allows you to get default values from a configuration file or some other central place.
Default providers need to implement the `picocli.CommandLine.IDefaultValueProvider` interface:
```java
public interface IDefaultValueProvider {
/**
* Returns the default value for an option or positional parameter or {@code null}.
* The returned value is converted to the type of the option/positional parameter
* via the same type converter used when populating this option/positional
* parameter from a command line argument.
*
* @param argSpec the option or positional parameter, never {@code null}
* @return the default value for the option or positional parameter, or {@code null} if
* this provider has no default value for the specified option or positional parameter
* @throws Exception when there was a problem obtaining the default value
*/
String defaultValue(ArgSpec argSpec) throws Exception;
}
```
### `@Command` Methods
From picocli 3.6, methods can be annotated with `@Command`. The method parameters provide the command options and parameters. For example:
```java
class Cat {
public static void main(String[] args) {
CommandLine.invoke("cat", Cat.class, args);
}
@Command(description = "Concatenate FILE(s) to standard output.",
mixinStandardHelpOptions = true, version = "3.6.0")
void cat(@Option(names = {"-E", "--show-ends"}) boolean showEnds,
@Option(names = {"-n", "--number"}) boolean number,
@Option(names = {"-T", "--show-tabs"}) boolean showTabs,
@Option(names = {"-v", "--show-nonprinting"}) boolean showNonPrinting,
@Parameters(paramLabel = "FILE") File[] files) {
// process files
}
}
```
The usage help of the above command looks like this:
```
Usage: cat [-EhnTvV] [FILE...]
Concatenate FILE(s) to standard output.
[FILE...]
-E, --show-ends
-h, --help Show this help message and exit.
-n, --number
-T, --show-tabs
-v, --show-nonprinting
-V, --version Print version information and exit.
```
See below for an example that uses a resource bundle to define usage help descriptions outside the code.
For positional parameters, the `@Parameters` annotation may be omitted on method parameters.
TIP: If compiled with the `-parameters` flag on Java 8 or higher, the `paramLabel` of positional parameters is obtained from the method parameter name using reflection instead of the generic arg0, arg1, etc.
#### Subcommand Methods
If the enclosing class is annotated with `@Command`, method commands are added as subcommands to the class command, unless the class command has attribute `@Command(addMethodSubcommands = false)`.
For example:
```java
@Command(name = "git", mixinStandardHelpOptions = true, version = "picocli-3.6.0")
class Git {
@Option(names = "--git-dir", descriptionKey = "GITDIR")
Path path;
@Command
void commit(@Option(names = {"-m", "--message"}) String commitMessage,
@Option(names = "--squash", paramLabel = "") String squash,
@Parameters(paramLabel = "") File[] files) {
// ... implement business logic
}
}
```
Use `@Command(addMethodSubcommands = false)` on the class `@Command` annotation if the `@Command`-annotated methods in this class should not be added as subcommands.
The usage help of the `git commit` command looks like this:
```
Usage: git commit [--squash=] [-m=] [...]
[...]
--squash=
-m, --message=
```
### Internationalization
From version 3.6, usage help message sections and the description for options and positional parameters can be specified in a resource bundle. A resource bundle can be set via annotations and programmatically.
Annotation example:
```java
@Command(name = "i18n-demo", resourceBundle = "my.org.I18nDemo_Messages")
class I18nDemo {}
```
Programmatic example:
```java
@Command class I18nDemo2 {}
CommandLine cmd = new CommandLine(new I18nDemo2());
cmd.setResourceBundle(ResourceBundle.getBundle("my.org.I18nDemo2_Messages"));
```
Resources for multiple commands can be specified in a single ResourceBundle. Keys and their value can be shared by multiple commands (so you don't need to repeat them for every command), but keys can be prefixed with `fully qualified command name + "."` to specify different values for different commands. The most specific key wins.
This is especially convenient for `@Command` methods where long description annotations would make the code less easy to read.
You can use a resource bundle to move the descriptions out of the code:
```
# shared between all commands
help = Show this help message and exit.
version = Print version information and exit.
# command-specific strings
git.usage.description = Version control system
git.GITDIR = Set the path to the repository
git.commit.usage.description = Record changes to the repository
git.commit.message = Use the given as the commit message.
git.commit.squash = Construct a commit message for use with rebase --autosquash.
git.commit.[0..*] = The files to commit.
```
With this resource bundle, the usage help for the above `git commit` command looks like this:
```
Usage: git commit [--squash=] [-m=] [...]
Record changes to the repository
[...] The files to commit.
--squash= Construct a commit message for use with rebase
--autosquash.
-m, --message= Use the given as the commit message.
```
### Improved Error Messages
The error messages on invalid input have been improved. For example:
Previously, if an argument could not be converted to a primitive type, the error looked like this:
`Could not convert 'abc' to int for option '-num': java.lang.NumberFormatException: For input string: \"abc\"`
The new error message for primitive types looks like this:
`Invalid value for option '-num': 'abc' is not an int`
Previously, if an argument could not be converted to an enum, the error looked like this:
`Could not convert 'xyz' to TimeUnit for option '-timeUnit': java.lang.IllegalArgumentException: No enum constant java.util.concurrent.TimeUnit.xyz`
The new error message for enums looks like this:
`Invalid value for option '-timeUnit': expected one of [NANOSECONDS, MILLISECONDS, MICROSECONDS, SECONDS, MINUTES, HOURS, DAYS] but was 'xyz'`
## Fixed issues
- [#321] API: Add support for IDefaultValueProvider. Thanks to [Nicolas MASSART](https://github.com/NicolasMassart) for the pull request.
- [#416] API: Added support for `@Command` annotation on methods (in addition to classes). Thanks to [illes](https://github.com/illes) for the pull request.
- [#433] API: Added method `printHelpIfRequested` that accepts a `ColorScheme` parameter. Thanks to [Benny Bottema](https://github.com/bbottema) for the suggestion.
- [#441] API: Added `hideParamSyntax` attribute to `@Option` and `@Parameters` to allow suppressing usage syntax decorations around the param label. Thanks to [Benny Bottema](https://github.com/bbottema) for the pull request.
- [#22], [#415], [#436] API: Added internationalization and localization support via resource bundles.
- [#473] Enhancement: Improved error messages for invalid input.
- [#461] Bugfix: Script auto-completion only suggests options and never default bash completions. Thanks to [David Walluck](https://github.com/dwalluck) for the pull request.
- [#466] Bugfix: Script auto-completion should not generate suggestions for options with arguments that have no known completions. Thanks to [David Walluck](https://github.com/dwalluck) for the pull request.
- [#470] Bugfix: Script auto-completion should generate suggestions for short options with arguments. Thanks to [David Walluck](https://github.com/dwalluck) for the pull request.
- [#444] Bugfix: Usage help shows duplicate aliases if registered with same alias multiple times.
- [#452] Doc: Add UML class diagrams to picocli Javadoc.
- [#475] Doc: Renamed module `examples` to `picocli-examples`.
- [#478] Doc: Add convenience API example to `CommandLine` class Javadoc.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
The error message displayed on invalid input is different from previous releases. This may break unit tests that expect an exact error message.
# Picocli 3.5.2
The picocli community is pleased to announce picocli 3.5.2.
This is a bugfix release that fixes an issue where subcommand aliases were not recognized in some cases.
This is the thirty-eighth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.5.2-new)
* [Promoted features](#3.5.2-promoted)
* [Fixed issues](#3.5.2-fixes)
* [Deprecations](#3.5.2-deprecated)
* [Potential breaking changes](#3.5.2-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#443] Bugfix: Subcommand aliases were not recognized in some cases. Thanks to [K. Alex Mills](https://github.com/kalexmills) for the bug report.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.5.1
The picocli community is pleased to announce picocli 3.5.1.
This is a bugfix release that fixes an issue where CommandSpec injected into Mixins had a `null` CommandLine.
This is the thirty-seventh public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.5.1-new)
* [Promoted features](#3.5.1-promoted)
* [Fixed issues](#3.5.1-fixes)
* [Deprecations](#3.5.1-deprecated)
* [Potential breaking changes](#3.5.1-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#439] Bugfix: CommandSpec injected into Mixins had a `null` CommandLine. Thanks to [Adam Zegelin](https://github.com/zegelin) for the bug report.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.5.0
The picocli community is pleased to announce picocli 3.5.0.
This release contains new features, bugfixes and enhancements.
Password support: for options and positional parameters marked as `interactive`, the user is prompted to enter a value on the console.
When running on Java 6 or higher, picocli will use the Console.readPassword
API so that user input is not echoed to the console.
Client code can now perform simple validation in annotated setter methods by throwing a `ParameterException` on invalid input.
Also, from this release, the comment character in @-files (argument files) and the end-of-options delimiter (`--` by default) are configurable.
This is the thirty-sixth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.5.0-new)
* [Promoted features](#3.5.0-promoted)
* [Fixed issues](#3.5.0-fixes)
* [Deprecations](#3.5.0-deprecated)
* [Potential breaking changes](#3.5.0-breaking-changes)
## New and Noteworthy
### `Interactive` Options for Passwords or Passphrases
This release introduces password support: for options and positional parameters marked as `interactive`, the user is prompted to enter a value on the console.
When running on Java 6 or higher, picocli will use the Console.readPassword
API so that user input is not echoed to the console.
Example usage:
```java
class Login implements Callable {
@Option(names = {"-u", "--user"}, description = "User name")
String user;
@Option(names = {"-p", "--password"}, description = "Passphrase", interactive = true)
String password;
public Object call() throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
System.out.printf("Hi %s, your passphrase is hashed to %s.%n", user, base64(md.digest()));
return null;
}
private String base64(byte[] arr) { /* ... */ }
}
```
When this command is invoked like this:
```java
CommandLine.call(new Login(), "-u", "user123", "-p");
```
Then the user will be prompted to enter a value:
```
Enter value for --password (Passphrase):
```
When running on Java 6 or higher, the user input is not echoed to the console.
After the user enters a value and presses enter, the `call()` method is invoked, which prints the following:
```bash
Hi user123, your passphrase is hashed to 75K3eLr+dx6JJFuJ7LwIpEpOFmwGZZkRiB84PURz6U8=.
```
### Simple Validation in Setter Methods
Methods annotated with `@Option` and `@Parameters` can do simple input validation by throwing a `ParameterException` when invalid values are specified on the command line.
```java
class ValidationExample {
private Map properties = new LinkedHashMap<>();
@Spec private CommandSpec spec; // injected by picocli
@Option(names = {"-D", "--property"}, paramLabel = "KEY=VALUE")
public void setProperty(Map map) {
for (String key : map.keySet()) {
String newValue = map.get(key);
validateUnique(key, newValue);
properties.put(key, newValue);
}
}
private void validateUnique(String key, String newValue) {
String existing = properties.get(key);
if (existing != null && !existing.equals(newValue)) {
throw new ParameterException(spec.commandLine(),
String.format("Duplicate key '%s' for values '%s' and '%s'.",
key, existing, newValue));
}
}
}
```
Prior to this release, the exception thrown from the method was wrapped in a `java.lang.reflect.InvocationTargetException`, which in turn was wrapped in a `PicocliException`, and finally in another `ParameterException`.
By following the recipe above and throwing a `ParameterException` on invalid input, all these intermediate exceptions are skipped.
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#430] Bugfix: formatting was incorrect (did not break on embedded newlines) in the subcommands list descriptions. Thanks to [Benny Bottema](https://github.com/bbottema) for the bug report.
- [#431] Better support for validation in setter methods: cleaner stack trace.
- [#432] Make comment character in @-files (argument files) configurable.
- [#359] Make end-of-options delimiter configurable.
- [#82] Support reading passwords from the console with echoing disabled.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.4.0
The picocli community is pleased to announce picocli 3.4.0.
This release contains new features, bugfixes and enhancements.
The parser can now ignore case when parsing arguments for an Enum option or positional parameter.
New methods `Help.Ansi.text(String)` and `Help.Ansi.string(String)` assist client code in easily creating ANSI messages outside usage help and version help.
This is the thirty-fifth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.4.0-new)
* [Promoted features](#3.4.0-promoted)
* [Fixed issues](#3.4.0-fixes)
* [Deprecations](#3.4.0-deprecated)
* [Potential breaking changes](#3.4.0-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#14] New API: Support enum values to be parsed in an case-insensitive way.
- [#376] New API: `Help.Ansi.text(String)` and `Help.Ansi.string(String)` help client code easily create ANSI messages outside usage help and version help.
- [#412] Enhancement: Enum constant names are now returned from `ArgSpec::completionCandidates()`. Thanks to [Radovan Panák](https://github.com/rpanak).
- [#417] Enhancement: Ensure bash scripts have correct line separators. Thanks to [Holger Stenger](https://github.com/stengerh).
- [#425] Enhancement: Fix autocomplete script errors in zsh. Thanks to [Anthony Keenan](https://github.com/anthonykeenan).
- [#419] Bugfix: Default value for arrays was not rendered correctly with `@{DEFAULT-VALUE}`.
- [#418] Doc: Improve installation instructions for autocompletion scripts.
- [#420] Doc: Added a Quick Guide
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.3.0
The picocli community is pleased to announce picocli 3.3.0.
This release contains a bugfix for the JLine TAB completion support and improves the error messages for missing required parameters and unmatched arguments.
This is the thirty-fourth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.3.0-new)
* [Promoted features](#3.3.0-promoted)
* [Fixed issues](#3.3.0-fixes)
* [Deprecations](#3.3.0-deprecated)
* [Potential breaking changes](#3.3.0-breaking-changes)
## New and Noteworthy
### `UnmatchedArgumentException` Improvements
The `UnmatchedArgumentException` class now has several methods that allow an application to offer suggestions for fixes to the end user.
For example:
```java
class App {
@Option(names = "--file") File[] files;
@Option(names = "--find") String pattern;
public static void main(String[] args) {
App app = new App();
try {
new CommandLine(app).parse(args);
// ...
} catch (ParameterException ex) {
System.err.println(ex.getMessage());
if (!UnmatchedArgumentException.printSuggestions(ex, System.err)) { // new API
ex.getCommandLine().usage(System.err, ansi);
}
}
}
}
```
If you run this class with an invalid option that is similar to an actual option, the `UnmatchedArgumentException.printSuggestions` method will show the actual options. For example:
```
-fi
```
Prints this output:
```
Unknown option: -fi
Possible solutions: --file, --find
```
This is the behaviour for the `CommandLine` convenience methods `run`, `call` and `parseWithHandlers`.
Note that if possible fixes are found, the usage help message is not displayed.
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#411] Bugfix: Completion candidates were only generated for the first option, not for subsequent options.
- [#409] Enhancement: Improve error message for missing required positional parameters. Thanks to [Mārtiņš Kalvāns](https://github.com/sisidra) and [Olle Lundberg](https://github.com/lndbrg).
- [#298] Enhancement: Add help for mistyped commands and options. Added new API to `UnmatchedArgumentException`. Thanks to [Philippe Charles](https://github.com/charphi).
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
The error message format has changed. This may impact client tests that expect a specific error message.
# Picocli 3.2.0
The picocli community is pleased to announce picocli 3.2.0.
This release contains new features and enhancements:
* Improved support for Dependency Injection
* Methods can now be annotated with `@Option` and `@Parameters`
* Support for JLine-based interactive command line interfaces (`completionCandidates` attribute on `@Option` and `@Parameters`, and the `AutoComplete.complete` method)
* New `@Spec` annotation for injecting a command with its `CommandSpec`
This is the thirty-third public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.2.0-new)
* [Promoted features](#3.2.0-promoted)
* [Fixed issues](#3.2.0-fixes)
* [Deprecations](#3.2.0-deprecated)
* [Potential breaking changes](#3.2.0-breaking-changes)
## New and Noteworthy
### Dependency Injection
This release makes integration with Dependency Injection containers extremely easy:
* `CommandLine` constructor now accepts a `Class` instance as the user object, and will delegate to the `IFactory` to get an instance.
* New `CommandLine.run(Class, IFactory, ...)` and `CommandLine.call(Class, IFactory, ...)` methods. These work the same as the existing `run` and `call` methods except that the `Runnable` or `Callable` instance is created by the factory.
The below example shows how to create an `IFactory` implementation with a Guice `Injector`:
```java
import com.google.inject.*;
import picocli.CommandLine.IFactory;
public class GuiceFactory implements IFactory {
private final Injector injector = Guice.createInjector(new DemoModule());
@Override
public K create(Class aClass) throws Exception {
return injector.getInstance(aClass);
}
static class DemoModule extends AbstractModule {
@Override
protected void configure() {
bind(java.util.List.class).to(java.util.LinkedList.class);
bind(Runnable.class).to(InjectionDemo.class);
}
}
}
```
Use the custom factory when creating a `CommandLine` instance, or when invoking the `run` or `call` convenience methods:
```java
import javax.inject.Inject;
@Command(name = "di-demo")
public class InjectionDemo implements Runnable {
@Inject java.util.List list;
@Option(names = "-x") int x;
public static void main(String[] args) {
CommandLine.run(Runnable.class, new GuiceFactory(), args);
}
@Override
public void run() {
assert list instanceof java.util.LinkedList;
}
}
```
### Annotated Methods
From this release, `@Option` and `@Parameter` annotations can be added to methods as well as fields of a class.
For concrete classes, annotate "setter" methods (methods that accept a parameter) and when the option is specified on the command line, picocli will invoke the method with the value specified on the command line, converted to the type of the method parameter.
Alternatively, you may annotate "getter-like" methods (methods that return a value) on an interface, and picocli will create an instance of the interface that returns the values specified on the command line, converted to the method return type. This feature is inspired by [Jewel CLI](https://github.com/lexicalscope/jewelcli).
#### Annotating Methods of an Interface
The `@Option` and `@Parameters` annotations can be used on methods of an interface that return a value. For example:
```java
interface Counter {
@Option(names = "--count")
int getCount();
}
```
You use it by specifying the class of the interface:
```java
CommandLine cmd = new CommandLine(Counter.class); // specify a class
String[] args = new String[] {"--count", "3"};
cmd.parse(args);
Counter counter = cmd.getCommand(); // picocli created an instance
assert counter.getCount() == 3; // method returns command line value
```
#### Annotating Methods of a Concrete Class
The `@Option` and `@Parameters` annotations can be used on methods of a class that accept a parameter. For example:
```java
class Counter {
int count;
@Option(names = "--count")
void setCount(int count) {
this.count = count;
}
}
```
You use it by passing an instance of the class:
```java
Counter counter = new Counter(); // the instance to populate
CommandLine cmd = new CommandLine(counter);
String[] args = new String[] {"--count", "3"};
cmd.parse(args);
assert counter.count == 3; // method was invoked with command line value
```
### JLine Tab-Completion Support
This release adds support for JLine Tab-Completion.
[Jline 2.x](https://github.com/jline/jline2) and [3.x](https://github.com/jline/jline3) is a Java library for handling console input, often used to create interactive shell applications.
Command line applications based on picocli can generate completion candidates for the command line in the JLine shell. The generated completion candidates are context sensitive, so once a subcommand is specified, only the options for that subcommand are shown, and once an option is specified, only parameters for that option are shown.
Below is an example picocli `Completer` implementation for JLine 2.x:
```java
import jline.console.completer.ArgumentCompleter;
import jline.console.completer.Completer;
import picocli.AutoComplete;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import java.util.List;
public class PicocliJLineCompleter implements Completer {
private final CommandSpec spec;
public PicocliJLineCompleter(CommandSpec spec) {
this.spec = spec;
}
@Override
public int complete(String buffer, int cursor, List candidates) {
// use the jline internal parser to split the line into tokens
ArgumentCompleter.ArgumentList list =
new ArgumentCompleter.WhitespaceArgumentDelimiter().delimit(buffer, cursor);
// let picocli generate completion candidates for the token where the cursor is at
return AutoComplete.complete(spec,
list.getArguments(),
list.getCursorArgumentIndex(),
list.getArgumentPosition(),
cursor,
candidates);
}
}
```
### Completion Candidates
From this release, `@Options` and `@Parameters` have a new `completionCandidates` attribute that can be used to generate a list of completions for this option or positional parameter. For example:
```java
static class MyAbcCandidates extends ArrayList {
MyAbcCandidates() { super(Arrays.asList("A", "B", "C")); }
}
class ValidValuesDemo {
@Option(names = "-o", completionCandidates = MyAbcCandidates.class)
String option;
}
```
This will generate completion option values `A`, `B` and `C` in the generated bash auto-completion script and in JLine.
### `${DEFAULT-VALUE}` Variable
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 `${DEFAULT-VALUE}` in the description text.
Picocli uses reflection to get the default values from the annotated fields.
The variable is replaced with the default value regardless of the `@Command(showDefaultValues)` attribute
and regardless of the `@Option(showDefaultValues)` or `@Parameters(showDefaultValues)` attribute.
```java
class DefaultValues {
@Option(names = {"-f", "--file"},
description = "the file to use (default: ${DEFAULT-VALUE})")
File file = new File("config.xml");
}
CommandLine.usage(new DefaultValues(), System.out);
```
This produces the following usage help:
```text
Usage: -f=
-f, --file= the file to use (default: config.xml)
```
### `${COMPLETION-CANDIDATES}` Variable
Similarly, it is possible to embed the completion candidates in the description for an option or positional parameter by
specifying the variable `${COMPLETION-CANDIDATES}` in the description text.
This works for java `enum` classes and for options or positional parameters of non-enum types for which completion candidates are specified.
```java
enum Lang { java, groovy, kotlin, javascript, frege, clojure }
static class MyAbcCandidates extends ArrayList {
MyAbcCandidates() { super(Arrays.asList("A", "B", "C")); }
}
class ValidValuesDemo {
@Option(names = "-l", description = "Enum. Values: ${COMPLETION-CANDIDATES}")
Lang lang = null;
@Option(names = "-o", completionCandidates = MyAbcCandidates.class,
description = "Candidates: ${COMPLETION-CANDIDATES}")
String option;
}
CommandLine.usage(new ValidValuesDemo(), System.out);
```
This produces the following usage help:
```text
Usage: -l= -o=
-l= Enum. Values: java, groovy, kotlin, javascript, frege, clojure
-o= Candidates: A, B, C
```
### `@Spec` Annotation
A new `@Spec` annotation is now available that injects the `CommandSpec` model of the command into a command field.
This is useful when a command needs to use the picocli API, for example to walk the command hierarchy and iterate over its sibling commands.
This complements the `@ParentCommand` annotation; the `@ParentCommand` annotation injects a user-defined command object, whereas this annotation injects a picocli class.
```java
class InjectSpecExample implements Runnable {
@Spec CommandSpec commandSpec;
//...
public void run() {
// do something with the injected spec
}
}
```
### Lenient Parse Mode
This release adds the ability to continue parsing invalid input to the end.
When `collectErrors` is set to `true`, and a problem occurs during parsing, an `Exception` is added to the `ParseResult.errors()` list and parsing continues. The default behaviour (when `collectErrors` is `false`) is to abort parsing by throwing the `Exception`.
This is useful when generating completion candidates on partial input, and is also useful when using picocli in
languages like Clojure where idiomatic error handling does not involve throwing and catching exceptions.
When using this feature, applications are responsible for actively verifying that no errors occurred before executing the business logic. Use with care!
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#182] New Feature: Add support for annotating methods with `@Option` and `@Parameters`.
- [#393] New feature: Add support for JLine completers.
- [#389] New feature: Support 'lenient' parsing mode: don't throw `Exceptions` but add them to the `ParseResult.errors()` list and continue parsing.
- [#392] New feature: Ability to map command line arguments to picocli spec elements. Internally used for generating completion candidates.
- [#391] New feature: Add API to get completion candidates for option and positional parameter values of any type.
- [#395] New feature: Allow embedding default values anywhere in description for `@Option` or `@Parameters`.
- [#259] New Feature: Added `@Spec` annotation to inject `CommandSpec` into application field.
- [#400] Enhancement: Add run/call static methods that accept an `IFactory`. This allows Dependency Injection containers to provide the Runnable/Callable implementation.
- [#404] Enhancement: Ask IFactory for implementation before creating Proxy for interface. Needed for Dependency Injection.
- [#398] Enhancement: Allow `@PicocliScript` annotation on Groovy script `@Field` variables instead of just on imports.
- [#322] Enhancement: Add `defaultValue` attribute to @Option and @Parameters annotation.
- [#375] Enhancement: Improve `ParameterIndexGapException` error message. Thanks to [gpettey](https://github.com/gpettey).
- [#405] Enhancement: Add method `CommandLine.getUsageMessage()`.
- [#406] Enhancement: Added fields to `ParameterException`. Thanks to [David Hait](https://github.com/dhait).
- [#401] Doc: The user manual no longer includes the full `CommandLine.java` source code.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.1.0
The picocli community is pleased to announce picocli 3.1.0.
This release contains bugfixes and support for command aliases.
Picocli has a new logo! Many thanks to [Reallinfo](https://github.com/reallinfo) for the design!
This is the thirty-second public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.1.0-new)
* [Promoted features](#3.1.0-promoted)
* [Fixed issues](#3.1.0-fixes)
* [Deprecations](#3.1.0-deprecated)
* [Potential breaking changes](#3.1.0-breaking-changes)
## New and Noteworthy
### Command Aliases
This release adds support for command aliases.
```java
@Command(name = "top", subcommands = {SubCommand.class},
description = "top level command")
static class TopLevelCommand { }
@Command(name = "sub", aliases = {"s", "sb"},
description = "I'm a subcommand")
static class SubCommand {}
new CommandLine(new TopLevelCommand()).usage(System.out);
```
The above would print the following usage help message:
```text
Usage: top [COMMAND]
top level command
Commands:
sub, s, sb I'm a subcommand
```
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#288] New feature: add support for command aliases.
- [#383] Enhancement: [Reallinfo](https://github.com/reallinfo) designed the new picocli logo. Amazing work, many thanks!
- [#388] Bugfix: Prevent AnnotationFormatError "Duplicate annotation for class" with @PicocliScript when the script contains classes. Thanks to [Bradford Powell](https://github.com/bpow) for the bug report.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.0.2
The picocli community is pleased to announce picocli 3.0.2.
This release contains bugfixes and enhancements for programmatic configuration.
This is the thirty-first public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.2-new)
* [Promoted features](#3.0.2-promoted)
* [Fixed issues](#3.0.2-fixes)
* [Deprecations](#3.0.2-deprecated)
* [Potential breaking changes](#3.0.2-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#381] Bugfix: Prevent NPE when adding programmatically created subcommands to CommandLine. Thanks to [Mikusch](https://github.com/Mikusch) for the bug report.
- [#382] Enhancement: Subcommand name should be initialized when added to parent.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
This release has no breaking changes.
# Picocli 3.0.1
The picocli community is pleased to announce picocli 3.0.1.
This release fixes a bug for map options and has several improvements for the usage help message, especially for subcommands.
This is the thirtieth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.1-new)
* [Promoted features](#3.0.1-promoted)
* [Fixed issues](#3.0.1-fixes)
* [Deprecations](#3.0.1-deprecated)
* [Potential breaking changes](#3.0.1-breaking-changes)
## New and Noteworthy
From this release, the usage help synopsis of the subcommand shows not only the subcommand name but also the parent command name. For example, take the following hierarchy of subcommands.
```java
@Command(name = "main", subcommands = {Sub.class}) class App { }
@Command(name = "sub", subcommands = {SubSub.class}) class Sub { }
@Command(name = "subsub", mixinStandardHelpOptions = true) class SubSub { }
CommandLine parser = new CommandLine(new App());
ParseResult result = parser.parseArgs("sub", "subsub", "--help");
CommandLine.printHelpIfRequested(result);
```
The above code prints the usage help for the `subsub` nested subcommand. Notice that this shows not only the subcommand name but the full command hierarchy:
```
Usage: main sub subsub [-hV]
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
```
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#287] Enhancement: Subcommand help now also shows parent command name in synopsis.
- [#378] Bugfix: Map option problem when value contains '=' separator. Thanks to [Markus Kramer](https://github.com/MarkusKramer) for the bug report.
- [#377] Bugfix: Standard help options should be added last: when `mixinStandardHelpOptions` is set and `sortOptions` is false, the help options should appear after the command options in the usage help message.
## Deprecations
No features were deprecated in this release.
## Potential breaking changes
The usage help synopsis of the subcommand shows not only the subcommand name but also the parent command name (and parent's parent command name, up to the top-level command).
# Picocli 3.0.0
The picocli community is pleased to announce picocli 3.0.0.
This release offers a [programmatic API](http://picocli.info/picocli-3.0-programmatic-api.html) for creating command line applications, in addition to the annotations API. The programmatic API allows applications to dynamically create command line options on the fly, and also makes it possible to create idiomatic domain-specific languages for processing command line arguments, using picocli, in other JVM languages. The picocli community is proud to announce that [Apache Groovy](http://groovy-lang.org/)'s [CliBuilder](http://docs.groovy-lang.org/docs/next/html/gapi/groovy/cli/picocli/CliBuilder.html) DSL for command line applications has been rewritten to use the picocli programmatic API, starting from Groovy 2.5.
Another new feature in this release are Mixins. Mixins allow reusing common options, parameters and command attributes in multiple applications without copy-and-paste duplication.
This release aims to reduce boilerplate code in user applications even further with the new `mixinStandardHelpOptions` command attribute. Picocli adds standard `usageHelp` and `versionHelp` options to commands with this attribute. Additionally picocli now offers a `HelpCommand` that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands.
From this release, picocli is better at following unix conventions: by default it now prints to stdout when the user requested help, and prints to stderr when the input was invalid or an unexpected error occurred. This release also gives better control over the process exit code.
A new `@Unmatched` annotation allows applications to easily capture unmatched arguments (arguments that could not be matched with any of the registered options or positional parameters).
Usage help message improvements: the usage help message width is now configurable, and the message layout is improved to reduce horizontal padding. Furthermore, you can now specify for individual options or positional parameters whether their default value should be shown in the description or hidden.
Finally, this release adds several options to configure parser behaviour. Picocli can now be configured to function like Apache Commons CLI, to facilitate migration from Apache Commons CLI to picocli.
This is the twenty-ninth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-new)
* [Promoted features](#3.0.0-promoted)
* [Fixed issues](#3.0.0-fixes)
* [Deprecations](#3.0.0-deprecated)
* [Potential breaking changes](#3.0.0-breaking-changes)
## New and Noteworthy
### Programmatic API
This release offers a programmatic API for creating command line applications, in addition to the annotations API. The programmatic API allows applications to dynamically create command line options on the fly, and also makes it possible to create idiomatic domain-specific languages for processing command line arguments, using picocli, in other JVM languages. (Example: Groovy [CliBuilder](http://docs.groovy-lang.org/docs/next/html/gapi/groovy/cli/picocli/CliBuilder.html).)
_If you have suggestions for improving the programmatic API, please raise a ticket on GitHub!_
#### Example
```java
CommandSpec spec = CommandSpec.create();
spec.mixinStandardHelpOptions(true); // --help and --version options
spec.addOption(OptionSpec.builder("-c", "--count")
.paramLabel("COUNT")
.type(int.class)
.description("number of times to execute").build());
spec.addPositional(PositionalParamSpec.builder()
.paramLabel("FILES")
.type(List.class).auxiliaryTypes(File.class) // List
.description("The files to process").build());
CommandLine commandLine = new CommandLine(spec);
try {
// see also the CommandLine.parseWithHandler(s) convenience methods
ParseResult pr = commandLine.parseArgs(args);
if (CommandLine.printHelpIfRequested(pr)) {
return;
}
int count = pr.matchedOptionValue('c', 1);
List files = pr.matchedPositionalValue(0, Collections.emptyList());
for (File f : files) {
for (int i = 0; i < count; i++) {
System.out.printf("%d: %s%n", i, f);
}
}
} catch (ParseException invalidInput) {
System.err.println(invalidInput.getMessage());
invalidInput.getCommandLine().usage(System.err);
}
```
#### CommandSpec
`CommandSpec` models a command. It is the programmatic variant of the `@Command` annotation. It has a name and a version, both of which may be empty. It also has a `UsageMessageSpec` to configure aspects of the usage help message and a `ParserSpec` that can be used to control the behaviour of the parser.
#### OptionSpec and PositionalParamSpec
`OptionSpec` models a named option, and `PositionalParamSpec` models one or more positional parameters. They are the programmatic variant of the `@Option` and `@Parameters` annotations, respectively.
An `OptionSpec` must have at least one name, which is used during parsing to match command line arguments. Other attributes can be left empty and picocli will give them a reasonable default value. This defaulting is why `OptionSpec` objects are created with a builder: this allows you to specify only some attributes and let picocli initialise the other attributes. For example, if only the option’s name is specified, picocli assumes the option takes no parameters (arity = 0), and is of type `boolean`. Another example, if arity is larger than `1`, picocli sets the type to `List` and the `auxiliary type` to `String`.
`PositionalParamSpec` objects don’t have names, but have an index range instead. A single `PositionalParamSpec` object can capture multiple positional parameters. The default index range is set to `0..*` (all indices). A command may have multiple `PositionalParamSpec` objects to capture positional parameters at different index ranges. This can be useful if positional parameters at different index ranges have different data types.
Similar to `OptionSpec` objects, Once a `PositionalParamSpec` is constructed, its configuration becomes immutable, but its `value` can still be modified. Usually the value is set during command line parsing when a non-option command line argument is encountered at a position in its index range.
#### ParseResult
A `ParseResult` class is now available that allows applications to inspect the result of parsing a sequence of command line arguments.
This class provides methods to query whether the command line arguments included certain options or position parameters, and what the value or values of these options and positional parameters was. Both the original command line argument String value as well as a strongly typed value can be obtained.
### Mixins for Reuse
Mixins are a convenient alternative to subclassing: picocli annotations from _any_ class can be added to ("mixed in" with) another command. This includes options, positional parameters, subcommands and command attributes. Picocli [autoHelp](#3.0.0-alpha-1-autohelp) internally uses a mixin.
A mixin is a separate class with options, positional parameters, subcommands and command attributes that can be reused in other commands. Mixins can be installed by calling the `CommandLine.addMixin` method with an object of this class, or annotating a field in your command with `@Mixin`. Here is an example mixin class:
```java
public class ReusableOptions {
@Option(names = { "-v", "--verbose" }, description = {
"Specify multiple -v options to increase verbosity.", "For example, `-v -v -v` or `-vvv`" })
protected boolean[] verbosity = new boolean[0];
}
```
#### Adding Mixins Programmatically
The below example shows how a mixin can be added programmatically with the `CommandLine.addMixin` method.
```java
CommandLine commandLine = new CommandLine(new MyCommand());
commandline.addMixin("myMixin", new ReusableOptions());
```
#### `@Mixin` Annotation
A command can also include mixins by annotating fields with `@Mixin`. All picocli annotations found in the mixin class are added to the command that has a field annotated with `@Mixin`. For example:
```java
@Command(name = "zip", description = "Example reuse with @Mixin annotation.")
public class MyCommand {
// adds the options defined in ReusableOptions to this command
@Mixin
private ReusableOptions myMixin;
}
```
### Standard Help Options
This release introduces the `mixinStandardHelpOptions` command attribute. When this attribute is set to `true`, picocli adds a mixin to the command that adds `usageHelp` and `versionHelp` options to the command. For example:
```java
@Command(mixinStandardHelpOptions = true, version = "auto help demo - picocli 3.0")
class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
@Override public void run() { }
}
```
Commands with `mixinStandardHelpOptions` do not need to explicitly declare fields annotated with `@Option(usageHelp = true)` and `@Option(versionHelp = true)` any more. The usage help message for the above example looks like this:
```text
Usage: [-hV] [--option=]
--option= Some option.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
```
### Help Command
From this release, picocli provides a `help` subcommand (`picocli.CommandLine.HelpCommand`) that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands. For example:
```java
@Command(subcommands = HelpCommand.class)
class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
@Override public void run() { }
}
```
```text
# print help for the `maincommand` command
maincommand help
# print help for the `subcommand` command
maincommand help subcommand
```
For applications that want to create a custom help command, this release also introduces a new interface `picocli.CommandLine.IHelpCommandInitializable` that provides custom help commands with the information they need: access to the parent command and sibling commands, whether to use Ansi colors or not, and the streams to print the usage help message to.
### `@Unmatched` Annotation
Unmatched arguments are the command line arguments that could not be assigned to any of the defined options or positional parameters. From this release, fields annotated with `@Unmatched` will be populated with the unmatched arguments. The field must be of type `String[]` or `List`.
If picocli finds a field annotated with `@Unmatched`, it automatically sets `unmatchedArgumentsAllowed` to `true` so no `UnmatchedArgumentException` is thrown when a command line argument cannot be assigned to an option or positional parameter.
### Stdout or Stderr
From picocli v3.0, the `run` and `call` convenience methods follow unix conventions: print to stdout when the user requested help, and print to stderr when the input was invalid or an unexpected error occurred.
Custom handlers can extend `AbstractHandler` to facilitate following this convention. `AbstractHandler` also provides `useOut` and `useErr` methods to allow customizing the target output streams, and `useAnsi` to customize the Ansi style to use:
```java
@Command class CustomizeTargetStreamsDemo implements Runnable {
public void run() { ... }
public static void main(String... args) {
CommandLine cmd = new CommandLine(new CustomizeTargetStreamsDemo());
PrintStream myOut = getOutputPrintStream(); // custom stream to send command output to
PrintStream myErr = getErrorPrintStream(); // custom stream for error messages
cmd.parseWithHandlers(
new RunLast().useOut(myOut).useAnsi(Help.Ansi.ON),
new DefaultExceptionHandler().useErr(myErr).useAnsi(Help.Ansi.OFF),
args);
}
}
```
### Exit Code Support
From picocli v3.0, the built-in parse result handlers (`RunFirst`, `RunLast` and `RunAll`) and exception handler (`DefaultExceptionHandler`) can specify an exit code. If an exit code was specified, the handler terminates the JVM with the specified status code when finished.
```java
@Command class ExitCodeDemo implements Runnable {
public void run() { throw new ParameterException(new CommandLine(this), "exit code demo"); }
public static void main(String... args) {
CommandLine cmd = new CommandLine(new ExitCodeDemo());
cmd.parseWithHandlers(
new RunLast().andExit(123),
new DefaultExceptionHandler().andExit(456),
args);
}
}
```
Running this command prints the following to stderr and exits the JVM with status code `456`.
```
exit code demo
Usage:
```
Custom handlers can extend `AbstractHandler` to inherit this behaviour.
### Fine-grained ShowDefault
This release adds a `showDefaultValue` attribute to the `@Option` and `@Parameters` annotation. This allows you to specify for each individual option and positional parameter whether its default value should be shown in the usage help.
This attribute accepts three values:
* `ALWAYS` - always display the default value of this option or positional parameter, even `null` values, regardless what value of `showDefaultValues` was specified on the command
* `NEVER` - don't show the default value for this option or positional parameter, regardless what value of `showDefaultValues` was specified on the command
* `ON_DEMAND` - (this is the default) only show the default value for this option or positional parameter if `showDefaultValues` was specified on the command
The `NEVER` value is useful for security sensitive command line arguments like passwords. The `ALWAYS` value is useful when you only want to show the default value for a few arguments but not for all (in combination with `@Command(showDefaultValues = false)`).
### Improved Usage Help Message Layout
Previously, the usage message layout had a fixed width long option name column: this column is always 24 characters, even if none of the options have a long option name.
This gave strange-looking usage help messages in some cases. For example:
```java
@Command(name="ls")
class App {
@Option(names = "-a", description = "display all files") boolean a;
@Option(names = "-l", description = "use a long listing format") boolean l;
@Option(names = "-t", description = "sort by modification time") boolean t;
}
```
The usage message for this example was:
```
Usage: ls [-alt]
-a display all files
-l use a long listing format
-t sort by modification time
```
From this release, picocli adjusts the width of the long option name column to the longest name (up to max 24).
The new usage message for this example looks like this:
```
Usage: ls [-alt]
-a display all files
-l use a long listing format
-t sort by modification time
```
### Stricter Arity Validation
Until this release, options with mandatory parameters would consume as many arguments as required, even if those arguments matched other option flags. For example:
Given a command like this:
```java
class App {
@Option(names = "-a", arity = "2")
String[] a;
@Option(names = "-v")
boolean v;
}
```
Prior to this change, the following input would be accepted:
```
-a 1 -v
```
In previous versions, picocli accepted this and assigned `"1"` and `"-v"` as the two values for the `-a` option.
From this release, the parser notices that one of the arguments is an option and throws a `MissingParameterException` because not enough parameters were specified for the first option.
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#371] Fixed bug where autocompletion did not work correctly for subcommands with embedded hyphens. Thanks to [Paulius Fadelis](https://github.com/Fadelis) for the bug report.
- [#372] Simplify Kotlin example in user manual. Thanks to [Dustin Spicuzza](https://github.com/virtuald).
### 3.0.0-alpha-1
- [#245] New Feature: from 3.0, picocli offers an API for programmatic configuration.
- [#257] New Feature: new `ParseResult` class allows programmatic inspection of the result of parsing a sequence of command line arguments.
- [#144] New Feature: added support for mixins to allow reusing common options, positional parameters, subcommands and command attributes from any object.
- [#253] New Feature: added `@Unmatched` annotation for unmatched arguments.
- [#175] New Feature: `mixinStandardHelpOptions` attribute to install the standard `--help` and `--version` options, obviating the need for fields annotated with `@Option(usageHelp = true)` and `@Option(versionHelp = true)`.
- [#175] New Feature: picocli now provides a `HelpCommand` that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands.
- [#175] New Feature: new `IHelpCommandInitializable` interface facilitates construction of custom help commands.
- [#250] Enhancement: the `run` and `call` convenience methods now follow convention: print to stdout when the user requested help, print to stderr when the input was invalid or an unexpected error occurred. Added `AbstractHandler` to facilitate following this convention for custom parse result handlers and exception handlers.
- [#251] New Feature: exit code support. The built-in parse result handlers (`RunFirst`, `RunLast` and `RunAll`) and exception handler (`DefaultExceptionHandler`) can now optionally specify an exit code. If specified, the handler terminates the JVM with the specified status code when finished. Custom handlers can extend `AbstractHandler` to inherit this behaviour.
- [#262] New Feature: new `showDefaultValue` attribute on `@Option` and `@Parameters` gives fine-grained control over which default values to show or hide. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#268] New Feature: new `helpCommand` attribute on `@Command`: if the command line arguments contain a subcommand annotated with `helpCommand`, the parser will not validate the required options or positional parameters of the parent command. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#277] New Feature: new `hidden` attribute on `@Command` to omit the specified subcommand from the usage help message command list of the parent command. Thanks to [pditommaso](https://github.com/pditommaso).
- [#159] Enhancement: make help usage message width configurable. Thanks to [pditommaso](https://github.com/pditommaso).
### 3.0.0-alpha-2
- [#312] Enhancement and API change (against earlier alpha version): Remove `AbstractSimpleParseResultHandler` class and `parseWithSimpleHandlers` method.
- [#311] Enhancement and API change (against earlier alpha version): Simplify parseWithHandlers: removed prototypeReturnValue parameter.
- [#307] Enhancement: Provide CommandLine.usage(PrintWriter) method for testing and to facilitate [GROOVY-8520](https://issues.apache.org/jira/browse/GROOVY-8520) migration from commons-cli to picocli.
- [#306] Enhancement: Support generating autocompletion scripts for non-public @Command classes. Thanks to [cbeams](https://github.com/cbeams) for the request.
- [#308] Enhancement: Provide API to disallow POSIX clustered short options.
- [#310] Enhancement: PicocliBaseScript should follow conventions for stdout and stderr: requested help to stdout, invalid input usage help to stderr.
- [#309] Bugfix: Tests were failing on environments that support ANSI colors.
### 3.0.0-alpha-3
- [#313] Enhancement and New API: add method (later removed in 3.0.0-beta-1) `CommandLine::setMaxArityIsMaxTotalParams` to configure the parser to use `arity` to limit the total number of values accumulated in an option or positional parameter.
- [#314] Enhancement and New API: add method `CommandLine::setUsageHelpWidth` and `UsageMessageSpec::width` to set the max usage help message width.
- [#316] Enhancement: Support lenient mode where annotations are optional when extracting annotations.
- [#317] Enhancement: Change semantics of ParseResult.rawOptionValue to mean values after split (but before type conversion).
### 3.0.0-alpha-4
- [#318] API Change: Split model IBinding into IGetter and ISetter.
- [#320] API Change: Rename parser config `maxArityIsMaxTotalParams` to `arityRestrictsCumulativeSize`. (Property was removed in 3.0.0-beta-1.)
- [#216] Enhancement: Parsed values now replace the default value of multi-value (array, Collection or Map) options and positional parameters instead of being appended to them. Thanks to [wiwie](https://github.com/wiwie) for the request.
- [#261] Enhancement: Options and positional parameters with a `defaultValue` are never required. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#315] Enhancement: Initialize ArgSpec value with `defaultValue` before parsing command line.
- [#263] Bugfix: positional parameter defaults were not shown in usage help message. Thanks to [ymenager](https://github.com/ymenager) for the bug report.
### 3.0.0-alpha-5
- [#329] New API: Add parser configuration to control whether boolean flags should be toggled.
- [#328] New API: Provide getter methods on `OptionSpec.Builder` and `PositionalParamSpec.Builder`.
- [#326] New API: Add parser configuration to treat unmatched options as positional parameters.
- [#283] New API: Provide `getMissing` method on MissingParameterException to get a reference to the problematic options and positional parameters. Thanks to [jcapsule](https://github.com/jcapsule) for the suggestion.
- [#334] API Change: Rename `ArgSpec.rawStringValues()` to `ArgSpec.stringValues()`.
- [#342] API Change: Prefix ParseResult methods with `matched` if they return only matched options/positionals.
- [#340] API Change: Rename `ParseResult.optionValue(String, T)` to `matchedOptionValue(String, T)`.
- [#338] API Change: Remove `ParseResult.rawOptionValue(s)` and `rawPositionalValue(s)` methods.
- [#339] API Change: Remove `ParseResult.matchedOptionValue(OptionSpec)` and `matchedPositionalValue(PositionalParamSpec)` methods.
- [#347] API Change: Make `ArgSpec.getValue`, `setValue` and `isMultiValue` public methods.
- [#333] Enhancement: Added subcommand to synopsis in generated usage help. Thanks to [jcapsule](https://github.com/jcapsule) for the pull request.
- [#323] Enhancement: Remove dependency on java.sql package: picocli should only require the java.base module when running in Java 9.
- [#325] Enhancement: Allow custom type converter to map empty String to custom default value for empty options. Thanks to [jesselong](https://github.com/jesselong) for the suggestion.
- [#303] Enhancement: Improve validation to prevent common mistakes.
- [#70] Enhancement: Positional parameters should only consume values where type conversion succeeds.
- [#346] Enhancement: Validate that arity min is never greater than max.
- [#348] Enhancement: Interpreter should call `ArgSpec.setValue` for every matched option or positional parameter.
- [#327] Bugfix: Default values should not cause options and positional parameters to be added to ParseResult.
- [#330] Bugfix: `Interpreter` should clear option's and positional parameter's `stringValues` list before parsing new input.
- [#335] Bugfix: Abstract class `ArgSpec` should not implement `equals` and `hashCode`.
- [#345] Bugfix: Stop processing varargs when cumulative size reached. (This functionality was removed in 3.0.0-beta-1.)
### 3.0.0-alpha-6
- [#349] New API: Add `longestName()` convenience method to OptionSpec.
- [#352] New API: Add method to copy all attributes of a ParserSpec to a CommandSpec.
- [#353] New API: Add method to copy all attributes of a UsageMessageSpec to a CommandSpec.
- [#343] New API: Add method `Help.Ansi.Text::concat` and deprecate the `append` method. ("Append" suggests the Text object is modified, like StringBuilder, but Text is immutable.)
- [#350] Enhancement: Improve error message for `usageHelp` and `versionHelp` validation.
- [#344] Enhancement: Don't show WARN message for unmatched args or overwritten options.
- [#351] Documentation: Improve javadoc for OptionSpec.usageHelp and versionHelp.
- [#354] Bug fix: Interpreter should reset options and positional parameters to their initial value before parsing new input.
### 3.0.0-beta-1
- [#364] API Change: Remove parser option `arityRestrictsCumulativeSize`.
- [#355] API Change: Add method `ArgSpec.hasInitialValue`.
- [#361] API Change: Add parser option `aritySatisfiedByAttachedOptionParam` for commons-cli compatibility.
- [#363] API Change: Add parser option to limit the number of parts when splitting to max arity, for compatibility with commons-cli.
- [#360] Enhancement: Dynamically adjust width of long option name column (up to max 24).
### 3.0.0-beta-2
- [#366] API Change: Add `ArgSpec.getTypedValues()` method.
- [#365] Enhancement: Stricter arity validation: options with mandatory parameters no longer consume other option flags.
- [#357] Enhancement: Improve synopsis format. Be more succinct when `limitSplit` is true. Support repeating groups.
## Deprecations
### 3.0.0-alpha-1
The `picocli.CommandLine.Help::Help(Object, CommandLine.Help.ColorScheme)` constructor has been deprecated. Use the `picocli.CommandLine.Help::Help(CommandLine.CommandSpec, CommandLine.Help.ColorScheme)` constructor instead.
The `picocli.CommandLine.IParseResultHandler` interface has been deprecated. Use the `picocli.CommandLine.IParseResultHandler2` interface instead.
The `picocli.CommandLine.IExceptionHandler` interface has been deprecated. Use the `picocli.CommandLine.IExceptionHandler2` interface instead.
### 3.0.0-alpha-6
- The `Help.Ansi.Text::append` method is now deprecated in favour of the new `concat` method.
## Potential breaking changes
### 3.0.0-alpha-1
#### Help API Changes
The following public fields were removed from the `picocli.CommandLine.Help` class. Instead, set these attributes on a `CommandLine.CommandSpec` object passed to any of the `Help` constructors.
* abbreviateSynopsis
* commandListHeading
* commandName
* customSynopsis
* description
* descriptionHeading
* footer
* footerHeading
* header
* headerHeading
* optionFields
* optionListHeading
* parameterLabelRenderer - replaced with the `Help.parameterLabelRenderer()` method
* parameterListHeading
* requiredOptionMarker
* separator
* showDefaultValues
* sortOptions
* synopsisHeading
Method signature changes on inner classes and interfaces of the `Help` class:
* Interface method `CommandLine.Help.IOptionRenderer::render` signature changed: `CommandLine.Option` and `Field` parameters are replaced with a single `CommandLine.OptionSpec` parameter.
* Interface method `CommandLine.Help.IParameterRenderer::render` signature changed: `CommandLine.Parameters` and `Field` parameters are replaced with a single `CommandLine.PositionalParamSpec` parameter.
* Interface method `CommandLine.Help.IParamLabelRenderer::renderParameterLabel` signature changed: `Field` parameter replaced with `CommandLine.ArgSpec` parameter.
* Class `CommandLine.Help.Layout` all methods changed: `Field` parameters replaced by `CommandLine.ArgSpec`, `CommandLine.OptionSpec` and `CommandLine.PositionalParamSpec` parameters.
### 3.0.0-alpha-2
- [#311] API change from 3.0.0-alpha-1: the `parseWithHandlers` methods signature changed: removed the `prototypeReturnValue` parameter.
- [#312] API change from 3.0.0-alpha-1: Remove `AbstractSimpleParseResultHandler` class and `parseWithSimpleHandlers` method.
### 3.0.0-alpha-3
- Utility method `CommandLine.Help.join` signature changed: now takes an additional `usageHelpWidth` parameter.
- Constructor `CommandLine.Help.Layout(ColorScheme)` signature changed: now takes an additional `usageHelpWidth` parameter.
- Public field `CommandLine.Help.TextTable.columns` is now private; added public method `CommandLine.Help.TextTable.columns()`.
- Constructor `CommandLine.Help.TextTable(Ansi)` is replaced with factory method `CommandLine.Help.TextTable.forDefaultColumns(Ansi, int)`.
- Constructor `CommandLine.Help.TextTable(Ansi, int...)` is replaced with factory method `CommandLine.Help.TextTable.forColumnWidths(Ansi, int...)`.
- Constructor `CommandLine.Help.TextTable(Ansi, Column...)` modifier changed from public to protected.
- Added factory method `CommandLine.Help.TextTable.forColumns(Ansi, Column...)`.
- Renamed `CommandLine.MaxValuesforFieldExceededException` to `CommandLine.MaxValuesExceededException`.
### 3.0.0-alpha-4
- Parsed values now replace the default value of multi-value (array, Collection or Map) options and positional parameters instead of being appended to them.
- The `IBinding` interface introduced in v3.0.0-alpha-1 has been replaced with two functional interfaces `IGetter` and `ISetter`.
- The `UnmatchedArgsBinding` factory methods introduced in v3.0.0-alpha-1 have been replaced with `forStringArrayConsumer` and `forStringCollectionSupplier`.
### 3.0.0-alpha-5
Changes against earlier 3.0.0-alpha versions:
* Renamed `ArgSpec.rawStringValues()` to `ArgSpec.stringValues()`.
* Renamed `ParseResult` methods with `matched` if they return only matched options/positionals:
* `options` to `matchedOptions`
* `positionalParams` to `matchedPositionals`
* `option(char)`, `option(String)` to `matchedOption`
* `positional(int)` to `matchedPositional`
* `hasOption(char)`, `hasOption(String)`, `hasOption(OptionSpec)` to `hasMatchedOption`
* `hasPositional(int)`, `hasPositional(PositionalParamSpec)` to `hasMatchedPositional`
* Renamed `ParseResult.optionValue(String, T)` to `matchedOptionValue(String, T)`, and `positionalValue` to `matchedPositionalValue`.
* Removed `ParseResult::rawOptionValue(s)` and `rawPositionalValue(s)` methods.
* Removed `ParseResult.matchedOptionValue(OptionSpec)` and `matchedPositionalValue(PositionalParamSpec)` methods.
### 3.0.0-beta-1
- The usage message format changed: it now dynamically adjusts the width of the long option name column. This may break tests.
- API Change: Removed parser option `arityRestrictsCumulativeSize` introduced in 3.0.0-alpha-3.
### 3.0.0-beta-2
- Stricter arity validation may break existing applications that intentionally consume arguments regardless of whether arguments are other options.
# Picocli 3.0.0-beta-2
The picocli community is pleased to announce picocli 3.0.0-beta-2.
This release contains enhancements and bug fixes.
This is the twenty-eighth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-beta-2-new)
* [Promoted features](#3.0.0-beta-2-promoted)
* [Fixed issues](#3.0.0-beta-2-fixes)
* [Deprecations](#3.0.0-beta-2-deprecated)
* [Potential breaking changes](#3.0.0-beta-2-breaking-changes)
## New and Noteworthy
### Stricter Arity Validation
Until this release, options with mandatory parameters would consume as many arguments as required, even if those arguments matched other option flags. For example:
Given a command like this:
```java
class App {
@Option(names = "-a", arity = "2")
String[] a;
@Option(names = "-v")
boolean v;
}
```
Prior to this change, the following input would be accepted:
```
-a 1 -v
```
In previous versions, picocli accepted this and assigned `"1"` and `"-v"` as the two values for the `-a` option.
From this release, the parser notices that one of the arguments is an option and throws a `MissingParameterException` because not enough parameters were specified for the first option.
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#366] API Change: Add `ArgSpec.getTypedValues()` method.
- [#365] Enhancement: Stricter arity validation: options with mandatory parameters no longer consume other option flags.
- [#357] Enhancement: Improve synopsis format. Be more succinct when `limitSplit` is true. Support repeating groups.
## Deprecations
## Potential breaking changes
- Stricter arity validation may break existing applications that intentionally consume arguments regardless of whether arguments are other options.
# Picocli 3.0.0-beta-1
The picocli community is pleased to announce picocli 3.0.0-beta-1.
This release contains enhancements and bug fixes.
This is the twenty-seventh public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-beta-1-new)
* [Promoted features](#3.0.0-beta-1-promoted)
* [Fixed issues](#3.0.0-beta-1-fixes)
* [Deprecations](#3.0.0-beta-1-deprecated)
* [Potential breaking changes](#3.0.0-beta-1-breaking-changes)
## New and Noteworthy
Previously, the usage message layout had a fixed width long option name column: this column is always 24 characters, even if none of the options have a long option name.
This gives weird-looking usage help messages in some cases. For example:
```java
@Command(name="ls")
class App {
@Option(names = "-a", description = "display all files") boolean a;
@Option(names = "-l", description = "use a long listing format") boolean l;
@Option(names = "-t", description = "sort by modification time") boolean t;
}
```
The usage message for this example was:
```
Usage: ls [-alt]
-a display all files
-l use a long listing format
-t sort by modification time
```
From this release, picocli adjusts the width of the long option name column to the longest name (max 24).
The new usage message for this example looks like this:
```
Usage: ls [-alt]
-a display all files
-l use a long listing format
-t sort by modification time
```
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#364] API Change: Remove parser option `arityRestrictsCumulativeSize`.
- [#355] API Change: Add method `ArgSpec.hasInitialValue`.
- [#361] API Change: Add parser option `aritySatisfiedByAttachedOptionParam` for commons-cli compatibility.
- [#363] API Change: Add parser option to limit the number of parts when splitting to max arity, for compatibility with commons-cli.
- [#360] Enhancement: Dynamically adjust width of long option name column (up to max 24).
## Deprecations
## Potential breaking changes
- The usage message format changed: it now dynamically adjusts the width of the long option name column. This may break tests.
- API Change: Removed parser option `arityRestrictsCumulativeSize` introduced in 3.0.0-alpha-3.
# Picocli 3.0.0-alpha-6
The picocli community is pleased to announce picocli 3.0.0-alpha-6.
This release contains enhancements and bug fixes.
This is the twenty-sixth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-alpha-6-new)
* [Promoted features](#3.0.0-alpha-6-promoted)
* [Fixed issues](#3.0.0-alpha-6-fixes)
* [Deprecations](#3.0.0-alpha-6-deprecated)
* [Potential breaking changes](#3.0.0-alpha-6-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#349] New API: Add `longestName()` convenience method to OptionSpec.
- [#352] New API: Add method to copy all attributes of a ParserSpec to a CommandSpec.
- [#353] New API: Add method to copy all attributes of a UsageMessageSpec to a CommandSpec.
- [#343] New API: Add method `Help.Ansi.Text::concat` and deprecate the `append` method. ("Append" suggests the Text object is modified, like StringBuilder, but Text is immutable.)
- [#350] Enhancement: Improve error message for `usageHelp` and `versionHelp` validation.
- [#344] Enhancement: Don't show WARN message for unmatched args or overwritten options.
- [#351] Documentation: Improve javadoc for OptionSpec.usageHelp and versionHelp.
- [#354] Bug fix: Interpreter should reset options and positional parameters to their initial value before parsing new input.
## Deprecations
- The `Help.Ansi.Text::append` method is now deprecated in favour of the new `concat` method.
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-deprecated)
## Potential breaking changes
See also breaking changes for
[3.0.0-alpha-5](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-5#3.0.0-alpha-5-breaking-changes),
[3.0.0-alpha-4](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-4#3.0.0-alpha-4-breaking-changes),
[3.0.0-alpha-3](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-3#3.0.0-alpha-3-breaking-changes),
[3.0.0-alpha-2](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-2#3.0.0-alpha-2-breaking-changes),
and [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-breaking-changes).
# Picocli 3.0.0-alpha-5
The picocli community is pleased to announce picocli 3.0.0-alpha-5.
This release contains enhancements and bug fixes.
This is the twenty-fifth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-alpha-5-new)
* [Promoted features](#3.0.0-alpha-5-promoted)
* [Fixed issues](#3.0.0-alpha-5-fixes)
* [Deprecations](#3.0.0-alpha-5-deprecated)
* [Potential breaking changes](#3.0.0-alpha-5-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#329] New API: Add parser configuration to control whether boolean flags should be toggled.
- [#328] New API: Provide getter methods on `OptionSpec.Builder` and `PositionalParamSpec.Builder`.
- [#326] New API: Add parser configuration to treat unmatched options as positional parameters.
- [#283] New API: Provide `getMissing` method on MissingParameterException to get a reference to the problematic options and positional parameters. Thanks to [jcapsule](https://github.com/jcapsule) for the suggestion.
- [#334] API Change: Rename `ArgSpec.rawStringValues()` to `ArgSpec.stringValues()`.
- [#342] API Change: Prefix ParseResult methods with `matched` if they return only matched options/positionals.
- [#340] API Change: Rename `ParseResult.optionValue(String, T)` to `matchedOptionValue(String, T)`.
- [#338] API Change: Remove `ParseResult.rawOptionValue(s)` and `rawPositionalValue(s)` methods.
- [#339] API Change: Remove `ParseResult.matchedOptionValue(OptionSpec)` and `matchedPositionalValue(PositionalParamSpec)` methods.
- [#347] API Change: Make `ArgSpec.getValue`, `setValue` and `isMultiValue` public methods.
- [#333] Enhancement: Added subcommand to synopsis in generated usage help. Thanks to [jcapsule](https://github.com/jcapsule) for the pull request.
- [#323] Enhancement: Remove dependency on java.sql package: picocli should only require the java.base module when running in Java 9.
- [#325] Enhancement: Allow custom type converter to map empty String to custom default value for empty options. Thanks to [jesselong](https://github.com/jesselong) for the suggestion.
- [#303] Enhancement: Improve validation to prevent common mistakes.
- [#70] Enhancement: Positional parameters should only consume values where type conversion succeeds.
- [#346] Enhancement: Validate that arity min is never greater than max.
- [#348] Enhancement: Interpreter should call `ArgSpec.setValue` for every matched option or positional parameter.
- [#327] Bugfix: Default values should not cause options and positional parameters to be added to ParseResult.
- [#330] Bugfix: `Interpreter` should clear option's and positional parameter's `stringValues` list before parsing new input.
- [#335] Bugfix: Abstract class `ArgSpec` should not implement `equals` and `hashCode`.
- [#345] Bugfix: Stop processing varargs when cumulative size reached.
## Deprecations
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-deprecated)
## Potential breaking changes
* Renamed `ArgSpec.rawStringValues()` to `ArgSpec.stringValues()`.
* Renamed `ParseResult` methods with `matched` if they return only matched options/positionals:
* `options` to `matchedOptions`
* `positionalParams` to `matchedPositionals`
* `option(char)`, `option(String)` to `matchedOption`
* `positional(int)` to `matchedPositional`
* `hasOption(char)`, `hasOption(String)`, `hasOption(OptionSpec)` to `hasMatchedOption`
* `hasPositional(int)`, `hasPositional(PositionalParamSpec)` to `hasMatchedPositional`
* Renamed `ParseResult.optionValue(String, T)` to `matchedOptionValue(String, T)`, and `positionalValue` to `matchedPositionalValue`.
* Removed `ParseResult::rawOptionValue(s)` and `rawPositionalValue(s)` methods.
* Removed `ParseResult.matchedOptionValue(OptionSpec)` and `matchedPositionalValue(PositionalParamSpec)` methods.
See also breaking changes for
[3.0.0-alpha-4](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-4#3.0.0-alpha-4-breaking-changes),
[3.0.0-alpha-3](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-3#3.0.0-alpha-3-breaking-changes),
[3.0.0-alpha-2](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-2#3.0.0-alpha-2-breaking-changes),
and [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-breaking-changes).
# Picocli 3.0.0-alpha-4
The picocli community is pleased to announce picocli 3.0.0-alpha-4.
This release contains enhancements and bug fixes.
This is the twenty-fourth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-alpha-4-new)
* [Promoted features](#3.0.0-alpha-4-promoted)
* [Fixed issues](#3.0.0-alpha-4-fixes)
* [Deprecations](#3.0.0-alpha-4-deprecated)
* [Potential breaking changes](#3.0.0-alpha-4-breaking-changes)
## New and Noteworthy
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#318] API Change: Split model IBinding into IGetter and ISetter.
- [#320] API Change: Rename parser config `maxArityIsMaxTotalParams` to `arityRestrictsCumulativeSize`.
- [#216] Enhancement: Parsed values now replace the default value of multi-value (array, Collection or Map) options and positional parameters instead of being appended to them. Thanks to [wiwie](https://github.com/wiwie) for the request.
- [#261] Enhancement: Options and positional parameters with a `defaultValue` are never required. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#315] Enhancement: Initialize ArgSpec value with `defaultValue` before parsing command line.
- [#263] Bugfix: positional parameter defaults were not shown in usage help message. Thanks to [ymenager](https://github.com/ymenager) for the bug report.
## Deprecations
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-deprecated)
## Potential breaking changes
- Parsed values now replace the default value of multi-value (array, Collection or Map) options and positional parameters instead of being appended to them.
- The `IBinding` interface introduced in v3.0.0-alpha-1 has been replaced with two functional interfaces `IGetter` and `ISetter`.
- The `UnmatchedArgsBinding` factory methods introduced in v3.0.0-alpha-1 have been replaced with `forStringArrayConsumer` and `forStringCollectionSupplier`.
See also breaking changes for [3.0.0-alpha-3](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-3#3.0.0-alpha-3-breaking-changes),
[3.0.0-alpha-2](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-2#3.0.0-alpha-2-breaking-changes),
and [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-breaking-changes).
# Picocli 3.0.0-alpha-3
The picocli community is pleased to announce picocli 3.0.0-alpha-3.
This release includes changes to allow picocli to be configured to function like Apache Commons CLI, to support [GROOVY-8520](https://issues.apache.org/jira/browse/GROOVY-8520):
* `maxArityIsMaxTotalParams` parser configuration option to use `arity` to limit the total number of values accumulated in an option or positional parameter.
* Usage message width can now be configured programmatically.
* "Lenient" mode when extracting annotations from a class where picocli annotations are optional (to allow mixing Groovy CLI annotations in Groovy CliBuilder).
* Change semantics of ParseResult.rawOptionValue to mean values after split (but before type conversion).
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1) and [3.0.0-alpha-2](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-2#3.0.0-alpha-2) for recent functional changes.
This is the twenty-third public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-alpha-3-new)
* [Promoted features](#3.0.0-alpha-3-promoted)
* [Fixed issues](#3.0.0-alpha-3-fixes)
* [Deprecations](#3.0.0-alpha-3-deprecated)
* [Potential breaking changes](#3.0.0-alpha-3-breaking-changes)
## New and Noteworthy
### Max Arity Is Max Total Params
This release introduces a `maxArityIsMaxTotalParams` parser configuration option.
By default, the arity of an option is the number of arguments _for each occurrence_ of the option.
For example, if option `-a` has `arity = "2"`, then the following is a perfectly valid command:
for each occurrence of the option, two option parameters are specified.
```bash
-a 1 2 -a 3 4 -a 5 6
```
However, if `CommandLine.setMaxArityIsMaxTotalParams(true)` is called first, the above example would result in a `MaxValuesExceededException` because the total number of values (6) exceeds the arity of 2.
Additionally, by default, when `maxArityIsMaxTotalParams` is `false`, arity is only applied _before_ the argument is split into parts,
while when `maxArityIsMaxTotalParams` is set to `true`, validation is applied _after_ a command line argument has been split into parts.
For example, if we have an option like this:
```java
@Option(name = "-a", arity = "1..2", split = ",") String[] values;
```
By default, the following input would be a valid command:
```bash
-a 1,2,3
```
By default, the option arity tells the parser to consume 1 to 2 arguments, and the option was followed by a single parameter, `"1,2,3"`, which is fine.
However, if `maxArityIsMaxTotalParams` is set to true, the above example would result in a `MaxValuesExceededException` because the argument is split into 3 parts, which exceeds the max arity of 2.
## Promoted Features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#313] Enhancement and New API: add method `CommandLine::setMaxArityIsMaxTotalParams` to configure the parser to use `arity` to limit the total number of values accumulated in an option or positional parameter.
- [#314] Enhancement and New API: add method `CommandLine::setUsageHelpWidth` and `UsageMessageSpec::width` to set the max usage help message width.
- [#316] Enhancement: Support lenient mode where annotations are optional when extracting annotations.
- [#317] Enhancement: Change semantics of ParseResult.rawOptionValue to mean values after split (but before type conversion).
## Deprecations
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-deprecated)
## Potential breaking changes
- Utility method `CommandLine.Help.join` signature changed: now takes an additional `usageHelpWidth` parameter.
- Constructor `CommandLine.Help.Layout(ColorScheme)` signature changed: now takes an additional `usageHelpWidth` parameter.
- Public field `CommandLine.Help.TextTable.columns` is now private; added public method `CommandLine.Help.TextTable.columns()`.
- Constructor `CommandLine.Help.TextTable(Ansi)` is replaced with factory method `CommandLine.Help.TextTable.forDefaultColumns(Ansi, int)`.
- Constructor `CommandLine.Help.TextTable(Ansi, int...)` is replaced with factory method `CommandLine.Help.TextTable.forColumnWidths(Ansi, int...)`.
- Constructor `CommandLine.Help.TextTable(Ansi, Column...)` modifier changed from public to protected.
- Added factory method `CommandLine.Help.TextTable.forColumns(Ansi, Column...)`.
- Renamed `CommandLine.MaxValuesforFieldExceededException` to `CommandLine.MaxValuesExceededException`.
See [3.0.0-alpha-2](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-2#3.0.0-alpha-2-breaking-changes).
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-breaking-changes).
# Picocli 3.0.0-alpha-2
The picocli community is pleased to announce picocli 3.0.0-alpha-2.
This release includes some bug fixes and small enhancements. See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1) for recent functional changes.
This is the twenty-second public release.
Picocli follows [semantic versioning](http://semver.org/).
## Fixed issues
- [#312] Enhancement and API change: Remove `AbstractSimpleParseResultHandler` class and `parseWithSimpleHandlers` method.
- [#311] Enhancement and API change: Simplify parseWithHandlers: removed prototypeReturnValue parameter.
- [#307] Enhancement: Provide CommandLine.usage(PrintWriter) method for testing and to facilitate [GROOVY-8520](https://issues.apache.org/jira/browse/GROOVY-8520) migration from commons-cli to picocli.
- [#306] Enhancement: Support generating autocompletion scripts for non-public @Command classes. Thanks to [cbeams](https://github.com/cbeams) for the request.
- [#308] Enhancement: Provide API to disallow POSIX clustered short options.
- [#310] Enhancement: PicocliBaseScript should follow conventions for stdout and stderr: requested help to stdout, invalid input usage help to stderr.
- [#309] Bugfix: Tests were failing on environments that support ANSI colors.
## Deprecations
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-deprecated)
## Potential breaking changes
- [#311] API change from 3.0.0-alpha-1: the `parseWithHandlers` methods signature changed: removed the `prototypeReturnValue` parameter.
- [#312] API change from 3.0.0-alpha-1: Remove `AbstractSimpleParseResultHandler` class and `parseWithSimpleHandlers` method.
See [3.0.0-alpha-1](https://github.com/remkop/picocli/releases/tag/v3.0.0-alpha-1#3.0.0-alpha-1-breaking-changes)
# Picocli 3.0.0-alpha-1
The picocli community is pleased to announce picocli 3.0.0-alpha-1.
This release offers a programmatic API for creating command line applications, in addition to annotations. The programmatic API allows applications to dynamically create command line options on the fly, and also makes it possible to create idiomatic domain-specific languages for processing command line arguments, using picocli, in other JVM languages.
Another new feature in this release are Mixins. Mixins allow reusing common options, parameters and command attributes in multiple applications without copy-and-paste duplication.
Third, this release aims to reduce boilerplate code in user applications even further with the new `mixinStandardHelpOptions` command attribute. Picocli adds standard `usageHelp` and `versionHelp` options to commands with this attribute. Additionally picocli now offers a `HelpCommand` that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands.
From this release, picocli is better at following unix conventions: print to stdout when the user requested help, and print to stderr when the input was invalid or an unexpected error occurred.
Also, this release gives better control over the process exit code.
Additionally, fields annotated with `@Unmatched` will be populated with the unmatched arguments.
Furthermore, this release adds a `showDefaultValue` attribute to the `@Option` and `@Parameters` annotation.
This is the twenty-first public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#3.0.0-alpha-1-new)
* [Promoted features](#3.0.0-alpha-1-promoted)
* [Fixed issues](#3.0.0-alpha-1-fixes)
* [Deprecations](#3.0.0-alpha-1-deprecated)
* [Potential breaking changes](#3.0.0-alpha-1-breaking-changes)
## New and Noteworthy
### Programmatic API (INCUBATING)
This release offers a programmatic API for creating command line applications, in addition to annotations. The programmatic API allows applications to dynamically create command line options on the fly, and also makes it possible to create idiomatic domain-specific languages for processing command line arguments, using picocli, in other JVM languages.
Note that the programmatic API is incubating and the API may change in subsequent releases. _If you have suggestions for improving the programmatic API, please raise a ticket on GitHub!_
#### Example
```java
CommandSpec spec = CommandSpec.create();
spec.mixinStandardHelpOptions(true); // usageHelp and versionHelp options
spec.addOption(OptionSpec.builder("-c", "--count")
.paramLabel("COUNT")
.type(int.class)
.description("number of times to execute").build());
spec.addPositional(PositionalParamSpec.builder()
.paramLabel("FILES")
.type(List.class)
.auxiliaryTypes(File.class) // List
.description("The files to process").build());
CommandLine commandLine = new CommandLine(spec);
commandLine.parseWithSimpleHandlers(new AbstractSimpleParseResultHandler() {
public void handle(ParseResult pr) {
int count = pr.optionValue('c', 1);
List files = pr.positionalValue(0, Collections.emptyList());
for (int i = 0; i < count; i++) {
for (File f : files) {
System.out.printf("%d: %s%n", i, f);
}
}
}
}, args);
```
#### CommandSpec (INCUBATING)
`CommandSpec` models a command. It is the programmatic variant of the `@Command` annotation. It has a name and a version, both of which may be empty. It also has a `UsageMessageSpec` to configure aspects of the usage help message and a `ParserSpec` that can be used to control the behaviour of the parser.
#### OptionSpec and PositionalParamSpec (INCUBATING)
`OptionSpec` models a named option, and `PositionalParamSpec` models one or more positional parameters. They are the programmatic variant of the `@Option` and `@Parameters` annotations, respectively.
An `OptionSpec` must have at least one name, which is used during parsing to match command line arguments. Other attributes can be left empty and picocli will give them a reasonable default value. This defaulting is why `OptionSpec` objects are created with a builder: this allows you to specify only some attributes and let picocli initialise the other attributes. For example, if only the option’s name is specified, picocli assumes the option takes no parameters (arity = 0), and is of type `boolean`. Another example, if arity is larger than `1`, picocli sets the type to `List` and the `auxiliary type` to `String`.
`PositionalParamSpec` objects don’t have names, but have an index range instead. A single `PositionalParamSpec` object can capture multiple positional parameters. The default index range is set to `0..*` (all indices). A command may have multiple `PositionalParamSpec` objects to capture positional parameters at different index ranges. This can be useful if positional parameters at different index ranges have different data types.
Similar to `OptionSpec` objects, Once a `PositionalParamSpec` is constructed, its configuration becomes immutable, but its `value` can still be modified. Usually the value is set during command line parsing when a non-option command line argument is encountered at a position in its index range.
#### ParseResult (INCUBATING)
A `ParseResult` class is now available that allows applications to inspect the result of parsing a sequence of command line arguments.
This class provides methods to query whether the command line arguments included certain options or position parameters, and what the value or values of these options and positional parameters was. Both the original command line argument String value as well as a strongly typed value can be obtained.
### Mixins for Reuse
Mixins are a convenient alternative to subclassing: picocli annotations from _any_ class can be added to ("mixed in" with) another command. This includes options, positional parameters, subcommands and command attributes. Picocli [autoHelp](#3.0.0-alpha-1-autohelp) internally uses a mixin.
A mixin is a separate class with options, positional parameters, subcommands and command attributes that can be reused in other commands. Mixins can be installed by calling the `CommandLine.addMixin` method with an object of this class, or annotating a field in your command with `@Mixin`. Here is an example mixin class:
```java
public class ReusableOptions {
@Option(names = { "-v", "--verbose" }, description = {
"Specify multiple -v options to increase verbosity.", "For example, `-v -v -v` or `-vvv`" })
protected boolean[] verbosity = new boolean[0];
}
```
#### Adding Mixins Programmatically
The below example shows how a mixin can be added programmatically with the `CommandLine.addMixin` method.
```java
CommandLine commandLine = new CommandLine(new MyCommand());
commandline.addMixin("myMixin", new ReusableOptions());
```
#### `@Mixin` Annotation
A command can also include mixins by annotating fields with `@Mixin`. All picocli annotations found in the mixin class
are added to the command that has a field annotated with `@Mixin`. For example:
```java
@Command(name = "zip", description = "Example reuse with @Mixin annotation.")
public class MyCommand {
// adds the options defined in ReusableOptions to this command
@Mixin
private ReusableOptions myMixin;
}
```
### Standard Help Options
This release introduces the `mixinStandardHelpOptions` command attribute. When this attribute is set to `true`, picocli adds a mixin to the command that adds `usageHelp` and `versionHelp` options to the command. For example:
```java
@Command(mixinStandardHelpOptions = true, version = "auto help demo - picocli 3.0")
class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
@Override public void run() { }
}
```
Commands with `mixinStandardHelpOptions` do not need to explicitly declare fields annotated with `@Option(usageHelp = true)` and `@Option(versionHelp = true)` any more. The usage help message for the above example looks like this:
```text
Usage: [-hV] [--option=]
--option= Some option.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
```
### Help Command
From this release, picocli provides a `help` subcommand (`picocli.CommandLine.HelpCommand`) that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands. For example:
```java
@Command(subcommands = HelpCommand.class)
class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
@Override public void run() { }
}
```
```text
# print help for the `maincommand` command
maincommand help
# print help for the `subcommand` command
maincommand help subcommand
```
For applications that want to create a custom help command, this release also introduces a new interface `picocli.CommandLine.IHelpCommandInitializable` that provides custom help commands with the information they need: access to the parent command and sibling commands, whether to use Ansi colors or not, and the streams to print the usage help message to.
### `@Unmatched` Annotation
From this release, fields annotated with `@Unmatched` will be populated with the unmatched arguments.
The field must be of type `String[]` or `List`.
If picocli finds a field annotated with `@Unmatched`, it automatically sets `unmatchedArgumentsAllowed` to `true`
so no `UnmatchedArgumentException` is thrown when a command line argument cannot be assigned to an option or positional parameter.
### Stdout or Stderr
From picocli v3.0, the `run` and `call` convenience methods follow unix conventions:
print to stdout when the user requested help, and print to stderr when the input was invalid or an unexpected error occurred.
Custom handlers can extend `AbstractHandler` to facilitate following this convention.
`AbstractHandler` also provides `useOut` and `useErr` methods to allow customizing the target output streams,
and `useAnsi` to customize the Ansi style to use:
```java
@Command class CustomizeTargetStreamsDemo implements Runnable {
public void run() { ... }
public static void main(String... args) {
CommandLine cmd = new CommandLine(new CustomizeTargetStreamsDemo());
PrintStream myOut = getOutputPrintStream(); // custom stream to send command output to
PrintStream myErr = getErrorPrintStream(); // custom stream for error messages
cmd.parseWithHandlers(
new RunLast().useOut(myOut).useAnsi(Help.Ansi.ON),
new DefaultExceptionHandler().useErr(myErr).useAnsi(Help.Ansi.OFF),
args);
}
}
```
### Exit Code Support
From picocli v3.0, the built-in parse result handlers (`RunFirst`, `RunLast` and `RunAll`) and exception handler
(`DefaultExceptionHandler`) can specify an exit code.
If an exit code was specified, the handler terminates the JVM with the specified status code when finished.
```java
@Command class ExitCodeDemo implements Runnable {
public void run() { throw new ParameterException(new CommandLine(this), "exit code demo"); }
public static void main(String... args) {
CommandLine cmd = new CommandLine(new ExitCodeDemo());
cmd.parseWithHandlers(
new RunLast().andExit(123),
new DefaultExceptionHandler().andExit(456),
args);
}
}
```
Running this command prints the following to stderr and exits the JVM with status code `456`.
```
exit code demo
Usage:
```
Custom handlers can extend `AbstractHandler` to inherit this behaviour.
### Fine-grained ShowDefault
This release adds a `showDefaultValue` attribute to the `@Option` and `@Parameters` annotation. This allows you to specify for each individual option and positional parameter whether its default value should be shown in the usage help.
This attribute accepts three values:
* `ALWAYS` - always display the default value of this option or positional parameter, even `null` values, regardless what value of `showDefaultValues` was specified on the command
* `NEVER` - don't show the default value for this option or positional parameter, regardless what value of `showDefaultValues` was specified on the command
* `ON_DEMAND` - (this is the default) only show the default value for this option or positional parameter if `showDefaultValues` was specified on the command
The `NEVER` value is useful for security sensitive command line arguments like passwords. The `ALWAYS` value is useful when you only want to show the default value for a few arguments but not for all (in combination with `@Command(showDefaultValues = false)`).
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#245] New Feature: from 3.0, picocli offers an API for programmatic configuration.
- [#257] New Feature: new `ParseResult` class allows programmatic inspection of the result of parsing a sequence of command line arguments.
- [#144] New Feature: added support for mixins to allow reusing common options, positional parameters, subcommands and command attributes from any object.
- [#253] New Feature: added `@Unmatched` annotation for unmatched arguments.
- [#175] New Feature: `mixinStandardHelpOptions` attribute to install the standard `--help` and `--version` options, obviating the need for fields annotated with `@Option(usageHelp = true)` and `@Option(versionHelp = true)`.
- [#175] New Feature: picocli now provides a `HelpCommand` that can be installed as a subcommand on any application command to provide usage help for the parent command or sibling subcommands.
- [#175] New Feature: new `IHelpCommandInitializable` interface facilitates construction of custom help commands.
- [#250] Enhancement: the `run` and `call` convenience methods now follow convention: print to stdout when the user requested help, print to stderr when the input was invalid or an unexpected error occurred. Added `AbstractHandler` to facilitate following this convention for custom parse result handlers and exception handlers.
- [#251] New Feature: exit code support. The built-in parse result handlers (`RunFirst`, `RunLast` and `RunAll`) and exception handler (`DefaultExceptionHandler`) can now optionally specify an exit code. If specified, the handler terminates the JVM with the specified status code when finished. Custom handlers can extend `AbstractHandler` to inherit this behaviour.
- [#262] New Feature: new `showDefaultValue` attribute on `@Option` and `@Parameters` gives fine-grained control over which default values to show or hide. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#268] New Feature: new `helpCommand` attribute on `@Command`: if the command line arguments contain a subcommand annotated with `helpCommand`, the parser will not validate the required options or positional parameters of the parent command. Thanks to [ymenager](https://github.com/ymenager) for the request.
- [#277] New Feature: new `hidden` attribute on `@Command` to omit the specified subcommand from the usage help message command list of the parent command. Thanks to [pditommaso](https://github.com/pditommaso).
- [#159] Enhancement: make help usage message width configurable. Thanks to [pditommaso](https://github.com/pditommaso).
## Deprecations
The `picocli.CommandLine.Help::Help(Object, CommandLine.Help.ColorScheme)` constructor has been deprecated. Use the `picocli.CommandLine.Help::Help(CommandLine.CommandSpec, CommandLine.Help.ColorScheme)` constructor instead.
The `picocli.CommandLine.IParseResultHandler` interface has been deprecated. Use the `picocli.CommandLine.IParseResultHandler2` interface instead.
The `picocli.CommandLine.IExceptionHandler` interface has been deprecated. Use the `picocli.CommandLine.IExceptionHandler2` interface instead.
## Potential breaking changes
### Help API Changes
The following public fields were removed from the `picocli.CommandLine.Help` class. Instead, set these attributes on a `CommandLine.CommandSpec` object passed to any of the `Help` constructors.
* abbreviateSynopsis
* commandListHeading
* commandName
* customSynopsis
* description
* descriptionHeading
* footer
* footerHeading
* header
* headerHeading
* optionFields
* optionListHeading
* parameterLabelRenderer - replaced with the `Help.parameterLabelRenderer()` method
* parameterListHeading
* requiredOptionMarker
* separator
* showDefaultValues
* sortOptions
* synopsisHeading
Method signature changes on inner classes and interfaces of the `Help` class:
* Interface method `CommandLine.Help.IOptionRenderer::render` signature changed: `CommandLine.Option` and `Field` parameters are replaced with a single `CommandLine.OptionSpec` parameter.
* Interface method `CommandLine.Help.IParameterRenderer::render` signature changed: `CommandLine.Parameters` and `Field` parameters are replaced with a single `CommandLine.PositionalParamSpec` parameter.
* Interface method `CommandLine.Help.IParamLabelRenderer::renderParameterLabel` signature changed: `Field` parameter replaced with `CommandLine.ArgSpec` parameter.
* Class `CommandLine.Help.Layout` all methods changed: `Field` parameters replaced by `CommandLine.ArgSpec`, `CommandLine.OptionSpec` and `CommandLine.PositionalParamSpec` parameters.
# Picocli 2.3.0
The picocli community is pleased to announce picocli 2.3.0.
This release contains bugfixes and new features.
This release introduces a new parser flag `stopAtPositional` to treat the first positional parameter as end-of-options, and a `stopAtUnmatched` parser flag to stop matching options and positional parameters as soon as an unmatched argument is encountered.
These flags are useful for applications that need to delegate part of the command line to third party commands.
This release offers better support for options with optional values, allowing applications to distinguish between cases where the option was not specified at all, and cases where the option was specified without a value.
This is the twentieth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.3.0-new)
* [Promoted features](#2.3.0-promoted)
* [Fixed issues](#2.3.0-fixes)
* [Deprecations](#2.3.0-deprecated)
* [Potential breaking changes](#2.3.0-breaking-changes)
## New and noteworthy
### Stop At Positional
By default, positional parameters can be mixed with options on the command line, but this is not always desirable. From this release, applications can call `CommandLine.setStopAtPositional(true)` to force the parser to treat all values following the first positional parameter as positional parameters.
When this flag is set, the first positional parameter effectively serves as an "end of options" marker, without requiring a separate `--` argument.
### Stop At Unmatched
From this release, applications can call `CommandLine.setStopAtUnmatched(true)` to force the parser to stop interpreting options and positional parameters as soon as it encounters an unmatched argument.
When this flag is set, the first unmatched argument and all subsequent command line arguments are added to the unmatched arguments list returned by `CommandLine.getUnmatchedArguments()`.
### Optional Values
If an option is defined with `arity = "0..1"`, it may or not have a parameter value. If such an option is specified without a value on the command line, it is assigned an empty String. If the option is not specified, it keeps its default value. For example:
```java
class OptionalValueDemo implements Runnable {
@Option(names = "-x", arity = "0..1", description = "optional parameter")
String x;
public void run() { System.out.printf("x = '%s'%n", x); }
public static void main(String... args) {
CommandLine.run(new OptionalValueDemo(), System.out, args);
}
}
```
Gives the following results:
```bash
java OptionalValueDemo -x value
x = 'value'
java OptionalValueDemo -x
x = ''
java OptionalValueDemo
x = 'null'
```
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#215] API: `stopAtUnmatched` flag to stop parsing on first unmatched argument. Thanks to [defnull](https://github.com/defnull) for the request.
- [#284] API: `stopAtPositional` flag to treat first positional parameter as end-of-options. Thanks to [defnull](https://github.com/defnull) and [pditommaso](https://github.com/pditommaso) for the request.
- [#279] Enhancement: assign empty String when String option was specified without value. Thanks to [pditommaso](https://github.com/pditommaso) for the request.
- [#285] Bugfix: Vararg positional parameters should not consume options. Thanks to [pditommaso](https://github.com/pditommaso) for the bug report.
- [#286] Documentation: clarify when picocli instantiates fields for options and positional parameters. Thanks to [JanMosigItemis](https://github.com/JanMosigItemis) for pointing this out.
## Deprecations
This release has no additional deprecations.
## Potential breaking changes
This release has no breaking changes.
# Picocli 2.2.2
The picocli community is pleased to announce picocli 2.2.2.
This is a bugfix release.
This is the nineteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.2.2-new)
* [Promoted features](#2.2.2-promoted)
* [Fixed issues](#2.2.2-fixes)
* [Deprecations](#2.2.2-deprecated)
* [Potential breaking changes](#2.2.2-breaking-changes)
## New and noteworthy
This is a bugfix release and does not include any new features.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#282] Bugfix: unmatched option heuristic did not work when there were no options to compare against. Thanks to [jcapsule](https://github.com/jcapsule).
## Deprecations
This release has no additional deprecations.
## Potential breaking changes
This release has no breaking changes.
# Picocli 2.2.1
The picocli community is pleased to announce picocli 2.2.1.
This is a bugfix release.
This is the eighteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.2.1-new)
* [Promoted features](#2.2.1-promoted)
* [Fixed issues](#2.2.1-fixes)
* [Deprecations](#2.2.1-deprecated)
* [Potential breaking changes](#2.2.1-breaking-changes)
## New and noteworthy
This is a bugfix release and does not include any new features.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#254] Bugfix: Starting from 2.0.3, usage help didn't render empty lines in multi-line descriptions.
- [#255] Documentation: Update Kotlin example in user manual for the new Kotlin 1.2 array literal syntax in annotations.
## Deprecations
This release has no additional deprecations.
## Potential breaking changes
This release has no breaking changes.
# Picocli 2.2.0
The picocli community is pleased to announce picocli 2.2.
This release is a "Project Coin"-like release for picocli: small changes with a nice pay-off.
In command line applications with subcommands, options of the parent command are often intended as "global" options that apply to all the subcommands. This release introduces a new `@ParentCommand` annotation that makes it easy for subcommands to access such parent command options: fields of the subcommand annotated with `@ParentCommand` are initialized with a reference to the parent command.
This release adds support for more built-in types, so applications don't need to register custom converters for common types. The new types include Java 7 classes like `java.nio.file.Path` and Java 8 classes like the value classes in the `java.time` package. These converters are loaded using reflection and are not available when running on Java 5 or Java 6.
This release also adds a `converter` attribute to the `@Option` and `@Parameter` annotations. This allows a specific option or positional parameter to use a different converter than would be used by default based on the type of the field.
Furthermore, the `@Command` annotation now supports a `versionProvider` attribute. This is useful when the version of an application should be detected dynamically at runtime. For example, an implementation may return version information obtained from the JAR manifest, a properties file or some other source.
Finally, applications may now specify a custom factory for instantiating classes that were configured as annotation attributes, like subcommands, type converters and version providers.
This is the seventeenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.2.0-new)
* [Promoted features](#2.2.0-promoted)
* [Fixed issues](#2.2.0-fixes)
* [Deprecations](#2.2.0-deprecated)
* [Potential breaking changes](#2.2.0-breaking-changes)
## New and noteworthy
### New `@ParentCommand` annotation
In command line applications with subcommands, options of the top level command are often intended as "global" options that apply to all the subcommands. Prior to this release, subcommands had no easy way to access their parent command options unless the parent command made these values available in a global variable.
The `@ParentCommand` annotation makes it easy for subcommands to access their parent command options: subcommand fields annotated with `@ParentCommand` are initialized with a reference to the parent command. For example:
```java
@Command(name = "fileutils", subcommands = List.class)
class FileUtils {
@Option(names = {"-d", "--directory"},
description = "this option applies to all subcommands")
File baseDirectory;
}
@Command(name = "list")
class List implements Runnable {
@ParentCommand
private FileUtils parent; // picocli injects reference to parent command
@Option(names = {"-r", "--recursive"},
description = "Recursively list subdirectories")
private boolean recursive;
@Override
public void run() {
list(new File(parent.baseDirectory, "."));
}
private void list(File dir) {
System.out.println(dir.getAbsolutePath());
if (dir.isDirectory()) {
for (File f : dir.listFiles()) {
System.out.println(f.getAbsolutePath());
if (f.isDirectory() && recursive) {
list(f);
}
}
}
}
}
```
### More built-in types
This release adds support for more built-in types, so applications don't need to register custom converters for common types. The new types include Java 7 classes like `java.nio.file.Path` and Java 8 classes like the value classes in the `java.time` package. These converters are loaded using reflection and are not available when running on Java 5 or Java 6.
Converters for the following types were added in this release:
* `java.nio.file.Path` (requires Java 7 or higher)
* `java.time` value objects: `Duration`, `Instant`, `LocalDate`, `LocalDateTime`, `LocalTime`, `MonthDay`, `OffsetDateTime`, `OffsetTime`, `Period`, `Year`, `YearMonth`, `ZonedDateTime`, `ZoneId`, `ZoneOffset` (requires Java 8 or higher, invokes the `parse` method of these classes)
* `java.lang.Class` (for the fully qualified class name)
* `java.nio.ByteOrder` (for the Strings `"BIG_ENDIAN"` or `"LITTLE_ENDIAN"`)
* `java.util.Currency` (for the ISO 4217 code of the currency)
* `java.net.NetworkInterface` (for the InetAddress or name of the network interface)
* `java.util.TimeZoneConverter` (for the ID for a TimeZone)
* `java.sql.Connection` (for a database url of the form `jdbc:subprotocol:subname`)
* `java.sql.Driver` (for a database URL of the form `jdbc:subprotocol:subname`)
* `java.sql.Timestamp` (for values in the `"yyyy-MM-dd HH:mm:ss"` or `"yyyy-MM-dd HH:mm:ss.fffffffff"` formats)
### Option-specific Type Converters
This release adds a `converter` attribute to the `@Option` and `@Parameter` annotations. This allows a specific option or positional parameter to use a different converter than would be used by default based on the type of the field.
For example, you may want to convert the constant names defined in [`java.sql.Types`](https://docs.oracle.com/javase/9/docs/api/java/sql/Types.html) to their `int` value for a specific field, but this should not impact any other `int` fields: other `int` fields should continue to use the default int converter that parses numeric values.
Example usage:
```java
class App {
@Option(names = "--sqlType", converter = SqlTypeConverter.class)
int sqlType;
}
```
Example implementation:
```java
class SqlTypeConverter implements ITypeConverter {
public Integer convert(String value) throws Exception {
switch (value) {
case "ARRAY" : return Types.ARRAY;
case "BIGINT" : return Types.BIGINT;
case "BINARY" : return Types.BINARY;
case "BIT" : return Types.BIT;
case "BLOB" : return Types.BLOB;
//...
}
}
}
```
### Dynamic Version Information
From this release, the `@Command` annotation supports a `versionProvider` attribute. Applications may specify a `IVersionProvider` implementation in this attribute, and picocli will instantiate this class
and invoke it to collect version information.
This is useful when the version of an application should be detected dynamically at runtime. For example, an implementation may return version information obtained from the JAR manifest, a properties file or some other source.
Custom version providers need to implement the `picocli.CommandLine.IVersionProvider` interface:
```java
public interface IVersionProvider {
/**
* Returns version information for a command.
* @return version information (each string in the array is displayed on a separate line)
* @throws Exception an exception detailing what went wrong when obtaining version information
*/
String[] getVersion() throws Exception;
}
```
The GitHub project has a manifest file-based [example](https://github.com/remkop/picocli/blob/master/examples/src/main/java/picocli/examples/VersionProviderDemo2.java) and a build-generated version properties file-based [example](https://github.com/remkop/picocli/blob/master/examples/src/main/java/picocli/examples/VersionProviderDemo1.java) version provider implementation.
### Custom factory
Declaratively registered subcommands, type converters and version providers must be instantiated somehow. From this release, a custom factory can be specified when constructing a `CommandLine` instance. This allows full control over object creation and opens possibilities for Inversion of Control and Dependency Injection. For example:
```jshelllanguage
IFactory myFactory = getCustomFactory();
CommandLine cmdLine = new CommandLine(new Git(), myFactory);
```
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#247] New `@ParentCommand` annotation to inject a reference to the parent command into subcommand fields. Thanks to [michaelpj](https://github.com/michaelpj) for the request.
- [#83] Add more built-in converters. Thanks to [garydgregory](https://github.com/garydgregory/jcommander-addons) for the inspiration.
- [#237] Option and Positional Parameter-specific type converters. Thanks to [godzsa](https://github.com/godzsa) for the request.
- [#236] Allow obtaining version information dynamically at runtime. Thanks to [kcris](https://github.com/kcris) for the request.
- [#169] Configurable factory to instantiate subcommands that are registered via annotation attributes. Thanks to [kakawait](https://github.com/kakawait) for the request.
- [#252] Example version provider implementations.
## Deprecations
This release has no additional deprecations.
## Potential breaking changes
This release has no breaking changes.
# Picocli 2.1.0
This release contains bugfixes and new features.
Users sometimes run into system limitations on the length of a command line when creating a command line with lots of options or with long arguments for options.
Starting from this release, picocli supports "argument files" or "@-files". Argument files are files that themselves contain arguments to the command. When picocli encounters an argument beginning with the character `@', it expands the contents of that file into the argument list.
Secondly, this release adds support for multi-value boolean flags. A common use case where this is useful is to let users control the level of output verbosity by specifying more `-v` flags on the command line. For example, `-v` could give high-level output, `-vv` could show more detailed output, and `-vvv` could show debug-level information.
Finally, thanks to [aadrian](https://github.com/aadrian) and [RobertZenz](https://github.com/RobertZenz), an `examples` subproject containing running examples has been added. (Your contributions are welcome!)
This is the sixteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.1.0-new)
* [Promoted features](#2.1.0-promoted)
* [Fixed issues](#2.1.0-fixes)
* [Deprecations](#2.1.0-deprecated)
* [Potential breaking changes](#2.1.0-breaking-changes)
## New and noteworthy
### Argument Files (`@`-files)
An argument file can include options and positional parameters in any combination. The arguments within a file can be space-separated or newline-separated. If an argument contains embedded whitespace, put the whole argument in double or single quotes (`"-f=My Files\Stuff.java"`).
Lines starting with `#` are comments and are ignored. The file may itself contain additional @-file arguments; any such arguments will be processed recursively.
Multiple @-files may be specified on the command line.
For example, suppose a file with arguments exists at `/home/foo/args`, with these contents:
```text
# This line is a comment and is ignored.
ABC -option=123
'X Y Z'
```
A command may be invoked with the @file argument, like this:
```bash
java MyCommand @/home/foo/args
```
The above will be expanded to the contents of the file:
```bash
java MyCommand ABC -option=123 "X Y Z"
```
This feature is similar to the 'Command Line Argument File' processing supported by gcc, javadoc and javac.
The documentation for these tools shows further examples.
### Repeated Boolean Flags
Multi-valued boolean options are now supported. For example:
```jshelllanguage
@Option(names = "-v", description = { "Specify multiple -v options to increase verbosity.",
"For example, `-v -v -v` or `-vvv`"})
boolean[] verbosity;
```
Users may specify multiple boolean flag options without parameters. For example:
```bash
-v -v -v -vvv
```
The above example results in six `true` values being added to the `verbosity` array.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#126] New feature: Support expanding argument files, also called `@-files`.
- [#241] New feature (enhancing [#126]): Recursively process nested @-files; allow multiple arguments per line, allow quoted arguments with embedded whitespace.
- [#217] New feature: Support repeated boolean flag options captured in multi-valued fields.
- [#223] New feature: Added `examples` subproject containing running examples. Thanks to [aadrian](https://github.com/aadrian) and [RobertZenz](https://github.com/RobertZenz).
- [#68] Enhancement: Reject private final primitive fields annotated with @Option or @Parameters: because compile-time constants are inlined, updates by picocli to such fields would not be visible to the application.
- [#239] Enhancement: Improve error message when Exception thrown from Runnable/Callable.
- [#240] Bugfix: RunAll handler should return empty list, not null, when help is requested.
- [#244] Bugfix: the parser only considered `help` options instead of any of `help`, `usageHelp` and `versionHelp` to determine if missing required options can be ignored when encountering a subcommand. Thanks to [mkavanagh](https://github.com/mkavanagh).
## Deprecations
The `Range::defaultArity(Class)` method is now deprecated in favour of the `Range::defaultArity(Field)` method introduced in v2.0.
## Potential breaking changes
Private final fields that are either `String` or primitive types can no longer be annotated with `@Option` or `@Parameters`.
Picocli will throw an `InitializationException` when it detects such fields,
because compile-time constants are inlined, and updates by picocli to such fields would not be visible to the application.
# Picocli 2.0.3
The picocli community is pleased to announce picocli 2.0.3.
This is a bugfix release that fixes a parser bug where the first argument following a clustered options was treated as a positional parameter, and removes the erroneous runtime dependency on `groovy-lang` that slipped in with the 2.0 release.
This release also includes a minor enhancement to support embedded newlines in usage help sections like header or descriptions. This allows Groovy applications to use [triple-quoted](http://groovy-lang.org/syntax.html#_triple_double_quoted_string) and [dollar slashy](http://groovy-lang.org/syntax.html#_dollar_slashy_string) multi-line strings in usage help sections.
This is the fifteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.0.3-new)
* [Promoted features](#2.0.3-promoted)
* [Fixed issues](#2.0.3-fixes)
* [Deprecations](#2.0.3-deprecated)
* [Potential breaking changes](#2.0.3-breaking-changes)
## New and noteworthy
This is a bugfix release and does not include any new features.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#230] Enhancement: Support embedded newlines in usage help sections like header or descriptions. Thanks to [ddimtirov](https://github.com/ddimtirov).
- [#233] Bugfix: Parser bug: first argument following clustered options is treated as a positional parameter. Thanks to [mgrossmann](https://github.com/mgrossmann).
- [#232] Bugfix: Remove required runtime dependency on `groovy-lang`. Thanks to [aadrian](https://github.com/aadrian).
## Deprecations
This release does not deprecate any features.
## Potential breaking changes
This release does not include any breaking features.
# Picocli 2.0.2
The picocli community is pleased to announce picocli 2.0.2.
This is a bugfix release that prevents an EmptyStackException from being thrown when the command line
ends in a cluster of boolean options, and furthermore fixes two scripting-related minor issues.
This is the fourteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.0.2-new)
* [Promoted features](#2.0.2-promoted)
* [Fixed issues](#2.0.2-fixes)
* [Deprecations](#2.0.2-deprecated)
* [Potential breaking changes](#2.0.2-breaking-changes)
## New and noteworthy
This is a bugfix release and does not include any new features.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#226] Bugfix: EmptyStackException when command line ends in a cluster of boolean options. Thanks to [RobertZenz](https://github.com/RobertZenz).
- [#222] Bugfix: Register default converter for Object fields for better scripting support.
- [#219] Bugfix: Command line system property -Dpicocli.trace (without value) throws exception when used with Groovy.
- [#220] Enhancement: Improve tracing for positional parameters (provide detail on current position).
- [#221] Enhancement: Add documentation for Grapes bug workaround on Groovy versions before 2.4.7.
## Deprecations
This release does not deprecate any features.
## Potential breaking changes
This release does not include any breaking features.
# Picocli 2.0.1
The picocli community is pleased to announce picocli 2.0.1.
This is a bugfix release that removes a dependency on Java 1.7 which was accidentally included.
This is the thirteenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.0.1-new)
* [Promoted features](#2.0.1-promoted)
* [Fixed issues](#2.0.1-fixes)
* [Deprecations](#2.0.1-deprecated)
* [Potential breaking changes](#2.0.1-breaking-changes)
## New and noteworthy
This is a bugfix release and does not include any new features.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
No features have been promoted in this picocli release.
## Fixed issues
- [#214] Removed a dependency on Java 1.7 that was accidentally included. Thanks to [sjsajj](https://github.com/sjsajj).
## Deprecations
This release does not deprecate any features.
## Potential breaking changes
This release does not include any breaking features.
# Picocli 2.0
The picocli community is pleased to announce picocli 2.0.
First, picocli now provides tight integration for Groovy scripts.
The new `@picocli.groovy.PicocliScript` annotation allows Groovy scripts to use the `@Command` annotation,
and turns a Groovy script into a picocli-based command line application.
When the script is run, `@Field` variables annotated with `@Option` or `@Parameters`
are initialized from the command line arguments before the script body is executed.
Applications with subcommands will also benefit from upgrading to picocli 2.0.
The `CommandLine.run` and `CommandLine.call` methods now work for subcommands,
and if more flexibility is needed, take a look at the new `parseWithHandler` methods.
Error handling for subcommands has been improved in this release with the new `ParseException.getCommandLine` method.
Improved ease of use: Usage help is now printed automatically from the `CommandLine.run` and `CommandLine.call` methods
and from the built-in handlers used with the `parseWithHandler` method.
The parser has been improved and users can now mix positional arguments with options on the command line.
Previously, positional parameter had to follow the options.
**Important notice:** To make this feature possible, the default parsing behaviour of multi-value options and parameters changed to be non-greedy by default.
Finally, this release includes many [bug fixes](#2.0-fixes).
This is the twelfth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Table of Contents
* [New and noteworthy](#2.0-new)
* [Groovy Script Support](#2.0-groovy-script)
* [Better Subcommand Support](#2.0-subcommands)
* [Easier To Use](#2.0-ease-of-use)
* [Parser Improvements](#2.0-parser-improvements)
* [Usage Help Format Improvements](#2.0-help-improvements)
* [Promoted features](#2.0-promoted)
* [Fixed issues](#2.0-fixes)
* [Deprecations](#2.0-deprecated)
* [Potential breaking changes](#2.0-breaking-changes)
## New and noteworthy
### Groovy Script Support
Picocli 2.0 introduces special support for Groovy scripts.
Scripts annotated with `@picocli.groovy.PicocliScript` are automatically transformed to use
`picocli.groovy.PicocliBaseScript` as their base class and can also use the `@Command` annotation to
customize parts of the usage message like command name, description, headers, footers etc.
Before the script body is executed, the `PicocliBaseScript` base class parses the command line and initializes
`@Field` variables annotated with `@Option` or `@Parameters`.
The script body is executed if the user input was valid and did not request usage help or version information.
```groovy
// exampleScript.groovy
@Grab('info.picocli:picocli:2.0.0')
@Command(name = "myCommand", description = "does something special")
@PicocliScript
import picocli.groovy.PicocliScript
import picocli.CommandLine.Command
import picocli.CommandLine.Option
import groovy.transform.Field
@Option(names = "-x", description = "number of repetitions")
@Field int count;
@Option(names = ["-h", "--help"], usageHelp = true, description = "print this help message and exit")
@Field boolean helpRequested;
//if (helpRequested) { // not necessary: PicocliBaseScript takes care of this
// CommandLine.usage(this, System.err); return 0;
//}
count.times {
println "hi"
}
// the CommandLine that parsed the args is available as a property
assert this.commandLine.commandName == "myCommand"
```
### Better Subcommand Support
New methods `CommandLine::parseWithHandler` were added. These methods intend to offer the same ease of use as
the `run` and `call` methods, but with more flexibility and better support for nested subcommands.
The `CommandLine::call` and `CommandLine::run` now support subcommands and will execute the **last** subcommand
specified by the user. (Previously subcommands were ignored and only the top-level command was executed.)
From this release, picocli exceptions provide a `getCommandLine` method
that returns the command or subcommand where parsing or execution failed.
Previously, if the user provided invalid input for applications with subcommands,
it was difficult to pinpoint exactly which subcommand failed to parse the input.
### Easier To Use
The convenience methods will automatically print usage help and version information
when the user specifies options annotated with the `versionHelp` or `usageHelp` attributes.
Methods that automatically print help:
* CommandLine::call
* CommandLine::run
* CommandLine::parseWithHandler (with the built-in Run… handlers)
* CommandLine::parseWithHandlers (with the built-in Run… handlers)
Methods that do not automatically print help:
* CommandLine::parse
* CommandLine::populateCommand
Also notable: Collection and Map fields no longer require the `type` annotation attribute:
picocli now infers the conversion target type from the generic type parameters where possible.
### Parser Improvements
Positional parameters can now be mixed with options on the command line. Previously, positional parameter had to follow the options.
To make this feature possible, the default parsing behaviour of multi-value options and parameters changed to be non-greedy by default.
### Usage Help Format Improvements
This release contains various bugfixes related to improving the usage help format for multi-value options and collections.
For example, for Maps that don't have a `paramLabel`, picocli now shows key type and value type instead of the internal Java field name.
## Promoted features
Promoted features are features that were incubating in previous versions of picocli but are now supported and subject to backwards compatibility.
The following are the features that have been promoted in this picocli release.
* Autocomplete - as of picocli 2.0, autocompletion is no longer beta.
## Fixed issues
- [#207] API Change: Provide ability to find which subcommand threw a ParameterException API enhancement. Thanks to [velit](https://github.com/velit) and [AshwinJay](https://github.com/AshwinJay).
- [#179] API Change to remove full JRE dependency and require only Compact Profile. Replace use of `java.awt.Point` with `picocli.CommandLine.Help.TextTable.Cell`. Thanks to [webfolderio](https://github.com/webfolderio).
- [#205] API Change: `CommandLine::getCommand` now returns a generic type instead of Object so client code can avoid type casting.
- [#196] API Change: `Option::type()` and `Parameters::type()` now return empty array by default (was `{String.class}`).
- [#210] API Change: Deprecated the option `help` attribute in favour of the `usageHelp` and `versionHelp` attributes.
- [#115] New feature: Added new `CommandLine::parseWithHandler` convenience methods for commands with subcommands.
- [#130] New feature: Options and positional parameters can now be mixed on the command line.
- [#196] New feature: Infer type from collections and maps when `type` annotation not specified. Thanks to [ddimtirov](https://github.com/ddimtirov) for the suggestion.
- [#197] New feature: Use `type` attribute to determine conversion target type instead of field type. This allows fields to be declared as interfaces or abstract types (or arrays/collections/maps of these) and via the `type` attribute picocli will be able to convert String arguments to concrete implementation objects.
- [#187] New feature: Added methods to programmatically get and set the command name.
- [#192] Bugfix: Default arity should be 1, not *, for array and collection options. Thanks to [RobertZenz](https://github.com/RobertZenz).
- [#193] Bugfix: Splitting an argument should not cause max arity to be exceeded.
- [#191] Bugfix: Arity should not limit the total number of values put in an array or collection. Thanks to [RobertZenz](https://github.com/RobertZenz).
- [#186] Bugfix: Confusing usage message for collection options. Thanks to [AlexFalappa](https://github.com/AlexFalappa).
- [#181] Bugfix: Incorrect help message was displayed for short options with paramLabel when arity > 1.
- [#184] Bugfix/Enhancement: Programmatically setting the separator is now reflected in the usage help message. Thanks to [defnull](https://github.com/defnull).
- [#200] Bugfix: Prevent NPE when command name is set to empty string or spaces. Thanks to [jansohn](https://github.com/jansohn).
- [#203] Bugfix: Empty string parameter parsed incorrectly. Thanks to [AshwinJay](https://github.com/AshwinJay).
- [#194] Enhancement: Usage help should show split regex for option/parameters.
- [#198] Enhancement: Usage help parameter list details should indicate arity for positional parameters.
- [#195] Enhancement: Usage help should show Map types if paramLabel not specified.
- [#183] Enhancement: Add examples to user manual for using picocli in other JVM languages. Thanks to [binkley](https://github.com/binkley) for pointing out that Kotlin may support array literals in annotations from 1.2.
- [#185] Enhancement: Exception message text for missing options should not use field names but be more descriptive and consistent with usage help. Thanks to [AlexFalappa](https://github.com/AlexFalappa).
- [#201] Enhancement: Usage help should not show `null` default values. Thanks to [jansohn](https://github.com/jansohn).
- [#202] Enhancement: Java 9: add `Automatic-Module-Name: info.picocli` to MANIFEST.MF to make picocli play nice in the Java 9 module system.
- [#204] Enhancement: instantiate `LinkedHashSet` instead of `HashSet` for `Set` fields to preserve input ordering.
- [#208] Enhancement: Remove pom.xml, which was not being maintained. Picocli can only be built with gradle going forward.
- [#212] Enhancement: Improve javadoc for picocli.AutoComplete.
## Deprecations
The `help` attribute for options is now deprecated. Please change to use `usageHelp` and `versionHelp` attributes instead.
From picocli v2.0, the convenience methods will automatically print usage help and version information
when requested with the `versionHelp` and `usageHelp` option attributes (but not for the `help` attribute).
## Potential breaking changes
This release has a number of incompatible changes:
* Multi-value options (array, list and map fields) are **not greedy by default** any more.
* **Arity is not max values**: end users may specify multi-value options (array, list and map fields) an unlimited number of times.
* A single argument that is split into parts with a regex now **counts as a single argument** (so `arity="1"` won't prevent all parts from being added to the field)
* API change: replaced `java.awt.Point` with custom `Cell` class as return value type for public method `Help.TextTable.putValue()`.
* API change: `@Option.type()` and `@Parameters.type()` now return an empty array by default (was `{String.class}`).
* API change: `ParameterException` and all subclasses now require a `CommandLine` object indicating the command or subcommand that the user provided invalid input for.
* The `CommandLine::call` and `CommandLine::run` now support subcommands and will execute the **last** subcommand specified by the user. Previously subcommands were ignored and the top-level command was executed unconditionally.
I am not happy about the disruption these changes may cause, but I felt they were needed for three reasons:
the old picocli v1.0 behaviour caused ambiguity in common use cases,
was inconsistent with most Unix tools,
and prevented supporting mixing options with positional arguments on the command line.
To illustrate the new non-greedy behaviour, consider this example program:
```java
class MixDemo {
@Option(names="-o") List options;
@Parameters List positionalParams;
public void run() {
System.out.println("positional: " + positionalParams);
System.out.println("options : " + options);
}
public static void main(String[] args) {
CommandLine.run(new MixDemo(), System.err, args);
}
}
```
We run this program as below, where the option is followed by multiple values:
```bash
$ java MixDemo -o 1 2 3
```
Previously, the arguments following `-o` would all end up in the `options` list. Running the above command with picocli 1.0 would print out the following:
```bash
# (Previously, in picocli-1.0.1)
$ java MixDemo -o 1 2 3
positional: null
options : [1, 2, 3]
```
From picocli 2.0, only the first argument following `-o` is added to the `options` list, the remainder is parsed as positional parameters:
```bash
# (Currently, in picocli-2.0)
$ java MixDemo -o 1 2 3
positional: [2, 3]
options : [1]
```
To put multiple values in the options list in picocli 2.0, users can specify the `-o` option multiple times:
```bash
$ java MixDemo -o 1 -o 2 -o 3
positional: null
options : [1, 2, 3]
```
Alternatively, application authors can make a multi-value option greedy in picocli v2.0 by explicitly setting a variable arity:
```java
class Args {
@Option(names = "-o", arity = "1..*") List options;
}
```
(... "greedy" means consume until the next option, so not necessarily all remaining command line arguments.)
# 1.0.1 - Bugfix release.
## Summary: zsh autocompletion bugfix
This is the eleventh public release.
Picocli follows [semantic versioning](http://semver.org/).
- [#178] Fixed autocompletion bug for subcommands in zsh. Autocomplete on zsh would show only the global command options even when a subcommand was specified. Autocompletion now works for nested subcommands.
# 1.0.0 - Bugfix and enhancements release.
## Summary
New features: command line autocompletion, `-Dkey=value`-like Map options and parser tracing.
Non-breaking changes to support Callable commands, Map options and format specifiers in version help.
This is the tenth public release.
Picocli follows [semantic versioning](http://semver.org/).
## Fixed issues
* [#121] New feature: command line autocompletion. Picocli can generate bash and zsh completion scripts that allow the shell to generate potential completion matches based on the `@Option` and `@Command` annotations in your application. After this script is installed, the shell will show the options and subcommands available in your java command line application, and in some cases show possible option values.
* [#67] New feature: Map options like `-Dkey1=val1 -Dkey2=val2`. Both key and value can be strongly typed (not just Strings).
* [#158] New feature: parser TRACING for easy troubleshooting. The trace level can be controlled with a system property.
* [#170] New feature: added `call` convenience method similar to `run`. Applications whose main business logic may throw an exception or returns a result can now implement `Callable` and reduce some boilerplate code.
* [#149] Parser now throws UnmatchedArgumentException for args that resemble options but are not, instead of treating like them positional parameters. Thanks to [giaco777](https://github.com/giaco777).
* [#172] Parser now throws MaxValuesforFieldExceededException when multi-valued option or parameters max arity exceeded
* [#173] Parser now throws UnmatchedArgumentException when not all positional parameters are assigned to a field
* [#171] WARN when option overwritten with different value (when isOverwrittenOptionsAllowed=true); WARN for unmatched args (when isUnmatchedArgumentsAllowed=true). Thanks to [ddimtirov](https://github.com/ddimtirov).
* [#164] API change: Support format patterns in version string and printVersionHelp
* [#167] API change: Change `type` attribute from `Class` to `Class[]`. This was needed for Map options support.
* [#168] API change: `CommandLine::setSeparator` method now returns this CommandLine (was void), allowing for chained method calls.
* [#156] Added example to user manual to clarify main command common usage. Thanks to [nagkumar](https://github.com/nagkumar).
* [#166] Fixed bug where adjacent markup sections resulted in incorrect ANSI escape sequences
* [#174] Fixed bug where under some circumstances, unmatched parameters were added to UnmatchedParameters list twice
# 0.9.8 - Bugfix and enhancements release for public review. API may change.
## Summary
Non-breaking changes to add better help support and better subcommand support.
## Fixed issues
* [#162] Added new Version Help section to user manual; added `version` attribute on `@Command`; added `CommandLine::printVersionHelp` convenience method to print version information from this annotation to the console
* [#145] Added `usageHelp` and `versionHelp` attributes on `@Option`; added `CommandLine::isUsageHelpRequested` and `CommandLine::isVersionHelpRequested` to allow external components to detect whether usage help or version information was requested (without inspecting the annotated domain object). Thanks to [kakawait](https://github.com/kakawait).
* [#160] Added `@since` version in javadoc for recent API changes.
* [#157] API change: added `CommandLine::getParent` method to get the parent command of a subcommand. Thanks to [nagkumar](https://github.com/nagkumar).
* [#152] Added support for registering subcommands declaratively with the `@Command(subcommands#{...})` annotation. Thanks to [nagkumar](https://github.com/nagkumar).
* [#146] Show underlying error when type conversion fails
* [#147] Toggle boolean flags instead of setting to `true`
* [#148] Long string in default value no longer causes infinite loop when printing usage. Thanks to [smartboyathome](https://github.com/smartboyathome).
* [#142] First line of long synopsis no longer overshoots 80-character usage help width. Thanks to [waacc-gh](https://github.com/waacc-gh).
# 0.9.7 - Bugfix and enhancements release for public review. API may change.
## Summary
Version 0.9.7 has some breaking API changes.
**Better Groovy support**
It was [pointed out](https://github.com/remkop/picocli/issues/135) that Groovy had trouble distinguishing between
the static `parse(Object, String...)` method and the instance method `parse(String...)`.
To address this, the static `parse(Object, String...)` method has been renamed
to `populateCommand(Object, String...)` in version 0.9.7.
**Nested subcommands**
* Version 0.9.7 adds support for [nested sub-subcommands](https://github.com/remkop/picocli/issues/127)
* `CommandLine::parse` now returns `List` (was `List`)
* `CommandLine::getCommands` now returns `Map` (was `Map`)
* renamed method `CommandLine::addCommand` to `addSubcommand`
* renamed method `CommandLine::getCommands` to `getSubcommands`
**Miscellaneous**
Renamed class `Arity` to `Range` since it is not just used for @Option and @Parameters `arity` but also for `index` in positional @Parameters.
## Fixed issues
* [#127] Added support for nested sub-subcommands
* [#135] API change: renamed static convenience method `CommandLine::parse` to `populateCommand`
* [#134] API change: `CommandLine::parse` now returns `List` (was `List`)
* [#133] API change: `CommandLine::getCommands` now returns `Map` (was `Map`)
* [#133] API change: Added method `CommandLine::getCommand`
* [#136] API change: renamed method `CommandLine::addCommand` to `addSubcommand`;
* [#136] API change: renamed method `CommandLine::getCommands` to `getSubcommands`
* [#131] API change: Renamed class `Arity` to `Range`
* [#137] Improve validation: disallow index gap in @Parameters annotations
* [#132] Improve validation: parsing should fail when unmatched arguments remain
* [#138] Improve validation: disallow option overwriting by default
* [#129] Make "allow option overwriting" configurable
* [#140] Make "allow unmatched arguments" configurable
* [#139] Improve validation: CommandLine must be constructed with a command that has at least one of @Command, @Option or @Parameters annotation
* [#141] Bugfix: prevent NullPointerException when sorting required options/parameters
# 0.9.6 - Bugfix release for public review. API may change.
* [#128] Fix unexpected MissingParameterException when a help-option is supplied (bug)
# 0.9.5 - Bugfix and enhancements release for public review. API may change.
* [#122] API change: remove field CommandLine.ansi (enhancement)
* [#123] API change: make public Arity fields final (enhancement)
* [#124] API change: make Help fields optionFields and positionalParameterFields final and unmodifiable (enhancement)
* [#118] BumpVersion gradle task scrambles chars in manual (bug)
* [#119] Add gradle task to publish to local folder (enhancement)
# 0.9.4 - Bugfix release for public review. API may change.
* [#114] Replace ISO-8613-3 "true colors" with more widely supported 256-color palette (enhancement)
* [#113] Fix javadoc warnings (doc enhancement)
* [#117] The build should work for anyone checking out the project (bug)
* [#112] Improve (shorten) user manual (doc enhancement)
* [#105] Automate publishing to JCentral & Maven Central
# 0.9.3 - Bugfix release for public review. API may change.
* [#90] Automate release
* [#111] Improve picocli.Demo (enhancement)
* [#110] Fix javadoc for `parse(String...)` return value (doc enhancement)
* [#108] Improve user manual (doc enhancement)
* [#109] `run` convenience method should accept PrintStream (enhancement)
# 0.9.2 - Bugfix release for public review. API may change.
* [#106] MissingParameterException not thrown for missing mandatory @Parameters when options are specified
* [#104] Investigate why colors don't show by default on Cygwin
# 0.9.1 - Bugfix release for public review. API may change.
* [#103] Replace javadoc occurences of ASCII with ANSI. (doc bug)
* [#102] Move ColorScheme inside Ansi class (enhancement question wontfix)
* [#101] Cosmetics: indent `Default: ` by 2 spaces (enhancement)
* [#100] Improve error message for DuplicateOptionAnnotationsException (enhancement)
* [#99] MissingRequiredParams error shows optional indexed Parameters (bug)
* [#98] MissingRequiredParams error shows indexed Parameters in wrong order when not declared in index order (bug)
* [#97] Fix compiler warnings (bug)
* [#96] Synopsis shows indexed Parameters in wrong order when subclassing for reuse (bug)
* [#95] EmptyStackException when no args are passed to object annotated with Parameters (bug)
* [#94] heading fields are not inherited when subclassing for reuse (bug)
* [#93] Only option fields are set accessible, not parameters fields (bug)
* [#91] Syntax highlighting in manual source blocks (doc enhancement)
# 0.9.0 (was 0.4.0) - User Manual and API Changes. Initial public release.
* [#89] Improve error message for missing required options and parameters (enhancement)
* [#88] Code cleanup (enhancement)
* [#87] Add `CommandLine.usage` methods with a ColorScheme parameter (enhancement)
* [#86] Work around issue on Windows (Jansi?) where style OFF has no effect (bug)
* [#85] Javadoc for Ansi classes (doc)
* [#84] System property to let end users set color scheme (enhancement)
* [#81] Improve README (doc enhancement)
* [#80] Support customizable Ansi color scheme (enhancement)
* [#79] Approximate `istty()` by checking `System.console() != null` (enhancement)
* [#78] Add method CommandLine.setUsageWidth(int) (enhancement wontfix)
* [#77] Replace PicoCLI in javadoc with picocli (doc enhancement)
* [#76] @Parameters javadoc is out of date (bug doc)
* [#75] The default value for the `showDefaultValues` attribute should be `false` (bug)
* [#74] rename attribute `valueLabel` to `paramLabel` (enhancement)
* [#73] Remove @Parameters synopsis attribute enhancement)
* [#72] numeric parameter conversion should parse as decimal (bug enhancement)
* [#71] Allow multiple values for an option -pA,B,C or -q="A B C" (enhancement)
* [#66] Support ansi coloring (doc enhancement)
* [#65] Consider removing the `required` Option attribute (enhancement question wontfix)
* [#64] Test that boolean options with arity=1 throw MissingParameterException when no value exists (not ParameterException) (bug QA)
* [#35] Allow users to express arity as a range: 0..* or 1..3 (remove "varargs" attribute) (enhancement)
* [#30] Test & update manual for exceptions thrown from custom type converters (doc QA)
* [#26] Ergonomic API - convenience method to parse & run an app (duplicate enhancement)
* [#12] Create comparison feature table with prior art (doc)
* [#11] Write user manual (doc in-progress)
* [#6] Array field values should be preserved (like Collections) and new values appended (enhancement)
* [#4] Should @Option and @Parameters have listConverter attribute instead of elementType? (enhancement question wontfix)
# 0.3.0 - Customizable Usage Help
* [#69] Improve TextTable API (enhancement question)
* [#63] Unify @Option and @Parameters annotations (enhancement wontfix)
* [#59] Support declarative API for customizing usage help message (enhancement wontfix)
* [#58] Add unit tests for ShortestFirst comparator (QA)
* [#57] Consider using @Usage separator for parsing as well as for usage help (enhancement)
* [#56] Add unit tests for customizable option parameter name and positional parameter name (QA)
* [#55] Add unit tests for detailed Usage line (QA)
* [#54] Add unit tests for DefaultLayout (QA)
* [#53] Add unit tests for DefaultParameterRenderer (QA)
* [#52] Add unit tests for DefaultOptionRenderer (QA)
* [#51] Add unit tests for MinimalOptionRenderer (QA)
* [#50] Add unit tests for Arity (QA)
* [#49] Detailed usage header should cluster boolean options (enhancement)
* [#48] Show positional parameters details in TextTable similar to option details (enhancement)
* [#47] Reduce API surface for usage Help (enhancement)
* [#44] Support detailed Usage line instead of generic Usage \ \[option] [parameters] (enhancement)
* [#43] Generated help message should show parameter default value (except for boolean fields) (enhancement)
* [#42] Show option parameter in generated help (use field name or field type?) (enhancement)
* [#41] Required options should be visually distinct from optional options in usage help details (enhancement)
* [#40] Test SortByShortestOptionName (QA)
* [#39] Test that first declared option is selected by ShortestFirst comparator if both equally short (QA)
* [#38] Test DefaultRenderer chooses shortest option name in left-most field (QA)
* [#37] Consider returning a list of Points from TextTable::putValue (enhancement wontfix)
* [#36] javadoc ILayout, IRenderer, DefaultLayout, DefaultRenderer (doc)
* [#34] Usage should not show options if no options exist (enhancement)
* [#32] Support customizable user help format. (enhancement)
* [#31] Add test for recognizing clustered short option when parsing varargs array (bug QA)
* [#27] Support git-like commands (enhancement)
* [#8] Add positional @Parameter annotation (enhancement)
* [#7] Implement online usage help (enhancement)
* [#5] Rename `description` attribute to `helpText` or `usage` (enhancement wontfix)
# 0.2.0 - Vararg Support
* [#25] Use Integer.decode(String) rather than Integer.parseInt (enhancement)
* [#23] @Option should not greedily consume args if varargs=false (bug)
# 0.1.0 - Basic Option and Parameter Parsing
* [#20] add test where option name is "-p", give it input "-pa-p" (QA)
* [#19] Improve error message for type conversion: include field name (and option name?) (enhancement)
* [#18] test superclass bean and child class bean where child class field shadows super class and have different annotation Option name (QA)
* [#17] Test superclass bean and child class bean where child class field shadows super class and have same annotation Option name (invalid QA)
* [#16] Test arity > 1 for single-value fields (int, File, ...) (QA)
* [#13] Test for enum type conversation (QA)
* [#3] Interpreter should set helpRequested=false before parse() (bug)
* [#2] Test that separators other than '=' can be configured (QA)
* [#1] Test with other option prefixes than '-' (QA)
picocli-3.9.6/_config.yml 0000664 0000000 0000000 00000000035 13457642030 0015304 0 ustar 00root root 0000000 0000000 theme: jekyll-theme-architect picocli-3.9.6/build.gradle 0000664 0000000 0000000 00000034014 13457642030 0015440 0 ustar 00root root 0000000 0000000 group 'info.picocli'
description 'Java command line parser with both an annotations API and a programmatic API. Usage help with ANSI styles and colors. Autocomplete. Nested subcommands. Easily included as source to avoid adding a dependency.'
version "$projectVersion"
buildscript {
repositories {
jcenter()
}
dependencies {
classpath "org.asciidoctor:asciidoctor-gradle-plugin:$asciidoctorGradlePluginVersion"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradleBintrayPluginVersion"
}
}
apply plugin: 'org.asciidoctor.convert'
apply plugin: 'distribution'
apply plugin: 'maven-publish'
apply plugin: 'com.jfrog.bintray'
allprojects {
apply plugin: 'groovy'
apply plugin: 'java'
apply plugin: 'java-library' // to avoid https://github.com/gradle/gradle/issues/1118
sourceCompatibility = !org.gradle.api.JavaVersion.current().isJava9Compatible() ?
1.5 : org.gradle.api.JavaVersion.current().isJava11Compatible() ? 1.7 : 1.6
targetCompatibility = !org.gradle.api.JavaVersion.current().isJava9Compatible() ?
1.5 : org.gradle.api.JavaVersion.current().isJava11Compatible() ? 1.7 : 1.6
repositories {
jcenter()
}
configurations.all {
resolutionStrategy {
// avoid "Could not resolve junit:junit-dep:[4.9,)" caused by stefanbirkner:system-rules when building offline
force "junit:junit-dep:$junitDepVersion"
}
}
configurations {
ivy
}
dependencies {
compileOnly "org.codehaus.groovy:groovy-all:$groovyVersion"
ivy "org.apache.ivy:ivy:$ivyVersion" // for Gradle
testCompile "junit:junit:$junitVersion",
"org.hamcrest:hamcrest-core:$hamcrestCoreVersion",
"org.fusesource.jansi:jansi:$jansiVersion",
"org.codehaus.groovy:groovy-all:$groovyVersion",
"com.github.stefanbirkner:system-rules:$systemRulesVersion"
}
tasks.withType(GroovyCompile) {
// this, and the `configurations {ivy}` section, are a workaround for the dreaded
// java.lang.NoClassDefFoundError: org/apache/ivy/core/report/ResolveReport
// that occurs when trying to compile a groovy script containing a @Grab annotation in gradle.
// see https://stackoverflow.com/questions/18173908/error-compiling-a-groovy-project-using-grab-annotation
groovyClasspath += configurations.ivy
}
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation'
}
javadoc {
destinationDir = file("build/docs/apidocs")
}
javadoc.options.addStringOption('Xdoclint:none', '-quiet')
// work around https://github.com/gradle/gradle/issues/4046
javadoc.dependsOn('copyJavadocDocFiles')
task copyJavadocDocFiles(type: Copy) {
from('src/main/java')
into 'build/docs/apidocs'
include '**/doc-files/*.*'
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
task testJar(type: Jar, dependsOn: compileTestJava) {
from sourceSets.test.output
classifier = 'tests'
}
task sourcesJar(type: Jar) {
from sourceSets.main.java.srcDirs
classifier = 'sources'
}
task testSourcesJar(type: Jar) {
from sourceSets.test.java.srcDirs
classifier = 'test-sources'
}
artifacts {
archives javadocJar
archives sourcesJar
archives testSourcesJar
archives testJar
archives jar
}
distributions {
main {
baseName = "$archivesBaseName-all"
contents {
from jar
from sourcesJar
from testJar
from testSourcesJar
from javadocJar
from ('LICENSE')
from ("$rootDir/RELEASE-NOTES.md")
}
}
}
ext {
bintrayUsername = System.getenv('BINTRAY_USER')
bintrayApiKey = System.getenv('BINTRAY_KEY')
mavenOssUser = System.getenv('MAVEN_OSS_USER')
mavenOssPassword = System.getenv('MAVEN_OSS_PASSWORD')
// pom configuration for MavenPublication
pomConfig = {
licenses {
license {
name "The Apache Software License, version 2.0"
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
distribution "repo"
}
}
developers {
developer {
id "rpopma"
name "Remko Popma"
email "rpopma@apache.org"
}
}
scm {
url "https://github.com/remkop/picocli/tree/master"
connection 'scm:git:https://github.com/remkop/picocli.git'
developerConnection 'scm:git:ssh://github.com:remkop/picocli.git'
}
}
}
}
jar {
manifest {
attributes 'Specification-Title' : 'picocli',
'Specification-Vendor' : 'Remko Popma',
'Specification-Version' : version,
'Implementation-Title' : 'picocli',
'Implementation-Vendor' : 'Remko Popma',
'Implementation-Version': version,
'Main-Class' : 'picocli.AutoComplete',
'Automatic-Module-Name' : 'info.picocli'
}
}
javadoc.options.overview = "src/main/java/overview.html"
javadoc.dependsOn('asciidoctor')
asciidoctor {
sourceDir = file('docs')
outputDir = file('build/docs')
logDocuments = true
}
// jacoco 0.8.2 does not work with Java 13; gradle 4.x has no JavaVersion enum value for Java 12
if (org.gradle.api.JavaVersion.current().isJava11Compatible()) {
project.logger.lifecycle("skipping jacoco test for Java version ${org.gradle.api.JavaVersion.current()}")
} else {
project.logger.lifecycle("applying jacoco build file for Java version ${org.gradle.api.JavaVersion.current()}")
apply from: "gradle/jacoco.gradle"
}
task bumpReadmeVersion {
doLast {
// README.md
ant.replaceregexp(match: "$projectPreviousReleaseVersion", replace: "$version", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: '.', includes: 'README.md')
fileset(dir: './picocli-codegen/', includes: 'README.md')
fileset(dir: './picocli-shell-jline2/', includes: 'README.md')
fileset(dir: './picocli-shell-jline3/', includes: 'README.md')
}
}
}
task bumpVersion {
doLast {
ant.replaceregexp(match: "\"$projectPreviousVersionRegex\"", replace: "\"$version\"", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'src/main/java/picocli', includes: 'CommandLine.java')
fileset(dir: 'src/test/java/picocli', includes: 'CommandLineTest.java')
}
ant.replaceregexp(match: "version $projectPreviousVersionRegex", replace: "version $version", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'src/test/java/picocli', includes: 'AutoCompleteTest.java')
}
// Doc header
ant.replaceregexp(match: ":revnumber: $projectPreviousVersionRegex", replace: ":revnumber: $version", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
fileset(dir: 'docs', includes: 'quick-guide.adoc')
fileset(dir: 'docs', includes: 'autocomplete.adoc')
fileset(dir: 'docs', includes: 'picocli-3.0-programmatic-api.adoc')
}
// Downloads section, Gradle
ant.replaceregexp(match: ":picocli:$projectPreviousVersionRegex", replace: ":picocli:$version", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
}
// Downloads section, Maven
ant.replaceregexp(match: "$projectPreviousVersionRegex ", replace: "$version ", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
}
// Downloads section, SBT
ant.replaceregexp(match: "\"picocli\" % \"$projectPreviousVersionRegex\"", replace: "\\\"picocli\\\" % \\\"$version\\\"", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
}
// Downloads section, Ivy
ant.replaceregexp(match: "rev=\"$projectPreviousVersionRegex\"", replace: "rev=\\\"$version\\\"", flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
}
ant.replaceregexp(match: releaseDatePreviousRegex, replace: releaseDate, flags: 'g', byline: true, encoding: 'UTF8') {
fileset(dir: 'docs', includes: 'index.adoc')
fileset(dir: 'docs', includes: 'quick-guide.adoc')
fileset(dir: 'docs', includes: 'autocomplete.adoc')
fileset(dir: 'docs', includes: 'picocli-3.0-programmatic-api.adoc')
}
}
}
task copyDocs(type: Copy) {
from('build/docs/html5/') { include '*.html' }
from('build/docs/') { exclude 'html5'}
into 'docs'
}
allprojects {
ext {
bintrayDryRun = false //[Default: false] Whether to run this as dry-run, without deploying
bintrayPublish = true //[Default: false] Whether version should be auto published after an upload
bintrayOverride = false //[Default: false] Whether to override version artifacts already published
mavenOssSync = true //[Default: true] Determines whether to sync the version to Maven Central.
}
}
ext {
bintrayPackage = 'picocli'
bintrayWebsiteUrl = 'http://picocli.info'
bintrayLabels = ['cli', 'cli framework', 'java', 'command line', 'ergonomic', 'library', 'parser', 'ansi', 'colors', 'annotations', 'reflection', 'usage', 'help', 'customizable', 'stand-alone application', 'main method', 'picocli']
}
bintray {
user = bintrayUsername
key = bintrayApiKey
publications = ['MyPublication']
dryRun = bintrayDryRun //[Default: false] Whether to run this as dry-run, without deploying
publish = bintrayPublish //[Default: false] Whether version should be auto published after an upload
override = bintrayOverride //[Default: false] Whether to override version artifacts already published
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'picocli'
name = bintrayPackage
userOrg = 'remkop'
licenses = ['Apache-2.0']
desc = description
websiteUrl = bintrayWebsiteUrl
issueTrackerUrl = 'https://github.com/remkop/picocli/issues'
vcsUrl = 'https://github.com/remkop/picocli.git'
labels = bintrayLabels
publicDownloadNumbers = false
githubRepo = 'remkop/picocli' //Optional Github repository
githubReleaseNotesFile = 'RELEASE-NOTES.md' //Optional Github readme file
version {
name = "$projectVersion"
desc = description
released = new Date()
vcsTag = "v$projectVersion"
mavenCentralSync {
sync = mavenOssSync //[Default: true] Determines whether to sync the version to Maven Central.
user = mavenOssUser //OSS user token: mandatory
password = mavenOssPassword //OSS user password: mandatory
close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
}
}
}
}
publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact sourcesJar
artifact testJar
artifact testSourcesJar
artifact javadocJar
groupId 'info.picocli'
artifactId bintrayPackage
version "$projectVersion"
pom.withXml {
def root = asNode()
root.appendNode('packaging', 'jar')
root.appendNode('name', 'picocli - a mighty tiny Command Line Interface')
root.appendNode('description', description)
root.appendNode('url', 'http://picocli.info')
root.appendNode('inceptionYear', '2017')
root.children().last() + pomConfig
}
}
}
}
/*
Release procedure:
1. edit version numbers: remove -SNAPSHOT classifier
2. gradlew bumpVersion
3. check modified files
4. gradlew clean build
5. gradlew copyDocs
6. update RELEASE-NOTES.md
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
11. edit version numbers: increase minor version and add -SNAPSHOT classifier
12. gradlew bumpVersion
13. check modified files
14. commit -m "Prepare for next development cycle"
15. push (make sure that Push Tags is checked)
16. Log in to GitHub, go to https://github.com/remkop/picocli/releases
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)
(When releasing from branch)
25. Switch to master
26. cherry-pick the "Release picocli version ..." commit
27. gradlew bumpVersion
28. check modified files
29. commit -m "Update master for next development cycle after release x.x (from branch x.x)"
*/
picocli-3.9.6/gradle.properties 0000664 0000000 0000000 00000001257 13457642030 0016540 0 ustar 00root root 0000000 0000000 asciidoctorGradlePluginVersion = 1.5.3
gradleBintrayPluginVersion = 1.+
groovyVersion = 2.4.10
hamcrestCoreVersion = 1.3
ivyVersion = 2.4.0
jacocoVersion = 0.8.2
jansiVersion = 1.15
jlineVersion = 2.14.6
jline3Version = 3.9.0
junitDepVersion = 4.11
junitVersion = 4.12
# projectPreviousReleaseVersion is non-SNAPSHOT, only published releases
projectPreviousReleaseVersion = 3\\.9\\.5
# projectPreviousVersionRegex may be a SNAPSHOT
projectPreviousVersionRegex = 3\\.9\\.6-SNAPSHOT
projectVersion = 3.9.6
releaseDate = 2019-04-06
releaseDatePreviousRegex = 2019\\-02\\-18
systemRulesVersion = 1.17.1 picocli-3.9.6/gradle/ 0000775 0000000 0000000 00000000000 13457642030 0014415 5 ustar 00root root 0000000 0000000 picocli-3.9.6/gradle/jacoco.gradle 0000664 0000000 0000000 00000000756 13457642030 0017043 0 ustar 00root root 0000000 0000000 apply plugin: 'java'
apply plugin: 'jacoco'
jacoco {
toolVersion = "$jacocoVersion"
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled false
}
}
jacocoTestCoverageVerification {
violationRules {
rule {
limit {
minimum = 0.98
}
}
}
}
// run coverage verification during the build (and fail when appropriate)
check.finalizedBy jacocoTestCoverageVerification
check.finalizedBy jacocoTestReport
picocli-3.9.6/picocli-codegen/ 0000775 0000000 0000000 00000000000 13457642030 0016203 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/README.md 0000664 0000000 0000000 00000010561 13457642030 0017465 0 ustar 00root root 0000000 0000000
# Picocli Code Generation
Picocli Code Generation contains tools for generating source code, documentation and configuration files
for picocli-based applications.
## ReflectionConfigGenerator Tool for AOT Compilation to Native Image on GraalVM
`ReflectionConfigGenerator` generates a JSON String with the program elements that will be accessed reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native executable with GraalVM.
The output of `ReflectionConfigGenerator` is intended to be passed to the `-H:ReflectionConfigurationFiles=/path/to/reflectconfig` option of the `native-image` GraalVM utility. This allows picocli-based applications to be compiled to a native image.
See [Picocli on GraalVM: Blazingly Fast Command Line Apps](https://github.com/remkop/picocli/wiki/Picocli-on-GraalVM:-Blazingly-Fast-Command-Line-Apps) for details.
### Generating GraalVM Reflection Configuration During the Build
Below shows some examples of configuring your build to generate a GraalVM reflection configuration file with the `ReflectionConfigGenerator` tool during the build.
Note that the `--output` option allows you to specify the path to the file to write the configuration to.
When this option is omitted, the output is sent to standard out.
The `ReflectionConfigGenerator` tool accepts any number of fully qualified class names of command classes
(classes with picocli annotations like `@Command`, `@Option` and `@Parameters`).
The resulting configuration file will contain entries for the reflected elements of all specified classes.
#### Maven
For Maven, add an `exec:java` goal to generate a Graal reflection configuration file with the `ReflectionConfigGenerator` tool.
This example uses the `process-classes` phase of the build, there are [alternatives](http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html).
Note that the `picocli-codegen` module is only added as a dependency for the `exec` plugin, so it does not need to be added to the project dependencies.
```xml
org.codehaus.mojo
exec-maven-plugin
1.6.0
generateGraalReflectionConfig
process-classes
java
true
true
picocli.codegen.aot.graalvm.ReflectionConfigGenerator
--output=target/cli-reflect.json
com.your.package.YourCommand1
com.your.package.YourCommand2
info.picocli
picocli-codegen
3.9.6
jar
```
#### Gradle
For Gradle, add a custom configuration for the `picocli-codegen` module to your `gradle.build`.
This allows us to add this module to the classpath of our custom task without adding it as a dependency to the "standard" build.
```gradle
configurations {
generateConfig
}
dependencies {
compile 'info.picocli:picocli:3.9.6'
generateConfig 'info.picocli:picocli-codegen:3.9.6'
}
```
Then, add a custom task to run the `ReflectionConfigGenerator` tool.
This example generates the file during the `assemble` lifecycle task, there are [alternatives](https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_tasks).
```gradle
task(generateGraalReflectionConfig, dependsOn: 'classes', type: JavaExec) {
main = 'picocli.codegen.aot.graalvm.ReflectionConfigGenerator'
classpath = configurations.generateConfig + sourceSets.main.runtimeClasspath
def outputFile = new File(project.buildDir, 'cli-reflect.json')
args = ["--output=$outputFile", 'com.your.package.YourCommand1', 'com.your.package.YourCommand2']
}
assemble.dependsOn generateGraalReflectionConfig
``` picocli-3.9.6/picocli-codegen/build.gradle 0000664 0000000 0000000 00000007046 13457642030 0020471 0 ustar 00root root 0000000 0000000 plugins {
id 'java'
id 'distribution'
id 'maven-publish'
id 'com.jfrog.bintray'
}
group 'info.picocli'
description 'Picocli Code Generation - Tools to generate documentation, configuration, source code and other files from a picocli model.'
version "$projectVersion"
dependencies {
compile rootProject
testCompile "junit:junit:$junitVersion"
}
jar {
manifest {
attributes 'Specification-Title' : 'Picocli Code Generation',
'Specification-Vendor' : 'Remko Popma',
'Specification-Version' : version,
'Implementation-Title' : 'Picocli Code Generation',
'Implementation-Vendor' : 'Remko Popma',
'Implementation-Version': version,
'Automatic-Module-Name' : 'info.picocli.codegen'
}
}
ext {
bintrayPackage = 'picocli-codegen'
bintrayWebsiteUrl = 'https://github.com/remkop/picocli/tree/master/picocli-codegen'
bintrayLabels = ['cli', 'cli framework', 'command line', 'codegen', 'picocli']
}
bintray {
user = bintrayUsername
key = bintrayApiKey
publications = ['MyPublication']
dryRun = bintrayDryRun //[Default: false] Whether to run this as dry-run, without deploying
publish = bintrayPublish //[Default: false] Whether version should be auto published after an upload
override = bintrayOverride //[Default: false] Whether to override version artifacts already published
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'picocli'
name = bintrayPackage
userOrg = 'remkop'
licenses = ['Apache-2.0']
desc = description
websiteUrl = bintrayWebsiteUrl
issueTrackerUrl = 'https://github.com/remkop/picocli/issues'
vcsUrl = 'https://github.com/remkop/picocli.git'
labels = bintrayLabels
publicDownloadNumbers = false
version {
name = "$projectVersion"
desc = description
released = new Date()
vcsTag = "v$projectVersion"
mavenCentralSync {
sync = mavenOssSync //[Default: true] Determines whether to sync the version to Maven Central.
user = mavenOssUser //OSS user token: mandatory
password = mavenOssPassword //OSS user password: mandatory
close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
}
}
}
}
publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact sourcesJar
artifact testJar
artifact testSourcesJar
artifact javadocJar
groupId 'info.picocli'
artifactId bintrayPackage
version "$projectVersion"
pom.withXml {
def root = asNode()
root.appendNode('packaging', 'jar')
root.appendNode('name', bintrayPackage)
root.appendNode('description', description)
root.appendNode('url', 'http://picocli.info')
root.appendNode('inceptionYear', '2018')
root.children().last() + pomConfig
}
}
}
}
picocli-3.9.6/picocli-codegen/src/ 0000775 0000000 0000000 00000000000 13457642030 0016772 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/ 0000775 0000000 0000000 00000000000 13457642030 0017716 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/ 0000775 0000000 0000000 00000000000 13457642030 0020637 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0022261 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/picocli/codegen/ 0000775 0000000 0000000 00000000000 13457642030 0023665 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/picocli/codegen/aot/ 0000775 0000000 0000000 00000000000 13457642030 0024450 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm/ 0000775 0000000 0000000 00000000000 13457642030 0026101 5 ustar 00root root 0000000 0000000 ReflectionConfigGenerator.java 0000664 0000000 0000000 00000051054 13457642030 0033761 0 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/main/java/picocli/codegen/aot/graalvm package picocli.codegen.aot.graalvm;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Model.ArgSpec;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.IGetter;
import picocli.CommandLine.Model.ISetter;
import picocli.CommandLine.Model.OptionSpec;
import picocli.CommandLine.Model.PositionalParamSpec;
import picocli.CommandLine.Model.UnmatchedArgsBinding;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.util.*;
import java.util.concurrent.Callable;
/**
* {@code ReflectionConfigGenerator} generates a JSON String with the program elements that will be accessed
* reflectively in a picocli-based application, in order to compile this application ahead-of-time into a native
* executable with GraalVM.
*
* GraalVM has limited support for Java
* reflection and it needs to know ahead of time the reflectively accessed program elements.
*
* The output of {@code ReflectionConfigGenerator} is intended to be passed to the {@code -H:ReflectionConfigurationFiles=/path/to/reflectconfig}
* option of the {@code native-image} GraalVM utility .
* This allows picocli-based applications to be compiled to a native image.
*
* If necessary, it is possible to exclude classes with system property {@code picocli.codegen.excludes},
* which accepts a comma-separated list of regular expressions of the fully qualified class names that should
* not be included in the resulting JSON String.
*
*
* @since 3.7.0
*/
public class ReflectionConfigGenerator {
private static final String SYSPROP_CODEGEN_EXCLUDES = "picocli.codegen.excludes";
private static final String REFLECTED_FIELD_BINDING_CLASS = "picocli.CommandLine$Model$FieldBinding";
private static final String REFLECTED_METHOD_BINDING_CLASS = "picocli.CommandLine$Model$MethodBinding";
private static final String REFLECTED_FIELD_BINDING_FIELD = "field";
private static final String REFLECTED_METHOD_BINDING_METHOD = "method";
private static final String REFLECTED_BINDING_FIELD_SCOPE = "scope";
@Command(name = "ReflectionConfigGenerator",
description = {"Generates a JSON file with the program elements that will be " +
"accessed reflectively for the specified @Command classes. " +
"The generated JSON file can be passed to the -H:ReflectionConfigurationFiles=/path/to/reflectconfig " +
"option of the `native-image` GraalVM utility.",
"See https://github.com/oracle/graal/blob/master/substratevm/REFLECTION.md"},
mixinStandardHelpOptions = true, version = "picocli-codegen ReflectionConfigGenerator 3.7.0")
private static class App implements Callable {
@Parameters(arity = "1..*", description = "One or more classes to generate a GraalVM ReflectionConfiguration for.")
Class>[] classes = new Class>[0];
@Option(names = {"-o", "--output"}, description = "Output file to write the configuration to. " +
"If not specified, the configuration is written to the standard output stream.")
File outputFile;
public Void call() throws NoSuchFieldException, IllegalAccessException, IOException {
List specs = new ArrayList();
for (Class> cls : classes) {
specs.add(new CommandLine(cls).getCommandSpec());
}
String result = new ReflectionConfigGenerator().generateReflectionConfig(specs.toArray(new CommandSpec[0]));
if (result != null) {
if (outputFile == null) {
System.out.print(result);
} else {
writeToFile(result);
}
}
return null;
}
private void writeToFile(String result) throws IOException {
FileWriter writer = null;
try {
writer = new FileWriter(outputFile);
writer.write(result);
} finally {
if (writer != null) {
writer.close();
}
}
}
}
/**
* Runs this class as a standalone application, printing the resulting JSON String to a file or to {@code System.out}.
* @param args one or more fully qualified class names of {@code @Command}-annotated classes.
*/
public static void main(String... args) {
CommandLine.call(new App(), args);
}
/**
* Returns a JSON String with the program elements that will be accessed reflectively for the specified
* {@code CommandSpec} objects.
*
* @param specs one or more {@code CommandSpec} objects to inspect
* @return a JSON String in the format
* required by the {@code -H:ReflectionConfigurationFiles=/path/to/reflectconfig} option of the GraalVM {@code native-image} utility.
* @throws NoSuchFieldException if a problem occurs while processing the specified specs
* @throws IllegalAccessException if a problem occurs while processing the specified specs
*/
public String generateReflectionConfig(CommandSpec... specs) throws NoSuchFieldException, IllegalAccessException {
Visitor visitor = new Visitor();
for (CommandSpec spec : specs) {
visitor.visitCommandSpec(spec);
}
return generateReflectionConfig(visitor).toString();
}
StringBuilder generateReflectionConfig(Visitor visited) {
StringBuilder result = new StringBuilder(1024);
String prefix = String.format("[%n");
String suffix = String.format("%n]%n");
for (ReflectedClass cls : visited.visited.values()) {
result.append(prefix).append(cls);
prefix = String.format(",%n");
}
return result.append(suffix);
}
static final class Visitor {
Map visited = new TreeMap();
Visitor() {
getOrCreateClass(Method.class);
getOrCreateClassName("java.lang.reflect.Executable").addMethod("getParameters");
getOrCreateClassName("java.lang.reflect.Parameter").addMethod("getName");
// ANSI color enabled detection
getOrCreateClassName("java.lang.System").addMethod("console");
getOrCreateClassName("org.fusesource.jansi.AnsiConsole").addField("out", false);
// picocli 4.0
getOrCreateClassName("java.util.ResourceBundle").addMethod("getBaseBundleName");
// type converters registered with reflection
getOrCreateClassName("java.time.Duration").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.Instant").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.LocalDate").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.LocalDateTime").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.LocalTime").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.MonthDay").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.OffsetDateTime").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.OffsetTime").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.Period").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.Year").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.YearMonth").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.ZonedDateTime").addMethod("parse", CharSequence.class);
getOrCreateClassName("java.time.ZoneId").addMethod("of", String.class);
getOrCreateClassName("java.time.ZoneOffset").addMethod("of", String.class);
getOrCreateClassName("java.nio.file.Path");
getOrCreateClassName("java.nio.file.Paths").addMethod("get", String.class, String[].class);
getOrCreateClassName("java.sql.Connection");
getOrCreateClassName("java.sql.Driver");
getOrCreateClassName("java.sql.DriverManager")
.addMethod("getConnection", String.class)
.addMethod("getDriver", String.class);
getOrCreateClassName("java.sql.Timestamp").addMethod("valueOf", String.class);
}
void visitCommandSpec(CommandSpec spec) throws NoSuchFieldException, IllegalAccessException {
if (spec.userObject() != null) {
if (spec.userObject() instanceof Method) {
Method method = (Method) spec.userObject();
ReflectedClass cls = getOrCreateClass(method.getDeclaringClass());
cls.addMethod(method.getName(), method.getParameterTypes());
} else if (Proxy.isProxyClass(spec.userObject().getClass())) {
// do nothing
} else {
visitAnnotatedFields(spec.userObject().getClass());
}
}
visitObjectType(spec.versionProvider());
visitObjectType(spec.defaultValueProvider());
for (UnmatchedArgsBinding binding : spec.unmatchedArgsBindings()) {
visitGetter(binding.getter());
visitSetter(binding.setter());
}
for (OptionSpec option : spec.options()) {
visitArgSpec(option);
}
for (PositionalParamSpec positional : spec.positionalParameters()) {
visitArgSpec(positional);
}
for (CommandSpec mixin : spec.mixins().values()) {
visitCommandSpec(mixin);
}
for (CommandLine sub : spec.subcommands().values()) {
visitCommandSpec(sub.getCommandSpec());
}
}
private void visitAnnotatedFields(Class> cls) {
if (cls == null) {
return;
}
ReflectedClass reflectedClass = getOrCreateClass(cls);
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
if (f.isAnnotationPresent(CommandLine.Spec.class)) {
reflectedClass.addField(f.getName(), isFinal(f));
}
if (f.isAnnotationPresent(CommandLine.ParentCommand.class)) {
reflectedClass.addField(f.getName(), isFinal(f));
}
if (f.isAnnotationPresent(CommandLine.Mixin.class)) {
reflectedClass.addField(f.getName(), isFinal(f));
}
if (f.isAnnotationPresent(CommandLine.Unmatched.class)) {
reflectedClass.addField(f.getName(), isFinal(f));
}
}
visitAnnotatedFields(cls.getSuperclass());
}
private boolean isFinal(Field f) {
return (f.getModifiers() & Modifier.FINAL) == Modifier.FINAL;
}
private void visitArgSpec(ArgSpec argSpec) throws NoSuchFieldException, IllegalAccessException {
visitGetter(argSpec.getter());
visitSetter(argSpec.setter());
visitType(argSpec.type());
visitTypes(argSpec.auxiliaryTypes());
visitObjectType(argSpec.completionCandidates());
visitObjectTypes(argSpec.converters());
}
private void visitTypes(Class>[] classes) {
for (Class> cls : classes) { visitType(cls); }
}
private void visitType(Class> type) {
if (type != null) { getOrCreateClass(type); }
}
private void visitObjectType(Object object) {
if (object != null) { visitType(object.getClass()); }
}
private void visitObjectTypes(Object[] array) {
if (array != null) {
for (Object element : array) { visitObjectType(element); }
}
}
private void visitGetter(IGetter getter) throws NoSuchFieldException, IllegalAccessException {
if (getter == null) {
return;
}
if (REFLECTED_FIELD_BINDING_CLASS.equals(getter.getClass().getName())) {
visitFieldBinding(getter);
}
if (REFLECTED_METHOD_BINDING_CLASS.equals(getter.getClass().getName())) {
visitMethodBinding(getter);
}
}
private void visitSetter(ISetter setter) throws NoSuchFieldException, IllegalAccessException {
if (setter == null) {
return;
}
if (REFLECTED_FIELD_BINDING_CLASS.equals(setter.getClass().getName())) {
visitFieldBinding(setter);
}
if (REFLECTED_METHOD_BINDING_CLASS.equals(setter.getClass().getName())) {
visitMethodBinding(setter);
}
}
private void visitFieldBinding(Object fieldBinding) throws IllegalAccessException, NoSuchFieldException {
Field field = (Field) accessibleField(fieldBinding.getClass(), REFLECTED_FIELD_BINDING_FIELD).get(fieldBinding);
getOrCreateClass(field.getDeclaringClass())
.addField(field.getName(), isFinal(field));
Object scope = accessibleField(fieldBinding.getClass(), REFLECTED_BINDING_FIELD_SCOPE).get(fieldBinding);
getOrCreateClass(scope.getClass());
}
private void visitMethodBinding(Object methodBinding) throws IllegalAccessException, NoSuchFieldException {
Method method = (Method) accessibleField(methodBinding.getClass(), REFLECTED_METHOD_BINDING_METHOD).get(methodBinding);
ReflectedClass cls = getOrCreateClass(method.getDeclaringClass());
cls.addMethod(method.getName(), method.getParameterTypes());
Object scope = accessibleField(methodBinding.getClass(), REFLECTED_BINDING_FIELD_SCOPE).get(methodBinding);
ReflectedClass scopeClass = getOrCreateClass(scope.getClass());
if (!scope.getClass().equals(method.getDeclaringClass())) {
scopeClass.addMethod(method.getName(), method.getParameterTypes());
}
}
private static Field accessibleField(Class> cls, String fieldName) throws NoSuchFieldException {
Field field = cls.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
}
ReflectedClass getOrCreateClass(Class> cls) {
if (cls.isPrimitive()) {
return new ReflectedClass(cls.getName()); // don't store
}
return getOrCreateClassName(cls.getName());
}
private ReflectedClass getOrCreateClassName(String name) {
ReflectedClass result = visited.get(name);
if (result == null) {
result = new ReflectedClass(name);
if (!excluded(name)) {
visited.put(name, result);
}
}
return result;
}
static boolean excluded(String fqcn) {
String[] excludes = System.getProperty(SYSPROP_CODEGEN_EXCLUDES, "").split(",");
for (String regex : excludes) {
if (fqcn.matches(regex)) {
System.err.printf("Class %s is excluded: (%s=%s)%n", fqcn, SYSPROP_CODEGEN_EXCLUDES, System.getProperty(SYSPROP_CODEGEN_EXCLUDES));
return true;
}
}
return false;
}
}
static class ReflectedClass {
private final String name;
private final Set fields = new TreeSet();
private final Set methods = new TreeSet();
ReflectedClass(String name) {
this.name = name;
}
ReflectedClass addField(String fieldName, boolean isFinal) {
fields.add(new ReflectedField(fieldName, isFinal));
return this;
}
ReflectedClass addMethod0(String methodName, String... paramTypes) {
methods.add(new ReflectedMethod(methodName, paramTypes));
return this;
}
ReflectedClass addMethod(String methodName, Class... paramClasses) {
String[] paramTypes = new String[paramClasses.length];
for (int i = 0; i < paramClasses.length; i++) {
paramTypes[i] = paramClasses[i].getName();
}
return addMethod0(methodName, paramTypes);
}
@Override
public String toString() {
String result = String.format("" +
" {%n" +
" \"name\" : \"%s\",%n" +
" \"allDeclaredConstructors\" : true,%n" +
" \"allPublicConstructors\" : true,%n" +
" \"allDeclaredMethods\" : true,%n" +
" \"allPublicMethods\" : true", name);
if (!fields.isEmpty()) {
result += String.format(",%n \"fields\" : ");
String prefix = String.format("[%n"); // start JSON array
for (ReflectedField field : fields) {
result += String.format("%s %s", prefix, field);
prefix = String.format(",%n");
}
result += String.format("%n ]"); // end JSON array
}
if (!methods.isEmpty()) {
result += String.format(",%n \"methods\" : ");
String prefix = String.format("[%n"); // start JSON array
for (ReflectedMethod method : methods) {
result += String.format("%s %s", prefix, method);
prefix = String.format(",%n");
}
result += String.format("%n ]"); // end JSON array
}
result += String.format("%n }");
return result;
}
}
static class ReflectedMethod implements Comparable {
private final String name;
private final String[] paramTypes;
ReflectedMethod(String name, String... paramTypes) {
this.name = name;
this.paramTypes = paramTypes.clone();
}
@Override public int hashCode() { return name.hashCode() * Arrays.hashCode(paramTypes); }
@Override public boolean equals(Object o) {
return o instanceof ReflectedMethod
&& ((ReflectedMethod) o).name.equals(name)
&& Arrays.equals(((ReflectedMethod) o).paramTypes, paramTypes);
}
@Override
public String toString() {
return String.format("{ \"name\" : \"%s\", \"parameterTypes\" : [%s] }", name, formatParamTypes());
}
private String formatParamTypes() {
StringBuilder result = new StringBuilder();
for (String type : paramTypes) {
if (result.length() > 0) {
result.append(", ");
}
result.append('"').append(type).append('"');
}
return result.toString();
}
public int compareTo(ReflectedMethod o) {
int result = name.compareTo(o.name);
if (result == 0) {
result = Arrays.toString(this.paramTypes).compareTo(Arrays.toString(o.paramTypes));
}
return result;
}
}
static class ReflectedField implements Comparable {
private final String name;
private final boolean isFinal;
ReflectedField(String name, boolean isFinal) {
this.name = name;
this.isFinal = isFinal;
}
@Override public int hashCode() { return name.hashCode(); }
@Override public boolean equals(Object o) {
return o instanceof ReflectedField && ((ReflectedField) o).name.equals(name);
}
@Override
public String toString() {
return isFinal
? String.format("{ \"name\" : \"%s\", \"allowWrite\" : true }", name)
: String.format("{ \"name\" : \"%s\" }", name);
}
public int compareTo(ReflectedField o) {
return name.compareTo(o.name);
}
}
}
picocli-3.9.6/picocli-codegen/src/test/ 0000775 0000000 0000000 00000000000 13457642030 0017751 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/ 0000775 0000000 0000000 00000000000 13457642030 0020672 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0022314 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/ 0000775 0000000 0000000 00000000000 13457642030 0023720 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/ 0000775 0000000 0000000 00000000000 13457642030 0024503 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/ 0000775 0000000 0000000 00000000000 13457642030 0026134 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Example.java 0000664 0000000 0000000 00000004271 13457642030 0030376 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Parameters;
import picocli.CommandLine.Spec;
import picocli.CommandLine.Unmatched;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Command(name = "example", version = "3.7.0",
mixinStandardHelpOptions = true, subcommands = CommandLine.HelpCommand.class)
public class Example implements Runnable {
@Command public static class ExampleMixin {
@Option(names = "-l")
int length;
}
@Option(names = "-t")
final TimeUnit timeUnit = TimeUnit.SECONDS;
@Parameters(index = "0")
File file;
@Spec
CommandSpec spec;
@Mixin
ExampleMixin mixin;
@Unmatched
final List unmatched = new ArrayList();
private int minimum;
private List otherFiles;
@Command
int multiply(@Option(names = "--count") int count,
@Parameters int multiplier) {
System.out.println("Result is " + count * multiplier);
return count * multiplier;
}
@Option(names = "--minimum")
public void setMinimum(int min) {
if (min < 0) {
throw new ParameterException(spec.commandLine(), "Minimum must be a positive integer");
}
minimum = min;
}
@Parameters(index = "1..*")
public void setOtherFiles(List otherFiles) {
for (File f : otherFiles) {
if (!f.exists()) {
throw new ParameterException(spec.commandLine(), "File " + f.getAbsolutePath() + " must exist");
}
}
this.otherFiles = otherFiles;
}
public void run() {
System.out.printf("timeUnit=%s, length=%s, file=%s, unmatched=%s, minimum=%s, otherFiles=%s%n",
timeUnit, mixin.length, file, unmatched, minimum, otherFiles.toString());
}
public static void main(String[] args) {
CommandLine.run(new Example(), args);
}
}
picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Issue622AbstractCommand.java0000664 0000000 0000000 00000000377 13457642030 0033313 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
public class Issue622AbstractCommand {
@Option(names = "-v")
boolean verbose;
@Parameters
File file;
}
picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Issue622App.java 0000664 0000000 0000000 00000000337 13457642030 0030765 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine.Command;
@Command(name = "app", subcommands = {Issue622Command1.class, Issue622Command2.class})
public class Issue622App extends Issue622AbstractCommand {
}
picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Issue622Command1.java 0000664 0000000 0000000 00000000245 13457642030 0031702 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine.Command;
@Command(name = "cmd1")
public class Issue622Command1 extends Issue622AbstractCommand {
}
picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Issue622Command2.java 0000664 0000000 0000000 00000000426 13457642030 0031704 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "cmd2", subcommands = Issue622Command2Sub.class)
public class Issue622Command2 extends Issue622AbstractCommand {
@Option(names = "-x")
int x;
}
picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm/Issue622Command2Sub.java 0000664 0000000 0000000 00000000357 13457642030 0032361 0 ustar 00root root 0000000 0000000 package picocli.codegen.aot.graalvm;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(name = "sub")
public class Issue622Command2Sub extends Issue622AbstractCommand {
@Option(names = "-x")
int x;
}
ReflectionConfigGeneratorTest.java 0000664 0000000 0000000 00000004712 13457642030 0034653 0 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/java/picocli/codegen/aot/graalvm package picocli.codegen.aot.graalvm;
import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import static org.junit.Assert.assertEquals;
public class ReflectionConfigGeneratorTest {
@Test
public void testMainStdOut() throws IOException {
PrintStream old = System.out;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
System.setOut(new PrintStream(baos));
try {
ReflectionConfigGenerator.main(Example.class.getName());
} finally {
System.setOut(old);
}
String expected = read("/example-reflect.json");
expected = expected.replace("\r\n", "\n");
expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals(expected, baos.toString());
}
@Test
public void testMainOutputFile() throws IOException {
File file = File.createTempFile("picocli-codegen", ".json");
ReflectionConfigGenerator.main("--output", file.getAbsolutePath(), Example.class.getName());
String expected = read("/example-reflect.json");
expected = expected.replace("\r\n", "\n");
expected = expected.replace("\n", System.getProperty("line.separator"));
String actual = readAndClose(new FileInputStream(file));
file.delete();
assertEquals(expected, actual);
}
@Test
public void testIssue622FieldsFromAbstractSuperclass() throws IOException {
File file = File.createTempFile("picocli-codegen", ".json");
ReflectionConfigGenerator.main("--output", file.getAbsolutePath(), Issue622App.class.getName());
String expected = read("/issue622-reflect.json");
expected = expected.replace("\r\n", "\n");
expected = expected.replace("\n", System.getProperty("line.separator"));
String actual = readAndClose(new FileInputStream(file));
file.delete();
assertEquals(expected, actual);
}
private String read(String resource) throws IOException {
return readAndClose(getClass().getResourceAsStream(resource));
}
private String readAndClose(InputStream in) throws IOException {
try {
byte[] buff = new byte[15000];
int size = in.read(buff);
return new String(buff, 0, size);
} finally {
in.close();
}
}
}
picocli-3.9.6/picocli-codegen/src/test/resources/ 0000775 0000000 0000000 00000000000 13457642030 0021763 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-codegen/src/test/resources/example-reflect.json 0000664 0000000 0000000 00000022701 13457642030 0025735 0 ustar 00root root 0000000 0000000 [
{
"name" : "[Ljava.lang.String;",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.io.File",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.Object",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.String",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.System",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "console", "parameterTypes" : [] }
]
},
{
"name" : "java.lang.reflect.Executable",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getParameters", "parameterTypes" : [] }
]
},
{
"name" : "java.lang.reflect.Method",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.reflect.Parameter",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getName", "parameterTypes" : [] }
]
},
{
"name" : "java.nio.file.Path",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.nio.file.Paths",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "get", "parameterTypes" : ["java.lang.String", "[Ljava.lang.String;"] }
]
},
{
"name" : "java.sql.Connection",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.sql.Driver",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.sql.DriverManager",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getConnection", "parameterTypes" : ["java.lang.String"] },
{ "name" : "getDriver", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.sql.Timestamp",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "valueOf", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.Duration",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Instant",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalDate",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.MonthDay",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.OffsetDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.OffsetTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Period",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Year",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.YearMonth",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.ZoneId",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "of", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.ZoneOffset",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "of", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.ZonedDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.util.Collections$UnmodifiableRandomAccessList",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.util.List",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.util.ResourceBundle",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getBaseBundleName", "parameterTypes" : [] }
]
},
{
"name" : "java.util.concurrent.TimeUnit",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "org.fusesource.jansi.AnsiConsole",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "out" }
]
},
{
"name" : "picocli.CommandLine$AutoHelpMixin",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "helpRequested" },
{ "name" : "versionRequested" }
]
},
{
"name" : "picocli.CommandLine$HelpCommand",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "commands" },
{ "name" : "helpRequested" }
]
},
{
"name" : "picocli.codegen.aot.graalvm.Example",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "file" },
{ "name" : "mixin" },
{ "name" : "spec" },
{ "name" : "timeUnit", "allowWrite" : true },
{ "name" : "unmatched", "allowWrite" : true }
],
"methods" : [
{ "name" : "multiply", "parameterTypes" : ["int", "int"] },
{ "name" : "setMinimum", "parameterTypes" : ["int"] },
{ "name" : "setOtherFiles", "parameterTypes" : ["java.util.List"] }
]
},
{
"name" : "picocli.codegen.aot.graalvm.Example$ExampleMixin",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "length" }
]
}
]
picocli-3.9.6/picocli-codegen/src/test/resources/issue622-reflect.json 0000664 0000000 0000000 00000020415 13457642030 0025664 0 ustar 00root root 0000000 0000000 [
{
"name" : "java.io.File",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.Object",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.System",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "console", "parameterTypes" : [] }
]
},
{
"name" : "java.lang.reflect.Executable",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getParameters", "parameterTypes" : [] }
]
},
{
"name" : "java.lang.reflect.Method",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.lang.reflect.Parameter",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getName", "parameterTypes" : [] }
]
},
{
"name" : "java.nio.file.Path",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.nio.file.Paths",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "get", "parameterTypes" : ["java.lang.String", "[Ljava.lang.String;"] }
]
},
{
"name" : "java.sql.Connection",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.sql.Driver",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "java.sql.DriverManager",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getConnection", "parameterTypes" : ["java.lang.String"] },
{ "name" : "getDriver", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.sql.Timestamp",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "valueOf", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.Duration",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Instant",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalDate",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.LocalTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.MonthDay",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.OffsetDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.OffsetTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Period",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.Year",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.YearMonth",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.time.ZoneId",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "of", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.ZoneOffset",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "of", "parameterTypes" : ["java.lang.String"] }
]
},
{
"name" : "java.time.ZonedDateTime",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "parse", "parameterTypes" : ["java.lang.CharSequence"] }
]
},
{
"name" : "java.util.ResourceBundle",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"methods" : [
{ "name" : "getBaseBundleName", "parameterTypes" : [] }
]
},
{
"name" : "org.fusesource.jansi.AnsiConsole",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "out" }
]
},
{
"name" : "picocli.codegen.aot.graalvm.Issue622AbstractCommand",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "file" },
{ "name" : "verbose" }
]
},
{
"name" : "picocli.codegen.aot.graalvm.Issue622App",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "picocli.codegen.aot.graalvm.Issue622Command1",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true
},
{
"name" : "picocli.codegen.aot.graalvm.Issue622Command2",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "x" }
]
},
{
"name" : "picocli.codegen.aot.graalvm.Issue622Command2Sub",
"allDeclaredConstructors" : true,
"allPublicConstructors" : true,
"allDeclaredMethods" : true,
"allPublicMethods" : true,
"fields" : [
{ "name" : "x" }
]
}
]
picocli-3.9.6/picocli-examples/ 0000775 0000000 0000000 00000000000 13457642030 0016415 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/build.gradle 0000664 0000000 0000000 00000002077 13457642030 0020702 0 ustar 00root root 0000000 0000000 description 'Java and Groovy examples for the picocli project.'
dependencies {
compile rootProject
compile "org.apache.ivy:ivy:$ivyVersion", // for Intelli/J
"org.codehaus.groovy:groovy-all:$groovyVersion"
}
def generatedResources = "$buildDir/generated-resources/main"
sourceSets {
main {
//register an output folder on the main SourceSet:
output.dir(generatedResources, builtBy: 'generateVersionTxt')
//it is now a part of the 'main' classpath and will be a part of the jar
}
}
//a task that generates the resources for the example VersionProviderDemo1:
task generateVersionTxt {
description 'Creates a version.txt file with build info that is added to the root of the picocli-examples jar'
doLast {
new File(generatedResources).mkdirs()
def generated = new File(generatedResources, "version.txt")
generated.text = """
Version: $rootProject.version
Buildtime: ${new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())}
Application-name: $rootProject.name $project.name
"""
}
}
picocli-3.9.6/picocli-examples/src/ 0000775 0000000 0000000 00000000000 13457642030 0017204 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/ 0000775 0000000 0000000 00000000000 13457642030 0020130 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/groovy/ 0000775 0000000 0000000 00000000000 13457642030 0021455 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/groovy/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023077 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/ 0000775 0000000 0000000 00000000000 13457642030 0024715 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/UserManualExample.groovy 0000664 0000000 0000000 00000001227 13457642030 0031556 0 ustar 00root root 0000000 0000000 package picocli.examples
import picocli.CommandLine
import picocli.CommandLine.Command
import picocli.CommandLine.Option
@Command(name = "MyApp", version = "Groovy picocli demo v3.0",
mixinStandardHelpOptions = true,
description = "@|bold Groovy|@ @|underline picocli|@ example")
class UserManualExample implements Runnable {
@Option(names = ["-c", "--count"], paramLabel = "COUNT",
description = "the count")
int count = 0
void run() {
count.times {
println("hello world $it...")
}
}
static void main(String[] args) {
CommandLine.run(new UserManualExample(), args)
}
}
picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/UserManualScriptExample.groovy 0000664 0000000 0000000 00000001304 13457642030 0032737 0 ustar 00root root 0000000 0000000 package picocli.examples
//@Grab('info.picocli:picocli:3.0.0-beta-3-SNAPSHOT')
@Command(name = "myCommand",
mixinStandardHelpOptions = true,
description = "@|bold Groovy script|@ @|underline picocli|@ example")
@picocli.groovy.PicocliScript
import groovy.transform.Field
import static picocli.CommandLine.*
@Option(names = ["-c", "--count"], description = "number of repetitions")
@Field int count = 1;
//if (helpRequested) { // not necessary: PicocliBaseScript takes care of this
// CommandLine.usage(this, System.out); return 0;
//}
count.times {
println "hi"
}
// the CommandLine that parsed the args is available as a property
assert this.commandLine.commandName == "myCommand"
picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/checksum-with-banner.groovy 0000664 0000000 0000000 00000003576 13457642030 0032215 0 ustar 00root root 0000000 0000000 package picocli.examples
@Grab('info.picocli:picocli:2.0.2')
@GrabExclude('org.codehaus.groovy:groovy-all')
@Command(header = [
$/@|bold,green ___ ___ _ _ |@/$,
$/@|bold,green / __|_ _ ___ _____ ___ _ / __| |_ ___ __| |__ ____ _ _ __ |@/$,
$/@|bold,green | (_ | '_/ _ \/ _ \ V / || | | (__| ' \/ -_) _| / /(_-< || | ' \ |@/$,
$/@|bold,green \___|_| \___/\___/\_/ \_, | \___|_||_\___\__|_\_\/__/\_,_|_|_|_||@/$,
$/@|bold,green |__/ |@/$
],
description = "Print a checksum of each specified FILE, using the specified MessageDigest algorithm.",
version = 'checksum v1.2.3', showDefaultValues = true,
footerHeading = "%nFor more details, see:%n",
footer = ["[1] https://docs.oracle.com/javase/9/docs/specs/security/standard-names.html",
"ASCII Art thanks to http://patorjk.com/software/taag/"]
)
@picocli.groovy.PicocliScript
import groovy.transform.Field
import java.security.MessageDigest
import static picocli.CommandLine.*
@Parameters(arity = "1", paramLabel = "FILE", description = "The file(s) whose checksum to calculate.")
@Field private File[] files
@Option(names = ["-a", "--algorithm"], description = ["MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512, or",
" any other MessageDigest algorithm. See [1] for more details."])
@Field private String algorithm = "MD5"
@Option(names = ["-h", "--help"], usageHelp = true, description = "Show this help message and exit.")
@Field private boolean helpRequested
@Option(names = ["-V", "--version"], versionHelp = true, description = "Show version info and exit.")
@Field private boolean versionInfoRequested
files.each {
println MessageDigest.getInstance(algorithm).digest(it.bytes).encodeHex().toString() + "\t" + it
}
picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/checksum-without-base.groovy 0000664 0000000 0000000 00000002236 13457642030 0032402 0 ustar 00root root 0000000 0000000 package picocli.examples
@Grab('info.picocli:picocli:2.0.1')
@GrabExclude('org.codehaus.groovy:groovy-all')
import java.security.MessageDigest
import picocli.CommandLine
import static picocli.CommandLine.*
class Checksum {
@Parameters(arity = "1", paramLabel = "FILE", description = "The file(s) whose checksum to calculate.")
File[] files
@Option(names = ["-a", "--algorithm"], description = ["MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512,",
" or any other MessageDigest algorithm."])
String algorithm = "MD5"
@Option(names = ["-h", "--help"], usageHelp = true, description = "Show this help message and exit.")
boolean helpRequested
}
Checksum checksum = new Checksum()
CommandLine commandLine = new CommandLine(checksum)
try {
commandLine.parse(args)
if (commandLine.usageHelpRequested) {
commandLine.usage(System.out)
} else {
checksum.files.each {
byte[] digest = MessageDigest.getInstance(checksum.algorithm).digest(it.bytes)
println digest.encodeHex().toString() + "\t" + it
}
}
} catch (ParameterException ex) {
println ex.message
commandLine.usage(System.out)
}
picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/checksum.groovy 0000664 0000000 0000000 00000001470 13457642030 0027770 0 ustar 00root root 0000000 0000000 package picocli.examples
@Grab('info.picocli:picocli:2.0.2')
@GrabExclude('org.codehaus.groovy:groovy-all')
@picocli.groovy.PicocliScript
import groovy.transform.Field
import java.security.MessageDigest
import static picocli.CommandLine.*
@Parameters(arity = "1", paramLabel = "FILE", description = "The file(s) whose checksum to calculate.")
@Field private File[] files
@Option(names = ["-a", "--algorithm"], description = ["MD2, MD5, SHA-1, SHA-256, SHA-384, SHA-512,",
" or any other MessageDigest algorithm."])
@Field private String algorithm = "MD5"
@Option(names = ["-h", "--help"], usageHelp = true, description = "Show this help message and exit.")
@Field private boolean helpRequested
files.each {
println MessageDigest.getInstance(algorithm).digest(it.bytes).encodeHex().toString() + "\t" + it
}
picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/dsl/ 0000775 0000000 0000000 00000000000 13457642030 0025477 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/groovy/picocli/examples/dsl/PrototypeDSL.groovy 0000664 0000000 0000000 00000014527 13457642030 0031327 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples.dsl
import picocli.CommandLine
import picocli.CommandLine.Model.CommandSpec
import picocli.CommandLine.Model.OptionSpec
import picocli.CommandLine.Model.PositionalParamSpec
class PrototypeDSL {
static void main(String[] args) {
// The factory method takes key-value pairs for the CommandSpec itself,
// or its UsageMessageSpec or ParserSpec
CliBuilder2 cli = CliBuilder2.create(headerHeading: "test header heading%n", footer: ["test footer"]) {
// CommandSpec attributes
name "dsl-command"
version ("DSL v1.0-alpha1", "Second line")
// UsageMessageSpec attributes
usage {
header ("this is a header", "header line 2")
description "command description"
showDefaultValues true
}
// OptionSpec attributes on a single line
option("-h", "--help") { usageHelp true; type boolean; description "display this help and exit" }
// OptionSpec attributes on multiple lines
option ("-V", "--version") {
versionHelp true
type boolean
description "display version info and exit"
}
option { // names in named attribute
names ("-c", "--count") type int description "Number of times to repeat"
}
positional {index "0..*"; type int; description "a bunch of integers"; paramLabel "INT"}
addSubcommand("sub", create {
usage {description("subcommand description")}
option("-x") {
description("option X description")
}
}.commandSpec)
}
// adding an option outside the closure
cli.option {
names "-o", "--option"
type List
auxiliaryTypes String
description "list of options"
}
new CommandLine(cli.commandSpec).usage(System.out)
println()
cli.commandSpec.subcommands().sub.usage(System.out)
}
// prototype cli builder
static class CliBuilder2 {
private @Delegate CommandSpec commandSpec
// no user object needed when only using programmatic API
CliBuilder2() { this.commandSpec = CommandSpec.create()}
// Alternatively, automatically build (partial) model from annotations.
// This impl uses picocli annotations, but CliBuilder2 could use Groovy cli annotations instead.
CliBuilder2(userObject) { this.commandSpec = CommandSpec.forAnnotatedObject(userObject)}
static CliBuilder2 create(@DelegatesTo(CliBuilder2) Closure c) {
CliBuilder2 spec = new CliBuilder2()
spec.with c
spec
}
static CliBuilder2 create(Map map, @DelegatesTo(CliBuilder2) Closure c) {
def invokeOn = {}
CliBuilder2 cli = new CliBuilder2()
// There is probably a cleaner way to implement this...
// The intention is that key-value pairs are applied to either the CommandSpec itself,
// its UsageMessageSpec or its ParserSpec.
// TODO fail with better error message for unknown keys.
map.each {key, value ->
if (cli.commandSpec.usageMessage().hasProperty(key)) {
cli.commandSpec.usageMessage()[key] = value
return
} else if (CommandLine.Model.UsageMessageSpec.declaredMethods.find {m -> m.name == key} != null) {
if (value instanceof List) {
cli.commandSpec.invokeMethod(key, (value as List).toArray())
} else {
cli.commandSpec.invokeMethod(key, value)
}
return
}
if (cli.commandSpec.hasProperty(key)) {
cli.commandSpec[key] = value
} else {
if (value instanceof List) {
cli.commandSpec.invokeMethod(key, (value as List).toArray())
} else {
cli.commandSpec.invokeMethod(key, value)
}
}
}
cli.with c
cli
}
void option(String names, @DelegatesTo(OptionSpec.Builder) Closure details) { option(details, names) }
void option(String name1, String name2, @DelegatesTo(OptionSpec.Builder) Closure details) { option(details, name1, name2) }
void option(String name1, String name2, String name3, @DelegatesTo(OptionSpec.Builder) Closure details) { option(details, name1, name2, name3) }
void option(@DelegatesTo(OptionSpec.Builder) Closure details, String... names) {
OptionSpec optionSpec = withOption(details, names)
addOption(optionSpec)
}
static OptionSpec withOption(@DelegatesTo(OptionSpec.Builder) Closure details, String... names) {
def optionSpec = OptionSpec.builder(names)
def code = details.rehydrate(optionSpec, this, this)
code.resolveStrategy = Closure.DELEGATE_ONLY
code()
optionSpec.build()
}
void positional(@DelegatesTo(PositionalParamSpec.Builder) Closure details) {
def positionalSpec = PositionalParamSpec.builder()
def code = details.rehydrate(positionalSpec, this, this)
code.resolveStrategy = Closure.DELEGATE_ONLY
code()
addPositional positionalSpec.build()
}
void usage(@DelegatesTo(CommandLine.Model.UsageMessageSpec) Closure details) {
def code = details.rehydrate(commandSpec.usageMessage(), this, this)
code.resolveStrategy = Closure.DELEGATE_ONLY
code()
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/ 0000775 0000000 0000000 00000000000 13457642030 0021051 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/AutomaticHelpDemo.java 0000664 0000000 0000000 00000001413 13457642030 0025257 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// For "Picocli 2.0: Do More With Less" article
public class AutomaticHelpDemo {
public static void main(String[] args) {
picocli.examples.AutomaticHelpDemo.main(args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/Greet.java 0000664 0000000 0000000 00000001363 13457642030 0022765 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// For "Picocli 2.0: Do More With Less" article
public class Greet {
public static void main(String[] args) {
picocli.examples.Greet.main(args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0022473 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/ 0000775 0000000 0000000 00000000000 13457642030 0024311 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/AutomaticHelpDemo.java 0000664 0000000 0000000 00000003642 13457642030 0030525 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import static picocli.CommandLine.*;
@Command(version = "Help demo for picocli v2.0", header = "%nAutomatic Help Demo%n",
description = "Prints usage help and version help when requested.%n",
footer = "See AutomaticHelpDemo3 for the more compact syntax supported by picocli 3.0.")
public class AutomaticHelpDemo implements Runnable {
@Option(names = "--count", description = "The number of times to repeat.")
int count;
@Option(names = {"-h", "--help"}, usageHelp = true,
description = "Print usage help and exit.")
boolean usageHelpRequested;
@Option(names = {"-V", "--version"}, versionHelp = true,
description = "Print version information and exit.")
boolean versionHelpRequested;
public void run() {
// NOTE: code like below is no longer required:
//
// if (usageHelpRequested) {
// new CommandLine(this).usage(System.err);
// } else if (versionHelpRequested) {
// new CommandLine(this).printVersionHelp(System.err);
// } else { ... the business logic
for (int i = 0; i < count; i++) {
System.out.println("Hello world");
}
}
public static void main(String... args) {
CommandLine.run(new AutomaticHelpDemo(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/AutomaticHelpDemo3.java 0000664 0000000 0000000 00000002521 13457642030 0030603 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import static picocli.CommandLine.*;
@Command(version = "Help demo for picocli v3.0", header = "%nFully Automatic Help Demo%n",
description = "Prints usage help and version help when requested.%n",
mixinStandardHelpOptions = true)
public class AutomaticHelpDemo3 implements Runnable {
@Option(names = "--count", description = "The number of times to repeat.")
int count;
public void run() {
for (int i = 0; i < count; i++) {
System.out.println("Hello world");
}
}
// to run, execute:
// java picocli.examples.AutomaticHelpDemo3 help
public static void main(String... args) {
CommandLine.run(new AutomaticHelpDemo3(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/Example.java 0000664 0000000 0000000 00000003372 13457642030 0026554 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.io.File;
/**
* The picocli example in the README.md.
*/
public class Example implements Runnable {
@Option(names = { "-v", "--verbose" }, description = "Verbose mode. Helpful for troubleshooting. " +
"Multiple -v options increase the verbosity.")
private boolean[] verbose = new boolean[0];
@Option(names = { "-h", "--help" }, usageHelp = true,
description = "Displays this help message and quits.")
private boolean helpRequested = false;
@Parameters(arity = "1..*", paramLabel = "FILE", description = "File(s) to process.")
private File[] inputFiles;
public void run() {
if (verbose.length > 0) {
System.out.println(inputFiles.length + " files to process...");
}
if (verbose.length > 1) {
for (File f : inputFiles) {
System.out.println(f.getAbsolutePath());
}
}
}
public static void main(String[] args) {
CommandLine.run(new Example(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/ExitCodeDemo.java 0000664 0000000 0000000 00000002320 13457642030 0027462 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.ParameterException;
import java.util.Collections;
import java.util.List;
@Command
public class ExitCodeDemo implements Runnable {
public void run() { throw new ParameterException(new CommandLine(this), "exit code demo"); }
public static void main(String... args) {
CommandLine cmd = new CommandLine(new ExitCodeDemo());
cmd.parseWithHandlers(
new CommandLine.RunLast().andExit(123),
CommandLine.defaultExceptionHandler().andExit(456),
args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/Greet.java 0000664 0000000 0000000 00000002066 13457642030 0026226 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import static picocli.CommandLine.*;
@Command(name = "Greet", header = "%n@|green Hello world demo|@")
public class Greet implements Runnable {
@Option(names = {"-u", "--user"}, required = true, description = "The user name.")
String userName;
public void run() {
System.out.println("Hello, " + userName);
}
public static void main(String... args) {
CommandLine.run(new Greet(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/PopulateFlagsMain.java 0000664 0000000 0000000 00000006756 13457642030 0030545 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Robert 'Bobby' Zenz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
/**
* This example demonstrates the usage with a simple flag class.
*
*
*
* When no arguments are provided, the flags will have their default values:
*
*
* Arguments:
*
*
* Options:
* buffered: false
* overwriteOutput: true
* verbose: false
*
*
* When the flag is provided in the arguments, the default value of the flag
* will be inverted and set. So if we can provide all flags as arguments:
*
*
* Arguments:
* "-b" "-o" "-v"
*
* Options:
* buffered: true
* overwriteOutput: false
* verbose: true
*
*
* Because these flags are single letter names, we can also provide them
* concatenated in one argument:
*
*
* Arguments:
* "-bov"
*
* Options:
* buffered: true
* overwriteOutput: false
* verbose: true
*
*
* Or in any derivation there of.
*
* @author Robert 'Bobby' Zenz
*/
public class PopulateFlagsMain {
public static void main(String[] args) {
// Create a new Options class, which holds our flags.
Options options = new Options();
try {
// Populate the created class from the command line arguments.
CommandLine.populateCommand(options, args);
} catch (ParameterException e) {
// The given command line arguments are invalid, for example there
// are options specified which do not exist or one of the options
// is malformed (missing a value, for example).
System.out.println(e.getMessage());
CommandLine.usage(options, System.out);
return;
}
// Print the state.
System.out.println("Arguments:");
System.out.print(" ");
for (String arg : args) {
System.out.print("\"" + arg + "\" ");
}
System.out.println();
System.out.println();
System.out.println("Options:");
System.out.println(" buffered: " + options.isBuffered());
System.out.println(" overwriteOutput: " + options.isOverwriteOutput());
System.out.println(" verbose: " + options.isVerbose());
}
/**
* This is the main container which will be populated by picocli with values
* from the arguments.
*/
private static class Options {
@Option(names = "-b")
private boolean buffered = false;
@Option(names = "-o")
private boolean overwriteOutput = true;
@Option(names = "-v")
private boolean verbose = false;
public boolean isBuffered() {
return buffered;
}
public boolean isOverwriteOutput() {
return overwriteOutput;
}
public boolean isVerbose() {
return verbose;
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/PopulateFlagsWithLongNamesMain.java 0000664 0000000 0000000 00000005347 13457642030 0033200 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Robert 'Bobby' Zenz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
/**
* This example demonstrates the usage with a simple flag class with long names.
*
*
*
* When no arguments are provided, the flag will have its default value:
*
*
* Arguments:
*
*
* Options:
* verbose: false
*
*
* When the flag is provided in the arguments, the default value of the flag
* will be inverted and set.
*
*
* Arguments:
* "-v"
*
* Options:
* verbose: true
*
*
* We can also refer to the flag by its long name:
*
*
* Arguments:
* "--verbose"
*
* Options:
* verbose: true
*
*
* @author Robert 'Bobby' Zenz
*/
public class PopulateFlagsWithLongNamesMain {
public static void main(String[] args) {
// Create a new Options class, which holds our flag.
Options options = new Options();
try {
// Populate the created class from the command line arguments.
CommandLine.populateCommand(options, args);
} catch (ParameterException e) {
// The given command line arguments are invalid, for example there
// are options specified which do not exist or one of the options
// is malformed (missing a value, for example).
System.out.println(e.getMessage());
CommandLine.usage(options, System.out);
return;
}
// Print the state.
System.out.println("Arguments:");
System.out.print(" ");
for (String arg : args) {
System.out.print("\"" + arg + "\" ");
}
System.out.println();
System.out.println();
System.out.println("Options:");
System.out.println(" verbose: " + options.isVerbose());
}
/**
* This is the main container which will be populated by picocli with values
* from the arguments.
*/
private static class Options {
@Option(names = { "-v", "--verbose" })
private boolean verbose = false;
public boolean isVerbose() {
return verbose;
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/PopulateHelpRequestedMain.java 0000664 0000000 0000000 00000005106 13457642030 0032247 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Robert 'Bobby' Zenz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
/**
* This example demonstrates the printing of the usage/help message when
* requested.
*
*
*
* When no arguments are provided, no usage/help information will be printed:
*
*
* No help requested, application can continue.
*
*
* When the flag is provided in the arguments, with either {@code -h} or
* {@code --help}, the default usage/help text will be printed:
*
*
* Usage: <main class> [-h]
* -h, --help Prints this help text.
*
*
* @author Robert 'Bobby' Zenz
*/
public class PopulateHelpRequestedMain {
public static void main(String[] args) {
// Create a new Options class, which holds our options.
Options options = new Options();
try {
// Populate the created class from the command line arguments.
CommandLine.populateCommand(options, args);
} catch (ParameterException e) {
// The given command line arguments are invalid, for example there
// are options specified which do not exist or one of the options
// is malformed (missing a value, for example).
System.out.println(e.getMessage());
CommandLine.usage(options, System.out);
return;
}
// Print the state.
if (options.isHelpRequested()) {
CommandLine.usage(options, System.out);
} else {
System.out.println("No help requested, application can continue.");
}
}
/**
* This is the main container which will be populated by picocli with values
* from the arguments.
*/
private static class Options {
@Option(names = { "-h", "--help" }, description = "Prints this help text.")
private boolean helpRequested = false;
public boolean isHelpRequested() {
return helpRequested;
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/PopulateOptionsWithValuesMain.java 0000664 0000000 0000000 00000010105 13457642030 0033137 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Robert 'Bobby' Zenz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
/**
* This example demonstrates the usage with options which takes values.
*
*
*
* When no arguments are provided, the options will have their default values:
*
*
* Arguments:
*
*
* Options:
* name: default
* properties:
*
*
* When the option is provided without a value, an exception is thrown and in
* this example the error message is printed to sysout.
*
*
*
* The value can be provided either directly appended to the short option:
*
*
* Arguments:
* "-nvalue"
*
* Options:
* name: value
* properties:
*
*
* Or to the long option:
*
*
* Arguments:
* "--name=value"
*
* Options:
* name: value
* properties:
*
*
* Additionally, the following formats are also recognized:
*
*
* -n value
* -n=value
* --name value
*
*
* If the option is declared as array or list, the argument can be provided
* multiple times to populate the list:
*
*
* Arguments:
* "--name=value" "--properties=smart" "-p intelligent" "-p strong"
*
* Options:
* name: value
* properties: "smart" "intelligent" "strong"
*
*
* Alternatively, with the declaration of the option one can specify a separator
* to be used:
*
*
* Arguments:
* "--name=value" "--properties=smart,intelligent,strong"
*
* Options:
* name: value
* properties: "smart" "intelligent" "strong"
*
*
* @author Robert 'Bobby' Zenz
*/
public class PopulateOptionsWithValuesMain {
public static void main(String[] args) {
// Create a new Options class, which holds our options.
Options options = new Options();
try {
// Populate the created class from the command line arguments.
CommandLine.populateCommand(options, args);
} catch (ParameterException e) {
// The given command line arguments are invalid, for example there
// are options specified which do not exist or one of the options
// is malformed (missing a value, for example).
System.out.println(e.getMessage());
CommandLine.usage(options, System.out);
return;
}
// Print the state.
System.out.println("Arguments:");
System.out.print(" ");
for (String arg : args) {
System.out.print("\"" + arg + "\" ");
}
System.out.println();
System.out.println();
System.out.println("Options:");
System.out.println(" name: " + options.getName());
if (options.getProperties() != null) {
System.out.print(" properties: ");
for (String property : options.getProperties()) {
System.out.print("\"" + property + "\" ");
}
System.out.println();
} else {
System.out.println(" properties:");
}
}
/**
* This is the main container which will be populated by picocli with values
* from the arguments.
*/
private static class Options {
@Option(names = { "-n", "--name" })
private String name = "default";
@Option(names = { "-p", "--properties" }, split = ",")
private String[] properties = null;
public String getName() {
return name;
}
public String[] getProperties() {
return properties;
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/PopulatePositionalParametersMain.java 0000664 0000000 0000000 00000007526 13457642030 0033652 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Robert 'Bobby' Zenz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Parameters;
/**
* This example demonstrates the usage with positional parameters.
*
*
*
* When no arguments are provided, the options will have their default values:
*
*
* Arguments:
*
*
* Options:
* name: default
* properties:
*
*
* Positional parameters are parameters which are not specified with a leading
* name, for example when the application accepts a list of files as primary
* arguments:
*
*
* Arguments:
* "--name=value" "smart" "intelligent" "strong"
*
* Options:
* name: default
* properties: "smart" "intelligent" "strong"
*
*
* It does not matter where in the arguments these parameters are specified,
* all positional parameters will be added to the list:
*
*
* Arguments:
* "smart" "intelligent" "--name=value" "strong"
*
* Options:
* name: default
* properties: "smart" "intelligent" "strong"
*
*
* Additionally, one can also specify a separator to be able to specify a list:
*
*
* Arguments:
* "--name=value" "smart,intelligent,strong"
*
* Options:
* name: default
* properties: "smart" "intelligent" "strong"
*
*
* @author Robert 'Bobby' Zenz
*/
public class PopulatePositionalParametersMain {
public static void main(String[] args) {
// Create a new Options class, which holds our options.
Options options = new Options();
try {
// Populate the created class from the command line arguments.
CommandLine.populateCommand(options, args);
} catch (ParameterException e) {
// The given command line arguments are invalid, for example there
// are options specified which do not exist or one of the options
// is malformed (missing a value, for example).
System.out.println(e.getMessage());
CommandLine.usage(options, System.out);
return;
}
// Print the state.
System.out.println("Arguments:");
System.out.print(" ");
for (String arg : args) {
System.out.print("\"" + arg + "\" ");
}
System.out.println();
System.out.println();
System.out.println("Options:");
System.out.println(" name: " + options.getName());
if (options.getProperties() != null) {
System.out.print(" properties: ");
for (String property : options.getProperties()) {
System.out.print("\"" + property + "\" ");
}
System.out.println();
} else {
System.out.println(" properties:");
}
}
/**
* This is the main container which will be populated by picocli with values
* from the arguments.
*/
private static class Options {
@Option(names = { "-n", "--name" })
private String name = "default";
@Parameters(paramLabel = "PROPERTIES", split = ",")
private String[] properties = null;
public String getName() {
return name;
}
public String[] getProperties() {
return properties;
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/UserManualExamples.java 0000664 0000000 0000000 00000002127 13457642030 0030731 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
/**
*
*/
public class UserManualExamples {
@Command(mixinStandardHelpOptions = true, version = "1.0")
static class AutoHelpDemo implements Runnable {
@Option(names = "--option", description = "Some option.")
String option;
public void run() { }
}
public static void main(String[] args) {
CommandLine.run(new AutoHelpDemo(), "help");
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/VersionProviderDemo1.java 0000664 0000000 0000000 00000006521 13457642030 0031206 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IVersionProvider;
import picocli.CommandLine.Option;
import java.net.URL;
import java.util.Properties;
/**
* Demonstrates a {@link IVersionProvider} implementation that reads version information from a
* {@code /version.txt} file that is expected to be in the root of the classpath.
*
* The following gradle build snippet can be used to generate such a version.txt file and include it in the generated jar:
*
*
* def generatedResources = "$buildDir/generated-resources/main"
* sourceSets {
* main {
* //register an output folder on the main SourceSet:
* output.dir(generatedResources, builtBy: 'generateVersionTxt')
* //it is now a part of the 'main' classpath and will be a part of the jar
* }
* }
*
* //a task that generates the resources:
* task generateVersionTxt {
* description 'Creates a version.txt file with build info that is added to the root of the jar'
* doLast {
* new File(generatedResources).mkdirs()
* def generated = new File(generatedResources, "version.txt")
* generated.text = """
* Version: $rootProject.version
* Buildtime: ${new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())}
* Application-name: $rootProject.name $project.name
* """
* }
* }
*
*/
@Command(versionProvider = VersionProviderDemo1.PropertiesVersionProvider.class)
public class VersionProviderDemo1 implements Runnable {
@Option(names = {"-V", "--version"}, versionHelp = true, description = "Print version info from examples.jar/version.txt and exit")
boolean versionRequested;
public void run() {
CommandLine.usage(this, System.out);
}
public static void main(String[] args) {
CommandLine.run(new VersionProviderDemo1(), args);
}
/**
* {@link IVersionProvider} implementation that returns version information from a {@code /version.txt} file in the classpath.
*/
static class PropertiesVersionProvider implements IVersionProvider {
public String[] getVersion() throws Exception {
URL url = getClass().getResource("/version.txt");
if (url == null) {
return new String[] {"No version.txt file found in the classpath. Is examples.jar in the classpath?"};
}
Properties properties = new Properties();
properties.load(url.openStream());
return new String[] {
properties.getProperty("Application-name") + " version \"" + properties.getProperty("Version") + "\"",
"Built: " + properties.getProperty("Buildtime"),
};
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/VersionProviderDemo2.java 0000664 0000000 0000000 00000006024 13457642030 0031205 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IVersionProvider;
import picocli.CommandLine.Option;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* Demonstrates a {@link IVersionProvider} implementation that reads version information from the picocli-x.x.jar
* file's {@code /META-INF/MANIFEST.MF} file.
*/
@Command(versionProvider = VersionProviderDemo2.ManifestVersionProvider.class)
public class VersionProviderDemo2 implements Runnable {
@Option(names = {"-V", "--version"}, versionHelp = true, description = "Print version info from the picocli-x.x.jar file's /META-INF/MANIFEST.MF and exit")
boolean versionRequested;
public void run() {
CommandLine.usage(this, System.out);
}
public static void main(String[] args) {
CommandLine.run(new VersionProviderDemo2(), args);
}
/**
* {@link IVersionProvider} implementation that returns version information from the picocli-x.x.jar file's {@code /META-INF/MANIFEST.MF} file.
*/
static class ManifestVersionProvider implements IVersionProvider {
public String[] getVersion() throws Exception {
Enumeration resources = CommandLine.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
try {
Manifest manifest = new Manifest(url.openStream());
if (isApplicableManifest(manifest)) {
Attributes attr = manifest.getMainAttributes();
return new String[] { get(attr, "Implementation-Title") + " version \"" +
get(attr, "Implementation-Version") + "\"" };
}
} catch (IOException ex) {
return new String[] { "Unable to read from " + url + ": " + ex };
}
}
return new String[0];
}
private boolean isApplicableManifest(Manifest manifest) {
Attributes attributes = manifest.getMainAttributes();
return "picocli".equals(get(attributes, "Implementation-Title"));
}
private static Object get(Attributes attributes, String key) {
return attributes.get(new Attributes.Name(key));
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/customhelp/ 0000775 0000000 0000000 00000000000 13457642030 0026474 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/customhelp/ShowAll.java 0000664 0000000 0000000 00000010424 13457642030 0030711 0 ustar 00root root 0000000 0000000 package picocli.examples.customhelp;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Help;
import picocli.CommandLine.Help.Column;
import picocli.CommandLine.Help.Column.Overflow;
import picocli.CommandLine.Help.TextTable;
import picocli.CommandLine.IHelpSectionRenderer;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.UsageMessageSpec;
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
/**
* This example demonstrates how to customize a section of the usage help message.
* It replaces the standard command list with a custom list that displays
* not just the immediate subcommands but the full hierarchy of subcommands:
*
* Usage: showall [-hV] [COMMAND]
* Demonstrates a usage help message that shows not just the subcommands of this
* command, but also the nested sub-subcommands.
* -h, --help Show this help message and exit.
* -V, --version Print version information and exit.
* Commands:
* sub1 subcommand1 of showall
* sub1sub1 subcommand1 of subcommand1 of showall
* sub1sub2 subcommand2 of subcommand1 of showall
* sub2 subcommand2 of showall
* sub2sub1 subcommand1 of subcommand2 of showall
*
*
* As requested in https://github.com/remkop/picocli/issues/566
*/
@Command(name = "showall", mixinStandardHelpOptions = true,
version = "from picocli 3.9",
description = "Demonstrates a usage help message that shows " +
"not just the subcommands of this command, " +
"but also the nested sub-subcommands.",
subcommands = {Subcommand1.class, Subcommand2.class} )
public class ShowAll {
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new ShowAll());
cmd.getHelpSectionMap().put(SECTION_KEY_COMMAND_LIST, new MyCommandListRenderer());
cmd.usage(System.out);
}
}
class MyCommandListRenderer implements IHelpSectionRenderer {
//@Override
public String render(Help help) {
CommandSpec spec = help.commandSpec();
if (spec.subcommands().isEmpty()) { return ""; }
// prepare layout: two columns
// the left column overflows, the right column wraps if text is too long
TextTable textTable = TextTable.forColumns(help.ansi(),
new Column(15, 2, Overflow.SPAN),
new Column(spec.usageMessage().width() - 15, 2, Overflow.WRAP));
for (CommandLine subcommand : spec.subcommands().values()) {
addHierarchy(subcommand, textTable, "");
}
return textTable.toString();
}
private void addHierarchy(CommandLine cmd, TextTable textTable, String indent) {
// create comma-separated list of command name and aliases
String names = cmd.getCommandSpec().names().toString();
names = names.substring(1, names.length() - 1); // remove leading '[' and trailing ']'
// command description is taken from header or description
String description = description(cmd.getCommandSpec().usageMessage());
// add a line for this command to the layout
textTable.addRowValues(indent + names, description);
// add its subcommands (if any)
for (CommandLine sub : cmd.getSubcommands().values()) {
addHierarchy(sub, textTable, indent + " ");
}
}
private String description(UsageMessageSpec usageMessage) {
if (usageMessage.header().length > 0) {
return usageMessage.header()[0];
}
if (usageMessage.description().length > 0) {
return usageMessage.description()[0];
}
return "";
}
}
@Command(name = "sub1", description = "subcommand1 of showall",
subcommands = {Subcommand1Sub1.class, Subcommand1Sub2.class})
class Subcommand1 {}
@Command(name = "sub2", description = "subcommand2 of showall",
subcommands = {Subcommand2Sub1.class})
class Subcommand2 {}
@Command(name = "sub1sub1", description = "subcommand1 of subcommand1 of showall")
class Subcommand1Sub1 {}
@Command(name = "sub1sub2", description = "subcommand2 of subcommand1 of showall")
class Subcommand1Sub2 {}
@Command(name = "sub2sub1", description = "subcommand1 of subcommand2 of showall")
class Subcommand2Sub1 {}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/interactive/ 0000775 0000000 0000000 00000000000 13457642030 0026626 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/interactive/PasswordDemo.java 0000664 0000000 0000000 00000002417 13457642030 0032104 0 ustar 00root root 0000000 0000000 package picocli.examples.interactive;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Spec;
import java.io.File;
public class PasswordDemo implements Runnable {
@Option(names = "--password:file")
File passwordFile;
@Option(names = "--password:env")
String passwordEnvironmentVariable;
@Option(names = "--password", interactive = true)
String password;
@Spec
CommandSpec spec;
public void run() {
if (password != null) {
login(password);
} else if (passwordEnvironmentVariable != null) {
login(System.getenv(passwordEnvironmentVariable));
} else if (passwordFile != null) {
// below uses Java 8 NIO, create your own on older Java versions
/*
login(new String(Files.readAllBytes(passwordFile.toPath())));
*/
} else {
throw new ParameterException(spec.commandLine(), "Password required");
}
}
private void login(String pwd) {
System.out.printf("Password: %s%n", pwd);
}
public static void main(String[] args) {
CommandLine.run(new PasswordDemo(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/mixin/ 0000775 0000000 0000000 00000000000 13457642030 0025435 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/mixin/CommandWithMixin.java 0000664 0000000 0000000 00000001231 13457642030 0031514 0 ustar 00root root 0000000 0000000 package picocli.examples.mixin;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Mixin;
import picocli.CommandLine.Option;
@Command(name = "mixee", description = "This command has a footer and an option mixed in")
public class CommandWithMixin {
@Mixin
CommonOption commonOption = new CommonOption();
@Option(names = "-y", description = "command option")
int y;
public static void main(String[] args) {
CommandWithMixin cmd = new CommandWithMixin();
new CommandLine(cmd).parseArgs("-x", "3", "-y", "4");
System.out.printf("x=%s, y=%s%n", cmd.commonOption.x, cmd.y);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/mixin/CommonOption.java 0000664 0000000 0000000 00000000412 13457642030 0030716 0 ustar 00root root 0000000 0000000 package picocli.examples.mixin;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@Command(footer = "Common footer")
public class CommonOption {
@Option(names = "-x", description = "reusable option you want in many commands")
int x;
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/model/ 0000775 0000000 0000000 00000000000 13457642030 0025411 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/model/BasicResultProcessing.java 0000664 0000000 0000000 00000004323 13457642030 0032533 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples.model;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;
import picocli.CommandLine.Model.PositionalParamSpec;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.ParseResult;
import java.io.File;
import java.util.Collections;
import java.util.List;
public class BasicResultProcessing {
public static void main(final String[] args) {
CommandSpec spec = CommandSpec.create();
spec.mixinStandardHelpOptions(true);
spec.addOption(OptionSpec.builder("-c", "--count")
.paramLabel("COUNT")
.type(int.class)
.description("number of times to execute").build());
spec.addPositional(PositionalParamSpec.builder()
.paramLabel("FILES")
.type(List.class)
.auxiliaryTypes(File.class)
.description("The files to process").build());
CommandLine commandLine = new CommandLine(spec);
try {
ParseResult pr = commandLine.parseArgs(args);
if (CommandLine.printHelpIfRequested(pr)) { return; }
int count = pr.matchedOptionValue('c', 1);
List files = pr.matchedPositionalValue(0, Collections.emptyList());
for (File f : files) {
for (int i = 0; i < count; i++) {
System.out.println(i + " " + f.getName());
}
}
} catch (ParameterException ex) {
System.err.println(ex.getMessage());
ex.getCommandLine().usage(System.err);
}
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/model/ParseResultDemo.java 0000664 0000000 0000000 00000005026 13457642030 0031335 0 ustar 00root root 0000000 0000000 package picocli.examples.model;
import picocli.CommandLine;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;
import picocli.CommandLine.ParseResult;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ParseResultDemo {
public static void main(String[] args) {
CommandSpec spec = CommandSpec.create();
spec.addOption(OptionSpec.builder("-V", "--verbose").build());
spec.addOption(OptionSpec.builder("-f", "--file")
.paramLabel("FILES")
.type(List.class)
.auxiliaryTypes(File.class) // so, this option is of type List
.description("The files to process").build());
spec.addOption(OptionSpec.builder("-n", "--num")
.paramLabel("COUNT")
.type(int[].class)
.splitRegex(",")
.description("Comma-separated list of integers").build());
CommandLine commandLine = new CommandLine(spec);
args = new String[]{ "--verbose", "-f", "file1", "--file=file2", "-n1,2,3" };
ParseResult pr = commandLine.parseArgs(args);
// Querying for options
List originalArgs = pr.originalArgs(); // lists all command line args
assert Arrays.asList(args).equals(originalArgs);
assert pr.hasMatchedOption("--verbose"); // as specified on command line
assert pr.hasMatchedOption("-V"); // other aliases work also
assert pr.hasMatchedOption('V'); // single-character alias works too
assert pr.hasMatchedOption("verbose"); // and, command name without hyphens
// Matched Option Values
List defaultValue = Collections.emptyList();
List expected = Arrays.asList(new File("file1"), new File("file2"));
assert expected.equals(pr.matchedOptionValue('f', defaultValue));
assert expected.equals(pr.matchedOptionValue("--file", defaultValue));
assert Arrays.equals(new int[]{1,2,3}, pr.matchedOptionValue('n', new int[0]));
// Command line arguments after splitting but before type conversion
assert "1".equals(pr.matchedOption('n').stringValues().get(0));
assert "2".equals(pr.matchedOption('n').stringValues().get(1));
assert "3".equals(pr.matchedOption('n').stringValues().get(2));
// Command line arguments as found on the command line
assert "1,2,3".equals(pr.matchedOption("--num").originalStringValues().get(0));
}
}
ResultHandlerWithReturnValue.java 0000664 0000000 0000000 00000004421 13457642030 0034003 0 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/model /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples.model;
import picocli.CommandLine;
import picocli.CommandLine.AbstractParseResultHandler;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;
import picocli.CommandLine.Model.PositionalParamSpec;
import picocli.CommandLine.ParseResult;
import java.io.File;
import java.util.Collections;
import java.util.List;
public class ResultHandlerWithReturnValue {
public static void main(final String[] args) {
CommandSpec spec = CommandSpec.create();
spec.mixinStandardHelpOptions(true);
spec.addOption(OptionSpec.builder("-c", "--count")
.paramLabel("COUNT")
.type(int.class)
.description("number of times to execute").build());
spec.addPositional(PositionalParamSpec.builder()
.paramLabel("FILES")
.type(List.class)
.auxiliaryTypes(File.class)
.description("The files to process").build());
CommandLine commandLine = new CommandLine(spec);
class Handler extends AbstractParseResultHandler {
public Integer handle(ParseResult pr) {
int count = pr.matchedOptionValue('c', 1);
List files = pr.matchedPositionalValue(0, Collections.emptyList());
for (File f : files) {
for (int i = 0; i < count; i++) {
System.out.println(i + " " + f.getName());
}
}
return files.size();
}
protected Handler self() { return this; }
}
int processed = commandLine.parseWithHandler(new Handler(), args);
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/subcommands/ 0000775 0000000 0000000 00000000000 13457642030 0026624 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/subcommands/ParentCommandDemo.java 0000664 0000000 0000000 00000004064 13457642030 0033030 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples.subcommands;
import java.io.File;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
public class ParentCommandDemo {
@Command(name = "fileutils", subcommands = List.class)
static class FileUtils implements Runnable {
@Option(names = {"-d", "--directory"}, description = "this option applies to all subcommands")
private File baseDirectory;
public void run() { System.out.println("FileUtils: my dir is " + baseDirectory); }
}
@Command(name = "list")
static class List implements Runnable {
@ParentCommand
private FileUtils parent;
@Option(names = {"-r", "--recursive"}, description = "Recursively list subdirectories")
private boolean recursive;
public void run() {
list(new File(parent.baseDirectory, "."));
}
private void list(File dir) {
System.out.println(dir.getAbsolutePath());
if (dir.isDirectory()) {
for (File f : dir.listFiles()) {
if (f.isDirectory() && recursive) {
list(f);
} else {
System.out.println(f.getAbsolutePath());
}
}
}
}
}
public static void main(String[] args) {
CommandLine.run(new FileUtils(), "--directory=examples/src", "list", "-r");
}
}
picocli-3.9.6/picocli-examples/src/main/java/picocli/examples/subcommands/SubcommandDemo.java 0000664 0000000 0000000 00000004672 13457642030 0032375 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli.examples.subcommands;
import java.util.Locale;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
public class SubcommandDemo {
@Command(name = "ISOCodeResolve", subcommands = { Subcommand1.class, Subcommand2.class,
CommandLine.HelpCommand.class }, description = "Resolve ISO country codes (ISO-3166-1) or language codes (ISO 639-1 or -2)")
static class ParentCommand implements Runnable {
@Override
public void run() { }
}
@Command(name = "country", description = "Resolve ISO country code (ISO-3166-1, Alpha-2 code)")
static class Subcommand1 implements Runnable {
@Parameters(arity = "1..*", paramLabel = " ", description = "country code(s) to be resolved")
private String[] countryCodes;
@Override
public void run() {
for (String code : countryCodes) {
System.out.println(String.format("%s: %s", code.toUpperCase(), new Locale("", code).getDisplayCountry()));
}
}
}
@Command(name = "language", description = "Resolve ISO language code (ISO 639-1 or -2, two/three letters)")
static class Subcommand2 implements Runnable {
@Parameters(arity = "1..*", paramLabel = " ", description = "language code(s) to be resolved")
private String[] languageCodes;
@Override
public void run() {
for (String code : languageCodes) {
System.out.println(String.format("%s: %s", code.toLowerCase(), new Locale(code).getDisplayLanguage()));
}
}
}
public static void main(String[] args) {
CommandLine cmd = new CommandLine(new ParentCommand());
cmd.parseWithHandler(new CommandLine.RunAll(), args);
if (args.length == 0) { cmd.usage(System.out); }
}
} picocli-3.9.6/picocli-examples/src/main/kotlin/ 0000775 0000000 0000000 00000000000 13457642030 0021430 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023052 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/ 0000775 0000000 0000000 00000000000 13457642030 0024670 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/kotlin/ 0000775 0000000 0000000 00000000000 13457642030 0026170 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/kotlin/MyApp.kt 0000664 0000000 0000000 00000001364 13457642030 0027562 0 ustar 00root root 0000000 0000000 package picocli.examples.kotlin
import picocli.CommandLine
import picocli.CommandLine.*
@Command(name = "MyApp", version = ["Kotlin picocli demo v1.0"],
mixinStandardHelpOptions = true,
description = ["@|bold Kotlin|@ @|underline picocli|@ example"])
class MyApp : Runnable {
@Option(names = ["-c", "--count"], paramLabel = "COUNT",
description = ["the count"])
private var count: Int = 0
override fun run() {
for (i in 0 until count) {
println("hello world $i...")
}
}
// companion object {
// @JvmStatic fun main(args: Array) {
// CommandLine.run(MyApp(), *args)
// }
// }
}
fun main(args: Array) = CommandLine.run(MyApp(), *args) picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/kotlin/subcommands/ 0000775 0000000 0000000 00000000000 13457642030 0030503 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/kotlin/subcommands/SubCmd.kt 0000664 0000000 0000000 00000001366 13457642030 0032226 0 ustar 00root root 0000000 0000000 package picocli.examples.kotlin.subcommands
import picocli.CommandLine
import picocli.CommandLine.*
import picocli.CommandLine.Model.CommandSpec
import picocli.examples.kotlin.MyApp
@Command(name = "sub", mixinStandardHelpOptions = true,
description = ["I'm a subcommand. Prints help if count=7."])
class SubCmd : Runnable {
@Option(names = ["-c", "--count"], paramLabel = "COUNT",
description = ["the count"])
private var count: Int = 0
@Spec
var spec: CommandSpec? = null
override fun run() {
println("I'm a subcommand")
for (i in 0 until count) {
println("hello world $i...")
}
if (count == 7) {
spec?.commandLine()?.usage(System.out)
}
}
}
picocli-3.9.6/picocli-examples/src/main/kotlin/picocli/examples/kotlin/subcommands/TopCmd.kt 0000664 0000000 0000000 00000001320 13457642030 0032225 0 ustar 00root root 0000000 0000000 package picocli.examples.kotlin.subcommands
import picocli.CommandLine
import picocli.CommandLine.*
import picocli.CommandLine.Model.CommandSpec
import picocli.examples.kotlin.MyApp
@Command(name = "top", version = ["Kotlin picocli demo v3.8.1"],
mixinStandardHelpOptions = true,
description = ["@|bold Kotlin|@ @|underline picocli|@ example"],
subcommands = [SubCmd::class])
class TopCmd : Runnable {
@Spec
var spec: CommandSpec? = null
override fun run() {
throw ParameterException(spec?.commandLine(), "Specify a subcommand")
}
companion object {
@JvmStatic fun main(args: Array) {
CommandLine.run(TopCmd(), *args)
}
}
}
picocli-3.9.6/picocli-shell-jline2/ 0000775 0000000 0000000 00000000000 13457642030 0017067 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/README.md 0000664 0000000 0000000 00000012354 13457642030 0020353 0 ustar 00root root 0000000 0000000
# Picocli Shell JLine2 - build interactive shells with ease
Picocli Shell JLine2 contains components and documentation for building
interactive shell command line applications with JLine 2 and picocli.
JLine and picocli complement each other very well and have little or none functional overlap.
JLine provides interactive shell functionality but has no built-in command line parsing functionality.
What it does provide is a tokenizer for splitting a single command line String into an array of command line argument Strings.
Given an array of Strings, picocli can execute a command or subcommand.
Combining these two libraries makes it easy to build powerful interactive shell applications.
## About JLine 2
[JLine 2](https://github.com/jline/jline2) is a well-known library for building interactive shell applications.
From the JLine [web site](https://github.com/jline/jline.github.io/blob/master/index.md):
> JLine is a Java library for handling console input. It is similar in functionality to [BSD editline](http://www.thrysoee.dk/editline/) and [GNU readline](http://www.gnu.org/s/readline/) but with additional features that bring it in par with [ZSH line editor](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html).
## About picocli
Picocli is a Java command line parser with both an annotations API and a programmatic API, featuring usage help with ANSI colors, autocomplete and nested subcommands.
The picocli user manual is [here](https://picocli.info), and the GitHub project is [here](https://github.com/remkop/picocli).
## Command Completer
`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to
get command line TAB auto-completion for a picocli-based application running in a JLine 2 shell.
## Example
```java
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import jline.console.ConsoleReader;
import jline.console.completer.ArgumentCompleter.ArgumentList;
import jline.console.completer.ArgumentCompleter.WhitespaceArgumentDelimiter;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline2.PicocliJLineCompleter;
/**
* Example that demonstrates how to build an interactive shell with JLine and picocli.
* @since 3.7
*/
public class Example {
/**
* Top-level command that just prints help.
*/
@Command(name = "", description = "Example interactive shell with completion",
footer = {"", "Press Ctl-D to exit."},
subcommands = {MyCommand.class, ClearScreen.class})
static class CliCommands implements Runnable {
final ConsoleReader reader;
final PrintWriter out;
CliCommands(ConsoleReader reader) {
this.reader = reader;
out = new PrintWriter(reader.getOutput());
}
public void run() {
out.println(new CommandLine(this).getUsageMessage());
}
}
/**
* A command with some options to demonstrate completion.
*/
@Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0",
description = "Command with some options to demonstrate TAB-completion" +
" (note that enum values also get completed)")
static class MyCommand implements Runnable {
@Option(names = {"-v", "--verbose"})
private boolean[] verbosity = {};
@Option(names = {"-d", "--duration"})
private int amount;
@Option(names = {"-u", "--timeUnit"})
private TimeUnit unit;
@ParentCommand CliCommands parent;
public void run() {
if (verbosity.length > 0) {
parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit);
} else {
parent.out.println("hi!");
}
}
}
/**
* Command that clears the screen.
*/
@Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true,
description = "Clears the screen", version = "1.0")
static class ClearScreen implements Callable {
@ParentCommand CliCommands parent;
public Void call() throws IOException {
parent.reader.clearScreen();
return null;
}
}
public static void main(String[] args) {
try {
ConsoleReader reader = new ConsoleReader();
reader.setPrompt("prompt> ");
// set up the completion
CliCommands commands = new CliCommands(reader);
CommandLine cmd = new CommandLine(commands);
reader.addCompleter(new PicocliJLineCompleter(cmd.getCommandSpec()));
// start the shell and process input until the user quits with Ctl-D
String line;
while ((line = reader.readLine()) != null) {
ArgumentList list =
new WhitespaceArgumentDelimiter().delimit(line, line.length());
CommandLine.run(commands, list.getArguments());
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
```
picocli-3.9.6/picocli-shell-jline2/build.gradle 0000664 0000000 0000000 00000007104 13457642030 0021350 0 ustar 00root root 0000000 0000000 plugins {
id 'java'
id 'distribution'
id 'maven-publish'
id 'com.jfrog.bintray'
}
group 'info.picocli'
description 'Picocli Shell JLine2 - easily build interactive shell applications with JLine 2 and picocli.'
version "$projectVersion"
dependencies {
compile rootProject
compile "jline:jline:$jlineVersion"
testCompile "junit:junit:$junitVersion"
}
jar {
manifest {
attributes 'Specification-Title' : 'Picocli Shell JLine2',
'Specification-Vendor' : 'Remko Popma',
'Specification-Version' : version,
'Implementation-Title' : 'Picocli Shell JLine2',
'Implementation-Vendor' : 'Remko Popma',
'Implementation-Version': version,
'Automatic-Module-Name' : 'info.picocli.shell.jline2'
}
}
ext {
bintrayPackage = 'picocli-shell-jline2'
bintrayWebsiteUrl = 'https://github.com/remkop/picocli/tree/master/picocli-shell-jline2'
bintrayLabels = ['cli', 'interactive', 'commandline', 'shell', 'picocli', 'jline']
}
bintray {
user = bintrayUsername
key = bintrayApiKey
publications = ['MyPublication']
dryRun = bintrayDryRun //[Default: false] Whether to run this as dry-run, without deploying
publish = bintrayPublish //[Default: false] Whether version should be auto published after an upload
override = bintrayOverride //[Default: false] Whether to override version artifacts already published
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'picocli'
name = bintrayPackage
userOrg = 'remkop'
licenses = ['Apache-2.0']
desc = description
websiteUrl = bintrayWebsiteUrl
issueTrackerUrl = 'https://github.com/remkop/picocli/issues'
vcsUrl = 'https://github.com/remkop/picocli.git'
labels = bintrayLabels
publicDownloadNumbers = false
version {
name = "$projectVersion"
desc = description
released = new Date()
vcsTag = "v$projectVersion"
mavenCentralSync {
sync = mavenOssSync //[Default: true] Determines whether to sync the version to Maven Central.
user = mavenOssUser //OSS user token: mandatory
password = mavenOssPassword //OSS user password: mandatory
close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
}
}
}
}
publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact sourcesJar
artifact testJar
artifact testSourcesJar
artifact javadocJar
groupId 'info.picocli'
artifactId bintrayPackage
version "$projectVersion"
pom.withXml {
def root = asNode()
root.appendNode('packaging', 'jar')
root.appendNode('name', bintrayPackage)
root.appendNode('description', description)
root.appendNode('url', 'http://picocli.info')
root.appendNode('inceptionYear', '2018')
root.children().last() + pomConfig
}
}
}
}
picocli-3.9.6/picocli-shell-jline2/src/ 0000775 0000000 0000000 00000000000 13457642030 0017656 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/ 0000775 0000000 0000000 00000000000 13457642030 0020602 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/java/ 0000775 0000000 0000000 00000000000 13457642030 0021523 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023145 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/java/picocli/shell/ 0000775 0000000 0000000 00000000000 13457642030 0024254 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/java/picocli/shell/jline2/ 0000775 0000000 0000000 00000000000 13457642030 0025437 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/main/java/picocli/shell/jline2/PicocliJLineCompleter.java 0000664 0000000 0000000 00000004310 13457642030 0032457 0 ustar 00root root 0000000 0000000 package picocli.shell.jline2;
import jline.console.completer.ArgumentCompleter;
import jline.console.completer.Completer;
import picocli.AutoComplete;
import picocli.CommandLine.Model.CommandSpec;
import java.util.List;
/**
* Implementation of the JLine 2 {@link Completer} interface that generates completion
* candidates for the specified command line based on the {@link CommandSpec} that
* this {@code PicocliJLineCompleter} was constructed with.
*
* @since 3.7
*/
public class PicocliJLineCompleter implements Completer {
private final CommandSpec spec;
/**
* Constructs a new {@code PicocliJLineCompleter} for the given command spec.
* @param spec the command specification to generate completions for. Must be non-{@code null}.
*/
public PicocliJLineCompleter(CommandSpec spec) {
if (spec == null) { throw new NullPointerException("spec"); }
this.spec = spec;
}
/**
* Populates the specified list with completion candidates for the specified buffer
* based on the command specification that this shell was constructed with.
*
* @param buffer the command line string
* @param cursor the position of the cursor in the command line string
* @param candidates the list to populate with completion candidates that would produce
* valid options, parameters or subcommands at the cursor position
* in the command line
* @return the cursor position in the buffer for which the completion will be relative,
* or {@code -1} if no completions are found
*/
//@Override
public int complete(String buffer, int cursor, List candidates) {
// use the jline internal parser to split the line into tokens
ArgumentCompleter.ArgumentList list =
new ArgumentCompleter.WhitespaceArgumentDelimiter().delimit(buffer, cursor);
// let picocli generate completion candidates for the token where the cursor is at
return AutoComplete.complete(spec,
list.getArguments(),
list.getCursorArgumentIndex(),
list.getArgumentPosition(),
cursor,
candidates);
}
}
picocli-3.9.6/picocli-shell-jline2/src/test/ 0000775 0000000 0000000 00000000000 13457642030 0020635 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/ 0000775 0000000 0000000 00000000000 13457642030 0021556 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023200 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/picocli/shell/ 0000775 0000000 0000000 00000000000 13457642030 0024307 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/picocli/shell/jline2/ 0000775 0000000 0000000 00000000000 13457642030 0025472 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/picocli/shell/jline2/example/ 0000775 0000000 0000000 00000000000 13457642030 0027125 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline2/src/test/java/picocli/shell/jline2/example/Example.java 0000664 0000000 0000000 00000006623 13457642030 0031372 0 ustar 00root root 0000000 0000000 package picocli.shell.jline2.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import jline.console.ConsoleReader;
import jline.console.completer.ArgumentCompleter.ArgumentList;
import jline.console.completer.ArgumentCompleter.WhitespaceArgumentDelimiter;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline2.PicocliJLineCompleter;
/**
* Example that demonstrates how to build an interactive shell with JLine and picocli.
* @since 3.7
*/
public class Example {
/**
* Top-level command that just prints help.
*/
@Command(name = "", description = "Example interactive shell with completion",
footer = {"", "Press Ctl-D to exit."},
subcommands = {MyCommand.class, ClearScreen.class})
static class CliCommands implements Runnable {
final ConsoleReader reader;
final PrintWriter out;
CliCommands(ConsoleReader reader) {
this.reader = reader;
out = new PrintWriter(reader.getOutput());
}
public void run() {
out.println(new CommandLine(this).getUsageMessage());
}
}
/**
* A command with some options to demonstrate completion.
*/
@Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0",
description = "Command with some options to demonstrate TAB-completion" +
" (note that enum values also get completed)")
static class MyCommand implements Runnable {
@Option(names = {"-v", "--verbose"})
private boolean[] verbosity = {};
@Option(names = {"-d", "--duration"})
private int amount;
@Option(names = {"-u", "--timeUnit"})
private TimeUnit unit;
@ParentCommand CliCommands parent;
public void run() {
if (verbosity.length > 0) {
parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit);
} else {
parent.out.println("hi!");
}
}
}
/**
* Command that clears the screen.
*/
@Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true,
description = "Clears the screen", version = "1.0")
static class ClearScreen implements Callable {
@ParentCommand CliCommands parent;
public Void call() throws IOException {
parent.reader.clearScreen();
return null;
}
}
public static void main(String[] args) {
try {
ConsoleReader reader = new ConsoleReader();
reader.setPrompt("prompt> ");
// set up the completion
CliCommands commands = new CliCommands(reader);
CommandLine cmd = new CommandLine(commands);
reader.addCompleter(new PicocliJLineCompleter(cmd.getCommandSpec()));
// start the shell and process input until the user quits with Ctl-D
String line;
while ((line = reader.readLine()) != null) {
ArgumentList list =
new WhitespaceArgumentDelimiter().delimit(line, line.length());
CommandLine.run(commands, list.getArguments());
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
picocli-3.9.6/picocli-shell-jline3/ 0000775 0000000 0000000 00000000000 13457642030 0017070 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/README.md 0000664 0000000 0000000 00000014211 13457642030 0020346 0 ustar 00root root 0000000 0000000
# Picocli Shell JLine3 - build interactive shells with ease
Picocli Shell JLine3 contains components and documentation for building
interactive shell command line applications with JLine 3 and picocli.
JLine and picocli complement each other very well and have little or none functional overlap.
JLine provides interactive shell functionality but has no built-in command line parsing functionality.
What it does provide is a tokenizer for splitting a single command line String into an array of command line argument Strings.
Given an array of Strings, picocli can execute a command or subcommand.
Combining these two libraries makes it easy to build powerful interactive shell applications.
## About JLine 3
[JLine 3](https://github.com/jline/jline3) is a well-known library for building interactive shell applications.
From the JLine [web site](https://github.com/jline/jline.github.io/blob/master/index.md):
> JLine is a Java library for handling console input. It is similar in functionality to [BSD editline](http://www.thrysoee.dk/editline/) and [GNU readline](http://www.gnu.org/s/readline/) but with additional features that bring it in par with [ZSH line editor](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html).
## About picocli
Picocli is a Java command line parser with both an annotations API and a programmatic API, featuring usage help with ANSI colors, autocomplete and nested subcommands.
The picocli user manual is [here](https://picocli.info), and the GitHub project is [here](https://github.com/remkop/picocli).
## Command Completer
`PicocliJLineCompleter` is a small component that generates completion candidates to allow users to
get command line TAB auto-completion for a picocli-based application running in a JLine 3 shell.
## Example
```java
package picocli.shell.jline3.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.jline.reader.Completer;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.EndOfFileException;
import org.jline.reader.UserInterruptException;
import org.jline.reader.ParsedLine;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.terminal.TerminalBuilder;
import org.jline.terminal.Terminal;
import org.jline.reader.MaskingCallback;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline3.PicocliJLineCompleter;
/**
* Example that demonstrates how to build an interactive shell with JLine3 and picocli.
* @since 3.9
*/
public class Example {
/**
* Top-level command that just prints help.
*/
@Command(name = "", description = "Example interactive shell with completion",
footer = {"", "Press Ctl-D to exit."},
subcommands = {MyCommand.class, ClearScreen.class})
static class CliCommands implements Runnable {
LineReaderImpl reader;
PrintWriter out;
CliCommands() {}
public void setReader(LineReader reader){
this.reader = (LineReaderImpl)reader;
out = reader.getTerminal().writer();
}
public void run() {
out.println(new CommandLine(this).getUsageMessage());
}
}
/**
* A command with some options to demonstrate completion.
*/
@Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0",
description = "Command with some options to demonstrate TAB-completion" +
" (note that enum values also get completed)")
static class MyCommand implements Runnable {
@Option(names = {"-v", "--verbose"})
private boolean[] verbosity = {};
@Option(names = {"-d", "--duration"})
private int amount;
@Option(names = {"-u", "--timeUnit"})
private TimeUnit unit;
@ParentCommand CliCommands parent;
public void run() {
if (verbosity.length > 0) {
parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit);
} else {
parent.out.println("hi!");
}
}
}
/**
* Command that clears the screen.
*/
@Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true,
description = "Clears the screen", version = "1.0")
static class ClearScreen implements Callable {
@ParentCommand CliCommands parent;
public Void call() throws IOException {
parent.reader.clearScreen();
return null;
}
}
public static void main(String[] args) {
try {
// set up the completion
CliCommands commands = new CliCommands();
CommandLine cmd = new CommandLine(commands);
Terminal terminal = TerminalBuilder.builder().build();
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(new PicocliJLineCompleter(cmd.getCommandSpec()))
.parser(new DefaultParser())
.build();
commands.setReader(reader);
String prompt = "prompt> ";
String rightPrompt = null;
// start the shell and process input until the user quits with Ctl-D
String line;
while (true) {
try {
line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
ParsedLine pl = reader.getParser().parse(line, 0);
String[] arguments = pl.words().toArray(new String[0]);
CommandLine.run(commands, arguments);
} catch (UserInterruptException e) {
// Ignore
} catch (EndOfFileException e) {
return;
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
```
picocli-3.9.6/picocli-shell-jline3/build.gradle 0000664 0000000 0000000 00000007111 13457642030 0021347 0 ustar 00root root 0000000 0000000 plugins {
id 'java'
id 'distribution'
id 'maven-publish'
id 'com.jfrog.bintray'
}
group 'info.picocli'
description 'Picocli Shell JLine3 - easily build interactive shell applications with JLine 3 and picocli.'
version "$projectVersion"
dependencies {
compile rootProject
compile "org.jline:jline:$jline3Version"
testCompile "junit:junit:$junitVersion"
}
jar {
manifest {
attributes 'Specification-Title' : 'Picocli Shell JLine3',
'Specification-Vendor' : 'Remko Popma',
'Specification-Version' : version,
'Implementation-Title' : 'Picocli Shell JLine3',
'Implementation-Vendor' : 'Remko Popma',
'Implementation-Version': version,
'Automatic-Module-Name' : 'info.picocli.shell.jline3'
}
}
ext {
bintrayPackage = 'picocli-shell-jline3'
bintrayWebsiteUrl = 'https://github.com/remkop/picocli/tree/master/picocli-shell-jline3'
bintrayLabels = ['cli', 'interactive', 'commandline', 'shell', 'picocli', 'jline']
}
bintray {
user = bintrayUsername
key = bintrayApiKey
publications = ['MyPublication']
dryRun = bintrayDryRun //[Default: false] Whether to run this as dry-run, without deploying
publish = bintrayPublish //[Default: false] Whether version should be auto published after an upload
override = bintrayOverride //[Default: false] Whether to override version artifacts already published
//Package configuration. The plugin will use the repo and name properties to check if the package already exists. In that case, there's no need to configure the other package properties (like userOrg, desc, etc).
pkg {
repo = 'picocli'
name = bintrayPackage
userOrg = 'remkop'
licenses = ['Apache-2.0']
desc = description
websiteUrl = bintrayWebsiteUrl
issueTrackerUrl = 'https://github.com/remkop/picocli/issues'
vcsUrl = 'https://github.com/remkop/picocli.git'
labels = bintrayLabels
publicDownloadNumbers = false
version {
name = "$projectVersion"
desc = description
released = new Date()
vcsTag = "v$projectVersion"
mavenCentralSync {
sync = mavenOssSync //[Default: true] Determines whether to sync the version to Maven Central.
user = mavenOssUser //OSS user token: mandatory
password = mavenOssPassword //OSS user password: mandatory
close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
}
}
}
}
publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact sourcesJar
artifact testJar
artifact testSourcesJar
artifact javadocJar
groupId 'info.picocli'
artifactId bintrayPackage
version "$projectVersion"
pom.withXml {
def root = asNode()
root.appendNode('packaging', 'jar')
root.appendNode('name', bintrayPackage)
root.appendNode('description', description)
root.appendNode('url', 'http://picocli.info')
root.appendNode('inceptionYear', '2018')
root.children().last() + pomConfig
}
}
}
}
picocli-3.9.6/picocli-shell-jline3/src/ 0000775 0000000 0000000 00000000000 13457642030 0017657 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/ 0000775 0000000 0000000 00000000000 13457642030 0020603 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/java/ 0000775 0000000 0000000 00000000000 13457642030 0021524 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023146 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/java/picocli/shell/ 0000775 0000000 0000000 00000000000 13457642030 0024255 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/java/picocli/shell/jline3/ 0000775 0000000 0000000 00000000000 13457642030 0025441 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/main/java/picocli/shell/jline3/PicocliJLineCompleter.java 0000664 0000000 0000000 00000004557 13457642030 0032476 0 ustar 00root root 0000000 0000000 package picocli.shell.jline3;
import org.jline.reader.LineReader;
import org.jline.reader.Completer;
import org.jline.reader.Candidate;
import org.jline.reader.ParsedLine;
import picocli.AutoComplete;
import picocli.CommandLine.Model.CommandSpec;
import java.util.List;
import java.util.ArrayList;
import java.lang.CharSequence;
/**
* Implementation of the JLine 3 {@link Completer} interface that generates completion
* candidates for the specified command line based on the {@link CommandSpec} that
* this {@code PicocliJLineCompleter} was constructed with.
*
* @since 3.9
*/
public class PicocliJLineCompleter implements Completer {
private final CommandSpec spec;
/**
* Constructs a new {@code PicocliJLineCompleter} for the given command spec.
* @param spec the command specification to generate completions for. Must be non-{@code null}.
*/
public PicocliJLineCompleter(CommandSpec spec) {
if (spec == null) { throw new NullPointerException("spec"); }
this.spec = spec;
}
/**
* Populates candidates with a list of possible completions for the command line .
*
* The list of candidates will be sorted and filtered by the LineReader, so that
* the list of candidates displayed to the user will usually be smaller than
* the list given by the completer. Thus it is not necessary for the completer
* to do any matching based on the current buffer. On the contrary, in order
* for the typo matcher to work, all possible candidates for the word being
* completed should be returned.
*
* @param reader The line reader
* @param line The parsed command line
* @param candidates The {@link List} of candidates to populate
*/
//@Override
public void complete(LineReader reader, ParsedLine line, List candidates) {
// let picocli generate completion candidates for the token where the cursor is at
String[] words = new String[line.words().size()];
words = line.words().toArray(words);
List cs = new ArrayList();
AutoComplete.complete(spec,
words,
line.wordIndex(),
0,
line.cursor(),
cs);
for(CharSequence c: cs){
candidates.add(new Candidate((String)c));
}
}
}
picocli-3.9.6/picocli-shell-jline3/src/test/ 0000775 0000000 0000000 00000000000 13457642030 0020636 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/ 0000775 0000000 0000000 00000000000 13457642030 0021557 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0023201 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/picocli/shell/ 0000775 0000000 0000000 00000000000 13457642030 0024310 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/picocli/shell/jline3/ 0000775 0000000 0000000 00000000000 13457642030 0025474 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/picocli/shell/jline3/example/ 0000775 0000000 0000000 00000000000 13457642030 0027127 5 ustar 00root root 0000000 0000000 picocli-3.9.6/picocli-shell-jline3/src/test/java/picocli/shell/jline3/example/Example.java 0000664 0000000 0000000 00000010412 13457642030 0031363 0 ustar 00root root 0000000 0000000 package picocli.shell.jline3.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.jline.reader.Completer;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.EndOfFileException;
import org.jline.reader.UserInterruptException;
import org.jline.reader.ParsedLine;
import org.jline.reader.impl.DefaultParser;
import org.jline.reader.impl.LineReaderImpl;
import org.jline.terminal.TerminalBuilder;
import org.jline.terminal.Terminal;
import org.jline.reader.MaskingCallback;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;
import picocli.shell.jline3.PicocliJLineCompleter;
/**
* Example that demonstrates how to build an interactive shell with JLine3 and picocli.
* @since 3.9
*/
public class Example {
/**
* Top-level command that just prints help.
*/
@Command(name = "", description = "Example interactive shell with completion",
footer = {"", "Press Ctl-D to exit."},
subcommands = {MyCommand.class, ClearScreen.class})
static class CliCommands implements Runnable {
LineReaderImpl reader;
PrintWriter out;
CliCommands() {}
public void setReader(LineReader reader){
this.reader = (LineReaderImpl)reader;
out = reader.getTerminal().writer();
}
public void run() {
out.println(new CommandLine(this).getUsageMessage());
}
}
/**
* A command with some options to demonstrate completion.
*/
@Command(name = "cmd", mixinStandardHelpOptions = true, version = "1.0",
description = "Command with some options to demonstrate TAB-completion" +
" (note that enum values also get completed)")
static class MyCommand implements Runnable {
@Option(names = {"-v", "--verbose"})
private boolean[] verbosity = {};
@Option(names = {"-d", "--duration"})
private int amount;
@Option(names = {"-u", "--timeUnit"})
private TimeUnit unit;
@ParentCommand CliCommands parent;
public void run() {
if (verbosity.length > 0) {
parent.out.printf("Hi there. You asked for %d %s.%n", amount, unit);
} else {
parent.out.println("hi!");
}
}
}
/**
* Command that clears the screen.
*/
@Command(name = "cls", aliases = "clear", mixinStandardHelpOptions = true,
description = "Clears the screen", version = "1.0")
static class ClearScreen implements Callable {
@ParentCommand CliCommands parent;
public Void call() throws IOException {
parent.reader.clearScreen();
return null;
}
}
public static void main(String[] args) {
try {
// set up the completion
CliCommands commands = new CliCommands();
CommandLine cmd = new CommandLine(commands);
Terminal terminal = TerminalBuilder.builder().build();
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.completer(new PicocliJLineCompleter(cmd.getCommandSpec()))
.parser(new DefaultParser())
.build();
commands.setReader(reader);
String prompt = "prompt> ";
String rightPrompt = null;
// start the shell and process input until the user quits with Ctl-D
String line;
while (true) {
try {
line = reader.readLine(prompt, rightPrompt, (MaskingCallback) null, null);
ParsedLine pl = reader.getParser().parse(line, 0);
String[] arguments = pl.words().toArray(new String[0]);
CommandLine.run(commands, arguments);
} catch (UserInterruptException e) {
// Ignore
} catch (EndOfFileException e) {
return;
}
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
picocli-3.9.6/settings.gradle 0000664 0000000 0000000 00000000221 13457642030 0016172 0 ustar 00root root 0000000 0000000 rootProject.name = 'picocli'
include 'picocli-examples'
include 'picocli-shell-jline2'
include 'picocli-shell-jline3'
include 'picocli-codegen'
picocli-3.9.6/src/ 0000775 0000000 0000000 00000000000 13457642030 0013746 5 ustar 00root root 0000000 0000000 picocli-3.9.6/src/main/ 0000775 0000000 0000000 00000000000 13457642030 0014672 5 ustar 00root root 0000000 0000000 picocli-3.9.6/src/main/java/ 0000775 0000000 0000000 00000000000 13457642030 0015613 5 ustar 00root root 0000000 0000000 picocli-3.9.6/src/main/java/overview.html 0000664 0000000 0000000 00000004765 13457642030 0020363 0 ustar 00root root 0000000 0000000
Picocli is a one-file framework for creating Java command line applications with almost zero code.
It supports a variety of command line syntax styles including POSIX, GNU, MS-DOS and more.
Generates highly customizable usage help messages with ANSI colors and styles .
Picocli-based applications can have command line TAB completion
showing available options, option parameters and subcommands, for any level of nested subcommands.
How it works: annotate your class and picocli initializes it from the command line arguments,
converting the input to strongly typed values in the fields of your class.
Then invoke CommandLine.parse
or CommandLine.populateCommand
with the command line parameters and an object you want to initialize.
Picocli provides a number of convenience methods
that allow you to omit error handling and other boilerplate code for common use cases.
Here is a small example application that uses the CommandLine.call
convenience method
to do parsing and error handling in one line of code.
The full user manual is hosted at http://picocli.info .
@Command(name = "checksum", mixinStandardHelpOptions = true, version = "Checksum 2.0",
description = "Prints the checksum (MD5 by default) of a file to STDOUT.")
class CheckSum implements Callable<Void> {
@Parameters(index = "0", description = "The file whose checksum to calculate.")
private File file;
@Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
private String algorithm = "MD5";
public static void main(String[] args) throws Exception {
// 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);
}
@Override
public Void call() throws Exception {
// your business logic goes here
byte[] fileContents = Files.readAllBytes(file.toPath());
byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(digest));
return null;
}
}
picocli-3.9.6/src/main/java/picocli/ 0000775 0000000 0000000 00000000000 13457642030 0017235 5 ustar 00root root 0000000 0000000 picocli-3.9.6/src/main/java/picocli/AutoComplete.java 0000664 0000000 0000000 00000114376 13457642030 0022515 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import picocli.CommandLine.*;
import picocli.CommandLine.Model.PositionalParamSpec;
import picocli.CommandLine.Model.ArgSpec;
import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Model.OptionSpec;
import static java.lang.String.*;
/**
* Stand-alone tool that generates bash auto-complete scripts for picocli-based command line applications.
*/
public class AutoComplete {
/** Normal exit code of this application ({@value}). */
public static final int EXIT_CODE_SUCCESS = 0;
/** Exit code of this application when the specified command line arguments are invalid ({@value}). */
public static final int EXIT_CODE_INVALID_INPUT = 1;
/** Exit code of this application when the specified command script exists ({@value}). */
public static final int EXIT_CODE_COMMAND_SCRIPT_EXISTS = 2;
/** Exit code of this application when the specified completion script exists ({@value}). */
public static final int EXIT_CODE_COMPLETION_SCRIPT_EXISTS = 3;
/** Exit code of this application when an exception was encountered during operation ({@value}). */
public static final int EXIT_CODE_EXECUTION_ERROR = 4;
private AutoComplete() { }
/**
* Generates a bash completion script for the specified command class.
* @param args command line options. Specify at least the {@code commandLineFQCN} mandatory parameter, which is
* the fully qualified class name of the annotated {@code @Command} class to generate a completion script for.
* Other parameters are optional. Specify {@code -h} to see details on the available options.
*/
public static void main(String... args) {
AbstractParseResultHandler> resultHandler = new CommandLine.RunLast();
DefaultExceptionHandler> exceptionHandler = CommandLine.defaultExceptionHandler();
if (exitOnError()) { exceptionHandler.andExit(EXIT_CODE_INVALID_INPUT); }
List result = new CommandLine(new App()).parseWithHandlers(resultHandler, exceptionHandler, args);
int exitCode = result == null ? EXIT_CODE_SUCCESS : (Integer) result.get(0);
if ((exitCode == EXIT_CODE_SUCCESS && exitOnSuccess()) || (exitCode != EXIT_CODE_SUCCESS && exitOnError())) {
System.exit(exitCode);
}
}
private static boolean exitOnSuccess() {
return syspropDefinedAndNotFalse("picocli.autocomplete.systemExitOnSuccess");
}
private static boolean exitOnError() {
return syspropDefinedAndNotFalse("picocli.autocomplete.systemExitOnError");
}
private static boolean syspropDefinedAndNotFalse(String key) {
String value = System.getProperty(key);
return value != null && !"false".equalsIgnoreCase(value);
}
/**
* CLI command class for generating completion script.
*/
@Command(name = "picocli.AutoComplete", sortOptions = false,
description = "Generates a bash completion script for the specified command class.",
footerHeading = "%n@|bold Exit Code|@%n",
footer = {"Set the following system properties to control the exit code of this program:",
" \"@|yellow picocli.autocomplete.systemExitOnSuccess|@\" - call `System.exit(0)` when",
" execution completes normally",
" \"@|yellow picocli.autocomplete.systemExitOnError|@\" - call `System.exit(ERROR_CODE)`",
" when an error occurs",
"If these system properties are not defined or have value \"false\", this program completes without terminating the JVM."
})
private static class App implements Callable {
@Parameters(arity = "1", description = "Fully qualified class name of the annotated " +
"@Command class to generate a completion script for.")
String commandLineFQCN;
@Option(names = {"-c", "--factory"}, description = "Optionally specify the fully qualified class name of the custom factory to use to instantiate the command class. " +
"When omitted, the default picocli factory is used.")
String factoryClass;
@Option(names = {"-n", "--name"}, description = "Optionally specify the name of the command to create a completion script for. " +
"When omitted, the annotated class @Command 'name' attribute is used. " +
"If no @Command 'name' attribute exists, '' (in lower-case) is used.")
String commandName;
@Option(names = {"-o", "--completionScript"},
description = "Optionally specify the path of the completion script file to generate. " +
"When omitted, a file named '_completion' " +
"is generated in the current directory.")
File autoCompleteScript;
@Option(names = {"-w", "--writeCommandScript"},
description = "Write a '' sample command script to the same directory " +
"as the completion script.")
boolean writeCommandScript;
@Option(names = {"-f", "--force"}, description = "Overwrite existing script files.")
boolean overwriteIfExists;
@Option(names = { "-h", "--help"}, usageHelp = true, description = "Display this help message and quit.")
boolean usageHelpRequested;
public Integer call() {
try {
IFactory factory = CommandLine.defaultFactory();
if (factoryClass != null) {
factory = (IFactory) factory.create(Class.forName(factoryClass));
}
Class> cls = Class.forName(commandLineFQCN);
Object instance = factory.create(cls);
CommandLine commandLine = new CommandLine(instance, factory);
if (commandName == null) {
commandName = commandLine.getCommandName(); //new CommandLine.Help(commandLine.commandDescriptor).commandName;
if (CommandLine.Help.DEFAULT_COMMAND_NAME.equals(commandName)) {
commandName = cls.getSimpleName().toLowerCase();
}
}
if (autoCompleteScript == null) {
autoCompleteScript = new File(commandName + "_completion");
}
File commandScript = null;
if (writeCommandScript) {
commandScript = new File(autoCompleteScript.getAbsoluteFile().getParentFile(), commandName);
}
if (commandScript != null && !overwriteIfExists && checkExists(commandScript)) {
return EXIT_CODE_COMMAND_SCRIPT_EXISTS;
}
if (!overwriteIfExists && checkExists(autoCompleteScript)) {
return EXIT_CODE_COMPLETION_SCRIPT_EXISTS;
}
AutoComplete.bash(commandName, autoCompleteScript, commandScript, commandLine);
return EXIT_CODE_SUCCESS;
} catch (Exception ex) {
ex.printStackTrace();
CommandLine.usage(new App(), System.err);
return EXIT_CODE_EXECUTION_ERROR;
}
}
private boolean checkExists(final File file) {
if (file.exists()) {
System.err.printf("ERROR: picocli.AutoComplete: %s exists. Specify --force to overwrite.%n", file.getAbsolutePath());
CommandLine.usage(this, System.err);
return true;
}
return false;
}
}
private static interface Function {
V apply(T t);
}
/**
* Drops all characters that are not valid for bash function and identifier names.
*/
private static class Bashify implements Function {
public String apply(CharSequence value) {
return bashify(value);
}
}
private static String bashify(CharSequence value) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (Character.isLetterOrDigit(c) || c == '_') {
builder.append(c);
} else if (Character.isSpaceChar(c)) {
builder.append('_');
}
}
return builder.toString();
}
private static class NullFunction implements Function {
public String apply(CharSequence value) { return value.toString(); }
}
private static interface Predicate {
boolean test(T t);
}
private static class BooleanArgFilter implements Predicate {
public boolean test(ArgSpec f) {
return f.type() == Boolean.TYPE || f.type() == Boolean.class;
}
}
private static Predicate negate(final Predicate original) {
return new Predicate() {
public boolean test(T t) {
return !original.test(t);
}
};
}
private static List filter(List list, Predicate filter) {
List result = new ArrayList();
for (T t : list) { if (filter.test(t)) { result.add(t); } }
return result;
}
/** Package-private for tests; consider this class private. */
static class CommandDescriptor {
final String functionName;
final String commandName;
CommandDescriptor(String functionName, String commandName) {
this.functionName = functionName;
this.commandName = commandName;
}
public int hashCode() { return functionName.hashCode() * 37 + commandName.hashCode(); }
public boolean equals(Object obj) {
if (!(obj instanceof CommandDescriptor)) { return false; }
if (obj == this) { return true; }
CommandDescriptor other = (CommandDescriptor) obj;
return other.functionName.equals(functionName) && other.commandName.equals(commandName);
}
}
private static final String HEADER = "" +
"#!/usr/bin/env bash\n" +
"#\n" +
"# %1$s Bash Completion\n" +
"# =======================\n" +
"#\n" +
"# Bash completion support for the `%1$s` command,\n" +
"# generated by [picocli](http://picocli.info/) version %2$s.\n" +
"#\n" +
"# Installation\n" +
"# ------------\n" +
"#\n" +
"# 1. Source all completion scripts in your .bash_profile\n" +
"#\n" +
"# cd $YOUR_APP_HOME/bin\n" +
"# for f in $(find . -name \"*_completion\"); do line=\". $(pwd)/$f\"; grep \"$line\" ~/.bash_profile || echo \"$line\" >> ~/.bash_profile; done\n" +
"#\n" +
"# 2. Open a new bash console, and type `%1$s [TAB][TAB]`\n" +
"#\n" +
"# 1a. Alternatively, if you have [bash-completion](https://github.com/scop/bash-completion) installed:\n" +
"# Place this file in a `bash-completion.d` folder:\n" +
"#\n" +
"# * /etc/bash-completion.d\n" +
"# * /usr/local/etc/bash-completion.d\n" +
"# * ~/bash-completion.d\n" +
"#\n" +
"# Documentation\n" +
"# -------------\n" +
"# The script is called by bash whenever [TAB] or [TAB][TAB] is pressed after\n" +
"# '%1$s (..)'. By reading entered command line parameters,\n" +
"# it determines possible bash completions and writes them to the COMPREPLY variable.\n" +
"# Bash then completes the user input if only one entry is listed in the variable or\n" +
"# shows the options if more than one is listed in COMPREPLY.\n" +
"#\n" +
"# References\n" +
"# ----------\n" +
"# [1] http://stackoverflow.com/a/12495480/1440785\n" +
"# [2] http://tiswww.case.edu/php/chet/bash/FAQ\n" +
"# [3] https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html\n" +
"# [4] http://zsh.sourceforge.net/Doc/Release/Options.html#index-COMPLETE_005fALIASES\n" +
"# [5] https://stackoverflow.com/questions/17042057/bash-check-element-in-array-for-elements-in-another-array/17042655#17042655\n" +
"# [6] https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html#Programmable-Completion\n" +
"#\n" +
"\n" +
"if [ -n \"$BASH_VERSION\" ]; then\n" +
" # Enable programmable completion facilities when using bash (see [3])\n" +
" shopt -s progcomp\n" +
"elif [ -n \"$ZSH_VERSION\" ]; then\n" +
" # Make alias a distinct command for completion purposes when using zsh (see [4])\n" +
" setopt COMPLETE_ALIASES\n" +
" alias compopt=complete\n" +
"fi\n" +
"\n" +
"# ArrContains takes two arguments, both of which are the name of arrays.\n" +
"# It creates a temporary hash from lArr1 and then checks if all elements of lArr2\n" +
"# are in the hashtable.\n" +
"#\n" +
"# Returns zero (no error) if all elements of the 2nd array are in the 1st array,\n" +
"# otherwise returns 1 (error).\n" +
"#\n" +
"# Modified from [5]\n" +
"function ArrContains() {\n" +
" local lArr1 lArr2\n" +
" declare -A tmp\n" +
" eval lArr1=(\"\\\"\\${$1[@]}\\\"\")\n" +
" eval lArr2=(\"\\\"\\${$2[@]}\\\"\")\n" +
" for i in \"${lArr1[@]}\";{ [ -n \"$i\" ] && ((++tmp[$i]));}\n" +
" for i in \"${lArr2[@]}\";{ [ -n \"$i\" ] && [ -z \"${tmp[$i]}\" ] && return 1;}\n" +
" return 0\n" +
"}\n" +
"\n";
private static final String FOOTER = "" +
"\n" +
"# Define a completion specification (a compspec) for the\n" +
"# `%1$s`, `%1$s.sh`, and `%1$s.bash` commands.\n" +
"# Uses the bash `complete` builtin (see [6]) to specify that shell function\n" +
"# `_complete_%1$s` is responsible for generating possible completions for the\n" +
"# current word on the command line.\n" +
"# The `-o default` option means that if the function generated no matches, the\n" +
"# default Bash completions and the Readline default filename completions are performed.\n" +
"complete -F _complete_%1$s -o default %1$s %1$s.sh %1$s.bash\n";
/**
* Generates source code for an autocompletion bash script for the specified picocli-based application,
* and writes this script to the specified {@code out} file, and optionally writes an invocation script
* to the specified {@code command} file.
* @param scriptName the name of the command to generate a bash autocompletion script for
* @param commandLine the {@code CommandLine} instance for the command line application
* @param out the file to write the autocompletion bash script source code to
* @param command the file to write a helper script to that invokes the command, or {@code null} if no helper script file should be written
* @throws IOException if a problem occurred writing to the specified files
*/
public static void bash(String scriptName, File out, File command, CommandLine commandLine) throws IOException {
String autoCompleteScript = bash(scriptName, commandLine);
Writer completionWriter = null;
Writer scriptWriter = null;
try {
completionWriter = new FileWriter(out);
completionWriter.write(autoCompleteScript);
if (command != null) {
scriptWriter = new FileWriter(command);
scriptWriter.write("" +
"#!/usr/bin/env bash\n" +
"\n" +
"LIBS=path/to/libs\n" +
"CP=\"${LIBS}/myApp.jar\"\n" +
"java -cp \"${CP}\" '" + commandLine.getCommand().getClass().getName() + "' $@");
}
} finally {
if (completionWriter != null) { completionWriter.close(); }
if (scriptWriter != null) { scriptWriter.close(); }
}
}
/**
* Generates and returns the source code for an autocompletion bash script for the specified picocli-based application.
* @param scriptName the name of the command to generate a bash autocompletion script for
* @param commandLine the {@code CommandLine} instance for the command line application
* @return source code for an autocompletion bash script
*/
public static String bash(String scriptName, CommandLine commandLine) {
if (scriptName == null) { throw new NullPointerException("scriptName"); }
if (commandLine == null) { throw new NullPointerException("commandLine"); }
StringBuilder result = new StringBuilder();
result.append(format(HEADER, scriptName, CommandLine.VERSION));
Map function2command = new LinkedHashMap();
result.append(generateEntryPointFunction(scriptName, commandLine, function2command));
for (Map.Entry functionSpec : function2command.entrySet()) {
CommandDescriptor descriptor = functionSpec.getKey();
result.append(generateFunctionForCommand(descriptor.functionName, descriptor.commandName, functionSpec.getValue()));
}
result.append(format(FOOTER, scriptName));
return result.toString();
}
private static String generateEntryPointFunction(String scriptName,
CommandLine commandLine,
Map function2command) {
String HEADER = "" +
"# Bash completion entry point function.\n" +
"# _complete_%1$s finds which commands and subcommands have been specified\n" +
"# on the command line and delegates to the appropriate function\n" +
"# to generate possible options and subcommands for the last specified subcommand.\n" +
"function _complete_%1$s() {\n" +
// " CMDS1=(%1$s gettingstarted)\n" +
// " CMDS2=(%1$s tool)\n" +
// " CMDS3=(%1$s tool sub1)\n" +
// " CMDS4=(%1$s tool sub2)\n" +
// "\n" +
// " ArrContains COMP_WORDS CMDS4 && { _picocli_basic_tool_sub2; return $?; }\n" +
// " ArrContains COMP_WORDS CMDS3 && { _picocli_basic_tool_sub1; return $?; }\n" +
// " ArrContains COMP_WORDS CMDS2 && { _picocli_basic_tool; return $?; }\n" +
// " ArrContains COMP_WORDS CMDS1 && { _picocli_basic_gettingstarted; return $?; }\n" +
// " _picocli_%1$s; return $?;\n" +
// "}\n" +
// "\n" +
// "complete -F _complete_%1$s %1$s\n" +
// "\n";
"";
String FOOTER = "\n" +
" # No subcommands were specified; generate completions for the top-level command.\n" +
" _picocli_%1$s; return $?;\n" +
"}\n";
StringBuilder buff = new StringBuilder(1024);
buff.append(format(HEADER, scriptName));
List predecessors = new ArrayList();
List functionCallsToArrContains = new ArrayList();
function2command.put(new CommandDescriptor("_picocli_" + scriptName, scriptName), commandLine);
generateFunctionCallsToArrContains(scriptName, predecessors, commandLine, buff, functionCallsToArrContains, function2command);
buff.append("\n");
Collections.reverse(functionCallsToArrContains);
for (String func : functionCallsToArrContains) {
buff.append(func);
}
buff.append(format(FOOTER, scriptName));
return buff.toString();
}
private static void generateFunctionCallsToArrContains(String scriptName,
List predecessors,
CommandLine commandLine,
StringBuilder buff,
List functionCalls,
Map function2command) {
// breadth-first: generate command lists and function calls for predecessors + each subcommand
for (Map.Entry entry : commandLine.getSubcommands().entrySet()) {
int count = functionCalls.size();
String functionName = "_picocli_" + scriptName + "_" + concat("_", predecessors, entry.getKey(), new Bashify());
functionCalls.add(format(" ArrContains COMP_WORDS CMDS%2$d && { %1$s; return $?; }\n", functionName, count));
buff.append( format(" CMDS%2$d=(%1$s)\n", concat(" ", predecessors, entry.getKey(), new NullFunction()), count));
// remember the function name and associated subcommand so we can easily generate a function later
function2command.put(new CommandDescriptor(functionName, entry.getKey()), entry.getValue());
}
// then recursively do the same for all nested subcommands
for (Map.Entry entry : commandLine.getSubcommands().entrySet()) {
predecessors.add(entry.getKey());
generateFunctionCallsToArrContains(scriptName, predecessors, entry.getValue(), buff, functionCalls, function2command);
predecessors.remove(predecessors.size() - 1);
}
}
private static String concat(String infix, String... values) {
return concat(infix, Arrays.asList(values));
}
private static String concat(String infix, List values) {
return concat(infix, values, null, new NullFunction());
}
private static String concat(String infix, List values, T lastValue, Function normalize) {
StringBuilder sb = new StringBuilder();
for (T val : values) {
if (sb.length() > 0) { sb.append(infix); }
sb.append(normalize.apply(val));
}
if (lastValue == null) { return sb.toString(); }
if (sb.length() > 0) { sb.append(infix); }
return sb.append(normalize.apply(lastValue)).toString();
}
private static String generateFunctionForCommand(String functionName, String commandName, CommandLine commandLine) {
String HEADER = "" +
"\n" +
"# Generates completions for the options and subcommands of the `%s` %scommand.\n" +
"function %s() {\n" +
" # Get completion data\n" +
" CURR_WORD=${COMP_WORDS[COMP_CWORD]}\n" +
" PREV_WORD=${COMP_WORDS[COMP_CWORD-1]}\n" +
"\n" +
" COMMANDS=\"%s\"\n" + // COMMANDS="gettingstarted tool"
" FLAG_OPTS=\"%s\"\n" + // FLAG_OPTS="--verbose -V -x --extract -t --list"
" ARG_OPTS=\"%s\"\n"; // ARG_OPTS="--host --option --file -f -u --timeUnit"
String FOOTER = "" +
"\n" +
" if [[ \"${CURR_WORD}\" == -* ]]; then\n" +
" COMPREPLY=( $(compgen -W \"${FLAG_OPTS} ${ARG_OPTS}\" -- ${CURR_WORD}) )\n" +
" else\n" +
" COMPREPLY=( $(compgen -W \"${COMMANDS}\" -- ${CURR_WORD}) )\n" +
" fi\n" +
"}\n";
// Get the fields annotated with @Option and @Parameters for the specified CommandLine.
CommandSpec commandSpec = commandLine.getCommandSpec();
// Build a list of "flag" options that take no parameters and "arg" options that do take parameters, and subcommands.
String flagOptionNames = optionNames(filter(commandSpec.options(), new BooleanArgFilter()));
List argOptionFields = filter(commandSpec.options(), negate(new BooleanArgFilter()));
String argOptionNames = optionNames(argOptionFields);
String commands = concat(" ", new ArrayList(commandLine.getSubcommands().keySet())).trim();
// Generate the header: the function declaration, CURR_WORD, PREV_WORD and COMMANDS, FLAG_OPTS and ARG_OPTS.
StringBuilder buff = new StringBuilder(1024);
String sub = functionName.equals("_picocli_" + commandName) ? "" : "sub";
buff.append(format(HEADER, commandName, sub, functionName, commands, flagOptionNames, argOptionNames));
// Generate completion lists for options with a known set of valid values (including java enums)
for (OptionSpec f : commandSpec.options()) {
if (f.completionCandidates() != null) {
generateCompletionCandidates(buff, f);
}
}
// TODO generate completion lists for other option types:
// Charset, Currency, Locale, TimeZone, ByteOrder,
// javax.crypto.Cipher, javax.crypto.KeyGenerator, javax.crypto.Mac, javax.crypto.SecretKeyFactory
// java.security.AlgorithmParameterGenerator, java.security.AlgorithmParameters, java.security.KeyFactory, java.security.KeyPairGenerator, java.security.KeyStore, java.security.MessageDigest, java.security.Signature
// sql.Types?
// Now generate the "case" switches for the options whose arguments we can generate completions for
buff.append(generateOptionsSwitch(argOptionFields));
// Generate the footer: a default COMPREPLY to fall back to, and the function closing brace.
buff.append(format(FOOTER));
return buff.toString();
}
private static void generateCompletionCandidates(StringBuilder buff, OptionSpec f) {
buff.append(format(" %s_OPTION_ARGS=\"%s\" # %s values\n",
bashify(f.paramLabel()),
concat(" ", extract(f.completionCandidates())).trim(),
f.longestName()));
}
private static List extract(Iterable generator) {
List result = new ArrayList();
for (String e : generator) {
result.add(e);
}
return result;
}
private static String generateOptionsSwitch(List argOptions) {
String optionsCases = generateOptionsCases(argOptions, "", "${CURR_WORD}");
if (optionsCases.length() == 0) {
return "";
}
StringBuilder buff = new StringBuilder(1024);
buff.append("\n");
buff.append(" compopt +o default\n");
buff.append("\n");
buff.append(" case ${PREV_WORD} in\n");
buff.append(optionsCases);
buff.append(" esac\n");
return buff.toString();
}
private static String generateOptionsCases(List argOptionFields, String indent, String currWord) {
StringBuilder buff = new StringBuilder(1024);
for (OptionSpec option : argOptionFields) {
if (option.completionCandidates() != null) {
buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -u|--timeUnit)\n"
buff.append(format("%s COMPREPLY=( $( compgen -W \"${%s_OPTION_ARGS}\" -- %s ) )\n", indent, bashify(option.paramLabel()), currWord));
buff.append(format("%s return $?\n", indent));
buff.append(format("%s ;;\n", indent));
} else if (option.type().equals(File.class) || "java.nio.file.Path".equals(option.type().getName())) {
buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -f|--file)\n"
buff.append(format("%s compopt -o filenames\n", indent));
buff.append(format("%s COMPREPLY=( $( compgen -f -- %s ) ) # files\n", indent, currWord));
buff.append(format("%s return $?\n", indent));
buff.append(format("%s ;;\n", indent));
} else if (option.type().equals(InetAddress.class)) {
buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // " -h|--host)\n"
buff.append(format("%s compopt -o filenames\n", indent));
buff.append(format("%s COMPREPLY=( $( compgen -A hostname -- %s ) )\n", indent, currWord));
buff.append(format("%s return $?\n", indent));
buff.append(format("%s ;;\n", indent));
} else {
buff.append(format("%s %s)\n", indent, concat("|", option.names()))); // no completions available
buff.append(format("%s return\n", indent));
buff.append(format("%s ;;\n", indent));
}
}
return buff.toString();
}
private static String optionNames(List options) {
List result = new ArrayList();
for (OptionSpec option : options) {
result.addAll(Arrays.asList(option.names()));
}
return concat(" ", result, "", new NullFunction()).trim();
}
public static int complete(CommandSpec spec, String[] args, int argIndex, int positionInArg, int cursor, List candidates) {
if (spec == null) { throw new NullPointerException("spec is null"); }
if (args == null) { throw new NullPointerException("args is null"); }
if (candidates == null) { throw new NullPointerException("candidates list is null"); }
if (argIndex == args.length) {
String[] copy = new String[args.length + 1];
System.arraycopy(args, 0, copy, 0, args.length);
args = copy;
args[argIndex] = "";
}
if (argIndex < 0 || argIndex >= args.length) { throw new IllegalArgumentException("Invalid argIndex " + argIndex + ": args array only has " + args.length + " elements."); }
if (positionInArg < 0 || positionInArg > args[argIndex].length()) { throw new IllegalArgumentException("Invalid positionInArg " + positionInArg + ": args[" + argIndex + "] (" + args[argIndex] + ") only has " + args[argIndex].length() + " characters."); }
String currentArg = args[argIndex];
boolean reset = spec.parser().collectErrors();
try {
String committedPrefix = currentArg.substring(0, positionInArg);
spec.parser().collectErrors(true);
CommandLine parser = new CommandLine(spec);
ParseResult parseResult = parser.parseArgs(args);
if (argIndex >= parseResult.tentativeMatch.size()) {
Object startPoint = findCompletionStartPoint(parseResult);
addCandidatesForArgsFollowing(startPoint, candidates);
} else {
Object obj = parseResult.tentativeMatch.get(argIndex);
if (obj instanceof CommandSpec) { // subcommand
addCandidatesForArgsFollowing(((CommandSpec) obj).parent(), candidates);
} else if (obj instanceof OptionSpec) { // option
int sep = currentArg.indexOf(spec.parser().separator());
if (sep < 0 || positionInArg < sep) { // no '=' or cursor before '='
addCandidatesForArgsFollowing(findCommandFor((OptionSpec) obj, spec), candidates);
} else {
addCandidatesForArgsFollowing((OptionSpec) obj, candidates);
int sepLength = spec.parser().separator().length();
if (positionInArg < sep + sepLength) {
int posInSeparator = positionInArg - sep;
String prefix = spec.parser().separator().substring(posInSeparator);
for (int i = 0; i < candidates.size(); i++) {
candidates.set(i, prefix + candidates.get(i));
}
committedPrefix = currentArg.substring(sep, positionInArg);
} else {
committedPrefix = currentArg.substring(sep + sepLength, positionInArg);
}
}
} else if (obj instanceof PositionalParamSpec) { // positional
//addCandidatesForArgsFollowing(obj, candidates);
addCandidatesForArgsFollowing(findCommandFor((PositionalParamSpec) obj, spec), candidates);
} else {
int i = argIndex - 1;
while (i > 0 && !isPicocliModelObject(parseResult.tentativeMatch.get(i))) {i--;}
if (i < 0) { return -1; }
addCandidatesForArgsFollowing(parseResult.tentativeMatch.get(i), candidates);
}
}
filterAndTrimMatchingPrefix(committedPrefix, candidates);
return candidates.isEmpty() ? -1 : cursor;
} finally {
spec.parser().collectErrors(reset);
}
}
private static Object findCompletionStartPoint(ParseResult parseResult) {
List tentativeMatches = parseResult.tentativeMatch;
for (int i = 1; i <= tentativeMatches.size(); i++) {
Object found = tentativeMatches.get(tentativeMatches.size() - i);
if (found instanceof CommandSpec) {
return found;
}
if (found instanceof ArgSpec) {
CommandLine.Range arity = ((ArgSpec) found).arity();
if (i < arity.min) {
return found; // not all parameters have been supplied yet
} else {
return findCommandFor((ArgSpec) found, parseResult.commandSpec());
}
}
}
return parseResult.commandSpec();
}
private static CommandSpec findCommandFor(ArgSpec arg, CommandSpec cmd) {
return (arg instanceof OptionSpec) ? findCommandFor((OptionSpec) arg, cmd) : findCommandFor((PositionalParamSpec) arg, cmd);
}
private static CommandSpec findCommandFor(OptionSpec option, CommandSpec commandSpec) {
for (OptionSpec defined : commandSpec.options()) {
if (defined == option) { return commandSpec; }
}
for (CommandLine sub : commandSpec.subcommands().values()) {
CommandSpec result = findCommandFor(option, sub.getCommandSpec());
if (result != null) { return result; }
}
return null;
}
private static CommandSpec findCommandFor(PositionalParamSpec positional, CommandSpec commandSpec) {
for (PositionalParamSpec defined : commandSpec.positionalParameters()) {
if (defined == positional) { return commandSpec; }
}
for (CommandLine sub : commandSpec.subcommands().values()) {
CommandSpec result = findCommandFor(positional, sub.getCommandSpec());
if (result != null) { return result; }
}
return null;
}
private static boolean isPicocliModelObject(Object obj) {
return obj instanceof CommandSpec || obj instanceof OptionSpec || obj instanceof PositionalParamSpec;
}
private static void filterAndTrimMatchingPrefix(String prefix, List candidates) {
List replace = new ArrayList();
for (CharSequence seq : candidates) {
if (seq.toString().startsWith(prefix)) {
replace.add(seq.subSequence(prefix.length(), seq.length()));
}
}
candidates.clear();
candidates.addAll(replace);
}
private static void addCandidatesForArgsFollowing(Object obj, List candidates) {
if (obj == null) { return; }
if (obj instanceof CommandSpec) {
addCandidatesForArgsFollowing((CommandSpec) obj, candidates);
} else if (obj instanceof OptionSpec) {
addCandidatesForArgsFollowing((OptionSpec) obj, candidates);
} else if (obj instanceof PositionalParamSpec) {
addCandidatesForArgsFollowing((PositionalParamSpec) obj, candidates);
}
}
private static void addCandidatesForArgsFollowing(CommandSpec commandSpec, List candidates) {
if (commandSpec == null) { return; }
for (Map.Entry entry : commandSpec.subcommands().entrySet()) {
candidates.add(entry.getKey());
candidates.addAll(Arrays.asList(entry.getValue().getCommandSpec().aliases()));
}
candidates.addAll(commandSpec.optionsMap().keySet());
for (PositionalParamSpec positional : commandSpec.positionalParameters()) {
addCandidatesForArgsFollowing(positional, candidates);
}
}
private static void addCandidatesForArgsFollowing(OptionSpec optionSpec, List candidates) {
if (optionSpec != null) {
addCompletionCandidates(optionSpec.completionCandidates(), candidates);
}
}
private static void addCandidatesForArgsFollowing(PositionalParamSpec positionalSpec, List candidates) {
if (positionalSpec != null) {
addCompletionCandidates(positionalSpec.completionCandidates(), candidates);
}
}
private static void addCompletionCandidates(Iterable completionCandidates, List candidates) {
if (completionCandidates != null) {
for (String candidate : completionCandidates) { candidates.add(candidate); }
}
}
}
picocli-3.9.6/src/main/java/picocli/CommandLine.java 0000664 0000000 0000000 00002526247 13457642030 0022310 0 ustar 00root root 0000000 0000000 /*
Copyright 2017 Remko Popma
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package picocli;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.text.BreakIterator;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import picocli.CommandLine.Help.Ansi.IStyle;
import picocli.CommandLine.Help.Ansi.Style;
import picocli.CommandLine.Help.Ansi.Text;
import picocli.CommandLine.Model.*;
import static java.util.Locale.ENGLISH;
import static picocli.CommandLine.Model.ArgsReflection.abbreviate;
import static picocli.CommandLine.Help.Column.Overflow.SPAN;
import static picocli.CommandLine.Help.Column.Overflow.TRUNCATE;
import static picocli.CommandLine.Help.Column.Overflow.WRAP;
/**
*
* CommandLine interpreter that uses reflection to initialize an annotated domain object with values obtained from the
* command line arguments.
*
Example
* import static picocli.CommandLine.*;
*
* @Command(mixinStandardHelpOptions = true, version = "v3.0.0",
* header = "Encrypt FILE(s), or standard input, to standard output or to the output file.")
* public class Encrypt {
*
* @Parameters(type = File.class, description = "Any number of input files")
* private List<File> files = new ArrayList<File>();
*
* @Option(names = { "-o", "--out" }, description = "Output file (default: print to console)")
* private File outputFile;
*
* @Option(names = { "-v", "--verbose"}, description = "Verbose mode. Helpful for troubleshooting. Multiple -v options increase the verbosity.")
* private boolean[] verbose;
* }
*
*
* Use {@code CommandLine} to initialize a domain object as follows:
*
* public static void main(String... args) {
* Encrypt encrypt = new Encrypt();
* try {
* ParseResult parseResult = new CommandLine(encrypt).parseArgs(args);
* if (!CommandLine.printHelpIfRequested(parseResult)) {
* runProgram(encrypt);
* }
* } catch (ParameterException ex) { // command line arguments could not be parsed
* System.err.println(ex.getMessage());
* ex.getCommandLine().usage(System.err);
* }
* }
*
* Invoke the above program with some command line arguments. The below are all equivalent:
*
*
* --verbose --out=outfile in1 in2
* --verbose --out outfile in1 in2
* -v --out=outfile in1 in2
* -v -o outfile in1 in2
* -v -o=outfile in1 in2
* -vo outfile in1 in2
* -vo=outfile in1 in2
* -v -ooutfile in1 in2
* -vooutfile in1 in2
*
*
* Another example that implements {@code Callable} and uses the {@link #call(Callable, String...) CommandLine.call} convenience API to run in a single line of code:
*
*
* @Command(description = "Prints the checksum (MD5 by default) of a file to STDOUT.",
* name = "checksum", mixinStandardHelpOptions = true, version = "checksum 3.0")
* class CheckSum implements Callable<Void> {
*
* @Parameters(index = "0", description = "The file whose checksum to calculate.")
* private File file;
*
* @Option(names = {"-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")
* private String algorithm = "MD5";
*
* public static void main(String[] args) throws Exception {
* // 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);
* }
*
* @Override
* public Void call() throws Exception {
* // your business logic goes here...
* byte[] fileContents = Files.readAllBytes(file.toPath());
* byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
* System.out.println(javax.xml.bind.DatatypeConverter.printHexBinary(digest));
* return null;
* }
* }
*
* Classes and Interfaces for Defining a CommandSpec Model
*
*
*
* Classes Related to Parsing Command Line Arguments
*
*
*
*/
public class CommandLine {
/** This is picocli version {@value}. */
public static final String VERSION = "3.9.6";
private final Tracer tracer = new Tracer();
private final CommandSpec commandSpec;
private final Interpreter interpreter;
private final IFactory factory;
/**
* Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and a default subcommand factory.
* The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
* user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
* constructs a {@code CommandSpec} from this user object.
*
* When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
* initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
* user object will be initialized based on the command line arguments.
* @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
* @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
*/
public CommandLine(Object command) {
this(command, new DefaultFactory());
}
/**
* Constructs a new {@code CommandLine} interpreter with the specified object (which may be an annotated user object or a {@link CommandSpec CommandSpec}) and object factory.
* The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a {@code @Command}-annotated
* user object with {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
* constructs a {@code CommandSpec} from this user object.
*
If the specified command object is an interface {@code Class} with {@code @Option} and {@code @Parameters}-annotated methods,
* picocli creates a {@link java.lang.reflect.Proxy Proxy} whose methods return the matched command line values.
* If the specified command object is a concrete {@code Class}, picocli delegates to the {@linkplain IFactory factory} to get an instance.
*
* When the {@link #parse(String...)} method is called, the {@link CommandSpec CommandSpec} object will be
* initialized based on command line arguments. If the commandSpec is created from an annotated user object, this
* user object will be initialized based on the command line arguments.
* @param command an annotated user object or a {@code CommandSpec} object to initialize from the command line arguments
* @param factory the factory used to create instances of {@linkplain Command#subcommands() subcommands}, {@linkplain Option#converter() converters}, etc., that are registered declaratively with annotation attributes
* @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
* @since 2.2 */
public CommandLine(Object command, IFactory factory) {
this.factory = Assert.notNull(factory, "factory");
interpreter = new Interpreter();
commandSpec = CommandSpec.forAnnotatedObject(command, factory);
commandSpec.commandLine(this);
commandSpec.validate();
if (commandSpec.unmatchedArgsBindings().size() > 0) { setUnmatchedArgumentsAllowed(true); }
}
/**
* Returns the {@code CommandSpec} model that this {@code CommandLine} was constructed with.
* @return the {@code CommandSpec} model
* @since 3.0 */
public CommandSpec getCommandSpec() { return commandSpec; }
/**
* Adds the options and positional parameters in the specified mixin to this command.
* The specified object may be a {@link CommandSpec CommandSpec} object, or it may be a user object with
* {@code @Option} and {@code @Parameters}-annotated fields, in which case picocli automatically
* constructs a {@code CommandSpec} from this user object.
*
* @param name the name by which the mixin object may later be retrieved
* @param mixin an annotated user object or a {@link CommandSpec CommandSpec} object whose options and positional parameters to add to this command
* @return this CommandLine object, to allow method chaining
* @since 3.0 */
public CommandLine addMixin(String name, Object mixin) {
getCommandSpec().addMixin(name, CommandSpec.forAnnotatedObject(mixin, factory));
return this;
}
/**
* Returns a map of user objects whose options and positional parameters were added to ("mixed in" with) this command.
* @return a new Map containing the user objects mixed in with this command. If {@code CommandSpec} objects without
* user objects were programmatically added, use the {@link CommandSpec#mixins() underlying model} directly.
* @since 3.0 */
public Map getMixins() {
Map mixins = getCommandSpec().mixins();
Map result = new LinkedHashMap();
for (String name : mixins.keySet()) { result.put(name, mixins.get(name).userObject); }
return result;
}
/** Registers a subcommand with the specified name. For example:
*
* CommandLine commandLine = new CommandLine(new Git())
* .addSubcommand("status", new GitStatus())
* .addSubcommand("commit", new GitCommit();
* .addSubcommand("add", new GitAdd())
* .addSubcommand("branch", new GitBranch())
* .addSubcommand("checkout", new GitCheckout())
* //...
* ;
*
*
* The specified object can be an annotated object or a
* {@code CommandLine} instance with its own nested subcommands. For example:
*
* CommandLine commandLine = new CommandLine(new MainCommand())
* .addSubcommand("cmd1", new ChildCommand1()) // subcommand
* .addSubcommand("cmd2", new ChildCommand2())
* .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // subcommand with nested sub-subcommands
* .addSubcommand("cmd3sub1", new GrandChild3Command1())
* .addSubcommand("cmd3sub2", new GrandChild3Command2())
* .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // deeper nesting
* .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1())
* .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2())
* )
* );
*
* The default type converters are available on all subcommands and nested sub-subcommands, but custom type
* converters are registered only with the subcommand hierarchy as it existed when the custom type was registered.
* To ensure a custom type converter is available to all subcommands, register the type converter last, after
* adding subcommands.
* See also the {@link Command#subcommands()} annotation to register subcommands declaratively.
*
* @param name the string to recognize on the command line as a subcommand
* @param command the object to initialize with command line arguments following the subcommand name.
* This may be a {@code CommandLine} instance with its own (nested) subcommands
* @return this CommandLine object, to allow method chaining
* @see #registerConverter(Class, ITypeConverter)
* @since 0.9.7
* @see Command#subcommands()
*/
public CommandLine addSubcommand(String name, Object command) {
return addSubcommand(name, command, new String[0]);
}
/** Registers a subcommand with the specified name and all specified aliases. See also {@link #addSubcommand(String, Object)}.
*
*
* @param name the string to recognize on the command line as a subcommand
* @param command the object to initialize with command line arguments following the subcommand name.
* This may be a {@code CommandLine} instance with its own (nested) subcommands
* @param aliases zero or more alias names that are also recognized on the command line as this subcommand
* @return this CommandLine object, to allow method chaining
* @since 3.1
* @see #addSubcommand(String, Object)
*/
public CommandLine addSubcommand(String name, Object command, String... aliases) {
CommandLine subcommandLine = toCommandLine(command, factory);
subcommandLine.getCommandSpec().aliases.addAll(Arrays.asList(aliases));
getCommandSpec().addSubcommand(name, subcommandLine);
CommandLine.Model.CommandReflection.initParentCommand(subcommandLine.getCommandSpec().userObject(), getCommandSpec().userObject());
return this;
}
/** Returns a map with the subcommands {@linkplain #addSubcommand(String, Object) registered} on this instance.
* @return a map with the registered subcommands
* @since 0.9.7
*/
public Map getSubcommands() {
return new LinkedHashMap(getCommandSpec().subcommands());
}
/**
* Returns the command that this is a subcommand of, or {@code null} if this is a top-level command.
* @return the command that this is a subcommand of, or {@code null} if this is a top-level command
* @see #addSubcommand(String, Object)
* @see Command#subcommands()
* @since 0.9.8
*/
public CommandLine getParent() {
CommandSpec parent = getCommandSpec().parent();
return parent == null ? null : parent.commandLine();
}
/** Returns the annotated user object that this {@code CommandLine} instance was constructed with.
* @param the type of the variable that the return value is being assigned to
* @return the annotated object that this {@code CommandLine} instance was constructed with
* @since 0.9.7
*/
@SuppressWarnings("unchecked")
public T getCommand() {
return (T) getCommandSpec().userObject();
}
/** Returns {@code true} if an option annotated with {@link Option#usageHelp()} was specified on the command line.
* @return whether the parser encountered an option annotated with {@link Option#usageHelp()}.
* @since 0.9.8 */
public boolean isUsageHelpRequested() { return interpreter.parseResult != null && interpreter.parseResult.usageHelpRequested; }
/** Returns {@code true} if an option annotated with {@link Option#versionHelp()} was specified on the command line.
* @return whether the parser encountered an option annotated with {@link Option#versionHelp()}.
* @since 0.9.8 */
public boolean isVersionHelpRequested() { return interpreter.parseResult != null && interpreter.parseResult.versionHelpRequested; }
/** Returns the {@code IHelpFactory} that is used to construct the usage help message.
* @see #setHelpFactory(IHelpFactory)
* @since 3.9
*/
public IHelpFactory getHelpFactory() {
return getCommandSpec().usageMessage().helpFactory();
}
/** Sets a new {@code IHelpFactory} to customize the usage help message.
* @param helpFactory the new help factory. Must be non-{@code null}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.9
*/
public CommandLine setHelpFactory(IHelpFactory helpFactory) {
getCommandSpec().usageMessage().helpFactory(helpFactory);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setHelpFactory(helpFactory);
}
return this;
}
/**
* Returns the section keys in the order that the usage help message should render the sections.
* This ordering may be modified with {@link #setHelpSectionKeys(List) setSectionKeys}. The default keys are (in order):
*
* {@link UsageMessageSpec#SECTION_KEY_HEADER_HEADING SECTION_KEY_HEADER_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_HEADER SECTION_KEY_HEADER}
* {@link UsageMessageSpec#SECTION_KEY_SYNOPSIS_HEADING SECTION_KEY_SYNOPSIS_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_SYNOPSIS SECTION_KEY_SYNOPSIS}
* {@link UsageMessageSpec#SECTION_KEY_DESCRIPTION_HEADING SECTION_KEY_DESCRIPTION_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_DESCRIPTION SECTION_KEY_DESCRIPTION}
* {@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST_HEADING SECTION_KEY_PARAMETER_LIST_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_PARAMETER_LIST SECTION_KEY_PARAMETER_LIST}
* {@link UsageMessageSpec#SECTION_KEY_OPTION_LIST_HEADING SECTION_KEY_OPTION_LIST_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_OPTION_LIST SECTION_KEY_OPTION_LIST}
* {@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST_HEADING SECTION_KEY_COMMAND_LIST_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_COMMAND_LIST SECTION_KEY_COMMAND_LIST}
* {@link UsageMessageSpec#SECTION_KEY_FOOTER_HEADING SECTION_KEY_FOOTER_HEADING}
* {@link UsageMessageSpec#SECTION_KEY_FOOTER SECTION_KEY_FOOTER}
*
* @since 3.9
*/
public List getHelpSectionKeys() { return getCommandSpec().usageMessage().sectionKeys(); }
/**
* Sets the section keys in the order that the usage help message should render the sections.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* Use {@link UsageMessageSpec#sectionKeys(List)} to customize a command without affecting its subcommands.
* @see #getHelpSectionKeys
* @since 3.9
*/
public CommandLine setHelpSectionKeys(List keys) {
getCommandSpec().usageMessage().sectionKeys(keys);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setHelpSectionKeys(keys);
}
return this;
}
/**
* Returns the map of section keys and renderers used to construct the usage help message.
* The usage help message can be customized by adding, replacing and removing section renderers from this map.
* Sections can be reordered with {@link #setHelpSectionKeys(List) setSectionKeys}.
* Sections that are either not in this map or not in the list returned by {@link #getHelpSectionKeys() getSectionKeys} are omitted.
*
* NOTE: By modifying the returned {@code Map}, only the usage help message of this command is affected.
* Use {@link #setHelpSectionMap(Map)} to customize the usage help message for this command and all subcommands .
*
* @since 3.9
*/
public Map getHelpSectionMap() { return getCommandSpec().usageMessage().sectionMap(); }
/**
* Sets the map of section keys and renderers used to construct the usage help message.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* Use {@link UsageMessageSpec#sectionMap(Map)} to customize a command without affecting its subcommands.
* @see #getHelpSectionMap
* @since 3.9
*/
public CommandLine setHelpSectionMap(Map map) {
getCommandSpec().usageMessage().sectionMap(map);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setHelpSectionMap(map);
}
return this;
}
/** Returns whether the value of boolean flag options should be "toggled" when the option is matched.
* By default, flags are toggled, so if the value is {@code true} it is set to {@code false}, and when the value is
* {@code false} it is set to {@code true}. If toggling is off, flags are simply set to {@code true}.
* @return {@code true} the value of boolean flag options should be "toggled" when the option is matched, {@code false} otherwise
* @since 3.0
*/
public boolean isToggleBooleanFlags() {
return getCommandSpec().parser().toggleBooleanFlags();
}
/** Sets whether the value of boolean flag options should be "toggled" when the option is matched. The default is {@code true}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.0
*/
public CommandLine setToggleBooleanFlags(boolean newValue) {
getCommandSpec().parser().toggleBooleanFlags(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setToggleBooleanFlags(newValue);
}
return this;
}
/** Returns whether options for single-value fields can be specified multiple times on the command line.
* The default is {@code false} and a {@link OverwrittenOptionException} is thrown if this happens.
* When {@code true}, the last specified value is retained.
* @return {@code true} if options for single-value fields can be specified multiple times on the command line, {@code false} otherwise
* @since 0.9.7
*/
public boolean isOverwrittenOptionsAllowed() {
return getCommandSpec().parser().overwrittenOptionsAllowed();
}
/** Sets whether options for single-value fields can be specified multiple times on the command line without a {@link OverwrittenOptionException} being thrown.
* The default is {@code false}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 0.9.7
*/
public CommandLine setOverwrittenOptionsAllowed(boolean newValue) {
getCommandSpec().parser().overwrittenOptionsAllowed(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setOverwrittenOptionsAllowed(newValue);
}
return this;
}
/** Returns whether the parser accepts clustered short options. The default is {@code true}.
* @return {@code true} if short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}, {@code false} otherwise
* @since 3.0 */
public boolean isPosixClusteredShortOptionsAllowed() { return getCommandSpec().parser().posixClusteredShortOptionsAllowed(); }
/** Sets whether short options like {@code -x -v -f SomeFile} can be clustered together like {@code -xvfSomeFile}. The default is {@code true}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.0
*/
public CommandLine setPosixClusteredShortOptionsAllowed(boolean newValue) {
getCommandSpec().parser().posixClusteredShortOptionsAllowed(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setPosixClusteredShortOptionsAllowed(newValue);
}
return this;
}
/** Returns whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
* @return {@code true} if enum values can be specified that don't match the {@code toString()} value of the enum constant, {@code false} otherwise;
* e.g., for an option of type java.time.DayOfWeek ,
* values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
* @since 3.4 */
public boolean isCaseInsensitiveEnumValuesAllowed() { return getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(); }
/** Sets whether the parser should ignore case when converting arguments to {@code enum} values. The default is {@code false}.
* When set to true, for example, for an option of type java.time.DayOfWeek ,
* values {@code MonDaY}, {@code monday} and {@code MONDAY} are all recognized if {@code true}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.4
*/
public CommandLine setCaseInsensitiveEnumValuesAllowed(boolean newValue) {
getCommandSpec().parser().caseInsensitiveEnumValuesAllowed(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setCaseInsensitiveEnumValuesAllowed(newValue);
}
return this;
}
/** Returns whether the parser should trim quotes from command line arguments before processing them. The default is
* read from the system property "picocli.trimQuotes" and will be {@code true} if the property is present and empty,
* or if its value is "true".
* @return {@code true} if the parser should trim quotes from command line arguments before processing them, {@code false} otherwise;
* @since 3.7 */
public boolean isTrimQuotes() { return getCommandSpec().parser().trimQuotes(); }
/** Sets whether the parser should trim quotes from command line arguments before processing them. The default is
* read from the system property "picocli.trimQuotes" and will be {@code true} if the property is set and empty, or
* if its value is "true".
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* Calling this method will cause the "picocli.trimQuotes" property to have no effect.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.7
*/
public CommandLine setTrimQuotes(boolean newValue) {
getCommandSpec().parser().trimQuotes(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setTrimQuotes(newValue);
}
return this;
}
/** Returns whether the parser is allowed to split quoted Strings or not. The default is {@code false},
* so quoted strings are treated as a single value that cannot be split.
* @return {@code true} if the parser is allowed to split quoted Strings, {@code false} otherwise;
* @see ArgSpec#splitRegex()
* @since 3.7 */
public boolean isSplitQuotedStrings() { return getCommandSpec().parser().splitQuotedStrings(); }
/** Sets whether the parser is allowed to split quoted Strings. The default is {@code false}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting
* @return this {@code CommandLine} object, to allow method chaining
* @see ArgSpec#splitRegex()
* @since 3.7
*/
public CommandLine setSplitQuotedStrings(boolean newValue) {
getCommandSpec().parser().splitQuotedStrings(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setSplitQuotedStrings(newValue);
}
return this;
}
/** Returns the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
* @return the end-of-options delimiter. The default is {@code "--"}.
* @since 3.5 */
public String getEndOfOptionsDelimiter() { return getCommandSpec().parser().endOfOptionsDelimiter(); }
/** Sets the end-of-options delimiter that signals that the remaining command line arguments should be treated as positional parameters.
* @param delimiter the end-of-options delimiter; must not be {@code null}. The default is {@code "--"}.
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.5 */
public CommandLine setEndOfOptionsDelimiter(String delimiter) {
getCommandSpec().parser().endOfOptionsDelimiter(delimiter);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setEndOfOptionsDelimiter(delimiter);
}
return this;
}
/** Returns the default value provider for the command, or {@code null} if none has been set.
* @return the default value provider for this command, or {@code null}
* @since 3.6
* @see Command#defaultValueProvider()
* @see CommandSpec#defaultValueProvider()
* @see ArgSpec#defaultValueString()
*/
public IDefaultValueProvider getDefaultValueProvider() {
return getCommandSpec().defaultValueProvider();
}
/** Sets a default value provider for the command and sub-commands
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* sub-commands and nested sub-subcommands at the moment this method is called . Sub-commands added
* later will have the default setting. To ensure a setting is applied to all
* sub-commands, call the setter last, after adding sub-commands.
* @param newValue the default value provider to use
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.6
*/
public CommandLine setDefaultValueProvider(IDefaultValueProvider newValue) {
getCommandSpec().defaultValueProvider(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setDefaultValueProvider(newValue);
}
return this;
}
/** Returns whether the parser interprets the first positional parameter as "end of options" so the remaining
* arguments are all treated as positional parameters. The default is {@code false}.
* @return {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
* @since 2.3
*/
public boolean isStopAtPositional() {
return getCommandSpec().parser().stopAtPositional();
}
/** Sets whether the parser interprets the first positional parameter as "end of options" so the remaining
* arguments are all treated as positional parameters. The default is {@code false}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue {@code true} if all values following the first positional parameter should be treated as positional parameters, {@code false} otherwise
* @return this {@code CommandLine} object, to allow method chaining
* @since 2.3
*/
public CommandLine setStopAtPositional(boolean newValue) {
getCommandSpec().parser().stopAtPositional(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setStopAtPositional(newValue);
}
return this;
}
/** Returns whether the parser should stop interpreting options and positional parameters as soon as it encounters an
* unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
* positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
* The default is {@code false}.
* Setting this flag to {@code true} automatically sets the {@linkplain #isUnmatchedArgumentsAllowed() unmatchedArgumentsAllowed} flag to {@code true} also.
* @return {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
* {@linkplain #getUnmatchedArguments() unmatchedArguments list}
* @since 2.3
*/
public boolean isStopAtUnmatched() {
return getCommandSpec().parser().stopAtUnmatched();
}
/** Sets whether the parser should stop interpreting options and positional parameters as soon as it encounters an
* unmatched option. Unmatched options are arguments that look like an option but are not one of the known options, or
* positional arguments for which there is no available slots (the command has no positional parameters or their size is limited).
* The default is {@code false}.
* Setting this flag to {@code true} automatically sets the {@linkplain #setUnmatchedArgumentsAllowed(boolean) unmatchedArgumentsAllowed} flag to {@code true} also.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue {@code true} when an unmatched option should result in the remaining command line arguments to be added to the
* {@linkplain #getUnmatchedArguments() unmatchedArguments list}
* @return this {@code CommandLine} object, to allow method chaining
* @since 2.3
*/
public CommandLine setStopAtUnmatched(boolean newValue) {
getCommandSpec().parser().stopAtUnmatched(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setStopAtUnmatched(newValue);
}
if (newValue) { setUnmatchedArgumentsAllowed(true); }
return this;
}
/** Returns whether arguments on the command line that resemble an option should be treated as positional parameters.
* The default is {@code false} and the parser behaviour depends on {@link #isUnmatchedArgumentsAllowed()}.
* @return {@code true} arguments on the command line that resemble an option should be treated as positional parameters, {@code false} otherwise
* @see #getUnmatchedArguments()
* @since 3.0
*/
public boolean isUnmatchedOptionsArePositionalParams() {
return getCommandSpec().parser().unmatchedOptionsArePositionalParams();
}
/** Sets whether arguments on the command line that resemble an option should be treated as positional parameters.
* The default is {@code false}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, arguments on the command line that resemble an option should be treated as positional parameters.
* @return this {@code CommandLine} object, to allow method chaining
* @since 3.0
* @see #getUnmatchedArguments()
* @see #isUnmatchedArgumentsAllowed
*/
public CommandLine setUnmatchedOptionsArePositionalParams(boolean newValue) {
getCommandSpec().parser().unmatchedOptionsArePositionalParams(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setUnmatchedOptionsArePositionalParams(newValue);
}
return this;
}
/** Returns whether the end user may specify arguments on the command line that are not matched to any option or parameter fields.
* The default is {@code false} and a {@link UnmatchedArgumentException} is thrown if this happens.
* When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
* @return {@code true} if the end use may specify unmatched arguments on the command line, {@code false} otherwise
* @see #getUnmatchedArguments()
* @since 0.9.7
*/
public boolean isUnmatchedArgumentsAllowed() {
return getCommandSpec().parser().unmatchedArgumentsAllowed();
}
/** Sets whether the end user may specify unmatched arguments on the command line without a {@link UnmatchedArgumentException} being thrown.
* The default is {@code false}.
* The specified setting will be registered with this {@code CommandLine} and the full hierarchy of its
* subcommands and nested sub-subcommands at the moment this method is called . Subcommands added
* later will have the default setting. To ensure a setting is applied to all
* subcommands, call the setter last, after adding subcommands.
* @param newValue the new setting. When {@code true}, the last unmatched arguments are available via the {@link #getUnmatchedArguments()} method.
* @return this {@code CommandLine} object, to allow method chaining
* @since 0.9.7
* @see #getUnmatchedArguments()
*/
public CommandLine setUnmatchedArgumentsAllowed(boolean newValue) {
getCommandSpec().parser().unmatchedArgumentsAllowed(newValue);
for (CommandLine command : getCommandSpec().subcommands().values()) {
command.setUnmatchedArgumentsAllowed(newValue);
}
return this;
}
/** Returns the list of unmatched command line arguments, if any.
* @return the list of unmatched command line arguments or an empty list
* @see #isUnmatchedArgumentsAllowed()
* @since 0.9.7
*/
public List getUnmatchedArguments() {
return interpreter.parseResult == null ? Collections.emptyList() : UnmatchedArgumentException.stripErrorMessage(interpreter.parseResult.unmatched);
}
/**
*
* Convenience method that initializes the specified annotated object from the specified command line arguments.
*
* This is equivalent to
*
* CommandLine cli = new CommandLine(command);
* cli.parse(args);
* return command;
*
*
* @param command the object to initialize. This object contains fields annotated with
* {@code @Option} or {@code @Parameters}.
* @param args the command line arguments to parse
* @param the type of the annotated object
* @return the specified annotated object
* @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
* @throws ParameterException if the specified command line arguments are invalid
* @since 0.9.7
*/
public static T populateCommand(T command, String... args) {
CommandLine cli = toCommandLine(command, new DefaultFactory());
cli.parse(args);
return command;
}
/**
*
* Convenience method that derives the command specification from the specified interface class, and returns an
* instance of the specified interface. The interface is expected to have annotated getter methods. Picocli will
* instantiate the interface and the getter methods will return the option and positional parameter values matched on the command line.
*
* This is equivalent to
*
* CommandLine cli = new CommandLine(spec);
* cli.parse(args);
* return cli.getCommand();
*
*
* @param spec the interface that defines the command specification. This object contains getter methods annotated with
* {@code @Option} or {@code @Parameters}.
* @param args the command line arguments to parse
* @param the type of the annotated object
* @return an instance of the specified annotated interface
* @throws InitializationException if the specified command object does not have a {@link Command}, {@link Option} or {@link Parameters} annotation
* @throws ParameterException if the specified command line arguments are invalid
* @since 3.1
*/
public static T populateSpec(Class spec, String... args) {
CommandLine cli = toCommandLine(spec, new DefaultFactory());
cli.parse(args);
return cli.getCommand();
}
/** Parses the specified command line arguments and returns a list of {@code CommandLine} objects representing the
* top-level command and any subcommands (if any) that were recognized and initialized during the parsing process.
*
* If parsing succeeds, the first element in the returned list is always {@code this CommandLine} object. The
* returned list may contain more elements if subcommands were {@linkplain #addSubcommand(String, Object) registered}
* and these subcommands were initialized by matching command line arguments. If parsing fails, a
* {@link ParameterException} is thrown.
*
*
* @param args the command line arguments to parse
* @return a list with the top-level command and any subcommands initialized by this method
* @throws ParameterException if the specified command line arguments are invalid; use
* {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
*/
public List parse(String... args) {
return interpreter.parse(args);
}
/** Parses the specified command line arguments and returns a list of {@code ParseResult} with the options, positional
* parameters, and subcommands (if any) that were recognized and initialized during the parsing process.
* If parsing fails, a {@link ParameterException} is thrown.
*
* @param args the command line arguments to parse
* @return a list with the top-level command and any subcommands initialized by this method
* @throws ParameterException if the specified command line arguments are invalid; use
* {@link ParameterException#getCommandLine()} to get the command or subcommand whose user input was invalid
*/
public ParseResult parseArgs(String... args) {
interpreter.parse(args);
return interpreter.parseResult.build();
}
public ParseResult getParseResult() { return interpreter.parseResult == null ? null : interpreter.parseResult.build(); }
/**
* Represents a function that can process a List of {@code CommandLine} objects resulting from successfully
* {@linkplain #parse(String...) parsing} the command line arguments. This is a
* functional interface
* whose functional method is {@link #handleParseResult(List, PrintStream, CommandLine.Help.Ansi)}.
*
* Implementations of this functions can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandler}
* methods to take some next step after the command line was successfully parsed.
*
* @see RunFirst
* @see RunLast
* @see RunAll
* @deprecated Use {@link IParseResultHandler2} instead.
* @since 2.0 */
@Deprecated public static interface IParseResultHandler {
/** Processes a List of {@code CommandLine} objects resulting from successfully
* {@linkplain #parse(String...) parsing} the command line arguments and optionally returns a list of results.
* @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
* @param out the {@code PrintStream} to print help to if requested
* @param ansi for printing help messages using ANSI styles and colors
* @return a list of results, or an empty list if there are no results
* @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) throws ExecutionException;
}
/**
* Represents a function that can process the {@code ParseResult} object resulting from successfully
* {@linkplain #parseArgs(String...) parsing} the command line arguments. This is a
* functional interface
* whose functional method is {@link IParseResultHandler2#handleParseResult(CommandLine.ParseResult)}.
*
* Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) CommandLine::parseWithHandlers}
* methods to take some next step after the command line was successfully parsed.
*
* This interface replaces the {@link IParseResultHandler} interface; it takes the parse result as a {@code ParseResult}
* object instead of a List of {@code CommandLine} objects, and it has the freedom to select the {@link Help.Ansi} style
* to use and what {@code PrintStreams} to print to.
*
* @param the return type of this handler
* @see RunFirst
* @see RunLast
* @see RunAll
* @since 3.0 */
public static interface IParseResultHandler2 {
/** Processes the {@code ParseResult} object resulting from successfully
* {@linkplain CommandLine#parseArgs(String...) parsing} the command line arguments and returns a return value.
* @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
* @throws ParameterException if a help command was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
R handleParseResult(ParseResult parseResult) throws ExecutionException;
}
/**
* Represents a function that can handle a {@code ParameterException} that occurred while
* {@linkplain #parse(String...) parsing} the command line arguments. This is a
* functional interface
* whose functional method is {@link #handleException(CommandLine.ParameterException, PrintStream, CommandLine.Help.Ansi, String...)}.
*
* Implementations of this function can be passed to the {@link #parseWithHandlers(IParseResultHandler, PrintStream, Help.Ansi, IExceptionHandler, String...) CommandLine::parseWithHandlers}
* methods to handle situations when the command line could not be parsed.
*
* @deprecated Use {@link IExceptionHandler2} instead.
* @see DefaultExceptionHandler
* @since 2.0 */
@Deprecated public static interface IExceptionHandler {
/** Handles a {@code ParameterException} that occurred while {@linkplain #parse(String...) parsing} the command
* line arguments and optionally returns a list of results.
* @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
* and the CommandLine representing the command or subcommand whose input was invalid
* @param out the {@code PrintStream} to print help to if requested
* @param ansi for printing help messages using ANSI styles and colors
* @param args the command line arguments that could not be parsed
* @return a list of results, or an empty list if there are no results
*/
List handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args);
}
/**
* Classes implementing this interface know how to handle {@code ParameterExceptions} (usually from invalid user input)
* and {@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command.
*
* Implementations of this interface can be passed to the
* {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) CommandLine::parseWithHandlers} method.
*
* This interface replaces the {@link IParseResultHandler} interface.
*
* @param the return type of this handler
* @see DefaultExceptionHandler
* @since 3.0 */
public static interface IExceptionHandler2 {
/** Handles a {@code ParameterException} that occurred while {@linkplain #parseArgs(String...) parsing} the command
* line arguments and optionally returns a list of results.
* @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
* and the CommandLine representing the command or subcommand whose input was invalid
* @param args the command line arguments that could not be parsed
* @return an object resulting from handling the exception
*/
R handleParseException(ParameterException ex, String[] args);
/** Handles a {@code ExecutionException} that occurred while executing the {@code Runnable} or
* {@code Callable} command and optionally returns a list of results.
* @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or
* {@code Callable} command, and the CommandLine representing the command or subcommand that was being executed
* @param parseResult the result of parsing the command line arguments
* @return an object resulting from handling the exception
*/
R handleExecutionException(ExecutionException ex, ParseResult parseResult);
}
/** Abstract superclass for {@link IParseResultHandler2} and {@link IExceptionHandler2} implementations.
* Note that {@code AbstractHandler} is a generic type. This, along with the abstract {@code self} method,
* allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:
* {@code
* class MyResultHandler extends AbstractHandler implements IParseResultHandler2 {
*
* public MyReturnType handleParseResult(ParseResult parseResult) { ... }
*
* protected MyResultHandler self() { return this; }
* }
* }
* @param the return type of this handler
* @param The type of the handler subclass; for fluent API method chaining
* @since 3.0 */
public static abstract class AbstractHandler> {
private Help.Ansi ansi = Help.Ansi.AUTO;
private Integer exitCode;
private PrintStream out = System.out;
private PrintStream err = System.err;
/** Returns the stream to print command output to. Defaults to {@code System.out}, unless {@link #useOut(PrintStream)}
* was called with a different stream.
* {@code IParseResultHandler2} implementations should use this stream.
* By convention , when the user requests
* help with a {@code --help} or similar option, the usage help message is printed to the standard output stream so that it can be easily searched and paged.
*/
public PrintStream out() { return out; }
/** Returns the stream to print diagnostic messages to. Defaults to {@code System.err}, unless {@link #useErr(PrintStream)}
* was called with a different stream. {@code IExceptionHandler2} implementations should use this stream to print error
* messages (which may include a usage help message) when an unexpected error occurs.
*/
public PrintStream err() { return err; }
/** Returns the ANSI style to use. Defaults to {@code Help.Ansi.AUTO}, unless {@link #useAnsi(CommandLine.Help.Ansi)} was called with a different setting. */
public Help.Ansi ansi() { return ansi; }
/** Returns the exit code to use as the termination status, or {@code null} (the default) if the handler should
* not call {@link System#exit(int)} after processing completes.
* @see #andExit(int) */
public Integer exitCode() { return exitCode; }
/** Returns {@code true} if an exit code was set with {@link #andExit(int)}, or {@code false} (the default) if
* the handler should not call {@link System#exit(int)} after processing completes. */
public boolean hasExitCode() { return exitCode != null; }
/** Convenience method for subclasses that returns the specified result object if no exit code was set,
* or otherwise, if an exit code {@linkplain #andExit(int) was set}, calls {@code System.exit} with the configured
* exit code to terminate the currently running Java virtual machine. */
protected R returnResultOrExit(R result) {
if (hasExitCode()) { exit(exitCode()); }
return result;
}
/** Convenience method for subclasses that throws the specified ExecutionException if no exit code was set,
* or otherwise, if an exit code {@linkplain #andExit(int) was set}, prints the stacktrace of the specified exception
* to the diagnostic error stream and calls {@code System.exit} with the configured
* exit code to terminate the currently running Java virtual machine. */
protected R throwOrExit(ExecutionException ex) {
if (hasExitCode()) {
ex.printStackTrace(this.err());
exit(exitCode());
}
throw ex;
}
/** Calls {@code System.exit(int)} with the specified exit code. */
protected void exit(int exitCode) { System.exit(exitCode); }
/** Returns {@code this} to allow method chaining when calling the setters for a fluent API. */
protected abstract T self();
/** Sets the stream to print command output to. For use by {@code IParseResultHandler2} implementations.
* @see #out() */
public T useOut(PrintStream out) { this.out = Assert.notNull(out, "out"); return self(); }
/** Sets the stream to print diagnostic messages to. For use by {@code IExceptionHandler2} implementations.
* @see #err()*/
public T useErr(PrintStream err) { this.err = Assert.notNull(err, "err"); return self(); }
/** Sets the ANSI style to use.
* @see #ansi() */
public T useAnsi(Help.Ansi ansi) { this.ansi = Assert.notNull(ansi, "ansi"); return self(); }
/** Indicates that the handler should call {@link System#exit(int)} after processing completes and sets the exit code to use as the termination status. */
public T andExit(int exitCode) { this.exitCode = exitCode; return self(); }
}
/**
* Default exception handler that handles invalid user input by printing the exception message, followed by the usage
* message for the command or subcommand whose input was invalid.
* {@code ParameterExceptions} (invalid user input) is handled like this:
*
* err().println(paramException.getMessage());
* paramException.getCommandLine().usage(err(), ansi());
* if (hasExitCode()) System.exit(exitCode()); else return returnValue;
*
* {@code ExecutionExceptions} that occurred while executing the {@code Runnable} or {@code Callable} command are simply rethrown and not handled.
* @since 2.0 */
@SuppressWarnings("deprecation")
public static class DefaultExceptionHandler extends AbstractHandler> implements IExceptionHandler, IExceptionHandler2 {
public List handleException(ParameterException ex, PrintStream out, Help.Ansi ansi, String... args) {
internalHandleParseException(ex, out, ansi, args); return Collections.emptyList(); }
/** Prints the message of the specified exception, followed by the usage message for the command or subcommand
* whose input was invalid, to the stream returned by {@link #err()}.
* @param ex the ParameterException describing the problem that occurred while parsing the command line arguments,
* and the CommandLine representing the command or subcommand whose input was invalid
* @param args the command line arguments that could not be parsed
* @return the empty list
* @since 3.0 */
public R handleParseException(ParameterException ex, String[] args) {
internalHandleParseException(ex, err(), ansi(), args); return returnResultOrExit(null); }
private void internalHandleParseException(ParameterException ex, PrintStream out, Help.Ansi ansi, String[] args) {
out.println(ex.getMessage());
if (!UnmatchedArgumentException.printSuggestions(ex, out)) {
ex.getCommandLine().usage(out, ansi);
}
}
/** This implementation always simply rethrows the specified exception.
* @param ex the ExecutionException describing the problem that occurred while executing the {@code Runnable} or {@code Callable} command
* @param parseResult the result of parsing the command line arguments
* @return nothing: this method always rethrows the specified exception
* @throws ExecutionException always rethrows the specified exception
* @since 3.0 */
public R handleExecutionException(ExecutionException ex, ParseResult parseResult) { return throwOrExit(ex); }
@Override protected DefaultExceptionHandler self() { return this; }
}
/** Convenience method that returns {@code new DefaultExceptionHandler>()}. */
public static DefaultExceptionHandler> defaultExceptionHandler() { return new DefaultExceptionHandler>(); }
/** @deprecated use {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} instead
* @since 2.0 */
@Deprecated public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, Help.Ansi ansi) {
return printHelpIfRequested(parsedCommands, out, out, ansi);
}
/** Delegates to {@link #printHelpIfRequested(List, PrintStream, PrintStream, Help.Ansi)} with
* {@code parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO}.
* @since 3.0 */
public static boolean printHelpIfRequested(ParseResult parseResult) {
return printHelpIfRequested(parseResult.asCommandLineList(), System.out, System.err, Help.Ansi.AUTO);
}
/**
* Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
* {@linkplain #parse(String...) parsing} command line arguments. This method prints out
* {@linkplain #usage(PrintStream, Help.Ansi) usage help} if {@linkplain #isUsageHelpRequested() requested}
* or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
* and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
* that command is executed and this method returns {@code true}.
* Otherwise, if none of the specified {@code CommandLine} objects have help requested,
* this method returns {@code false}.
* Note that this method only looks at the {@link Option#usageHelp() usageHelp} and
* {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
*
Implementation note:
* When an error occurs while processing the help request, it is recommended custom Help commands throw a
* {@link ParameterException} with a reference to the parent command. This will print the error message and the
* usage for the parent command, and will use the exit code of the exception handler if one was set.
*
* @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
* @param out the {@code PrintStream} to print help to if requested
* @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
* @param ansi for printing help messages using ANSI styles and colors
* @return {@code true} if help was printed, {@code false} otherwise
* @see IHelpCommandInitializable
* @since 3.0 */
public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, PrintStream err, Help.Ansi ansi) {
return printHelpIfRequested(parsedCommands, out, err, Help.defaultColorScheme(ansi));
}
/**
* Helper method that may be useful when processing the list of {@code CommandLine} objects that result from successfully
* {@linkplain #parse(String...) parsing} command line arguments. This method prints out
* {@linkplain #usage(PrintStream, Help.ColorScheme) usage help} if {@linkplain #isUsageHelpRequested() requested}
* or {@linkplain #printVersionHelp(PrintStream, Help.Ansi) version help} if {@linkplain #isVersionHelpRequested() requested}
* and returns {@code true}. If the command is a {@link Command#helpCommand()} and {@code runnable} or {@code callable},
* that command is executed and this method returns {@code true}.
* Otherwise, if none of the specified {@code CommandLine} objects have help requested,
* this method returns {@code false}.
* Note that this method only looks at the {@link Option#usageHelp() usageHelp} and
* {@link Option#versionHelp() versionHelp} attributes. The {@link Option#help() help} attribute is ignored.
*
Implementation note:
* When an error occurs while processing the help request, it is recommended custom Help commands throw a
* {@link ParameterException} with a reference to the parent command. This will print the error message and the
* usage for the parent command, and will use the exit code of the exception handler if one was set.
*
* @param parsedCommands the list of {@code CommandLine} objects to check if help was requested
* @param out the {@code PrintStream} to print help to if requested
* @param err the error string to print diagnostic messages to, in addition to the output from the exception handler
* @param colorScheme for printing help messages using ANSI styles and colors
* @return {@code true} if help was printed, {@code false} otherwise
* @see IHelpCommandInitializable
* @since 3.6 */
public static boolean printHelpIfRequested(List parsedCommands, PrintStream out, PrintStream err, Help.ColorScheme colorScheme) {
for (int i = 0; i < parsedCommands.size(); i++) {
CommandLine parsed = parsedCommands.get(i);
if (parsed.isUsageHelpRequested()) {
parsed.usage(out, colorScheme);
return true;
} else if (parsed.isVersionHelpRequested()) {
parsed.printVersionHelp(out, colorScheme.ansi);
return true;
} else if (parsed.getCommandSpec().helpCommand()) {
if (parsed.getCommand() instanceof IHelpCommandInitializable) {
((IHelpCommandInitializable) parsed.getCommand()).init(parsed, colorScheme.ansi, out, err);
}
execute(parsed, new ArrayList());
return true;
}
}
return false;
}
private static List execute(CommandLine parsed, List executionResult) {
Object command = parsed.getCommand();
if (command instanceof Runnable) {
try {
((Runnable) command).run();
executionResult.add(null); // for compatibility with picocli 2.x
return executionResult;
} catch (ParameterException ex) {
throw ex;
} catch (ExecutionException ex) {
throw ex;
} catch (Exception ex) {
throw new ExecutionException(parsed, "Error while running command (" + command + "): " + ex, ex);
}
} else if (command instanceof Callable) {
try {
@SuppressWarnings("unchecked") Callable callable = (Callable) command;
executionResult.add(callable.call());
return executionResult;
} catch (ParameterException ex) {
throw ex;
} catch (ExecutionException ex) {
throw ex;
} catch (Exception ex) {
throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + ex, ex);
}
} else if (command instanceof Method) {
try {
if (Modifier.isStatic(((Method) command).getModifiers())) {
// invoke static method
executionResult.add(((Method) command).invoke(null, parsed.getCommandSpec().argValues()));
return executionResult;
} else if (parsed.getCommandSpec().parent() != null) {
executionResult.add(((Method) command).invoke(parsed.getCommandSpec().parent().userObject(), parsed.getCommandSpec().argValues()));
return executionResult;
} else {
for (Constructor> constructor : ((Method) command).getDeclaringClass().getDeclaredConstructors()) {
if (constructor.getParameterTypes().length == 0) {
executionResult.add(((Method) command).invoke(constructor.newInstance(), parsed.getCommandSpec().argValues()));
return executionResult;
}
}
throw new UnsupportedOperationException("Invoking non-static method without default constructor not implemented");
}
} catch (InvocationTargetException ex) {
Throwable t = ex.getTargetException();
if (t instanceof ParameterException) {
throw (ParameterException) t;
} else if (t instanceof ExecutionException) {
throw (ExecutionException) t;
} else {
throw new ExecutionException(parsed, "Error while calling command (" + command + "): " + t, t);
}
} catch (Exception ex) {
throw new ExecutionException(parsed, "Unhandled error while calling command (" + command + "): " + ex, ex);
}
}
throw new ExecutionException(parsed, "Parsed command (" + command + ") is not Method, Runnable or Callable");
}
/** Command line parse result handler that returns a value. This handler prints help if requested, and otherwise calls
* {@link #handle(CommandLine.ParseResult)} with the parse result. Facilitates implementation of the {@link IParseResultHandler2} interface.
* Note that {@code AbstractParseResultHandler} is a generic type. This, along with the abstract {@code self} method,
* allows method chaining to work properly in subclasses, without the need for casts. An example subclass can look like this:
* {@code
* class MyResultHandler extends AbstractParseResultHandler {
*
* protected MyReturnType handle(ParseResult parseResult) throws ExecutionException { ... }
*
* protected MyResultHandler self() { return this; }
* }
* }
* @since 3.0 */
public abstract static class AbstractParseResultHandler extends AbstractHandler> implements IParseResultHandler2 {
/** Prints help if requested, and otherwise calls {@link #handle(CommandLine.ParseResult)}.
* Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
*
* @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
* @return the result of {@link #handle(ParseResult) processing parse results}
* @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler2}
* @throws ExecutionException if a problem occurred while processing the parse results; client code can use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
public R handleParseResult(ParseResult parseResult) throws ExecutionException {
if (printHelpIfRequested(parseResult.asCommandLineList(), out(), err(), ansi())) {
return returnResultOrExit(null);
}
return returnResultOrExit(handle(parseResult));
}
/** Processes the specified {@code ParseResult} and returns the result as a list of objects.
* Implementations are responsible for catching any exceptions thrown in the {@code handle} method, and
* rethrowing an {@code ExecutionException} that details the problem and captures the offending {@code CommandLine} object.
*
* @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
* @return the result of processing parse results
* @throws ExecutionException if a problem occurred while processing the parse results; client code can use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
protected abstract R handle(ParseResult parseResult) throws ExecutionException;
}
/**
* Command line parse result handler that prints help if requested, and otherwise executes the top-level
* {@code Runnable} or {@code Callable} command.
* For use in the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) parseWithHandler} methods.
* @since 2.0 */
public static class RunFirst extends AbstractParseResultHandler> implements IParseResultHandler {
/** Prints help if requested, and otherwise executes the top-level {@code Runnable} or {@code Callable} command.
* Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
* If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
* is thrown detailing the problem and capturing the offending {@code CommandLine} object.
*
* @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
* @param out the {@code PrintStream} to print help to if requested
* @param ansi for printing help messages using ANSI styles and colors
* @return an empty list if help was requested, or a list containing a single element: the result of calling the
* {@code Callable}, or a {@code null} element if the top-level command was a {@code Runnable}
* @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
public List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) {
if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
return returnResultOrExit(execute(parsedCommands.get(0), new ArrayList()));
}
/** Executes the top-level {@code Runnable} or {@code Callable} subcommand.
* If the top-level command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
* is thrown detailing the problem and capturing the offending {@code CommandLine} object.
*
* @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
* @return an empty list if help was requested, or a list containing a single element: the result of calling the
* {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
* @since 3.0 */
protected List handle(ParseResult parseResult) throws ExecutionException {
return execute(parseResult.commandSpec().commandLine(), new ArrayList()); // first
}
@Override protected RunFirst self() { return this; }
}
/**
* Command line parse result handler that prints help if requested, and otherwise executes the most specific
* {@code Runnable} or {@code Callable} subcommand.
* For use in the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) parseWithHandler} methods.
*
* Something like this:
* {@code
* // RunLast implementation: print help if requested, otherwise execute the most specific subcommand
* List parsedCommands = parseResult.asCommandLineList();
* if (CommandLine.printHelpIfRequested(parsedCommands, out(), err(), ansi())) {
* return emptyList();
* }
* CommandLine last = parsedCommands.get(parsedCommands.size() - 1);
* Object command = last.getCommand();
* Object result = null;
* if (command instanceof Runnable) {
* try {
* ((Runnable) command).run();
* } catch (Exception ex) {
* throw new ExecutionException(last, "Error in runnable " + command, ex);
* }
* } else if (command instanceof Callable) {
* try {
* result = ((Callable) command).call();
* } catch (Exception ex) {
* throw new ExecutionException(last, "Error in callable " + command, ex);
* }
* } else {
* throw new ExecutionException(last, "Parsed command (" + command + ") is not Runnable or Callable");
* }
* if (hasExitCode()) { System.exit(exitCode()); }
* return Arrays.asList(result);
* }
*
* From picocli v2.0, {@code RunLast} is used to implement the {@link #run(Runnable, PrintStream, PrintStream, Help.Ansi, String...) run}
* and {@link #call(Callable, PrintStream, PrintStream, Help.Ansi, String...) call} convenience methods.
*
* @since 2.0 */
public static class RunLast extends AbstractParseResultHandler> implements IParseResultHandler {
/** Prints help if requested, and otherwise executes the most specific {@code Runnable} or {@code Callable} subcommand.
* Finally, either a list of result objects is returned, or the JVM is terminated if an exit code {@linkplain #andExit(int) was set}.
* If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
* is thrown detailing the problem and capturing the offending {@code CommandLine} object.
*
* @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
* @param out the {@code PrintStream} to print help to if requested
* @param ansi for printing help messages using ANSI styles and colors
* @return an empty list if help was requested, or a list containing a single element: the result of calling the
* {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
* @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
public List handleParseResult(List parsedCommands, PrintStream out, Help.Ansi ansi) {
if (printHelpIfRequested(parsedCommands, out, err(), ansi)) { return returnResultOrExit(Collections.emptyList()); }
return returnResultOrExit(execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList()));
}
/** Executes the most specific {@code Runnable} or {@code Callable} subcommand.
* If the last (sub)command does not implement either {@code Runnable} or {@code Callable}, an {@code ExecutionException}
* is thrown detailing the problem and capturing the offending {@code CommandLine} object.
*
* @param parseResult the {@code ParseResult} that resulted from successfully parsing the command line arguments
* @return an empty list if help was requested, or a list containing a single element: the result of calling the
* {@code Callable}, or a {@code null} element if the last (sub)command was a {@code Runnable}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
* @since 3.0 */
protected List handle(ParseResult parseResult) throws ExecutionException {
List parsedCommands = parseResult.asCommandLineList();
return execute(parsedCommands.get(parsedCommands.size() - 1), new ArrayList());
}
@Override protected RunLast self() { return this; }
}
/**
* Command line parse result handler that prints help if requested, and otherwise executes the top-level command and
* all subcommands as {@code Runnable} or {@code Callable}.
* For use in the {@link #parseWithHandlers(IParseResultHandler2, IExceptionHandler2, String...) parseWithHandler} methods.
* @since 2.0 */
public static class RunAll extends AbstractParseResultHandler> implements IParseResultHandler {
/** Prints help if requested, and otherwise executes the top-level command and all subcommands as {@code Runnable}
* or {@code Callable}. Finally, either a list of result objects is returned, or the JVM is terminated if an exit
* code {@linkplain #andExit(int) was set}. If any of the {@code CommandLine} commands does not implement either
* {@code Runnable} or {@code Callable}, an {@code ExecutionException}
* is thrown detailing the problem and capturing the offending {@code CommandLine} object.
*
* @param parsedCommands the {@code CommandLine} objects that resulted from successfully parsing the command line arguments
* @param out the {@code PrintStream} to print help to if requested
* @param ansi for printing help messages using ANSI styles and colors
* @return an empty list if help was requested, or a list containing the result of executing all commands:
* the return values from calling the {@code Callable} commands, {@code null} elements for commands that implement {@code Runnable}
* @throws ParameterException if the {@link HelpCommand HelpCommand} was invoked for an unknown subcommand. Any {@code ParameterExceptions}
* thrown from this method are treated as if this exception was thrown during parsing and passed to the {@link IExceptionHandler}
* @throws ExecutionException if a problem occurred while processing the parse results; use
* {@link ExecutionException#getCommandLine()} to get the command or subcommand where processing failed
*/
public List handleParseResult(List