or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-org-apache-groovy--groovy-cli-picocli

A Groovy-based command line interface builder that leverages the picocli framework to provide both dynamic API and annotation-based approaches for parsing command line arguments

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.apache.groovy/groovy-cli-picocli@5.0.x

To install, run

npx @tessl/cli install tessl/maven-org-apache-groovy--groovy-cli-picocli@5.0.0

index.mddocs/

Groovy CLI Picocli

Groovy CLI Picocli is a command line interface builder for Groovy applications that integrates with the picocli framework. It provides both dynamic API and annotation-based approaches for parsing command line arguments, handling option validation, generating help messages, and accessing parsed values through a convenient interface.

Package Information

  • Package Name: org.apache.groovy:groovy-cli-picocli
  • Package Type: maven
  • Language: Groovy/Java
  • Installation: Add dependency to your Gradle build script:
dependencies {
    implementation 'org.apache.groovy:groovy-cli-picocli:5.0.0'
}

Core Imports

import groovy.cli.picocli.CliBuilder
import groovy.cli.picocli.OptionAccessor
import groovy.cli.Option
import groovy.cli.Unparsed
import groovy.cli.TypedOption
import groovy.cli.CliBuilderException

Basic Usage

Dynamic API Style

import groovy.cli.picocli.CliBuilder

def cli = new CliBuilder(name: 'myapp')
cli.h(longOpt: 'help', 'Show usage information')
cli.v(longOpt: 'verbose', 'Enable verbose output')
cli.f(longOpt: 'file', args: 1, argName: 'filename', 'Input file to process')

def options = cli.parse(args)
if (!options) {
    // Parse failed, error message already printed
    return
}

if (options.h) {
    cli.usage()
    return
}

println "Verbose: ${options.v}"
println "File: ${options.f}"
println "Arguments: ${options.arguments()}"

Annotation-Based Interface Style

import groovy.cli.picocli.CliBuilder
import groovy.cli.Option
import groovy.cli.Unparsed

interface MyOptions {
    @Option(shortName='h', description='Show usage information')
    boolean help()
    
    @Option(shortName='v', description='Enable verbose output')
    boolean verbose()
    
    @Option(shortName='f', description='Input file to process')
    String file()
    
    @Unparsed
    List<String> remaining()
}

def cli = new CliBuilder()
def options = cli.parseFromSpec(MyOptions, args)
if (options.help()) {
    cli.usage()
}

Annotation-Based Class Style

import groovy.cli.picocli.CliBuilder
import groovy.cli.Option
import groovy.cli.Unparsed

class MyOptions {
    @Option(shortName='h', description='Show usage information')
    boolean help
    
    @Option(shortName='v', description='Enable verbose output')
    boolean verbose
    
    @Option(shortName='f', description='Input file to process')
    String file
    
    @Unparsed
    List<String> remaining
}

def cli = new CliBuilder()
def options = new MyOptions()
cli.parseFromInstance(options, args)

Architecture

The Groovy CLI Picocli library is built around several key components:

  • CliBuilder: The main builder class providing both dynamic API and annotation-based parsing
  • OptionAccessor: Interface for accessing parsed command line options and arguments
  • Annotation System: @Option and @Unparsed annotations for declarative option definition
  • Picocli Integration: Leverages the robust picocli library for underlying parsing logic
  • Type System: Support for automatic type conversion and custom converters

Capabilities

CLI Builder

The main command line builder class for creating CLI parsers with flexible configuration options.

class CliBuilder {
    // Constructor
    CliBuilder()
    CliBuilder(Map args)
    
    // Configuration Properties
    String usage           // Command synopsis displayed in usage help
    String name           // Program name displayed in synopsis
    boolean posix         // Enable/disable POSIX short option clustering (default: true)
    boolean expandArgumentFiles    // Whether @-file arguments are expanded (default: true)
    boolean stopAtNonOption       // How to handle non-option arguments (default: true)
    boolean acceptLongOptionsWithSingleHyphen  // Accept long options with single hyphen (default: false)
    PrintWriter writer    // Writer for usage help messages (default: System.out)
    PrintWriter errorWriter  // Writer for error messages (default: System.err)
    String header         // Additional message displayed after usage summary
    String footer         // Additional message displayed after options
    int width            // Usage message width
    ParserSpec parser    // Fine-grained parser behaviour control
    UsageMessageSpec usageMessage  // Fine-grained usage message control
    
    // Parsing Methods
    OptionAccessor parse(String[] args)
    OptionAccessor parse(List args)
    <T> T parseFromSpec(Class<T> optionsClass, String[] args)
    <T> T parseFromInstance(T optionInstance, String[] args)
    
    // Option Definition (Dynamic API)
    TypedOption option(Map args, Class type, String description)
    def invokeMethod(String name, Object args)  // Dynamic method for option definition
    
    // Utility Methods
    void usage()          // Print usage message
    void setUsage(String usage)
    void setFooter(String footer)
    void setHeader(String header)
    void setWidth(int width)
}

Dynamic Option Definition Examples:

// Short option with description
cli.h('Show help')

// Short option with long option and description  
cli.h(longOpt: 'help', 'Show help')

// Option with argument
cli.f(longOpt: 'file', args: 1, argName: 'filename', 'Input file')

// Option with multiple arguments
cli.lib(args: 3, valueSeparator: ',', 'Library paths')

// Option with type conversion
cli.port(type: Integer, 'Port number')

// Option with Map type for key=value pairs
cli.D(type: Map, argName: 'property=value', 'System properties')

// Long-only option (no short name)
cli._(longOpt: 'verbose', 'Enable verbose output')

Option Accessor

Provides access to parsed command line options and arguments with type-safe value retrieval.

class OptionAccessor {
    ParseResult parseResult  // Underlying picocli parse result
    
    // Constructor
    OptionAccessor(ParseResult parseResult)
    
    // Option Value Access
    boolean hasOption(TypedOption typedOption)
    <T> T getOptionValue(TypedOption<T> typedOption)
    <T> T getOptionValue(TypedOption<T> typedOption, T defaultValue)
    <T> T getAt(TypedOption<T> typedOption)      // Alternative syntax []
    <T> T getAt(TypedOption<T> typedOption, T defaultValue)
    Properties getOptionProperties(String name)  // For Map-type options
    <T> T defaultValue(String name)              // Get default value for option name
    
    // Argument Access
    List<String> arguments()  // Get remaining non-option arguments
    
    // Dynamic Property Access
    def invokeMethod(String name, Object args)   // Dynamic method dispatch
    def getProperty(String name)                 // Dynamic property access
}

Usage Examples:

def cli = new CliBuilder()
def helpOption = cli.h(longOpt: 'help', 'Show help')
def fileOption = cli.f(longOpt: 'file', args: 1, 'Input file')

def options = cli.parse(args)

// Check if option was specified
if (options.hasOption(helpOption)) {
    cli.usage()
}

// Get option value with type safety
String filename = options.getOptionValue(fileOption)
String filenameWithDefault = options.getOptionValue(fileOption, "default.txt")

// Alternative bracket syntax
String filename2 = options[fileOption]
String filename3 = options[fileOption, "default.txt"]

// Dynamic property access (for simple cases)
boolean help = options.h
String file = options.f

// Get remaining arguments
List<String> remaining = options.arguments()

// Access Map-type option properties (for -D key=value style options)
Properties props = options.getOptionProperties("D")
String value = props.getProperty("key")

// Get default value for an option
String defaultFile = options.defaultValue("file")  // Returns default if specified

Option Annotation

Marks methods or fields as CLI options in annotation-based usage with comprehensive configuration options.

@interface Option {
    String description() default ""           // Description of the option
    String shortName() default ""            // Short name (single character)
    String longName() default ""             // Long name (multi-character)
    String valueSeparator() default ""       // Value separator for multivalued options
    boolean optionalArg() default false     // Whether option has optional argument
    int numberOfArguments() default 1       // Number of arguments
    String numberOfArgumentsString() default ""  // Number of arguments as string ('+', '*')
    String defaultValue() default ""         // Default value as string
    Class convert() default Undefined.class // Custom conversion closure class
}

Target: Methods, Fields

Usage Examples:

interface MyOptions {
    @Option(shortName='h', longName='help', description='Show usage information')
    boolean help()
    
    @Option(shortName='v', description='Enable verbose output')
    boolean verbose()
    
    @Option(shortName='f', longName='file', description='Input file to process')
    String file()
    
    @Option(shortName='p', longName='port', description='Port number', defaultValue='8080')
    int port()
    
    @Option(longName='libs', valueSeparator=',', numberOfArgumentsString='+', 
            description='Comma-separated library paths')
    String[] libraries()
    
    @Option(shortName='D', numberOfArgumentsString='*', 
            description='System properties as key=value pairs')
    Map<String, String> properties()
}

class MyOptions {
    @Option(shortName='h', description='Show help')
    boolean help
    
    @Option(shortName='f', description='Input file')
    String file
    
    @Option(shortName='c', description='Count', defaultValue='1')
    int count
}

Unparsed Annotation

Marks methods or fields to contain remaining non-option arguments after parsing.

@interface Unparsed {
    String description() default "ARGUMENTS"  // Description for remaining arguments
}

Target: Methods, Fields

Usage Examples:

interface MyOptions {
    @Option(shortName='v', description='Verbose output')
    boolean verbose()
    
    @Unparsed(description='Input files to process')
    List<String> files()
}

class MyOptions {
    @Option(shortName='v', description='Verbose output')  
    boolean verbose
    
    @Unparsed
    List<String> remaining
}

Typed Option

Container for typed option information that extends HashMap and provides access to default values.

class TypedOption<T> extends HashMap<String, Object> {
    // Constructor
    TypedOption()
    
    // Methods
    T defaultValue()    // Get default value for the option
    
    // Properties (inherited from HashMap and option definition)
    String opt          // Short option name
    String longOpt      // Long option name  
    Class<T> type      // Option value type
    String description  // Option description
    Object cliOption    // Reference to underlying picocli OptionSpec
    Closure convert     // Custom conversion closure if specified
    
    // Inherits all HashMap methods:
    // put(String, Object), get(String), containsKey(String), etc.
}

Usage Example:

def cli = new CliBuilder()
def portOption = cli.port(type: Integer, defaultValue: '8080', 'Port number')

// Access default value
Integer defaultPort = portOption.defaultValue()  // Returns 8080

// Use in parsing
def options = cli.parse(args)
Integer port = options.getOptionValue(portOption, portOption.defaultValue())

CLI Builder Exception

Exception thrown for CLI builder configuration errors and validation issues.

class CliBuilderException extends RuntimeException {
    // Constructor (inherits all RuntimeException constructors)
    CliBuilderException()
    CliBuilderException(String message)
    CliBuilderException(String message, Throwable cause)
    CliBuilderException(Throwable cause)
}

Types

// Import types from picocli for advanced configuration
import picocli.CommandLine.Model.ParserSpec
import picocli.CommandLine.Model.UsageMessageSpec
import picocli.CommandLine.ParseResult

// Groovy transform for annotation defaults
import groovy.transform.Undefined

Error Handling

  • Parse Errors: The parse() method returns null when parsing fails, with error messages written to the error writer (default: System.err)
  • Configuration Errors: CliBuilderException is thrown for invalid option configurations or builder setup issues
  • Type Conversion Errors: Automatic type conversion failures are reported as parse errors
  • Validation Errors: Option validation failures (e.g., missing required arguments) are reported as parse errors

Example Error Handling:

import groovy.cli.picocli.CliBuilder
import groovy.cli.CliBuilderException

try {
    def cli = new CliBuilder()
    cli.h('Help')
    cli.f(args: 1, 'File name')
    
    def options = cli.parse(args)
    if (!options) {
        // Parse failed, error already printed to System.err
        System.exit(1)
    }
    
    // Safe to use options here
    if (options.h) {
        cli.usage()
    }
} catch (CliBuilderException e) {
    System.err.println("Configuration error: ${e.message}")
    System.exit(2)
}

Advanced Features

Custom Type Converters

// Using convert closure for custom type conversion
cli.date(convert: { String input -> 
    Date.parse('yyyy-MM-dd', input) 
}, 'Date in yyyy-MM-dd format')

Parser Configuration

def cli = new CliBuilder(
    name: 'myapp',
    posix: false,                    // Disable POSIX clustering
    expandArgumentFiles: true,       // Enable @file expansion
    stopAtNonOption: false,         // Continue parsing after non-options
    acceptLongOptionsWithSingleHyphen: true  // Accept --option and -option
)

Usage Message Customization

def cli = new CliBuilder(
    usage: 'myapp [options] files...',
    header: 'Process files with various options:',
    footer: 'Examples:\n  myapp -v file1.txt file2.txt\n  myapp --help',
    width: 120
)