I am not a professional translator, nor a professional Go developer. If there are errors in the document, please do not edit it directly. Please click to view the original document.

about

Cobra is the CLI framework for Go. It includes a library for creating powerful modern CLI applications and a tool for quickly generating Cobra based applications and command files.

Cobra was created by Go project members and Hugo author SPF13 and has been adopted by many popular Go projects such as GitHub CLI and Docker CLI.

features

  • Simple subcommand-based CLIs:app server,app fetchAnd so on;
  • Marks for full POSIX (Portable Operating System Interface) compatibility (both short and long versions)
  • Nested subcommands
  • Global, local, and cascading flags
  • usecobra init appnamecobra add cmdnameEasily generate applications and commands
  • Smart Tips (app srver. did you meanapp server)
  • Automatically generates help for commands and flags
  • Automatic identification-h,--helpSuch as help identification
  • The bash generated automatically for your application completes automatically
  • Automatically generate a MAN manual for your application
  • Command aliases so that you can change the contents without breaking them
  • Flexibility to define your own help, usage, etc.
  • Optional tight integration with viper for 12factor applications

The installation

Cobra is very easy to use. First install the latest version using the go get command. This command installs the COBRA Generator executable and its dependencies:

$ go get -u github.com/spf13/cobra/cobra
Copy the code

concept

Cobra is built on commands, arguments, and flags.

Commands represent actions, Args are things, and Flags are modifiers for these actions.

The best applications read like a sentence when used. Users will know how to use the application because they will naturally understand how to use it.

The pattern follows is APPNAME VERB NOUN –ADJECTIVE. Or APPNAME COMMAND ARG –FLAG

Some real life examples can better illustrate this point.

In the following example, server is the command and port is the flag:

hugo server --port=1313
Copy the code

In this command, we tell Git the contents of the cloned URL:

git clone URL --bare
Copy the code

Command

Commands are at the heart of an application. Every interaction provided by the application is contained in the Command. A command can have subcommands and optionally run an action.

In the example above, server is the command.

cobra.Command API

Flags

A flag is a way of embellishing the behavior of a command. Cobra supports full POSIX (Portable Operating system Interface) flags and Go Flag packages.

The Cobra command can define flags that are reserved up to the subcommand and flags that can be used only for that command.

In the example above, port is the flag.

The function of flags is provided by the PFlag library, which is a fork of the standard library and is POSIX (Portable Operating system Interface) compliant while maintaining the same interface.

An introduction to

You are welcome to provide your own project organizational structure, but typically Cobra based applications will follow the following organizational structure

  • cmd The folder where the commands are placed
    • add.go
    • your.go
    • commands.go
    • here.go
  • main.go Application entry

In Cobra applications, usually the main.go file is very. It has one purpose: to initialize Cobra.

package main

import (
  "{pathToYourApp}/cmd"
)

func main(a) {
  cmd.Execute()
}
Copy the code

Using Cobra generator

Cobra provides the CLI to create your application and add any commands you want. This is the easiest way to integrate Cobra into your application.

You can check out more information about generators here.

Use the Cobra library

To access Cobra manually, you need to create a main.go file and a rootCmd file. You can choose to provide other commands as appropriate.

Create rootCmd

Cobra does not require any special constructor. Simply create your command.

Ideally, put it in/CMD /root.go:

// rootCmd represents the base command when no subcommand is invoked
var rootCmd = &cobra.Command{
	Use:   "hugo",
	Short: "Hugo is a very fast static site generator",
  Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://hugo.spf13.com`.// Uncomment the following line of code if there is an action to execute
  // Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all subcommands to the root command and sets flags as appropriate.
// This is called by main.main(). It only needs to call rootCmd once.
func Execute(a) {
	iferr := rootCmd.Execute(); err ! =nil {
		fmt.Println(err)
		os.Exit(1)}}Copy the code

You’ll also define flags and handle configuration in the init() function. Here’s an example:

// cmd/root.go
package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/viper"
)

var cfgFile string
var projectBase string
var userLicense string

// rootCmd represents the base command when no subcommand is invoked
var rootCmd = &cobra.Command{
	Use:   "hugo",
	Short: "Hugo is a very fast static site generator",
  Long: `A Fast and Flexible Static Site Generator built with love by spf13 and friends in Go. Complete documentation is available at http://hugo.spf13.com`.// Uncomment the following line of code if there is an action to execute
  // Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all subcommands to the root command and sets flags as appropriate. Is called once by main.main().
func Execute(a) {
	iferr := rootCmd.Execute(); err ! =nil {
		fmt.Println(err)
		os.Exit(1)}}func init(a) {
	cobra.OnInitialize(initConfig)
	rootCmd.PersistentFlags().StringVar(&cfgFile, "config".""."config file (default is $HOME/.cobra.yaml)")
	rootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase"."b".""."base project directory eg. github.com/spf13/")
	rootCmd.PersistentFlags().StringP("author"."a"."YOUR NAME"."Author name for copyright attribution")
	rootCmd.PersistentFlags().StringVarP(&userLicense, "license"."l".""."Name of license for the project (can provide `licensetext` in config)")
	rootCmd.PersistentFlags().Bool("viper".true."Use Viper for configuration")
	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
	viper.BindPFlag("projectbase", rootCmd.PersistentFlags().Lookup("projectbase"))
	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
	viper.SetDefault("author"."NAME HERE <EMAIL ADDRESS>")
	viper.SetDefault("license"."apache")}func initConfig(a) {
	// Don't forget to read config either from cfgFile or from home directory!
	ifcfgFile ! ="" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		iferr ! =nil {
			fmt.Println(err)
			os.Exit(1)}// Search config in home directory with name ".cobra" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".cobra")}iferr := viper.ReadInConfig(); err ! =nil {
		fmt.Println("Can't read config:", err)
		os.Exit(1)}}Copy the code

Create the main. Go

With the root command, you need a main function to execute it. For clarity, Execute should be run on the root directory, although it can be invoked on any command.

Main. go is very simple in the Cobra application. It only does one thing — it initializes Cobra.

// main.go
package main

import (
  "{pathToYourApp}/cmd"
)

func main(a) {
  cmd.Execute()
}
Copy the code

Create additional commands

Other commands can be defined, and typically each command has its own file in the CMD/directory.

To create a version command, create CMD /version.go and populate it with the following command:

// cmd/version.go
package cmd

import (
  "fmt"

  "github.com/spf13/cobra"
)

func init(a) {
  rootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
  Use:   "version",
  Short: "Print the version number of Hugo",
  Long:  `All software has versions. This is Hugo's`,
  Run: func(cmd *cobra.Command, args []string) {
    fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")}},Copy the code

Use sign

Flags provide modifiers to control how commands operate.

Since flags are defined and used in different places, we need to define a variable externally with the correct scope to assign the flags to be used.

var verbose bool
var source string
Copy the code

There are two different ways to assign flags.

Lasting mark

The flag can be “persistent”, which means that the flag will be available to the command assigned to it and to every command under that command. For global flags, the flags are assigned as persistent flags at the root.

rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose"."v".false."verbose output")
Copy the code

Local mark

It is also possible to assign a flag locally that applies only to that particular command.

rootCmd.Flags().StringVarP(&source, "source"."s".""."Source directory to read from")
Copy the code

The local flag on the parent command

By default, Cobra only resolves the local flags on the target command and ignores any local flags on the parent command. By enabling command-Traversechildren, Cobra will resolve the local flags on each Command before executing the target Command

command := cobra.Command{
  Use: "print [OPTIONS] [COMMANDS]",
  TraverseChildren: true,}Copy the code

Use the configuration binding flag

You can also bind flags to Viper:

var author string

func init(a) {
  rootCmd.PersistentFlags().StringVar(&author, "author"."YOUR NAME"."Author name for copyright attribution")
  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))}Copy the code

In this example, the persistent tag author is bound to Viper. Note that the variable author is not set to the value in config when the user does not provide the –author flag.

See Viper for more information.

Must sign

Flags are optional by default. If you want the command to report an error when the flag is missing, set this flag to required:

var region string

rootCmd.Flags().StringVarP(&region, "region"."r".""."AWS region (required)")
rootCmd.MarkFlagRequired("region")
Copy the code

Location and custom parameters

Validation of positional parameters can be specified using the Args field of Command.

The following validators are built-in:

  • NoArgs– If there are any positional arguments, this command will report an error.
  • ArbitraryArgs– The command accepts any parameter
  • OnlyValidArgs– If CommandValidArgsIf the positional parameter does not exist in the field, the command reports an error.
  • MinimumNArgs(int)– If there are no at least N positional parameters, the command will report an error.
  • MaximumNArgs(int)– If there are more than N positional parameters, the command reports an error.
  • ExactArgs(int)– If there are no N positional parameters, the command will report an error.
  • ExactValidArgs(int)– If there are no exact N positional arguments, or if the positional argument does not exist in the ValidArgs field of Command, the Command reports with an error.
  • RangeArgs(min, max)– If the number of Args is not between the expected minimum and maximum number of Args, this command will report with an error.

Examples of built-in validators:

var cmd = &cobra.Command{
	Use:   "hello",
	Short: "hello",
	Args:  cobra.MinimumNArgs(2),
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Hello, World!")}},Copy the code

Error: requires at least 2 ARg (s), only received 1

Example of setting a custom validator:

var cmd = &cobra.Command{
  Short: "hello",
  Args: func(cmd *cobra.Command, args []string) error {
    if len(args) < 1 {
      return errors.New("requires at least one arg")}if myapp.IsValidColor(args[0]) {
      return nil
    }
    return fmt.Errorf("invalid color specified: %s", args[0])
  },
  Run: func(cmd *cobra.Command, args []string) {
    fmt.Println("Hello, World!")}},Copy the code

The sample

In the following example, we define three commands. Two are at the top level and one (cmdTimes) is a subcommand. In this case, the root directory is not executable, which means a subcommand is required. This is done by not providing Run for rootCmd.

We have defined only one flag for a command.

Documentation for flags is available at [pflag]github.com/spf13/pflag…

package main

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"
)

func main(a) {
	var echoTimes int

	var cmdPrint = &cobra.Command{
		Use:   "Print [string to print]",
		Short: "Print anything to the screen",
		Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Print: " + strings.Join(args, ""))}},var cmdEcho = &cobra.Command{
		Use:   "echo [string to echo]",
		Short: "Echo anything to the screen",
		Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Println("Print: " + strings.Join(args, ""))}},var cmdTimes = &cobra.Command{
		Use:   "times [# times] [string to echo]",
		Short: "Echo anyting to the screen more times",
		Long: `echo things multiple times back to the user y providing a count and a string.`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			for i := 0; i < echoTimes; i++ {
				fmt.Println("Echo: " + strings.Join(args, ""))
			}
		},
	}

	cmdTimes.Flags().IntVarP(&echoTimes, "times"."t".1."times to echo the input")

	// Set root command
	var rootCmd = &cobra.Command{Use: "app"}
	rootCmd.AddCommand(cmdPrint, cmdEcho)
	cmdEcho.AddCommand(cmdTimes)

	// Initialize the application
	rootCmd.Execute()
}
Copy the code

For more complex applications, see Hugo or GitHub CLI.

The help command

Cobra automatically adds help commands when you add subcommands. Help information is displayed when you run the app help command. In addition, help supports other commands as input parameters. For example, if you have a create command with no additional configuration, app help create works. Each command also automatically gets a –help flag.

The sample

The following output is automatically generated by Cobra. Nothing is needed except command and flag definitions.

Help is just like any other command. There is no particular logic or behavior. In fact, you can offer your own services as needed.

Define your own help

You can provide your own Help command or template using the method below.

cmd.SetHelpCommand(cmd *Command)
cmd.setHelpCommand(f func(*Command, []string))
cmd.setHelpTemplate(s string)
Copy the code

The latter two also apply to all subcommands.

The use of information

When the user provides an invalid flag or an invalid command, Cobra responds by showing the usage to the user.

Define your own usage information

You can provide your own usage function or template. Like help, functions and templates can be overridden with public methods:

cmd.SetUsageFunc(f func(*Command) error)
cmd.SetUsageTemplate(s string)
Copy the code

See GitHub CLI for details.

Version of the logo

If the Version field is set to the root command, Cobra will add a top-level — Version flag. Running an application with the -version flag will print the version to STdout using the version template. Templates can be customized using the cmd.setversionTemplate (s string) function.

See GitHub CLI for the SetVersionTemplate

PreRun and PostRun Hooks

You can run a function before and after executing a command. The PersistentPreRun and PreRun functions are executed before Run. PersistentPostRun and PostRun are Run after the Run. If the child does not declare its own Persistent * Run function, the child will inherit from the parent. The execution of these functions follows:

  • PersistentPreRun
  • PreRun
  • Run
  • PostRun
  • PersistentPostRun

The following example, which contains two commands, uses these features. When the subcommand executes, it runs the PersistentPreRun of the root command but not the PersistentPostRun of the root command:

package main

import (
	"fmt"

	"github.com/spf13/cobra"
)

func main(a) {
	var rootCmd = &cobra.Command{
		Use:   "root [sub]",
		Short: "My root command",
		PersistentPreRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
		},
		PreRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
		},
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside rootCmd Run with args: %v\n", args)
		},
		PostRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
		},
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
		},
	}

	subCmd := &cobra.Command{
		Use:   "sub [no options!] ",
		Short: "My subcommand",
		PreRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
		},
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside subCmd Run with args: %v\n", args)
		},
		PostRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
		},
		PersistentPostRun: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
		},
	}

	rootCmd.AddCommand(subCmd)

	rootCmd.SetArgs([]string{""})
	rootCmd.Execute()
	fmt.Println()
	rootCmd.SetArgs([]string{"sub"."arg1"."arg2"})
	rootCmd.Execute()
}
Copy the code

Output:

Inside rootCmd PersistentPreRun with args: []
Inside rootCmd PreRun with args: []
Inside rootCmd Run with args: []
Inside rootCmd PostRun with args: []
Inside rootCmd PersistentPostRun with args: []

Inside rootCmd PersistentPreRun with args: [arg1 arg2]
Inside subCmd PreRun with args: [arg1 arg2]
Inside subCmd Run with args: [arg1 arg2]
Inside subCmd PostRun with args: [arg1 arg2]
Inside subCmd PersistentPostRun with args: [arg1 arg2]
Copy the code

“Unknown command” prompt

Cobra will automatically print a message when an “unknown Command “error occurs. This is consistent with the behavior of git commands. Such as

$ hugo srever
Error: unknown command "srever" for "hugo"

Did you mean this?
        server

Run 'hugo --help' for usage.
Copy the code

The system automatically generates recommendations based on each subcommand registered and uses an implementation of the Levenstein distance. Each registration command that matches a minimum distance of 2 (case ignored) is displayed as a recommendation.

To disable suggestions or adjust string distances in a command, use:

cmd.DisableSuggestions = true
Copy the code

or

cmd.SuggestionsMinimumDistance = 1
Copy the code

You can also use the SuggestFor attribute to explicitly set the suggested name for a given command. This allows suggestions for strings that are not very close together, but they make sense for your command set and for commands that you don’t want to use aliases. Such as:

$ kubectl remove
Error: unknown command "remove" for "kubectl"

Did you mean this?
        delete

Run 'kubectl help' for usage.
Copy the code

Generate documentation for your commands

Cobra can generate documentation based on subcommands, flags, and so on. The available formats are as follows:

  • Markdown
  • ReStructured Text
  • Man Page

Generate Bash Completions for your command

Cobra can generate bash-completion files. These autoprompt analyses can be very powerful and flexible if you add more information to your commands. Read Bash Completions for more information

Doodle Smart has a large number of high-quality HC, welcome to join, you need to add my wechat yang_jun_ning, or directly send your resume to [email protected]