@@ -7,13 +7,13 @@ to [Scroll 11](https://scr.k8s.netic.dk/0011/).
7
7
8
8
The packages are:
9
9
10
- - ` cmd ` — provides helpers for building the root command and
10
+ - [ ` cmd ` ] ( cmd/ ) — provides helpers for building the root command and
11
11
sub-commands. It sets sensible defaults, global flags, configuration
12
12
files, etc. It also adds an interface to sub-commands that makes
13
- completing, validating and running commands more uniform .
14
- - ` errors ` — provides error handling and error types.
15
- - ` ui ` — provides UI elements such as tables, spinners, select boxes,
16
- prompts, etc.
13
+ completing, validating and running commands more predictable .
14
+ - [ ` errors ` ] ( errors/ ) — provides error handling and error types.
15
+ - [ ` ui ` ] ( ui/ ) — provides UI elements such as tables, spinners, select
16
+ boxes, prompts, etc.
17
17
18
18
This tutorial covers basic usage and the core concepts of these packages.
19
19
@@ -74,8 +74,8 @@ func NewContext() *Context {
74
74
Here we set up the Application Context . Think of it as the container for
75
75
application information and dependencies. It will vary from project to project.
76
76
77
- For now it just holds a pointer to the ` ExecutionContext ` which you will learn
78
- more about later.
77
+ For now it just holds a pointer to the
78
+ [ ` ExecutionContext ` ] ( #the-execution-context ) which you will learn more about later.
79
79
80
80
Create the ` cmd ` directory which will hold the code for the CLI commands:
81
81
@@ -237,6 +237,17 @@ func main() {
237
237
}
238
238
```
239
239
240
+ This runs the ` Execute ` function and exits with the status code returned.
241
+
242
+ We use the ` version ` variable to set the version of the CLI when building it.
243
+ The ` go build ` flag ` -ldflags ` can override variable values at build time and we
244
+ use that to set the version to the current git tag. Example:
245
+
246
+ ``` bash
247
+ VERSION=$( git describe --tags --always --match=v* 2> /dev/null || echo v0 | sed -e s/^v//)
248
+ go build -o bin/ -ldflags ' -s -w -X main.version=${VERSION}'
249
+ ```
250
+
240
251
Install dependencies:
241
252
242
253
``` bash
@@ -360,8 +371,8 @@ are used.
360
371
361
372
#### Using the ` ExecutionContext `
362
373
363
- The ` ExecutionContext ` can be used by itself but works better in most cases if
364
- embedded in other context structs such an application context:
374
+ The ` ExecutionContext ` can be used by itself but works better when embedded in
375
+ other context structs such an application context:
365
376
366
377
``` go
367
378
package myapp
@@ -378,8 +389,8 @@ ac := &Context{
378
389
}
379
390
```
380
391
381
- That way you will always have things like the ` Logger ` and ` ErrorHandler `
382
- as well as the I/O pipes available.
392
+ That way you will always have things like the ` Logger ` , ` ErrorHandler `
393
+ and I/O pipes available.
383
394
384
395
Create it and pass it to ` newRootCmd ` from ` Execute() ` in ` cmd/root.go ` :
385
396
@@ -391,8 +402,8 @@ ac := &myapp.Context{EC: ec}
391
402
rootCmd := newRootCmd (ac)
392
403
` ` `
393
404
394
- ` newRootCmd` passes the ` ExecutionContext ` to the functions used to create
395
- commands:
405
+ The pass it from ` newRootCmd` via ` myapp. Context ` to the functions used to
406
+ create commands:
396
407
397
408
` ` ` go
398
409
func newRootCmd (ac *myapp.Context ) {
@@ -403,7 +414,7 @@ func newRootCmd(ac *myapp.Context) {
403
414
)
404
415
}
405
416
406
- // or
417
+ // or for sub-commands
407
418
408
419
func newSubCmd (ac *myapp.Context ) {
409
420
o := &options{}
@@ -412,6 +423,11 @@ func newSubCmd(ac *myapp.Context) {
412
423
}
413
424
` ` `
414
425
426
+ The [Commands and Sub-Commands](#commands-and-sub-commands) section explains
427
+ the ` NewRootCommand` and ` NewSubCommand` functions in detail. For now it's fine
428
+ to know that they create the respective ` cobra.Command ` and make the ` Context`
429
+ available later on.
430
+
415
431
In the root command the ` ExecutionContext` is available for all fields of the
416
432
` *cobra.Command ` passed to or returned from ` NewRootCommand` :
417
433
@@ -431,6 +447,11 @@ func newRootCmd(ac *myapp.Context) {
431
447
}
432
448
` ` `
433
449
450
+ Here the ` WithInitFunc` uses functions on the ` Context` to do some
451
+ initialization. ` WithInitFunc` is a way to add code to the ` PersistentPreRunE`
452
+ function on the ` cobra.Command ` struct. It can be used like here to setup
453
+ defaults or dependencies on the ` Concext` .
454
+
434
455
For sub-commands, the ` NewSubCommand` passes down the context to the
435
456
` Complete` , ` Validate` and ` Run` functions:
436
457
@@ -471,21 +492,24 @@ func (o *options) Run(ctx context.Context, ac *myapp.Context) error {
471
492
472
493
Note that the third argument passed to ` NewSubCommand` is generic, so anything
473
494
you pass there will end up becoming the second argument to the three functions.
474
- More on that later.
495
+ In most cases this will be the Application Context. More on that later.
475
496
476
497
### Persistent/Global Flags
477
498
478
499
The ` cmd` package comes with default persistent flags, some of which are
479
500
permanent/mandatory and some of which can be toggled. Persistent flags are
480
501
always present for all commands.
481
502
482
- To enable a flag, set ` <FLAG>Enabled` to ` true ` :
503
+ To enable setting a flag (not enabling the flag itself), set ` <FLAG>Enabled`
504
+ to ` true ` :
483
505
484
506
` ` ` go
485
507
ec := cmd.NewExecutionContext (...)
486
508
ec.PFlags .DryRunEnabled = true
487
509
` ` `
488
510
511
+ This makes it possible to use the ` --dry-run` flag.
512
+
489
513
See [` cmd/flags.go ` ](cmd/flags.go) for more information about available flags.
490
514
491
515
Flags that can't be disabled:
@@ -507,6 +531,7 @@ like JSON for machines. This can be set via flags.
507
531
- ` cmd.OutputFormatJSON `
508
532
- ` cmd.OutputFormatYAML `
509
533
- ` cmd.OutputFormatMarkdown `
534
+ - ` cmd.OutputFormatTable `
510
535
511
536
To set it, enable the format flags you want to support.
512
537
@@ -516,6 +541,7 @@ For now, these are:
516
541
- ` --json`
517
542
- ` --yaml`
518
543
- ` --markdown`
544
+ - ` --table`
519
545
520
546
They are mutually exclusive. Enable them like this:
521
547
@@ -524,6 +550,7 @@ ec.PFlags.PlainEnabled = true
524
550
ec.PFlags .JSONEnabled = true
525
551
ec.PFlags .YAMLEnabled = true
526
552
ec.PFlags .MarkdownEnabled = true
553
+ ec.PFlags .TableEnabled = true
527
554
` ` `
528
555
529
556
#### Enabling flags
@@ -984,7 +1011,7 @@ func (o *helloOptions) Run(_ context.Context, ac *helloworld.Context) error {
984
1011
` ` `
985
1012
986
1013
In real life applications things are rarely so simple. So, we encourage the use
987
- of the 'Use cases' term taken from Clean Architecture.
1014
+ of 'Use cases', a term taken from Clean Architecture.
988
1015
989
1016
From the Clean Architecture book:
990
1017
@@ -1038,6 +1065,16 @@ func (o *options) Run(ctx context.Context, ac *myapp.Context) error {
1038
1065
1039
1066
This makes it easier to separate concerns.
1040
1067
1068
+ #### When to Create Use Cases
1069
+
1070
+ As mentioned, we encourage the use of use cases. But there is no need to
1071
+ needlessly complicate things. If you are just doing something that borders what
1072
+ may be called business logic or something small (think a few lines of code) it
1073
+ is OK to keep the code in ` Run` . But keep in mind that code in ` cmd/` is *meant*
1074
+ to handle command line logic, not business logic. So in the long run and for
1075
+ maintainability it might be smart to create use cases even though they don't do
1076
+ much.
1077
+
1041
1078
### UI Elements
1042
1079
1043
1080
There's a couple of UI elements included in the ` ui` package. There are:
0 commit comments