Apache Groovy - A powerful multi-faceted programming language for the JVM platform with comprehensive module support
—
Groovy provides powerful command-line argument parsing capabilities through CliBuilder, which integrates with PicoCLI for creating robust CLI applications.
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)
}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()
}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"
}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}"
}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)
}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.
"""
}
}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"
}
}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()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