user_guide.md (22665B)
1 # User Guide 2 3 While you are welcome to provide your own organization, typically a Cobra-based 4 application will follow the following organizational structure: 5 6 ``` 7 ▾ appName/ 8 ▾ cmd/ 9 add.go 10 your.go 11 commands.go 12 here.go 13 main.go 14 ``` 15 16 In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. 17 18 ```go 19 package main 20 21 import ( 22 "{pathToYourApp}/cmd" 23 ) 24 25 func main() { 26 cmd.Execute() 27 } 28 ``` 29 30 ## Using the Cobra Generator 31 32 Cobra-CLI is its own program that will create your application and add any 33 commands you want. It's the easiest way to incorporate Cobra into your application. 34 35 For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) 36 37 ## Using the Cobra Library 38 39 To manually implement Cobra you need to create a bare main.go file and a rootCmd file. 40 You will optionally provide additional commands as you see fit. 41 42 ### Create rootCmd 43 44 Cobra doesn't require any special constructors. Simply create your commands. 45 46 Ideally you place this in app/cmd/root.go: 47 48 ```go 49 var rootCmd = &cobra.Command{ 50 Use: "hugo", 51 Short: "Hugo is a very fast static site generator", 52 Long: `A Fast and Flexible Static Site Generator built with 53 love by spf13 and friends in Go. 54 Complete documentation is available at https://gohugo.io/documentation/`, 55 Run: func(cmd *cobra.Command, args []string) { 56 // Do Stuff Here 57 }, 58 } 59 60 func Execute() { 61 if err := rootCmd.Execute(); err != nil { 62 fmt.Fprintln(os.Stderr, err) 63 os.Exit(1) 64 } 65 } 66 ``` 67 68 You will additionally define flags and handle configuration in your init() function. 69 70 For example cmd/root.go: 71 72 ```go 73 package cmd 74 75 import ( 76 "fmt" 77 "os" 78 79 "github.com/spf13/cobra" 80 "github.com/spf13/viper" 81 ) 82 83 var ( 84 // Used for flags. 85 cfgFile string 86 userLicense string 87 88 rootCmd = &cobra.Command{ 89 Use: "cobra-cli", 90 Short: "A generator for Cobra based Applications", 91 Long: `Cobra is a CLI library for Go that empowers applications. 92 This application is a tool to generate the needed files 93 to quickly create a Cobra application.`, 94 } 95 ) 96 97 // Execute executes the root command. 98 func Execute() error { 99 return rootCmd.Execute() 100 } 101 102 func init() { 103 cobra.OnInitialize(initConfig) 104 105 rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") 106 rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") 107 rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") 108 rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") 109 viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) 110 viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) 111 viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") 112 viper.SetDefault("license", "apache") 113 114 rootCmd.AddCommand(addCmd) 115 rootCmd.AddCommand(initCmd) 116 } 117 118 func initConfig() { 119 if cfgFile != "" { 120 // Use config file from the flag. 121 viper.SetConfigFile(cfgFile) 122 } else { 123 // Find home directory. 124 home, err := os.UserHomeDir() 125 cobra.CheckErr(err) 126 127 // Search config in home directory with name ".cobra" (without extension). 128 viper.AddConfigPath(home) 129 viper.SetConfigType("yaml") 130 viper.SetConfigName(".cobra") 131 } 132 133 viper.AutomaticEnv() 134 135 if err := viper.ReadInConfig(); err == nil { 136 fmt.Println("Using config file:", viper.ConfigFileUsed()) 137 } 138 } 139 ``` 140 141 ### Create your main.go 142 143 With the root command you need to have your main function execute it. 144 Execute should be run on the root for clarity, though it can be called on any command. 145 146 In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra. 147 148 ```go 149 package main 150 151 import ( 152 "{pathToYourApp}/cmd" 153 ) 154 155 func main() { 156 cmd.Execute() 157 } 158 ``` 159 160 ### Create additional commands 161 162 Additional commands can be defined and typically are each given their own file 163 inside of the cmd/ directory. 164 165 If you wanted to create a version command you would create cmd/version.go and 166 populate it with the following: 167 168 ```go 169 package cmd 170 171 import ( 172 "fmt" 173 174 "github.com/spf13/cobra" 175 ) 176 177 func init() { 178 rootCmd.AddCommand(versionCmd) 179 } 180 181 var versionCmd = &cobra.Command{ 182 Use: "version", 183 Short: "Print the version number of Hugo", 184 Long: `All software has versions. This is Hugo's`, 185 Run: func(cmd *cobra.Command, args []string) { 186 fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") 187 }, 188 } 189 ``` 190 191 ### Organizing subcommands 192 193 A command may have subcommands which in turn may have other subcommands. This is achieved by using 194 `AddCommand`. In some cases, especially in larger applications, each subcommand may be defined in 195 its own go package. 196 197 The suggested approach is for the parent command to use `AddCommand` to add its most immediate 198 subcommands. For example, consider the following directory structure: 199 200 ```text 201 ├── cmd 202 │ ├── root.go 203 │ └── sub1 204 │ ├── sub1.go 205 │ └── sub2 206 │ ├── leafA.go 207 │ ├── leafB.go 208 │ └── sub2.go 209 └── main.go 210 ``` 211 212 In this case: 213 214 * The `init` function of `root.go` adds the command defined in `sub1.go` to the root command. 215 * The `init` function of `sub1.go` adds the command defined in `sub2.go` to the sub1 command. 216 * The `init` function of `sub2.go` adds the commands defined in `leafA.go` and `leafB.go` to the 217 sub2 command. 218 219 This approach ensures the subcommands are always included at compile time while avoiding cyclic 220 references. 221 222 ### Returning and handling errors 223 224 If you wish to return an error to the caller of a command, `RunE` can be used. 225 226 ```go 227 package cmd 228 229 import ( 230 "fmt" 231 232 "github.com/spf13/cobra" 233 ) 234 235 func init() { 236 rootCmd.AddCommand(tryCmd) 237 } 238 239 var tryCmd = &cobra.Command{ 240 Use: "try", 241 Short: "Try and possibly fail at something", 242 RunE: func(cmd *cobra.Command, args []string) error { 243 if err := someFunc(); err != nil { 244 return err 245 } 246 return nil 247 }, 248 } 249 ``` 250 251 The error can then be caught at the execute function call. 252 253 ## Working with Flags 254 255 Flags provide modifiers to control how the action command operates. 256 257 ### Assign flags to a command 258 259 Since the flags are defined and used in different locations, we need to 260 define a variable outside with the correct scope to assign the flag to 261 work with. 262 263 ```go 264 var Verbose bool 265 var Source string 266 ``` 267 268 There are two different approaches to assign a flag. 269 270 ### Persistent Flags 271 272 A flag can be 'persistent', meaning that this flag will be available to the 273 command it's assigned to as well as every command under that command. For 274 global flags, assign a flag as a persistent flag on the root. 275 276 ```go 277 rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") 278 ``` 279 280 ### Local Flags 281 282 A flag can also be assigned locally, which will only apply to that specific command. 283 284 ```go 285 localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") 286 ``` 287 288 ### Local Flag on Parent Commands 289 290 By default, Cobra only parses local flags on the target command, and any local flags on 291 parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will 292 parse local flags on each command before executing the target command. 293 294 ```go 295 command := cobra.Command{ 296 Use: "print [OPTIONS] [COMMANDS]", 297 TraverseChildren: true, 298 } 299 ``` 300 301 ### Bind Flags with Config 302 303 You can also bind your flags with [viper](https://github.com/spf13/viper): 304 ```go 305 var author string 306 307 func init() { 308 rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") 309 viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) 310 } 311 ``` 312 313 In this example, the persistent flag `author` is bound with `viper`. 314 **Note**: the variable `author` will not be set to the value from config, 315 when the `--author` flag is provided by user. 316 317 More in [viper documentation](https://github.com/spf13/viper#working-with-flags). 318 319 ### Required flags 320 321 Flags are optional by default. If instead you wish your command to report an error 322 when a flag has not been set, mark it as required: 323 ```go 324 rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") 325 rootCmd.MarkFlagRequired("region") 326 ``` 327 328 Or, for persistent flags: 329 ```go 330 rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") 331 rootCmd.MarkPersistentFlagRequired("region") 332 ``` 333 334 ### Flag Groups 335 336 If you have different flags that must be provided together (e.g. if they provide the `--username` flag they MUST provide the `--password` flag as well) then 337 Cobra can enforce that requirement: 338 ```go 339 rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)") 340 rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)") 341 rootCmd.MarkFlagsRequiredTogether("username", "password") 342 ``` 343 344 You can also prevent different flags from being provided together if they represent mutually 345 exclusive options such as specifying an output format as either `--json` or `--yaml` but never both: 346 ```go 347 rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON") 348 rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML") 349 rootCmd.MarkFlagsMutuallyExclusive("json", "yaml") 350 ``` 351 352 In both of these cases: 353 - both local and persistent flags can be used 354 - **NOTE:** the group is only enforced on commands where every flag is defined 355 - a flag may appear in multiple groups 356 - a group may contain any number of flags 357 358 ## Positional and Custom Arguments 359 360 Validation of positional arguments can be specified using the `Args` field of `Command`. 361 The following validators are built in: 362 363 - Number of arguments: 364 - `NoArgs` - report an error if there are any positional args. 365 - `ArbitraryArgs` - accept any number of args. 366 - `MinimumNArgs(int)` - report an error if less than N positional args are provided. 367 - `MaximumNArgs(int)` - report an error if more than N positional args are provided. 368 - `ExactArgs(int)` - report an error if there are not exactly N positional args. 369 - `RangeArgs(min, max)` - report an error if the number of args is not between `min` and `max`. 370 - Content of the arguments: 371 - `OnlyValidArgs` - report an error if there are any positional args not specified in the `ValidArgs` field of `Command`, which can optionally be set to a list of valid values for positional args. 372 373 If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`. 374 375 Moreover, `MatchAll(pargs ...PositionalArgs)` enables combining existing checks with arbitrary other checks. 376 For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional 377 args that are not in the `ValidArgs` field of `Command`, you can call `MatchAll` on `ExactArgs` and `OnlyValidArgs`, as 378 shown below: 379 380 ```go 381 var cmd = &cobra.Command{ 382 Short: "hello", 383 Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs), 384 Run: func(cmd *cobra.Command, args []string) { 385 fmt.Println("Hello, World!") 386 }, 387 } 388 ``` 389 390 It is possible to set any custom validator that satisfies `func(cmd *cobra.Command, args []string) error`. 391 For example: 392 393 ```go 394 var cmd = &cobra.Command{ 395 Short: "hello", 396 Args: func(cmd *cobra.Command, args []string) error { 397 // Optionally run one of the validators provided by cobra 398 if err := cobra.MinimumNArgs(1)(cmd, args); err != nil { 399 return err 400 } 401 // Run the custom validation logic 402 if myapp.IsValidColor(args[0]) { 403 return nil 404 } 405 return fmt.Errorf("invalid color specified: %s", args[0]) 406 }, 407 Run: func(cmd *cobra.Command, args []string) { 408 fmt.Println("Hello, World!") 409 }, 410 } 411 ``` 412 413 ## Example 414 415 In the example below, we have defined three commands. Two are at the top level 416 and one (cmdTimes) is a child of one of the top commands. In this case the root 417 is not executable, meaning that a subcommand is required. This is accomplished 418 by not providing a 'Run' for the 'rootCmd'. 419 420 We have only defined one flag for a single command. 421 422 More documentation about flags is available at https://github.com/spf13/pflag 423 424 ```go 425 package main 426 427 import ( 428 "fmt" 429 "strings" 430 431 "github.com/spf13/cobra" 432 ) 433 434 func main() { 435 var echoTimes int 436 437 var cmdPrint = &cobra.Command{ 438 Use: "print [string to print]", 439 Short: "Print anything to the screen", 440 Long: `print is for printing anything back to the screen. 441 For many years people have printed back to the screen.`, 442 Args: cobra.MinimumNArgs(1), 443 Run: func(cmd *cobra.Command, args []string) { 444 fmt.Println("Print: " + strings.Join(args, " ")) 445 }, 446 } 447 448 var cmdEcho = &cobra.Command{ 449 Use: "echo [string to echo]", 450 Short: "Echo anything to the screen", 451 Long: `echo is for echoing anything back. 452 Echo works a lot like print, except it has a child command.`, 453 Args: cobra.MinimumNArgs(1), 454 Run: func(cmd *cobra.Command, args []string) { 455 fmt.Println("Echo: " + strings.Join(args, " ")) 456 }, 457 } 458 459 var cmdTimes = &cobra.Command{ 460 Use: "times [string to echo]", 461 Short: "Echo anything to the screen more times", 462 Long: `echo things multiple times back to the user by providing 463 a count and a string.`, 464 Args: cobra.MinimumNArgs(1), 465 Run: func(cmd *cobra.Command, args []string) { 466 for i := 0; i < echoTimes; i++ { 467 fmt.Println("Echo: " + strings.Join(args, " ")) 468 } 469 }, 470 } 471 472 cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") 473 474 var rootCmd = &cobra.Command{Use: "app"} 475 rootCmd.AddCommand(cmdPrint, cmdEcho) 476 cmdEcho.AddCommand(cmdTimes) 477 rootCmd.Execute() 478 } 479 ``` 480 481 For a more complete example of a larger application, please checkout [Hugo](https://gohugo.io/). 482 483 ## Help Command 484 485 Cobra automatically adds a help command to your application when you have subcommands. 486 This will be called when a user runs 'app help'. Additionally, help will also 487 support all other commands as input. Say, for instance, you have a command called 488 'create' without any additional configuration; Cobra will work when 'app help 489 create' is called. Every command will automatically have the '--help' flag added. 490 491 ### Example 492 493 The following output is automatically generated by Cobra. Nothing beyond the 494 command and flag definitions are needed. 495 496 $ cobra-cli help 497 498 Cobra is a CLI library for Go that empowers applications. 499 This application is a tool to generate the needed files 500 to quickly create a Cobra application. 501 502 Usage: 503 cobra-cli [command] 504 505 Available Commands: 506 add Add a command to a Cobra Application 507 completion Generate the autocompletion script for the specified shell 508 help Help about any command 509 init Initialize a Cobra Application 510 511 Flags: 512 -a, --author string author name for copyright attribution (default "YOUR NAME") 513 --config string config file (default is $HOME/.cobra.yaml) 514 -h, --help help for cobra-cli 515 -l, --license string name of license for the project 516 --viper use Viper for configuration 517 518 Use "cobra-cli [command] --help" for more information about a command. 519 520 521 Help is just a command like any other. There is no special logic or behavior 522 around it. In fact, you can provide your own if you want. 523 524 ### Grouping commands in help 525 526 Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly 527 defined using `AddGroup()` on the parent command. Then a subcommand can be added to a group using the `GroupID` element 528 of that subcommand. The groups will appear in the help output in the same order as they are defined using different 529 calls to `AddGroup()`. If you use the generated `help` or `completion` commands, you can set their group ids using 530 `SetHelpCommandGroupId()` and `SetCompletionCommandGroupId()` on the root command, respectively. 531 532 ### Defining your own help 533 534 You can provide your own Help command or your own template for the default command to use 535 with the following functions: 536 537 ```go 538 cmd.SetHelpCommand(cmd *Command) 539 cmd.SetHelpFunc(f func(*Command, []string)) 540 cmd.SetHelpTemplate(s string) 541 ``` 542 543 The latter two will also apply to any children commands. 544 545 ## Usage Message 546 547 When the user provides an invalid flag or invalid command, Cobra responds by 548 showing the user the 'usage'. 549 550 ### Example 551 You may recognize this from the help above. That's because the default help 552 embeds the usage as part of its output. 553 554 $ cobra-cli --invalid 555 Error: unknown flag: --invalid 556 Usage: 557 cobra-cli [command] 558 559 Available Commands: 560 add Add a command to a Cobra Application 561 completion Generate the autocompletion script for the specified shell 562 help Help about any command 563 init Initialize a Cobra Application 564 565 Flags: 566 -a, --author string author name for copyright attribution (default "YOUR NAME") 567 --config string config file (default is $HOME/.cobra.yaml) 568 -h, --help help for cobra-cli 569 -l, --license string name of license for the project 570 --viper use Viper for configuration 571 572 Use "cobra [command] --help" for more information about a command. 573 574 ### Defining your own usage 575 You can provide your own usage function or template for Cobra to use. 576 Like help, the function and template are overridable through public methods: 577 578 ```go 579 cmd.SetUsageFunc(f func(*Command) error) 580 cmd.SetUsageTemplate(s string) 581 ``` 582 583 ## Version Flag 584 585 Cobra adds a top-level '--version' flag if the Version field is set on the root command. 586 Running an application with the '--version' flag will print the version to stdout using 587 the version template. The template can be customized using the 588 `cmd.SetVersionTemplate(s string)` function. 589 590 ## PreRun and PostRun Hooks 591 592 It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: 593 594 - `PersistentPreRun` 595 - `PreRun` 596 - `Run` 597 - `PostRun` 598 - `PersistentPostRun` 599 600 An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: 601 602 ```go 603 package main 604 605 import ( 606 "fmt" 607 608 "github.com/spf13/cobra" 609 ) 610 611 func main() { 612 613 var rootCmd = &cobra.Command{ 614 Use: "root [sub]", 615 Short: "My root command", 616 PersistentPreRun: func(cmd *cobra.Command, args []string) { 617 fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) 618 }, 619 PreRun: func(cmd *cobra.Command, args []string) { 620 fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) 621 }, 622 Run: func(cmd *cobra.Command, args []string) { 623 fmt.Printf("Inside rootCmd Run with args: %v\n", args) 624 }, 625 PostRun: func(cmd *cobra.Command, args []string) { 626 fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) 627 }, 628 PersistentPostRun: func(cmd *cobra.Command, args []string) { 629 fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) 630 }, 631 } 632 633 var subCmd = &cobra.Command{ 634 Use: "sub [no options!]", 635 Short: "My subcommand", 636 PreRun: func(cmd *cobra.Command, args []string) { 637 fmt.Printf("Inside subCmd PreRun with args: %v\n", args) 638 }, 639 Run: func(cmd *cobra.Command, args []string) { 640 fmt.Printf("Inside subCmd Run with args: %v\n", args) 641 }, 642 PostRun: func(cmd *cobra.Command, args []string) { 643 fmt.Printf("Inside subCmd PostRun with args: %v\n", args) 644 }, 645 PersistentPostRun: func(cmd *cobra.Command, args []string) { 646 fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) 647 }, 648 } 649 650 rootCmd.AddCommand(subCmd) 651 652 rootCmd.SetArgs([]string{""}) 653 rootCmd.Execute() 654 fmt.Println() 655 rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) 656 rootCmd.Execute() 657 } 658 ``` 659 660 Output: 661 ``` 662 Inside rootCmd PersistentPreRun with args: [] 663 Inside rootCmd PreRun with args: [] 664 Inside rootCmd Run with args: [] 665 Inside rootCmd PostRun with args: [] 666 Inside rootCmd PersistentPostRun with args: [] 667 668 Inside rootCmd PersistentPreRun with args: [arg1 arg2] 669 Inside subCmd PreRun with args: [arg1 arg2] 670 Inside subCmd Run with args: [arg1 arg2] 671 Inside subCmd PostRun with args: [arg1 arg2] 672 Inside subCmd PersistentPostRun with args: [arg1 arg2] 673 ``` 674 675 ## Suggestions when "unknown command" happens 676 677 Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: 678 679 ``` 680 $ hugo srever 681 Error: unknown command "srever" for "hugo" 682 683 Did you mean this? 684 server 685 686 Run 'hugo --help' for usage. 687 ``` 688 689 Suggestions are automatically generated based on existing subcommands and use an implementation of [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. 690 691 If you need to disable suggestions or tweak the string distance in your command, use: 692 693 ```go 694 command.DisableSuggestions = true 695 ``` 696 697 or 698 699 ```go 700 command.SuggestionsMinimumDistance = 1 701 ``` 702 703 You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but make sense in your set of commands but for which 704 you don't want aliases. Example: 705 706 ``` 707 $ kubectl remove 708 Error: unknown command "remove" for "kubectl" 709 710 Did you mean this? 711 delete 712 713 Run 'kubectl help' for usage. 714 ``` 715 716 ## Generating documentation for your command 717 718 Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md). 719 720 ## Generating shell completions 721 722 Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md). 723 724 ## Providing Active Help 725 726 Cobra makes use of the shell-completion system to define a framework allowing you to provide Active Help to your users. Active Help are messages (hints, warnings, etc) printed as the program is being used. Read more about it in [Active Help](active_help.md).