CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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
)
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/org.apache.groovy/groovy-cli-picocli@5.0.x
Publish Source
CLI
Badge
tessl/maven-org-apache-groovy--groovy-cli-picocli badge