or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Groovy CLI Picocli

1

2

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.

3

4

## Package Information

5

6

- **Package Name**: org.apache.groovy:groovy-cli-picocli

7

- **Package Type**: maven

8

- **Language**: Groovy/Java

9

- **Installation**: Add dependency to your Gradle build script:

10

11

```groovy

12

dependencies {

13

implementation 'org.apache.groovy:groovy-cli-picocli:5.0.0'

14

}

15

```

16

17

## Core Imports

18

19

```groovy { .api }

20

import groovy.cli.picocli.CliBuilder

21

import groovy.cli.picocli.OptionAccessor

22

import groovy.cli.Option

23

import groovy.cli.Unparsed

24

import groovy.cli.TypedOption

25

import groovy.cli.CliBuilderException

26

```

27

28

## Basic Usage

29

30

### Dynamic API Style

31

32

```groovy

33

import groovy.cli.picocli.CliBuilder

34

35

def cli = new CliBuilder(name: 'myapp')

36

cli.h(longOpt: 'help', 'Show usage information')

37

cli.v(longOpt: 'verbose', 'Enable verbose output')

38

cli.f(longOpt: 'file', args: 1, argName: 'filename', 'Input file to process')

39

40

def options = cli.parse(args)

41

if (!options) {

42

// Parse failed, error message already printed

43

return

44

}

45

46

if (options.h) {

47

cli.usage()

48

return

49

}

50

51

println "Verbose: ${options.v}"

52

println "File: ${options.f}"

53

println "Arguments: ${options.arguments()}"

54

```

55

56

### Annotation-Based Interface Style

57

58

```groovy

59

import groovy.cli.picocli.CliBuilder

60

import groovy.cli.Option

61

import groovy.cli.Unparsed

62

63

interface MyOptions {

64

@Option(shortName='h', description='Show usage information')

65

boolean help()

66

67

@Option(shortName='v', description='Enable verbose output')

68

boolean verbose()

69

70

@Option(shortName='f', description='Input file to process')

71

String file()

72

73

@Unparsed

74

List<String> remaining()

75

}

76

77

def cli = new CliBuilder()

78

def options = cli.parseFromSpec(MyOptions, args)

79

if (options.help()) {

80

cli.usage()

81

}

82

```

83

84

### Annotation-Based Class Style

85

86

```groovy

87

import groovy.cli.picocli.CliBuilder

88

import groovy.cli.Option

89

import groovy.cli.Unparsed

90

91

class MyOptions {

92

@Option(shortName='h', description='Show usage information')

93

boolean help

94

95

@Option(shortName='v', description='Enable verbose output')

96

boolean verbose

97

98

@Option(shortName='f', description='Input file to process')

99

String file

100

101

@Unparsed

102

List<String> remaining

103

}

104

105

def cli = new CliBuilder()

106

def options = new MyOptions()

107

cli.parseFromInstance(options, args)

108

```

109

110

## Architecture

111

112

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

113

114

- **CliBuilder**: The main builder class providing both dynamic API and annotation-based parsing

115

- **OptionAccessor**: Interface for accessing parsed command line options and arguments

116

- **Annotation System**: `@Option` and `@Unparsed` annotations for declarative option definition

117

- **Picocli Integration**: Leverages the robust picocli library for underlying parsing logic

118

- **Type System**: Support for automatic type conversion and custom converters

119

120

## Capabilities

121

122

### CLI Builder

123

124

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

125

126

```groovy { .api }

127

class CliBuilder {

128

// Constructor

129

CliBuilder()

130

CliBuilder(Map args)

131

132

// Configuration Properties

133

String usage // Command synopsis displayed in usage help

134

String name // Program name displayed in synopsis

135

boolean posix // Enable/disable POSIX short option clustering (default: true)

136

boolean expandArgumentFiles // Whether @-file arguments are expanded (default: true)

137

boolean stopAtNonOption // How to handle non-option arguments (default: true)

138

boolean acceptLongOptionsWithSingleHyphen // Accept long options with single hyphen (default: false)

139

PrintWriter writer // Writer for usage help messages (default: System.out)

140

PrintWriter errorWriter // Writer for error messages (default: System.err)

141

String header // Additional message displayed after usage summary

142

String footer // Additional message displayed after options

143

int width // Usage message width

144

ParserSpec parser // Fine-grained parser behaviour control

145

UsageMessageSpec usageMessage // Fine-grained usage message control

146

147

// Parsing Methods

148

OptionAccessor parse(String[] args)

149

OptionAccessor parse(List args)

150

<T> T parseFromSpec(Class<T> optionsClass, String[] args)

151

<T> T parseFromInstance(T optionInstance, String[] args)

152

153

// Option Definition (Dynamic API)

154

TypedOption option(Map args, Class type, String description)

155

def invokeMethod(String name, Object args) // Dynamic method for option definition

156

157

// Utility Methods

158

void usage() // Print usage message

159

void setUsage(String usage)

160

void setFooter(String footer)

161

void setHeader(String header)

162

void setWidth(int width)

163

}

164

```

165

166

**Dynamic Option Definition Examples:**

167

168

```groovy

169

// Short option with description

170

cli.h('Show help')

171

172

// Short option with long option and description

173

cli.h(longOpt: 'help', 'Show help')

174

175

// Option with argument

176

cli.f(longOpt: 'file', args: 1, argName: 'filename', 'Input file')

177

178

// Option with multiple arguments

179

cli.lib(args: 3, valueSeparator: ',', 'Library paths')

180

181

// Option with type conversion

182

cli.port(type: Integer, 'Port number')

183

184

// Option with Map type for key=value pairs

185

cli.D(type: Map, argName: 'property=value', 'System properties')

186

187

// Long-only option (no short name)

188

cli._(longOpt: 'verbose', 'Enable verbose output')

189

```

190

191

### Option Accessor

192

193

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

194

195

```groovy { .api }

196

class OptionAccessor {

197

ParseResult parseResult // Underlying picocli parse result

198

199

// Constructor

200

OptionAccessor(ParseResult parseResult)

201

202

// Option Value Access

203

boolean hasOption(TypedOption typedOption)

204

<T> T getOptionValue(TypedOption<T> typedOption)

205

<T> T getOptionValue(TypedOption<T> typedOption, T defaultValue)

206

<T> T getAt(TypedOption<T> typedOption) // Alternative syntax []

207

<T> T getAt(TypedOption<T> typedOption, T defaultValue)

208

Properties getOptionProperties(String name) // For Map-type options

209

<T> T defaultValue(String name) // Get default value for option name

210

211

// Argument Access

212

List<String> arguments() // Get remaining non-option arguments

213

214

// Dynamic Property Access

215

def invokeMethod(String name, Object args) // Dynamic method dispatch

216

def getProperty(String name) // Dynamic property access

217

}

218

```

219

220

**Usage Examples:**

221

222

```groovy

223

def cli = new CliBuilder()

224

def helpOption = cli.h(longOpt: 'help', 'Show help')

225

def fileOption = cli.f(longOpt: 'file', args: 1, 'Input file')

226

227

def options = cli.parse(args)

228

229

// Check if option was specified

230

if (options.hasOption(helpOption)) {

231

cli.usage()

232

}

233

234

// Get option value with type safety

235

String filename = options.getOptionValue(fileOption)

236

String filenameWithDefault = options.getOptionValue(fileOption, "default.txt")

237

238

// Alternative bracket syntax

239

String filename2 = options[fileOption]

240

String filename3 = options[fileOption, "default.txt"]

241

242

// Dynamic property access (for simple cases)

243

boolean help = options.h

244

String file = options.f

245

246

// Get remaining arguments

247

List<String> remaining = options.arguments()

248

249

// Access Map-type option properties (for -D key=value style options)

250

Properties props = options.getOptionProperties("D")

251

String value = props.getProperty("key")

252

253

// Get default value for an option

254

String defaultFile = options.defaultValue("file") // Returns default if specified

255

```

256

257

### Option Annotation

258

259

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

260

261

```groovy { .api }

262

@interface Option {

263

String description() default "" // Description of the option

264

String shortName() default "" // Short name (single character)

265

String longName() default "" // Long name (multi-character)

266

String valueSeparator() default "" // Value separator for multivalued options

267

boolean optionalArg() default false // Whether option has optional argument

268

int numberOfArguments() default 1 // Number of arguments

269

String numberOfArgumentsString() default "" // Number of arguments as string ('+', '*')

270

String defaultValue() default "" // Default value as string

271

Class convert() default Undefined.class // Custom conversion closure class

272

}

273

```

274

275

**Target**: Methods, Fields

276

277

**Usage Examples:**

278

279

```groovy

280

interface MyOptions {

281

@Option(shortName='h', longName='help', description='Show usage information')

282

boolean help()

283

284

@Option(shortName='v', description='Enable verbose output')

285

boolean verbose()

286

287

@Option(shortName='f', longName='file', description='Input file to process')

288

String file()

289

290

@Option(shortName='p', longName='port', description='Port number', defaultValue='8080')

291

int port()

292

293

@Option(longName='libs', valueSeparator=',', numberOfArgumentsString='+',

294

description='Comma-separated library paths')

295

String[] libraries()

296

297

@Option(shortName='D', numberOfArgumentsString='*',

298

description='System properties as key=value pairs')

299

Map<String, String> properties()

300

}

301

302

class MyOptions {

303

@Option(shortName='h', description='Show help')

304

boolean help

305

306

@Option(shortName='f', description='Input file')

307

String file

308

309

@Option(shortName='c', description='Count', defaultValue='1')

310

int count

311

}

312

```

313

314

### Unparsed Annotation

315

316

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

317

318

```groovy { .api }

319

@interface Unparsed {

320

String description() default "ARGUMENTS" // Description for remaining arguments

321

}

322

```

323

324

**Target**: Methods, Fields

325

326

**Usage Examples:**

327

328

```groovy

329

interface MyOptions {

330

@Option(shortName='v', description='Verbose output')

331

boolean verbose()

332

333

@Unparsed(description='Input files to process')

334

List<String> files()

335

}

336

337

class MyOptions {

338

@Option(shortName='v', description='Verbose output')

339

boolean verbose

340

341

@Unparsed

342

List<String> remaining

343

}

344

```

345

346

### Typed Option

347

348

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

349

350

```groovy { .api }

351

class TypedOption<T> extends HashMap<String, Object> {

352

// Constructor

353

TypedOption()

354

355

// Methods

356

T defaultValue() // Get default value for the option

357

358

// Properties (inherited from HashMap and option definition)

359

String opt // Short option name

360

String longOpt // Long option name

361

Class<T> type // Option value type

362

String description // Option description

363

Object cliOption // Reference to underlying picocli OptionSpec

364

Closure convert // Custom conversion closure if specified

365

366

// Inherits all HashMap methods:

367

// put(String, Object), get(String), containsKey(String), etc.

368

}

369

```

370

371

**Usage Example:**

372

373

```groovy

374

def cli = new CliBuilder()

375

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

376

377

// Access default value

378

Integer defaultPort = portOption.defaultValue() // Returns 8080

379

380

// Use in parsing

381

def options = cli.parse(args)

382

Integer port = options.getOptionValue(portOption, portOption.defaultValue())

383

```

384

385

### CLI Builder Exception

386

387

Exception thrown for CLI builder configuration errors and validation issues.

388

389

```groovy { .api }

390

class CliBuilderException extends RuntimeException {

391

// Constructor (inherits all RuntimeException constructors)

392

CliBuilderException()

393

CliBuilderException(String message)

394

CliBuilderException(String message, Throwable cause)

395

CliBuilderException(Throwable cause)

396

}

397

```

398

399

## Types

400

401

```groovy { .api }

402

// Import types from picocli for advanced configuration

403

import picocli.CommandLine.Model.ParserSpec

404

import picocli.CommandLine.Model.UsageMessageSpec

405

import picocli.CommandLine.ParseResult

406

407

// Groovy transform for annotation defaults

408

import groovy.transform.Undefined

409

```

410

411

## Error Handling

412

413

- **Parse Errors**: The `parse()` method returns `null` when parsing fails, with error messages written to the error writer (default: System.err)

414

- **Configuration Errors**: `CliBuilderException` is thrown for invalid option configurations or builder setup issues

415

- **Type Conversion Errors**: Automatic type conversion failures are reported as parse errors

416

- **Validation Errors**: Option validation failures (e.g., missing required arguments) are reported as parse errors

417

418

**Example Error Handling:**

419

420

```groovy

421

import groovy.cli.picocli.CliBuilder

422

import groovy.cli.CliBuilderException

423

424

try {

425

def cli = new CliBuilder()

426

cli.h('Help')

427

cli.f(args: 1, 'File name')

428

429

def options = cli.parse(args)

430

if (!options) {

431

// Parse failed, error already printed to System.err

432

System.exit(1)

433

}

434

435

// Safe to use options here

436

if (options.h) {

437

cli.usage()

438

}

439

} catch (CliBuilderException e) {

440

System.err.println("Configuration error: ${e.message}")

441

System.exit(2)

442

}

443

```

444

445

## Advanced Features

446

447

### Custom Type Converters

448

449

```groovy

450

// Using convert closure for custom type conversion

451

cli.date(convert: { String input ->

452

Date.parse('yyyy-MM-dd', input)

453

}, 'Date in yyyy-MM-dd format')

454

```

455

456

### Parser Configuration

457

458

```groovy

459

def cli = new CliBuilder(

460

name: 'myapp',

461

posix: false, // Disable POSIX clustering

462

expandArgumentFiles: true, // Enable @file expansion

463

stopAtNonOption: false, // Continue parsing after non-options

464

acceptLongOptionsWithSingleHyphen: true // Accept --option and -option

465

)

466

```

467

468

### Usage Message Customization

469

470

```groovy

471

def cli = new CliBuilder(

472

usage: 'myapp [options] files...',

473

header: 'Process files with various options:',

474

footer: 'Examples:\n myapp -v file1.txt file2.txt\n myapp --help',

475

width: 120

476

)

477

```