CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-codehaus-groovy--groovy-all

Apache Groovy - A powerful multi-faceted programming language for the JVM platform with comprehensive module support

Pending
Overview
Eval results
Files

cli.mddocs/

Command Line Interface

Groovy provides powerful command-line argument parsing capabilities through CliBuilder, which integrates with PicoCLI for creating robust CLI applications.

CliBuilder

Basic CLI Builder

class CliBuilder {
    CliBuilder()
    CliBuilder(String usage)
    CliBuilder(PrintWriter writer)
    CliBuilder(PrintWriter writer, String usage)
    
    void setUsage(String usage)
    String getUsage()
    void setHeader(String header)
    void setFooter(String footer)
    void setWidth(int width)
    void setFormatter(HelpFormatter formatter)
    
    OptionAccessor parse(String[] args)
    OptionAccessor parse(List<String> args)
    
    void usage()
    String usage()
    
    // Option definition methods
    def opt(String opt, String description)
    def opt(String opt, String longOpt, String description) 
    def opt(String opt, String longOpt, String description, boolean required)
    def opt(String opt, boolean hasArg, String description)
    def opt(String opt, String longOpt, boolean hasArg, String description)
    def opt(Map args, String description)
}

OptionAccessor

Interface for accessing parsed command-line options.

interface OptionAccessor {
    boolean hasOption(String opt)
    boolean hasOption(char opt)
    Object getProperty(String property)
    
    String getOptionValue(String opt)
    String getOptionValue(char opt)
    String getOptionValue(String opt, String defaultValue)
    String[] getOptionValues(String opt)
    
    List arguments()
    String[] getArgs()
}

Basic Usage Examples

Simple CLI Application

import groovy.cli.picocli.CliBuilder

def cli = new CliBuilder(usage: 'myapp [options] <files>')
cli.header = 'Process files with various options'
cli.footer = 'Example: myapp -v -o output.txt input1.txt input2.txt'

// Define options
cli.h(longOpt: 'help', 'Show usage information')
cli.v(longOpt: 'verbose', 'Enable verbose output')
cli.o(longOpt: 'output', args: 1, argName: 'file', 'Output file')
cli.n(longOpt: 'number', args: 1, argName: 'num', type: Integer, 'Number of iterations')
cli.f(longOpt: 'force', 'Force overwrite existing files')

// Parse arguments
def options = cli.parse(args)

if (!options) {
    System.exit(1)
}

if (options.h) {
    cli.usage()
    System.exit(0)
}

// Access options
if (options.v) {
    println "Verbose mode enabled"
}

def outputFile = options.o ?: 'default-output.txt'
def iterations = options.n ?: 1
def forceOverwrite = options.f

println "Output file: $outputFile"
println "Iterations: $iterations"
println "Force overwrite: $forceOverwrite"

// Process remaining arguments (files)
def files = options.arguments()
files.each { file ->
    println "Processing file: $file"
}

Advanced Option Types

import groovy.cli.picocli.CliBuilder

def cli = new CliBuilder()

// Different option types
cli.s(longOpt: 'string', args: 1, 'String option')
cli.i(longOpt: 'integer', args: 1, type: Integer, 'Integer option')
cli.d(longOpt: 'double', args: 1, type: Double, 'Double option')
cli.b(longOpt: 'boolean', type: Boolean, 'Boolean option')
cli.f(longOpt: 'file', args: 1, type: File, 'File option')
cli.u(longOpt: 'url', args: 1, type: URL, 'URL option')

// Multiple values
cli.m(longOpt: 'multiple', args: '+', 'Multiple string values')
cli.l(longOpt: 'list', args: '*', 'Optional multiple values')

// Required options
cli.r(longOpt: 'required', args: 1, required: true, 'Required option')

def options = cli.parse([
    '--string', 'hello',
    '--integer', '42',
    '--double', '3.14',
    '--boolean', 'true',
    '--file', '/path/to/file.txt',
    '--multiple', 'value1', 'value2', 'value3',
    '--required', 'must-have'
])

if (options) {
    println "String: ${options.s}"
    println "Integer: ${options.i}"
    println "Double: ${options.d}"  
    println "Boolean: ${options.b}"
    println "File: ${options.f}"
    println "Multiple: ${options.ms}"  // Returns array
    println "Required: ${options.r}"
}

Validation and Error Handling

import groovy.cli.picocli.CliBuilder

def cli = new CliBuilder(usage: 'validator [options]')

cli.p(longOpt: 'port', args: 1, type: Integer, 'Port number (1-65535)')
cli.e(longOpt: 'email', args: 1, 'Email address')
cli.d(longOpt: 'date', args: 1, type: Date, 'Date in format yyyy-MM-dd')

def options = cli.parse(args)

if (!options) {
    println "Failed to parse command line options"
    System.exit(1)
}

// Custom validation
try {
    if (options.p && (options.p < 1 || options.p > 65535)) {
        throw new IllegalArgumentException("Port must be between 1 and 65535")
    }
    
    if (options.e && !options.e.matches(/[\w._%+-]+@[\w.-]+\.[A-Za-z]{2,}/)) {
        throw new IllegalArgumentException("Invalid email format")
    }
    
    println "All validations passed"
    
} catch (Exception e) {
    println "Validation error: ${e.message}"
    cli.usage()
    System.exit(1)
}

Advanced Features

Subcommands

import groovy.cli.picocli.CliBuilder

class GitLikeApp {
    static void main(String[] args) {
        if (args.length == 0) {
            printUsage()
            return
        }
        
        def command = args[0]
        def commandArgs = args.length > 1 ? args[1..-1] : []
        
        switch (command) {
            case 'init':
                handleInit(commandArgs)
                break
            case 'add':
                handleAdd(commandArgs)
                break
            case 'commit':
                handleCommit(commandArgs)
                break
            default:
                println "Unknown command: $command"
                printUsage()
        }
    }
    
    static void handleInit(String[] args) {
        def cli = new CliBuilder(usage: 'myapp init [options]')
        cli.b(longOpt: 'bare', 'Create bare repository')
        cli.q(longOpt: 'quiet', 'Suppress output')
        
        def options = cli.parse(args)
        if (!options) return
        
        println "Initializing repository..."
        if (options.b) println "Creating bare repository"
        if (!options.q) println "Repository initialized"
    }
    
    static void handleAdd(String[] args) {
        def cli = new CliBuilder(usage: 'myapp add [options] <files>')
        cli.A(longOpt: 'all', 'Add all files')
        cli.v(longOpt: 'verbose', 'Verbose output')
        
        def options = cli.parse(args)
        if (!options) return
        
        if (options.A) {
            println "Adding all files"
        } else {
            options.arguments().each { file ->
                println "Adding file: $file"
            }
        }
    }
    
    static void handleCommit(String[] args) {
        def cli = new CliBuilder(usage: 'myapp commit [options]')
        cli.m(longOpt: 'message', args: 1, required: true, 'Commit message')
        cli.a(longOpt: 'all', 'Commit all changes')
        
        def options = cli.parse(args)
        if (!options) return
        
        println "Committing with message: ${options.m}"
        if (options.a) println "Including all changes"
    }
    
    static void printUsage() {
        println """
Usage: myapp <command> [options]

Commands:
  init     Initialize a new repository
  add      Add files to staging area  
  commit   Create a new commit

Use 'myapp <command> --help' for command-specific options.
"""
    }
}

Configuration File Integration

import groovy.cli.picocli.CliBuilder
import groovy.json.JsonSlurper

class ConfigurableApp {
    def config = [:]
    
    void loadConfig(String configFile) {
        def file = new File(configFile)
        if (file.exists()) {
            def slurper = new JsonSlurper()
            config = slurper.parse(file)
        }
    }
    
    void run(String[] args) {
        def cli = new CliBuilder(usage: 'app [options]')
        cli.c(longOpt: 'config', args: 1, 'Configuration file')
        cli.h(longOpt: 'host', args: 1, 'Server host')
        cli.p(longOpt: 'port', args: 1, type: Integer, 'Server port')
        cli.v(longOpt: 'verbose', 'Verbose output')
        
        def options = cli.parse(args)
        if (!options) return
        
        // Load configuration file if specified
        if (options.c) {
            loadConfig(options.c)
        }
        
        // Command line options override config file
        def host = options.h ?: config.host ?: 'localhost'
        def port = options.p ?: config.port ?: 8080
        def verbose = options.v ?: config.verbose ?: false
        
        println "Host: $host"
        println "Port: $port"
        println "Verbose: $verbose"
        
        startServer(host, port, verbose)
    }
    
    void startServer(String host, int port, boolean verbose) {
        if (verbose) {
            println "Starting server in verbose mode..."
        }
        println "Server started on $host:$port"
    }
}

Interactive CLI

import groovy.cli.picocli.CliBuilder
import java.util.Scanner

class InteractiveCLI {
    private Scanner scanner = new Scanner(System.in)
    private boolean running = true
    
    void start() {
        println "Interactive CLI started. Type 'help' for commands."
        
        while (running) {
            print "> "
            def input = scanner.nextLine().trim()
            if (input) {
                processCommand(input.split(/\s+/))
            }
        }
    }
    
    void processCommand(String[] args) {
        def command = args[0]
        def commandArgs = args.length > 1 ? args[1..-1] : []
        
        switch (command) {
            case 'help':
                showHelp()
                break
            case 'echo':
                handleEcho(commandArgs)
                break
            case 'calc':
                handleCalculator(commandArgs)
                break
            case 'exit':
            case 'quit':
                running = false
                println "Goodbye!"
                break
            default:
                println "Unknown command: $command. Type 'help' for available commands."
        }
    }
    
    void handleEcho(String[] args) {
        def cli = new CliBuilder(usage: 'echo [options] <text>')
        cli.n('No newline')
        cli.u('Uppercase')
        
        def options = cli.parse(args)
        if (!options) return
        
        def text = options.arguments().join(' ')
        if (options.u) text = text.toUpperCase()
        
        if (options.n) {
            print text
        } else {
            println text
        }
    }
    
    void handleCalculator(String[] args) {
        def cli = new CliBuilder(usage: 'calc <operation> <num1> <num2>')
        
        def options = cli.parse(args)
        if (!options || options.arguments().size() != 3) {
            println "Usage: calc <add|sub|mul|div> <number1> <number2>"
            return
        }
        
        try {
            def operation = options.arguments()[0]
            def num1 = Double.parseDouble(options.arguments()[1])
            def num2 = Double.parseDouble(options.arguments()[2])
            
            def result = switch (operation) {
                case 'add' -> num1 + num2
                case 'sub' -> num1 - num2
                case 'mul' -> num1 * num2
                case 'div' -> num2 != 0 ? num1 / num2 : { throw new ArithmeticException("Division by zero") }()
                default -> { println "Unknown operation: $operation"; return }
            }
            
            println "Result: $result"
            
        } catch (NumberFormatException e) {
            println "Invalid number format"
        } catch (ArithmeticException e) {
            println "Math error: ${e.message}"
        }
    }
    
    void showHelp() {
        println """
Available commands:
  help                    Show this help message
  echo [options] <text>   Echo text with options
    -n                    No newline
    -u                    Uppercase
  calc <op> <n1> <n2>     Calculator (add, sub, mul, div)
  exit, quit              Exit the program
"""
    }
}

// Usage
new InteractiveCLI().start()

Best Practices

Error Handling and User Experience

import groovy.cli.picocli.CliBuilder

class RobustCLI {
    static void main(String[] args) {
        try {
            def app = new RobustCLI()
            app.run(args)
        } catch (Exception e) {
            System.err.println("Unexpected error: ${e.message}")
            if (System.getProperty('debug')) {
                e.printStackTrace()
            }
            System.exit(1)
        }
    }
    
    void run(String[] args) {
        def cli = new CliBuilder(usage: 'robustapp [options] <files>')
        cli.width = 120
        cli.header = 'A robust CLI application example'
        cli.footer = '''
Examples:
  robustapp -v file1.txt file2.txt
  robustapp --output=result.txt --format=json input.csv
'''
        
        // Define comprehensive options
        cli.h(longOpt: 'help', 'Show this help message')
        cli.v(longOpt: 'verbose', 'Enable verbose output')
        cli.q(longOpt: 'quiet', 'Suppress output')
        cli.o(longOpt: 'output', args: 1, argName: 'file', 'Output file')
        cli.f(longOpt: 'format', args: 1, argName: 'fmt', 'Output format (json|xml|csv)')
        cli._(longOpt: 'version', 'Show version information')
        
        def options = cli.parse(args)
        
        // Handle parse errors
        if (!options) {
            println "Use --help for usage information"
            System.exit(1)
        }
        
        // Handle help and version
        if (options.h) {
            cli.usage()
            return
        }
        
        if (options.version) {
            println "RobustApp version 1.0.0"
            return
        }
        
        // Validate conflicting options
        if (options.v && options.q) {
            System.err.println("Error: --verbose and --quiet cannot be used together")
            System.exit(1)
        }
        
        // Validate required arguments
        if (!options.arguments()) {
            System.err.println("Error: At least one input file is required")
            cli.usage()
            System.exit(1)
        }
        
        // Validate format option
        def validFormats = ['json', 'xml', 'csv']
        if (options.f && !validFormats.contains(options.f)) {
            System.err.println("Error: Invalid format '${options.f}'. Valid formats: ${validFormats.join(', ')}")
            System.exit(1)
        }
        
        // Process with validated options
        processFiles(options)
    }
    
    void processFiles(options) {
        def verbose = options.v && !options.q
        def outputFile = options.o ?: 'stdout'
        def format = options.f ?: 'json'
        
        if (verbose) {
            println "Processing ${options.arguments().size()} files"
            println "Output: $outputFile"
            println "Format: $format"
        }
        
        options.arguments().each { file ->
            if (verbose) println "Processing: $file"
            // Process file...
        }
        
        if (!options.q) {
            println "Processing completed successfully"
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-codehaus-groovy--groovy-all

docs

ast-transforms.md

cli.md

core-language.md

index.md

json.md

sql.md

swing.md

templates.md

xml.md

tile.json