Skip to content

Releases: remkop/picocli

Picocli 4.0.0-beta-2

19 Jun 16:18
Compare
Choose a tag to compare

Picocli 4.0.0-beta-2

The picocli community is pleased to announce picocli 4.0.0-beta-2.

Bugfixes and improvements.

This release introduces two new attributes on the Option annotation:

  • fallbackValue
  • parameterConsumer

fallbackValue is for options with optional parameter: assign this value when the option was specified on the command line without parameter. parameterConsumer and the associated IParameterConsumer interface allows for options to bypass picocli's parsing logic and replace it with custom logic. One use case is collecting arguments to pass them through to another command.

This release introduces a new synopsisSubcommandLabel attribute on the @Command annotation to allow customization of the subcommands part of the synopsis. This is useful for applications that have required subcommands.

Also, this release adds the ability to dynamically detect the terminal width.

From this release, the picocli JAR is an OSGi bundle with Bundle-Name: picocli and other appropriate metadata in the manifest.

Please try this and provide feedback. We can still make changes.

What do you think of the @ArgGroup annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?

Many thanks to the picocli community for the contributions!

This is the fifty-sixth public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Fallback Value API

This release introduces a new attribute on the Option annotation: fallbackValue for options with optional parameter: assign this value when the option was specified on the command line without parameter.

This is different from the defaultValue, which is assigned if the option is not specified at all on the command line.

Using a fallbackValue allows applications to distinguish between cases where

  • the option was not specified on the command line (default value assigned)
  • the option was specified without parameter on the command line (fallback value assigned)
  • the option was specified with parameter on the command line (command line argument value assigned)

This is useful to define options that can function as a boolean "switch" and optionally allow users to provide a (strongly typed) extra parameter value.

The option description may contain the ${FALLBACK-VALUE} variable which will be replaced with the actual fallback value when the usage help is shown.

Synopsis Subcommand Label

For commands with subcommands, the string [COMMAND] is appended to the end of the synopsis (whether the synopsis is abbreviated or not). This looks something like this:

<cmd> [OPTIONS] FILES [COMMAND]

From picocli 4.0, this can be customized with the synopsisSubcommandLabel attribute.

For example, to clarify that a subcommand is mandatory, an application may specify COMMAND, without the [ and ] brackets:

@Command(name = "git", synopsisSubcommandLabel = "COMMAND")
class Git implements Runnable {
    @Spec CommandSpec spec;
    public void run() {
        throw new ParameterException(spec.commandLine(), "Missing required subcommand");
    }
}

An application with a limited number of subcommands may want to show them all in the synopsis, for example:

@Command(name = "fs", synopsisSubcommandLabel = "(list | add | delete)",
         subcommands = {List.class, Add.class, Delete.class})
class Fs { ... }

Dynamically Detect Terminal Size

From this release, commands defined with @Command(usageHelpAutoWidth = true) will try to adjust the usage message help layout to the terminal width.
There is also programmatic API to control this via the CommandLine::setUsageHelpAutoWidth and UsageMessageSpec::autoWidth methods.

End users may enable this by setting system property picocli.usage.width to AUTO, and may disable this by setting this system property to a numeric value.

This feature requires Java 7.

Custom Parameter Processing

Options or positional parameters can be assigned a IParameterConsumer that implements custom logic to process the parameters for this option or this position. When an option or positional parameter with a custom IParameterConsumer is matched on the command line, picocli's internal parser is temporarily suspended, and the custom parameter consumer becomes responsible for consuming and processing as many command line arguments as needed.

This can be useful when passing options through to another command.

For example, the unix find command has a -exec option to execute some action for each file found. Any arguments following the -exec option until a ; or + argument are not options for the find command itself, but are interpreted as a separate command and its options.

The example below demonstrates how to implement find -exec using this API:

@Command(name = "find")
class Find {
    @Option(names = "-exec", parameterConsumer = ExecParameterConsumer.class)
    List<String> list = new ArrayList<String>();
}

class ExecParameterConsumer implements IParameterConsumer {
    public void consumeParameters(Stack<String> args, ArgSpec argSpec, CommandSpec commandSpec) {
        List<String> list = argSpec.getValue();
        while (!args.isEmpty()) {
            String arg = args.pop();
            list.add(arg);

            // `find -exec` semantics: stop processing after a ';' or '+' argument
            if (";".equals(arg) || "+".equals(arg)) {
                break;
            }
        }
    }
}

Fixed issues

  • [#280] API: @Option(fallbackValue = "...") for options with optional parameter: assign this value when the option was specified on the command line without parameter. Thanks to Paolo Di Tommaso and marinier for the suggestion and in-depth discussion.
  • [#625] API: @Command(synopsisSubcommandLabel = "...") to allow customization of the subcommands part of the synopsis: by default this is [COMMAND]. Thanks to Sebastian Thomschke and AlcaYezz for the feature request and subsequent discussion.
  • [#718] API: Add IParameterConsumer and @Option(parameterConsumer = Xxx.class) for passing arguments through to another command, like find -exec. Thanks to Reinhard Pointner for the suggestion.
  • [#721] API: Add public method Text.getCJKAdjustedLength().
  • [#634] API: Dynamically detect terminal size. Requires Java 7. Thanks to my colleague Takuya Ishibashi for the suggestion.
  • [#737] Deprecate the parse method in favor of parseArgs.
  • [#717] Negatable options change: avoid unmappable character ± for synopsis: it renders as scrambled characters in encoding ASCII and in some terminals.
  • [#734][#735] Make the picocli jar OSGi friendly. Thanks to Radu Cotescu for the pull request.
  • [#733] Improve error message for unmatched arguments. Thanks to my colleague Takuya Ishibashi for raising this.
  • [#719] Bugfix: options with variable arity should stop consuming arguments on custom end-of-options delimiter.
  • [#720] Bugfix: @Unmatched list should be cleared prior to subsequent invocations.
  • [#723] Bugfix: variables in defaultValue were not expanded in usage help option description line for showDefaultValues = true. Thanks to Mikaël Barbero for raising this.
  • [#722] Bugfix: synopsis of deeply nested @ArgGroup shows @Options duplicate on outer level of command. Thanks to Shane Rowatt for raising this.
  • [#724] Bugfix: Usage message exceeds width.
  • [#731] Doc: Add Zero Bugs Commitment to README.

Deprecations

From this release, the parse method is deprecated in favor of parseArgs.

Potential breaking changes

The error message for unmatched arguments now shows the index in the command line arguments where the unmatched argument was found,
and shows the unmatched value in single quotes. This is useful when the unmatched value is whitespace or an empty String.

For example:

Previously:  Unmatched arguments: B, C
New       :  Unmatched arguments from index 1: 'B', 'C'

This may break tests that rely on the exact error message.

Picocli 4.0.0-beta-1b

05 Jun 12:25
Compare
Choose a tag to compare

Picocli 4.0.0-beta-1b

The picocli community is pleased to announce picocli 4.0.0-beta-1b. (That should have been 4.0.0-beta-1, :-) there were a few hiccups along the way...)

Annotation Processor

This release includes the first cut of an annotation processor that can build a model from the picocli annotations at compile time rather than at runtime.

Use this if you’re interested in:

  • Compile time error checking. The annotation processor shows errors for invalid annotations and attributes immediately when you compile, instead of during testing at runtime, resulting in shorter feedback cycles.
  • Graal native images. The annotation processor generates Graal configuration
    files under META-INF/native-image/picocli-generated/$project during compilation, to be included in the application jar. By embedding these configuration files, your jar is instantly Graal-enabled. In most cases no further configuration is needed when generating a native image.

Modular

The main picocli-4.x.jar is now an explicit JPMS module, with a module-info.class located in META-INF/versions/9. The picocli-jpms-module subproject has been removed.

Also, from this release the main picocli-4.x artifact no longer contains the picocli.groovy classes: these have been split off into a separate picocli-groovy-4.x artifact.

Negatable Options

From picocli 4.0, options can be negatable. When an option is negatable, picocli will recognize negative aliases of the option on the command line. See the New and Noteworthy section below for more details.

Feedback Welcome

Please try this and provide feedback. We can still make changes.

What do you think of the @ArgGroup annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?

Many thanks to the picocli community for the contributions!

This is the fifty-fifth public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Annotation Processor

This release includes the first cut of an annotation processor that can build a model from the picocli annotations at compile time rather than at runtime.

Use this if you’re interested in:

  • Compile time error checking. The annotation processor shows errors for invalid annotations and attributes immediately when you compile, instead of during testing at runtime, resulting in shorter feedback cycles.
  • Graal native images. The annotation processor generates and updates Graal configuration files under
    META-INF/native-image/picocli-generated/$project during compilation, to be included in the application jar.
    This includes configuration files for reflection, resources and dynamic proxies.
    By embedding these configuration files, your jar is instantly Graal-enabled.
    The $project location is configurable, see processor options below.
    In most cases no further configuration is needed when generating a native image.

Enabling the Annotation Processor

Since Java 6, annotation processing is part of the standard javac compiler, but many IDEs and build tools require something extra to enable annotation processing.

IDE

This page shows the steps to configure Eclipse and IntelliJ IDEA to enable annotation processing.

Maven

In Maven, use annotationProcessorPaths in the configuration of the maven-compiler-plugin.
This requires maven-compiler-plugin plugin version 3.5 or higher.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <!-- annotationProcessorPaths requires maven-compiler-plugin version 3.5 or higher -->
  <version>${maven-compiler-plugin-version}</version>
  <configuration>
    <annotationProcessorPaths>
      <path>
        <groupId>info.picocli</groupId>
        <artifactId>picocli-codegen</artifactId>
        <version>4.0.0-beta-1b</version>
      </path>
    </annotationProcessorPaths>
  </configuration>
</plugin>

An alternative that works with older versions of the maven-compiler-plugin is to specify the picocli-codegen module on the classpath as a provided dependency. This also prevents the picocli-codegen module from being included in the artifact the module produces as a transitive dependency.

<dependency>
  <groupId>info.picocli</groupId>
  <artifactId>picocli</artifactId>
  <version>4.0.0-beta-1b</version>
</dependency>

<dependency>
  <groupId>info.picocli</groupId>
  <artifactId>picocli-codegen</artifactId>
  <version>4.0.0-beta-1b</version>
  <provided>true</provided>
</dependency>

See Processor Options below.

Gradle

Use the annotationProcessor path in Gradle 4.6 and higher:

dependencies {
    compile 'info.picocli:picocli:4.0.0-beta-1b'
    annotationProcessor 'info.picocli:picocli-codegen:4.0.0-beta-1b'
}

For Gradle versions prior to 4.6, use compileOnly, to prevent the picocli-codegen jar from being a transitive dependency included in the artifact the module produces.

dependencies {
    compile 'info.picocli:picocli:4.0.0-beta-1b'
    compileOnly 'info.picocli:picocli-codegen:4.0.0-beta-1b'
}

Picocli Processor Options

The picocli annotation processor supports the options below.

Recommended Options
  • project - output subdirectory

The generated files are written to META-INF/native-image/picocli-generated/${project}.

The project option can be omitted, but it is a good idea to specify the project option with a unique value for your project (e.g. ${groupId}/${artifactId}) if your jar may be shaded with other jars into an uberjar.

Other Options
  • other.resource.patterns - comma-separated list of regular expressions matching additional resources to include in the image
  • other.resource.bundles - comma-separated list of the base names of additional resource bundles to include in the image
  • other.proxy.interfaces - comma-separated list of the fully qualified class names of additional interfaces for which to generate proxy classes when building the image
  • disable.proxy.config - don’t generate proxy-config.json
  • disable.reflect.config - don’t generate reflect-config.json
  • disable.resource.config - don’t generate resources-config.json
Javac

To pass an annotation processor option with javac, specify the -A command line option:

javac -Aproject=org.myorg.myproject/myapp -cp ...

The -A option lets you pass options to annotation processors. See the javac documentation for details.

Maven

To set an annotation processor option in Maven, you need to use the maven-compiler-plugin and configure the compilerArgs section.

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <!-- annotationProcessorPaths requires maven-compiler-plugin version 3.5 or higher -->
      <version>${maven-compiler-plugin-version}</version>
      <configuration>
        <compilerArgs>
          <arg>-Aproject=${groupId}/${artifactId}</arg>
        </compilerArgs>
      </configuration>
    </plugin>
  </plugins>
</build>

See https://maven.apache.org/plugins/maven-compiler-plugin/compile-mojo.html for details.

Gradle Example

To set an annotation processor option in Gradle, add these options to the options.compilerArgs list in the compileJava block.

compileJava {
    // minimum 1.6
    sourceCompatibility = ${java-version}
    targetCompatibility = ${java-version}
    options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
}

See the Gradle documentation for details.

Negatable Options

From picocli 4.0, options can be negatable.

class App {
    @Option(names = "--verbose",           negatable = true) boolean verbose;
    @Option(names = "-XX:+PrintGCDetails", negatable = true) boolean printGCDetails;
    @Option(names = "-XX:-UseG1GC",        negatable = true) boolean useG1GC = true;
}

When an option is negatable, picocli will recognize negative aliases of the option on the command line.

For *nix-style long options, aliases have the prefix 'no-' to the given names.
For Java JVM-style options, the :+ is turned into :- and vice versa. (This can be changed by customizing the INegatableOptionTransformer.)

If the negated form of the option is found, for example --no-verbose, the value is set to the provided default. Otherwise, with a regular call, for example --verbose, it is set to the opposite of the default.

<a name="...

Read more

Picocli 4.0.0-alpha-3

13 May 12:39
Compare
Choose a tag to compare

Picocli 4.0.0-alpha-3

The picocli community is pleased to announce picocli 4.0.0-alpha-3.

This release adds improved support for command execution via the new execute method.
This method returns an exit code that applications can use to call System.exit.

The older run, call, invoke and parseWithHandlers convenience methods that were similar to execute but had limited support for parser configuration and and limited support for exit codes are deprecated from this release.

This release also improves the picocli tools for configuring GraalVM native image builds: there is now support for commands with resource bundles and jewelcli-style @Command-annotated interfaces for which picocli generates a dynamic proxy.

Please try this and provide feedback. We can still make changes.

What do you think of the @ArgGroup annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?

Many thanks to the picocli community for the contributions!

This is the fifty-fourth public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Executing Commands

Picocli 4.0 introduces new API to execute commands. Let’s take a quick look at what changed.

Exit Code

Many command line applications return an exit code to signify success or failure. Zero often means success, a non-zero exit code is often used for errors, but other than that, meanings differ per application.

The new CommandLine.execute method introduced in picocli 4.0 returns an int, and applications can use this return value to call System.exit if desired. For example:

public static void main(String... args) {
  CommandLine cmd = new CommandLine(new App());
  int exitCode = cmd.execute(args);
  System.exit(exitCode);
}

Older versions of picocli had some limited exit code support where picocli would call System.exit, but this is now deprecated.

Generating an Exit Code

@Command-annotated classes that implement Callable and @Command-annotated methods can simply return an int or Integer, and this value will be returned from CommandLine.execute. For example:

@Command(name = "greet")
class Greet implements Callable<Integer> {
  public Integer call() {
    System.out.println("hi");
    return 1;
  }

  @Command
  int shout() {
    System.out.println("HI!");
    return 2;
  }
}

assert 1 == new CommandLine(new Greet()).execute();
assert 2 == new CommandLine(new Greet()).execute("shout");

Commands with a user object that implements Runnable can implement the IExitCodeGenerator interface to generate an exit code. For example:

@Command(name = "wave")
class Gesture implements Runnable, IExitCodeGenerator {
  public void run() {
    System.out.println("wave");
  }
  public int getExitCode() {
    return 3;
  }
}

assert 3 == new CommandLine(new Gesture()).execute();

Exception Exit Codes

By default, the execute method returns CommandLine.ExitCode.USAGE (64) for invalid input, and CommandLine.ExitCode.SOFTWARE (70) when an exception occurred in the Runnable, Callable or command method. (For reference, these values are EX_USAGE and EX_SOFTWARE, respectively, from Unix and Linux sysexits.h). This can be customized with the @Command annotation. For example:

@Command(exitCodeOnInvalidInput = 123,
   exitCodeOnExecutionException = 456)

Additionally, applications can configure a IExitCodeExceptionMapper to map a specific exception to an exit code:

class MyMapper implements IExitCodeExceptionMapper {
  public int getExitCode(Throwable t) {
    if (t instance of FileNotFoundException) {
      return 74;
    }
    return 1;
  }
}

When the end user specified invalid input, the execute method prints an error message followed by the usage help message of the command, and returns an exit code. This can be customized by configuring a IParameterExceptionHandler.

If the business logic of the command throws an exception, the execute method prints the stack trace of the exception and returns an exit code. This can be customized by configuring a IExecutionExceptionHandler.

Configuration

The new CommandLine.execute method is an instance method. The older run, call and invoke methods are static methods. Static methods don’t allow configuration. The new API lets applications configure the parser or other aspects before execution. For example:

public static void main(String... args) {
  CommandLine cmd = new CommandLine(new App());
  cmd.setCaseInsensitiveEnumValuesAllowed(true);
  cmd.setUnmarchedArgumentsAllowed(true);
  cmd.setStopAtPositional(true);
  cmd.setExpandAtFiles(false);
  cmd.execute(args);
}

Execution Configuration

The following configuration methods are new and are only applicable with the execute method (and executeHelpRequest):

  • get/setOut
  • get/setErr
  • get/setColorScheme
  • get/setExecutionStrategy
  • get/setParameterExceptionHandler
  • get/setExecutionExceptionHandler
  • get/setExitCodeExceptionMapper

The above methods are not applicable (and ignored) with other entry points like parse, parseArgs, populateCommand, run, call, invoke, parseWithHandler and parseWithHandlers.

API Evolution and Trade-offs

Previous versions of picocli offered the run, call and invoke methods to execute a Runnable, Callable or Method command. Here are some trade-offs versus the new execute method:

  • Static - These are static methods, with the drawback that they don't allow configuration, as mentioned above.
  • Type Safety - It is a compile-time error when an application tries to pass anything else than a Runnable to the run method, and a Callable to the call method. The execute method does not have this type safety, since the CommandLine constructor allows any Object as a parameter.
  • Return Value - The call and invoke static methods allow commands to return any value, while the execute method only returns an int exit code. From 4.0 the result object will be available from the CommandLine.getExecutionResult method.

Feedback Requested

With the new execute API the ColorScheme class will start to play a more central role. I decided to make the ColorScheme class immutable from this release. This is a breaking API change.
Should it be deprecated first, or not changed at all, or is the 4.0 release a good time to make breaking changes? Your feedback is very welcome on #675.

Tools for Configuring GraalVM Native Image Builds

The picocli-codegen module now has two new tools, in addition to the existing ReflectionConfigGenerator:

  • ResourceConfigGenerator
  • DynamicProxyConfigGenerator

ResourceConfigGenerator

The GraalVM native-image builder by default will not integrate any of the
classpath resources into the image it creates.

ResourceConfigGenerator generates a JSON String with the resource bundles and other classpath resources
that should be included in the Substrate VM native image.

The output of ResourceConfigGenerator is intended to be passed to the -H:ResourceConfigurationFiles=/path/to/reflect-config.json option of the native-image GraalVM utility,
or placed in a META-INF/native-image/ subdirectory of the JAR.

This allows picocli-based native image applications to access these resources.

DynamicProxyConfigGenerator

Substrate VM doesn't provide machinery for generating and interpreting bytecodes at run time. Therefore all dynamic proxy classes
need to be generated at native image build time.

DynamicProxyConfigGenerator generates a JSON String with the fully qualified interface names for which
dynamic proxy classes should be generated at native image build time.

The output of DynamicProxyConfigGenerator is intended to be passed to the -H:DynamicProxyConfigurationFiles=/path/to/proxy-config.json option of the native-image GraalVM utility,
or placed in a META-INF/native-image/ subdirectory of the JAR.

This allows picocli-based native image applications that use @Command-annotated interfaces with
@Option and @Parameters-annotated methods.

Fixed issues

  • [#516] API: Add support for color schemes in the convenience methods and associated classes and interfaces. Thanks to Bob Tiernay for the suggestion.
  • [#561] API: Parser configuration for convenience methods.
  • [#650] API: Global parser configuration if using Runnable. Thanks to gitfineon for raising this.
  • [#424] API: Exit on help, version or invalid arguments. Thanks to Gerard Bosch for raising this.
  • [#541] API: Improved exception handling for Runnable/Callable.
  • [#680] API: Add annotation API for exitCodeList and exitCodeListHeading.
  • [#611] API: Add CommandLine.addSubcommand overloaded method without name or alias....
Read more

Picocli 4.0.0-alpha-2

18 Apr 11:24
Compare
Choose a tag to compare

Picocli 4.0.0-alpha-2

The picocli community is pleased to announce picocli 4.0.0-alpha-2.

Thanks to great feedback from the picocli community on the 4.0.0-alpha-1 release, this release contains many argument group-related bugfixes.
See the 4.0.0-alpha-1 New and Noteworthy section below for more details on argument groups.

Please try this and provide feedback. We can still make changes.

What do you think of the annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?

This release also has support for variable expansion and improved support for Chinese, Japanese and Korean.

Many thanks to the picocli community for the contributions!

This is the fifty-third public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Argument Groups

Many bugfixes for argument groups.

Variable Interpolation

From this release, picocli supports variable interpolation (variable expansion) in annotation attributes as well as in text attributes of the programmatic API.

Variable Interpolation Example

@Command(name = "status", description = "This command logs the status for ${PARENT-COMMAND-NAME}.")
class Status {
    @Option(names = {"${dirOptionName1:--d}", "${dirOptionName2:---directories}"}, // -d or --directories
            description = {"Specify one or more directories, separated by '${sys:path.separator}'.",
                           "The default is the user home directory (${DEFAULT-VALUE})."},  
            arity = "${sys:dirOptionArity:-1..*}",
            defaultValue = "${sys:user.home}",
            split = "${sys:path.separator}")
    String[] directories;
}

Predefined Variables

The following variables are predefined:

  • ${DEFAULT-VALUE}: (since 3.2) - can be used in the description for an option or positional parameter, replaced with the default value for that option or positional parameter
  • ${COMPLETION-CANDIDATES}: (since 3.2) - can be used in the description for an option or positional parameter, replaced with the completion candidates for that option or positional parameter
  • ${COMMAND-NAME}: (since 4.0) - can be used in any section of the usage help message for a command, replaced with the name of the command
  • ${COMMAND-FULL-NAME}: (since 4.0) - can be used in any section of the usage help message for a command, replaced with the fully qualified name of the command (that is, preceded by its parent fully qualified name)
  • ${PARENT-COMMAND-NAME}: (since 4.0) - can be used in any section of the usage help message for a command, replaced with the name of its parent command
  • ${PARENT-COMMAND-FULL-NAME}: (since 4.0) - can be used in any section of the usage help message for a command, replaced with the fully qualified name of its parent command (that is, preceded by the name(s) of the parent command's ancestor commands)

Custom Variables

In addition, you can define your own variables. Currently the following syntaxes are supported:

  • ${sys:key}: system property lookup, replaced by the value of System.getProperty("key")
  • ${env:key}: environment variable lookup, replaced by the value of System.getEnv("key")
  • ${bundle:key}: look up the value of key in the resource bundle of the command
  • ${key}: search all of the above, first system properties, then environment variables, and finally the resource bundle of the command

Default Values for Custom Variables

You can specify a default value to use when no value is found for a custom variable. The syntax for specifying a default is ${a:-b}, where a is the variable name and b is the default value to use if a is not found.

So, for the individual lookups, this looks like this:

${key:-defaultValue}
${sys:key:-defaultValue}
${env:key:-defaultValue}
${bundle:key:-defaultValue}

The default value may contain other custom variables. For example:

${bundle:a:-${env:b:-${sys:c:-X}}}

The above variable is expanded as follows. First, try to find key a in the command's resource bundle. If a is not found in the resource bundle, get the value of environment variable b. If no environment variable b exists, get the value of system property c. Finally, no system property c exists, the value of the expression becomes X.

Escaping Variables

Sometimes you want to show a string like "${VAR}" in a description.
A $ character can be escaped with another $ character. Therefore, $${VAR} will not be interpreted as a VAR variable, but will be replaced by ${VAR} instead.

Switching Off Variable Interpolation

Variable interpolation can be switched off for the full command hierarchy by calling CommandLine.setInterpolateVariables(false), or for a particular command by calling CommandSpec.interpolateVariables(false).

Limitations of Variable Interpolation

Some attribute values need to be resolved early, when the model is constructed from the annotation values.

Specifically:

  • command names and aliases, option names, mixin names
  • arity (for options and positional parameters)
  • index (for positional parameters)
  • separator (for commands)

It is possible for these attributes to contain variables, but be aware of the limitations.

If these attributes have variables, and the variables get a different value after the model is constructed, the change will not be reflected in the model.

Improved Support for Chinese, Japanese and Korean

Picocli will align the usage help message to fit within some user-defined width (80 columns by default).
A number of characters in Chinese, Japanese and Korean (CJK) are wider than others.
If those characters are treated to have the same width as other characters, the usage help message may extend past the right margin.

From this release, picocli will use 2 columns for these wide characters when calculating where to put line breaks, resulting in better usage help message text.

This can be switched off with CommandLine.setAdjustLineBreaksForWideCJKCharacters(false).

Fixed issues

  • [#495] Publish picocli as a JPMS module in a new artifact picocli-core-module. Thanks to Warkdev for the pull request.
  • [#21] Count double-width Asian characters as two characters for line-breaking purposes.
  • [#526] Add support for variable interpolation in message strings. Thanks to Bob Tiernay for the suggestion.
  • [#660] Added @java.lang.annotation.Inherited to the @picocli.CommandLine.Command annotation. Thanks to Devin Smith for the suggestion.
  • [#661] Bugfix for stack overflow when option in an argument group had a default value. Thanks to Andreas Deininger for reporting this.
  • [#656] Bugfix for issue where synopsis for composite argument groups did not expand for n..* (n > 1). Thanks to Arno Tuomainen for finding this issue.
  • [#654] Bugfix: argument group heading text was not retrieved from ResourceBundle. Thanks to Andreas Deininger for raising this.
  • [#635] Bugfix in argument group validation: did not show an error if some but not all parts of a co-occurring group were specified. Thanks to Philipp Hanslovsky for the pull request.
  • [#653] Bugfix: argument group validation should be skipped if help was requested. Thanks to Andreas Deininger for raising this.
  • [#655] Bugfix: argument group validation silently accepts missing subgroup with multiplicity=1.
  • [#652] Documentation: fixes in user manual. Thanks to Andreas Deininger for the pull request.
  • [#651] Documentation: fixes in user manual. Thanks to Andreas Deininger for the pull request.

Deprecations

No features were deprecated in this release.

Potential breaking changes

The following classes and methods introduced in 4.0.0-alpha-1 have been renamed:

Classes:

  • picocli.CommandLine.ParseResult.MatchedGroup -> picocli.CommandLine.ParseResult.GroupMatchContainer
  • picocli.CommandLine.ParseResult.MatchedGroupMultiple -> picocli.CommandLine.ParseResult.GroupMatch

Methods:

  • ParseResult::getMatchedGroupMultiples has been renamed to ParseResult::getGroupMatches
  • ParseResult::findMatchedGroup(ArgGroupSpec) has been renamed to ParseResult::findMatches(ArgGroupSpec)

Removed:

These may be implemented in a future version.

  • picocli.CommandLine.Option.excludes() and picocli.CommandLine.Parameters.excludes()
  • picocli.CommandLine.Option.needs(() and picocli.CommandLine.Parameters.needs(()

Picocli 3.9.6

06 Apr 10:54
Compare
Choose a tag to compare

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.

Table of Contents

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:

@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ý for raising this issue.
  • [#536] Support optionally interactive options. Thanks to Lukas Heumos for raising this issue.

Deprecations

No features were deprecated in this release.

Potential breaking changes

This release has no breaking changes.

Picocli 4.0.0-alpha-1

30 Mar 10:47
Compare
Choose a tag to compare

Picocli 4.0.0-alpha-1

The picocli community is pleased to announce picocli 4.0.0-alpha-1.

This release adds support for argument groups (incubating). Argument groups enable the following:

  • mutually exclusive options
  • options that must co-occur (dependent options)
  • option sections in the usage help message
  • repeating composite arguments

See the New and Noteworthy section below for more details.

Please try this and provide feedback. We can still make changes.

What do you think of the annotations API? What about the programmatic API? Does it work as expected? Are the input validation error messages correct and clear? Is the documentation clear and complete? Anything you want to change or improve? Any other feedback?

Many thanks to the picocli community members who contributed!

This is the fifty-first public release.
Picocli follows semantic versioning.

Table of Contents

New and Noteworthy

Argument Groups (Incubating)

This release introduces a new @ArgGroup annotation and its ArgGroupSpec programmatic equivalent.

Argument Groups can be used to define:

  • mutually exclusive options
  • options that must co-occur (dependent options)
  • option sections in the usage help message
  • repeating composite arguments

To create a group using the annotations API, annotate a field or method with @ArgGroup.
The field's type refers to the class containing the options and positional parameters in the group.
(For annotated interface methods this would be the return type, for annotated setter methods in a concrete class this would be the setter's parameter type.)

Picocli will instantiate this class as necessary to capture command line argument values in the @Option and @Parameters-annotated fields and methods of this class.

Mutually Exclusive Options

Annotate a field or method with @ArgGroup(exclusive = true) to create a group of mutually exclusive options and positional parameters. For example:

@Command(name = "exclusivedemo")
public class MutuallyExclusiveOptionsDemo {

    @ArgGroup(exclusive = true, multiplicity = "1")
    Exclusive exclusive;

    static class Exclusive {
        @Option(names = "-a", required = true) int a;
        @Option(names = "-b", required = true) int b;
        @Option(names = "-c", required = true) int c;
    }
}

The above example defines a command with mutually exclusive options -a, -b and -c.

The group itself has a multiplicity attribute that defines how many times the group may be specified within the command.
The default is multiplicity = "0..1", meaning that by default a group may be omitted or specified once.
In this example the group has multiplicity = "1", so the group must occur once: one of the exclusive options must occur on the command line.

The synopsis of this command is exclusivedemo (-a=<a> | -b=<b> | -c=<c>).

Note that the options are defined as required = true; this means required within the group, not required within the command.

Picocli will validate the arguments and throw a MutuallyExclusiveArgsException if multiple mutually exclusive arguments were specified. For example:

MutuallyExclusiveOptionsDemo example = new MutuallyExclusiveOptionsDemo();
CommandLine cmd = new CommandLine(example);

try {
    cmd.parseArgs("-a=1", "-b=2");
} catch (MutuallyExclusiveArgsException ex) {
    assert "Error: -a=<a>, -b=<b> are mutually exclusive (specify only one)"
            .equals(ex.getMessage());
}

For the above group, only one of the options can be specified. Any other combination of options, or the absence of options, is invalid.

Co-occurring (Dependent) Options

Annotate a field or method with @ArgGroup(exclusive = false) to create a group of dependent options and positional parameters that must co-occur. For example:

@Command(name = "co-occur")
public class DependentOptionsDemo {

    @ArgGroup(exclusive = false)
    Dependent dependent;

    static class Dependent {
        @Option(names = "-a", required = true) int a;
        @Option(names = "-b", required = true) int b;
        @Option(names = "-c", required = true) int c;
    }
}

The above example defines a command with dependent options -a, -b and -c that must co-occur.

The group itself has a multiplicity attribute that defines how many times the group may be specified within the command.
In this example the group uses the default multiplicity, multiplicity = "0..1", meaning that the group may be omitted or specified once.

The synopsis of this command is co-occur [-a=<a> -b=<b> -c=<c>].

Note that the options are defined as required = true; this means required within the group, not required within the command.

Picocli will validate the arguments and throw a MissingParameterException if not all dependent arguments were specified. For example:

DependentOptionsDemo example = new DependentOptionsDemo();
CommandLine cmd = new CommandLine(example);

try {
    cmd.parseArgs("-a=1", "-b=2");
} catch (MissingParameterException ex) {
    assert "Error: Missing required argument(s): -c=<c>".equals(ex.getMessage());
}

Option Sections in Usage Help

The example below uses groups to define options sections in the usage help.
When a group has a non-null heading (or headingKey), the options in the group are given the specified heading in the usage help message.
The headingKey attribute can be used to get the heading text from the command's resource bundle.

This works for mutually exclusive or co-occurring groups, but it is also possible to define a group that does no validation but only creates an option section in the usage help.

Annotate a field or method with @ArgGroup(validate = false) to create a group for display purposes only. For example:

@Command(name = "sectiondemo", description = "Section demo")
public class OptionSectionDemo {

    @ArgGroup(validate = false, heading = "This is the first section%n")
    Section1 section1;

    static class Section1 {
        @Option(names = "-a", description = "Option A") int a;
        @Option(names = "-b", description = "Option B") int b;
        @Option(names = "-c", description = "Option C") int c;
    }

    @ArgGroup(validate = false, heading = "This is the second section%n")
    Section2 section2;

    static class Section2 {
        @Option(names = "-x", description = "Option X") int x;
        @Option(names = "-y", description = "Option Y") int y;
        @Option(names = "-z", description = "Option X") int z;
    }

    public static void main(String[] args) {
        new CommandLine(new OptionSectionDemo()).usage(System.out);
    }
}

This prints the following usage help message:

Usage: sectiondemo [-a=<a>] [-b=<b>] [-c=<c>] [-x=<x>] [-y=<y>] [-z=<z>]
Section demo
This is the first section
  -a=<a>    Option A
  -b=<b>    Option B
  -c=<c>    Option C
This is the second section
  -x=<x>    Option X
  -y=<y>    Option Y
  -z=<z>    Option X

Note that the heading text must end with %n to insert a newline between the heading text and the first option.
This is for consistency with other headings in the usage help, like @Command(headerHeading = "Usage:%n", optionListHeading = "%nOptions:%n").

Repeating Composite Argument Groups

The below example shows how groups can be composed of other groups, and how arrays and collections can be used to capture repeating groups (with a multiplicity greater than one):

public class CompositeGroupDemo {

    @ArgGroup(exclusive = false, multiplicity = "1..*")
    List<Composite> composites;

    static class Composite {
        @ArgGroup(exclusive = false, multiplicity = "1")
        Dependent dependent;

        @ArgGroup(exclusive = true, multiplicity = "1")
        Exclusive exclusive;
    }

    static class Dependent {
        @Option(names = "-a", required = true) int a;
        @Option(names = "-b", required = true) int b;
        @Option(names = "-c", required = true) int c;
    }

    static class Exclusive {
        @Option(names = "-x", required = true) boolean x;
        @Option(names = "-y", required = true) boolean y;
        @Option(names = "-z", required = true) boolean z;
    }
}

In the above example, the annotated composites field defines a composite group that must be specified at least once, and may be specified many times, on the command line.
Each time the group is matched, picocli creates an instance of the Composite class and adds it to the composites list.

The Composite class itself contains two groups: a group of dependent options that must co-occur, and another group of mutually exclusive options.
Both of these subgroups have multiplicity = "1", so they can occur exactly once for each multiple of the Composite group. The below example illustrates:

CompositeGroupDemo example = new CompositeGroupDemo();
CommandLine cmd = new CommandLine(example);

cmd.parseArgs("-x", "-a=1", "-b=1", "-c=1", "-a=2", "-b=2", "-c=2", "-y");
assert example.composites.size() == 2;

Composite c1 = example.composites.get(0);
assert c1.exclusive.x;
assert c1.dependent.a == 1;
assert c1.dependent.b == 1;
assert c1.dependent.c == 1;

Composite c2 = example.composites.get(1);
assert c2.exclusive.y;
assert c2.dependent.a == 2;
assert c2.dependent.b == 2;
assert c2.dependent.c == 2;

Positional Parameters

When a...

Read more

Picocli 3.9.5

18 Feb 13:47
Compare
Choose a tag to compare

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 detecting when to emit ANSI escape sequences. 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.

The underlying problem may be a bug in the native library in jansi 1.14, see fusesource/jansi-native#17 for details.

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.

Note that this issue can manifest itself when running in Gradle (e.g. continuous integration tests) even if the application itself does not have the jansi library in the classpath, since the jansi classes can be loaded from the jansi-1.14 jar included in Gradle 4.5.x.

This is the fiftieth public release.
Picocli follows semantic versioning.

Table of Contents

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] For generating GraalVM native images, ReflectionConfigGenerator in picocli-codegen 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

17 Feb 11:49
Compare
Choose a tag to compare

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.

Table of Contents

New and Noteworthy

Fixed issues

  • [#628] Add support for collecting enum multi-value options and positional parameters in EnumSet<> collections. Thanks to Lee Atkinson for raising this.
  • [#619] Bugfix: Method subcommands in commands that subclass another command caused InitializationException: "Another subcommand named 'method' already exists...". Thanks to 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 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

01 Feb 10:22
Compare
Choose a tag to compare

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.

Table of Contents

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 for the bug report.
  • [#615] Bugfix: Opaque stacktrace for "%" in Option description. Thanks to petermr for the bug report.
  • [#616] Bugfix: showDefaultValues=true with defaultValueProvider did not render defaultValues in usage help. Thanks to Sebastian Thomschke 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

20 Jan 11:14
Compare
Choose a tag to compare

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 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.

Table of Contents

New and Noteworthy

Picocli now has a mailing list picocli at googlegroups dot com. Alternatively visit the picocli Google group 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 for the pull request.
  • [#608] Bugfix: defaulting usageHelp or versionHelp options incorrectly prevented validation of required options and positional parameters. Thanks to Pietro Braione 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 for the bug report.
  • [#606] Doc: Added subcommand example. Thanks to Andreas Deininger for the pull request.
  • [#605] Doc: Improved documentation for internationalization and localization. Thanks to Andreas Deininger for raising this.
  • [#604] Doc: Improve user manual section on Dependency Injection: add Spring Boot example. Thanks to Alistair Rutherford for the example code.
  • [#610] Build: add JDKs to Travis CI build.
  • [#609] Created mailing list picocli at googlegroups dot com: picocli Google group.

Deprecations

No features were deprecated in this release.

Potential breaking changes

This release has no breaking changes.