From 19097e2aca82886c8052011411357df91e47cf03 Mon Sep 17 00:00:00 2001 From: GHA Date: Tue, 29 Aug 2023 14:08:55 +0000 Subject: [PATCH] update 89c1e0df766123ac41513b8c20630e57c7d33b85 --- .nojekyll | 0 404.html | 116 + categories/index.html | 1941 ++++++++++++++++ categories/index.xml | 10 + completions/index.html | 1941 ++++++++++++++++ completions/index.xml | 50 + docgen/index.html | 1941 ++++++++++++++++ docgen/index.xml | 53 + fonts/slate.eot | Bin 0 -> 1876 bytes fonts/slate.svg | 14 + fonts/slate.ttf | Bin 0 -> 1720 bytes fonts/slate.woff | Bin 0 -> 1796 bytes fonts/slate.woff2 | Bin 0 -> 796 bytes images/logo.png | Bin 0 -> 77987 bytes images/navbar.png | Bin 0 -> 96 bytes index.html | 1942 +++++++++++++++++ index.xml | 124 ++ ...7edf1ddeb0953be47b26637ab73a984517149f3.js | 56 + sitemap.xml | 37 + ...3d02b9f76a8be7c142071725edffc30df8e67f.css | 1 + ...73c5b8f6dea25319370ccb4a1dbff90b86a91b.css | 1 + tags/index.html | 1941 ++++++++++++++++ tags/index.xml | 10 + 23 files changed, 10178 insertions(+) create mode 100644 .nojekyll create mode 100644 404.html create mode 100644 categories/index.html create mode 100644 categories/index.xml create mode 100644 completions/index.html create mode 100644 completions/index.xml create mode 100644 docgen/index.html create mode 100644 docgen/index.xml create mode 100644 fonts/slate.eot create mode 100644 fonts/slate.svg create mode 100644 fonts/slate.ttf create mode 100644 fonts/slate.woff create mode 100644 fonts/slate.woff2 create mode 100644 images/logo.png create mode 100644 images/navbar.png create mode 100644 index.html create mode 100644 index.xml create mode 100644 js/index.9eb557de32bb57d26313bf5737edf1ddeb0953be47b26637ab73a984517149f3.js create mode 100644 sitemap.xml create mode 100644 styles/print.min.b6ef0215cf5b87a6b35afb71fb3d02b9f76a8be7c142071725edffc30df8e67f.css create mode 100644 styles/screen.min.4da12525a66a84ce812f93508873c5b8f6dea25319370ccb4a1dbff90b86a91b.css create mode 100644 tags/index.html create mode 100644 tags/index.xml diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/404.html b/404.html new file mode 100644 index 000000000..7e3596328 --- /dev/null +++ b/404.html @@ -0,0 +1,116 @@ + + + + + + + + 404 Page not found + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NAV + + + +
+ + + + + + + + + + + + +
+
+
+
+ +

Page Not Found!

+ +
+
+ +
+
+ + + diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 000000000..2733fa71b --- /dev/null +++ b/categories/index.html @@ -0,0 +1,1941 @@ + + + + + + + + Categories + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NAV + + + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Active Help

+

Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.

+

For example,

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/    internal/    scripts/    pkg/     testdata/
+

Hint: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.

+ + + + + + + + +

Supported shells

+

Active Help is currently only supported for the following shells:

+
    +
  • Bash (using bash completion V2 only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
  • +
  • Zsh
  • +
+ + + + + + + + +

Adding Active Help messages

+

As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to Shell Completions.

+

Adding Active Help is done through the use of the cobra.AppendActiveHelp(...) function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.

+ + + + + + + + +

Active Help for nouns

+

Adding Active Help when completing a noun is done within the ValidArgsFunction(...) of a command. Please notice the use of cobra.AppendActiveHelp(...) in the following example:

+
cmd := &cobra.Command{
+	Use:   "add [NAME] [URL]",
+	Short: "add a chart repository",
+	Args:  require.ExactArgs(2),
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return addRepo(args)
+	},
+	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var comps []string
+		if len(args) == 0 {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		} else if len(args) == 1 {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		} else {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+		return comps, cobra.ShellCompDirectiveNoFileComp
+	},
+}
+

The example above defines the completions (none, in this specific example) as well as the Active Help messages for the helm repo add command. It yields the following behavior:

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+

Hint: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.

+ + + + + + + + +

Active Help for flags

+

Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:

+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		if len(args) != 2 {
+			return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+		}
+		return compVersionFlag(args[1], toComplete)
+	})
+

The example above prints an Active Help message when not enough information was given by the user to complete the --version flag.

+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1  2.0.2  2.0.3
+
+ + + + + + + +

User control of Active Help

+

You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.

+

The way to configure Active Help is to use the program’s Active Help environment +variable. That variable is named <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of your +program in uppercase with any - replaced by an _. The variable should be set by the user to whatever +Active Help configuration values are supported by the program.

+

For example, say helm has chosen to support three levels for Active Help: on, off, local. Then a user +would set the desired behavior to local by doing export HELM_ACTIVE_HELP=local in their shell.

+

For simplicity, when in cmd.ValidArgsFunction(...) or a flag’s completion function, the program should read the +Active Help configuration using the cobra.GetActiveHelpConfig(cmd) function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly).

+

For example:

+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+	var comps []string
+	if len(args) == 0 {
+		if activeHelpLevel != "off"  {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		}
+	} else if len(args) == 1 {
+		if activeHelpLevel != "off" {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		}
+	} else {
+		if activeHelpLevel == "local" {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+	}
+	return comps, cobra.ShellCompDirectiveNoFileComp
+},
+

Note 1: If the <PROGRAM>_ACTIVE_HELP environment variable is set to the string “0”, Cobra will automatically disable all Active Help output (even if some output was specified by the program using the cobra.AppendActiveHelp(...) function). Using “0” can simplify your code in situations where you want to blindly disable Active Help without having to call cobra.GetActiveHelpConfig(cmd) explicitly.

+

Note 2: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable COBRA_ACTIVE_HELP to “0”. In this case cobra.GetActiveHelpConfig(cmd) will return “0” no matter what the variable <PROGRAM>_ACTIVE_HELP is set to.

+

Note 3: If the user does not set <PROGRAM>_ACTIVE_HELP or COBRA_ACTIVE_HELP (which will be a common case), the default value for the Active Help configuration returned by cobra.GetActiveHelpConfig(cmd) will be the empty string.

+ + + + + + + + +

Active Help with Cobra’s default completion command

+

Cobra provides a default completion command for programs that wish to use it. +When using the default completion command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users.

+ + + + + + + + +

Debugging Active Help

+

Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra’s hidden __complete command. Please refer to debugging shell completion for details.

+

When debugging with the __complete command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named <PROGRAM>_ACTIVE_HELP where any - is replaced by an _. For example, we can test deactivating some Active Help as shown below:

+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+ + + + + + + + + +

Generating Bash Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Bash legacy dynamic completions

+

For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution.

+

Note: Cobra’s default completion command uses bash completion V2. If you are currently using Cobra’s legacy dynamic completion solution, you should not use the default completion command but continue using your own.

+

The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions.

+

Some code that works in kubernetes:

+
const (
+        bash_completion_func = `__kubectl_parse_get()
+{
+    local kubectl_output out
+    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
+        out=($(echo "${kubectl_output}" | awk '{print $1}'))
+        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
+    fi
+}
+
+__kubectl_get_resource()
+{
+    if [[ ${#nouns[@]} -eq 0 ]]; then
+        return 1
+    fi
+    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
+    if [[ $? -eq 0 ]]; then
+        return 0
+    fi
+}
+
+__kubectl_custom_func() {
+    case ${last_command} in
+        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
+            __kubectl_get_resource
+            return
+            ;;
+        *)
+            ;;
+    esac
+}
+`)
+

And then I set that in my command definition:

+
cmds := &cobra.Command{
+	Use:   "kubectl",
+	Short: "kubectl controls the Kubernetes cluster manager",
+	Long: `kubectl controls the Kubernetes cluster manager.
+
+Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
+	Run: runHelp,
+	BashCompletionFunction: bash_completion_func,
+}
+

The BashCompletionFunction option is really only valid/useful on the root command. Doing the above will cause __kubectl_custom_func() (__<command-use>_custom_func()) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like kubectl get pod [mypod]. If you type kubectl get pod [tab][tab] the __kubectl_customc_func() will run because the cobra.Command only understood “kubectl” and “get.” __kubectl_custom_func() will see that the cobra.Command is “kubectl_get” and will thus call another helper __kubectl_get_resource(). __kubectl_get_resource will look at the ’nouns’ collected. In our example the only noun will be pod. So it will call __kubectl_parse_get pod. __kubectl_parse_get will actually call out to kubernetes and get any pods. It will then set COMPREPLY to valid pods!

+

Similarly, for flags:

+
	annotation := make(map[string][]string)
+	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
+
+	flag := &pflag.Flag{
+		Name:        "namespace",
+		Usage:       usage,
+		Annotations: annotation,
+	}
+	cmd.Flags().AddFlag(flag)
+

In addition add the __kubectl_get_namespaces implementation in the BashCompletionFunction +value, e.g.:

+
__kubectl_get_namespaces()
+{
+    local template
+    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
+    local kubectl_out
+    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
+        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
+    fi
+}
+
+ + + + + + + + + +

Generating Fish Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating PowerShell Completions For Your Own cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating Zsh Completion For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Zsh completions standardization

+

Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced.

+ + + + + + + + +

Deprecation summary

+

See further below for more details on these deprecations.

+
    +
  • cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored.
  • +
  • cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction with ShellCompDirectiveFilterFileExt.
    • +
    +
  • +
  • cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction.
    • +
    +
  • +
+ + + + + + + + +

Behavioral changes

+

Noun completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use ValidArgsFunction with ShellCompDirectiveNoFileComp to turn off file completion on a per-argument basis
Completion of flag names without the - prefix having been typedFlag names are only completed if the user has typed the first -
cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) used to turn on file completion on a per-argument position basisFile completion for all arguments by default; cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored
cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) used to turn on file completion with glob filtering on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored; use ValidArgsFunction with ShellCompDirectiveFilterFileExt for file extension filtering (not full glob filtering)
cmd.MarkZshCompPositionalArgumentWords(pos, words[]) used to provide completion choices on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored; use ValidArgsFunction to achieve the same behavior
+

Flag-value completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use RegisterFlagCompletionFunc() with ShellCompDirectiveNoFileComp to turn off file completion
cmd.MarkFlagFilename(flag, []string{}) and similar used to turn on file completionFile completion by default; cmd.MarkFlagFilename(flag, []string{}) no longer needed in this context and silently ignored
cmd.MarkFlagFilename(flag, glob[]) used to turn on file completion with glob filtering (syntax of []string{"*.yaml", "*.yml"} incompatible with bash)Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells ([]string{"yaml", "yml"})
cmd.MarkFlagDirname(flag) only completes directories (zsh-specific)Has been added for all shells
Completion of a flag name does not repeat, unless flag is of type *Array or *Slice (not supported by bash)Retained for zsh and added to fish
Completion of a flag name does not provide the = form (unlike bash)Retained for zsh and added to fish
+

Improvements

+
    +
  • Custom completion support (ValidArgsFunction and RegisterFlagCompletionFunc())
  • +
  • File completion by default if no other completions found
  • +
  • Handling of required flags
  • +
  • File extension filtering no longer mutually exclusive with bash usage
  • +
  • Completion of directory names within another directory
  • +
  • Support for = form of flags
  • +
+ + + + + + + + + + +

Generating Man Pages For Your Own cobra.Command

+

Generating man pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	header := &doc.GenManHeader{
+		Title: "MINE",
+		Section: "3",
+	}
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a man page /tmp/test.3

+ + + + + + + + + + +

Generating Markdown Docs For Your Own cobra.Command

+

Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenMarkdownTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Markdown document /tmp/test.md

+ + + + + + + + +

Generate markdown docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenMarkdownTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate markdown docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenMarkdown instead of GenMarkdownTree

+
	out := new(bytes.Buffer)
+	err := doc.GenMarkdown(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the markdown doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + +

Customize the output

+

Both GenMarkdown and GenMarkdownTree have alternate versions with callbacks to get some control of the output:

+
func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Generating ReStructured Text Docs For Your Own cobra.Command

+

Generating ReST pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenReSTTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a ReST document /tmp/test.rst

+ + + + + + + + +

Generate ReST docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenReSTTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate ReST docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenReST instead of GenReSTTree

+
	out := new(bytes.Buffer)
+	err := doc.GenReST(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the ReST doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenReST and GenReSTTree have alternate versions with callbacks to get some control of the output:

+
func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+	//...
+}
+
func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where :ref: is used:

+
// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+    return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+
+ + + + + + + + + +

Generating Yaml Docs For Your Own cobra.Command

+

Generating yaml files from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Yaml document /tmp/test.yaml

+ + + + + + + + +

Generate yaml docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate yaml docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenYaml instead of GenYamlTree

+
	out := new(bytes.Buffer)
+	doc.GenYaml(cmd, out)
+

This will write the yaml doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenYaml and GenYamlTree have alternate versions with callbacks to get some control of the output:

+
func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Projects using Cobra

+ + + + + + + + + + + +

User Guide

+

While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure:

+
  ▾ appName/
+    ▾ cmd/
+        add.go
+        your.go
+        commands.go
+        here.go
+      main.go
+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Using the Cobra Generator

+

Cobra-CLI is its own program that will create your application and add any commands you want. +It’s the easiest way to incorporate Cobra into your application.

+

For complete details on using the Cobra generator, please refer to The Cobra-CLI Generator README

+ + + + + + + + +

Using the Cobra Library

+

To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit.

+ + + + + + + + +

Create rootCmd

+

Cobra doesn’t require any special constructors. Simply create your commands.

+

Ideally you place this in app/cmd/root.go:

+
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 https://gohugo.io/documentation/`,
+  Run: func(cmd *cobra.Command, args []string) {
+    // Do Stuff Here
+  },
+}
+
+func Execute() {
+  if err := rootCmd.Execute(); err != nil {
+    fmt.Fprintln(os.Stderr, err)
+    os.Exit(1)
+  }
+}
+

You will additionally define flags and handle configuration in your init() function.

+

For example cmd/root.go:

+
package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// Used for flags.
+	cfgFile     string
+	userLicense string
+
+	rootCmd = &cobra.Command{
+		Use:   "cobra-cli",
+		Short: "A generator for Cobra based Applications",
+		Long: `Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	}
+)
+
+// Execute executes the root command.
+func Execute() error {
+	return rootCmd.Execute()
+}
+
+func init() {
+	cobra.OnInitialize(initConfig)
+
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
+	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
+	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
+	viper.SetDefault("license", "apache")
+
+	rootCmd.AddCommand(addCmd)
+	rootCmd.AddCommand(initCmd)
+}
+
+func initConfig() {
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := os.UserHomeDir()
+		cobra.CheckErr(err)
+
+		// Search config in home directory with name ".cobra" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigType("yaml")
+		viper.SetConfigName(".cobra")
+	}
+
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
+}
+
+ + + + + + + +

Create your main.go

+

With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command.

+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Create additional commands

+

Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory.

+

If you wanted to create a version command you would create cmd/version.go and +populate it with the following:

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  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")
+  },
+}
+
+ + + + + + + +

Organizing subcommands

+

A command may have subcommands which in turn may have other subcommands. This is achieved by using +AddCommand. In some cases, especially in larger applications, each subcommand may be defined in +its own go package.

+

The suggested approach is for the parent command to use AddCommand to add its most immediate +subcommands. For example, consider the following directory structure:

+
├── cmd
+│   ├── root.go
+│   └── sub1
+│       ├── sub1.go
+│       └── sub2
+│           ├── leafA.go
+│           ├── leafB.go
+│           └── sub2.go
+└── main.go
+

In this case:

+
    +
  • The init function of root.go adds the command defined in sub1.go to the root command.
  • +
  • The init function of sub1.go adds the command defined in sub2.go to the sub1 command.
  • +
  • The init function of sub2.go adds the commands defined in leafA.go and leafB.go to the +sub2 command.
  • +
+

This approach ensures the subcommands are always included at compile time while avoiding cyclic +references.

+ + + + + + + + +

Returning and handling errors

+

If you wish to return an error to the caller of a command, RunE can be used.

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  rootCmd.AddCommand(tryCmd)
+}
+
+var tryCmd = &cobra.Command{
+  Use:   "try",
+  Short: "Try and possibly fail at something",
+  RunE: func(cmd *cobra.Command, args []string) error {
+    if err := someFunc(); err != nil {
+	return err
+    }
+    return nil
+  },
+}
+

The error can then be caught at the execute function call.

+ + + + + + + + +

Working with Flags

+

Flags provide modifiers to control how the action command operates.

+ + + + + + + + +

Assign flags to a command

+

Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with.

+
var Verbose bool
+var Source string
+

There are two different approaches to assign a flag.

+ + + + + + + + +

Persistent Flags

+

A flag can be ‘persistent’, meaning that this flag will be available to the +command it’s assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root.

+
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
+
+ + + + + + + +

Local Flags

+

A flag can also be assigned locally, which will only apply to that specific command.

+
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+
+ + + + + + + +

Local Flag on Parent Commands

+

By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling Command.TraverseChildren, Cobra will +parse local flags on each command before executing the target command.

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

Bind Flags with Config

+

You can also bind your flags with viper:

+
var author string
+
+func init() {
+  rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
+  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+}
+

In this example, the persistent flag author is bound with viper. +Note: the variable author will not be set to the value from config, +when the --author flag is provided by user.

+

More in viper documentation.

+ + + + + + + + +

Required flags

+

Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required:

+
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkFlagRequired("region")
+

Or, for persistent flags:

+
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkPersistentFlagRequired("region")
+
+ + + + + + + +

Flag Groups

+

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 +Cobra can enforce that requirement:

+
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+

You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either --json or --yaml but never both:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

If you want to require at least one flag from a group to be present, you can use MarkFlagsOneRequired. +This can be combined with MarkFlagsMutuallyExclusive to enforce exactly one flag from a given group:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsOneRequired("json", "yaml")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

In these cases:

+
    +
  • both local and persistent flags can be used +
      +
    • NOTE: the group is only enforced on commands where every flag is defined
    • +
    +
  • +
  • a flag may appear in multiple groups
  • +
  • a group may contain any number of flags
  • +
+ + + + + + + + +

Positional and Custom Arguments

+

Validation of positional arguments can be specified using the Args field of Command. +The following validators are built in:

+
    +
  • Number of arguments: +
      +
    • NoArgs - report an error if there are any positional args.
    • +
    • ArbitraryArgs - accept any number of args.
    • +
    • MinimumNArgs(int) - report an error if less than N positional args are provided.
    • +
    • MaximumNArgs(int) - report an error if more than N positional args are provided.
    • +
    • ExactArgs(int) - report an error if there are not exactly N positional args.
    • +
    • RangeArgs(min, max) - report an error if the number of args is not between min and max.
    • +
    +
  • +
  • Content of the arguments: +
      +
    • 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.
    • +
    +
  • +
+

If Args is undefined or nil, it defaults to ArbitraryArgs.

+

Moreover, MatchAll(pargs ...PositionalArgs) enables combining existing checks with arbitrary other checks. +For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional +args that are not in the ValidArgs field of Command, you can call MatchAll on ExactArgs and OnlyValidArgs, as +shown below:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
+  Run: func(cmd *cobra.Command, args []string) {
+    fmt.Println("Hello, World!")
+  },
+}
+

It is possible to set any custom validator that satisfies func(cmd *cobra.Command, args []string) error. +For example:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: func(cmd *cobra.Command, args []string) error {
+    // Optionally run one of the validators provided by cobra
+    if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
+        return err
+    }
+    // Run the custom validation logic
+    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!")
+  },
+}
+
+ + + + + + + +

Example

+

In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a ‘Run’ for the ‘rootCmd’.

+

We have only defined one flag for a single command.

+

More documentation about flags is available at https://github.com/spf13/pflag

+
package main
+
+import (
+  "fmt"
+  "strings"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+  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("Echo: " + strings.Join(args, " "))
+    },
+  }
+
+  var cmdTimes = &cobra.Command{
+    Use:   "times [string to echo]",
+    Short: "Echo anything to the screen more times",
+    Long: `echo things multiple times back to the user by 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")
+
+  var rootCmd = &cobra.Command{Use: "app"}
+  rootCmd.AddCommand(cmdPrint, cmdEcho)
+  cmdEcho.AddCommand(cmdTimes)
+  rootCmd.Execute()
+}
+

For a more complete example of a larger application, please checkout Hugo.

+ + + + + + + + +

Help Command

+

Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs ‘app help’. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +‘create’ without any additional configuration; Cobra will work when ‘app help +create’ is called. Every command will automatically have the ‘–help’ flag added.

+ + + + + + + + +

Example

+

The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed.

+
$ cobra-cli help
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.
+
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra-cli [command] --help" for more information about a command.
+
+

Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want.

+ + + + + + + + +

Grouping commands in help

+

Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly +defined using AddGroup() on the parent command. Then a subcommand can be added to a group using the GroupID element +of that subcommand. The groups will appear in the help output in the same order as they are defined using different +calls to AddGroup(). If you use the generated help or completion commands, you can set their group ids using +SetHelpCommandGroupId() and SetCompletionCommandGroupId() on the root command, respectively.

+ + + + + + + + +

Defining your own help

+

You can provide your own Help command or your own template for the default command to use +with the following functions:

+
cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
+

The latter two will also apply to any children commands.

+ + + + + + + + +

Usage Message

+

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

+ + + + + + + + +

Example

+

You may recognize this from the help above. That’s because the default help +embeds the usage as part of its output.

+
$ cobra-cli --invalid
+Error: unknown flag: --invalid
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra [command] --help" for more information about a command.
+
+ + + + + + + + +

Defining your own usage

+

You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods:

+
cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
+
+ + + + + + + +

Version Flag

+

Cobra adds a top-level ‘–version’ flag if the Version field is set on the root command. +Running an application with the ‘–version’ flag will print the version to stdout using +the version template. The template can be customized using the +cmd.SetVersionTemplate(s string) function.

+ + + + + + + + +

PreRun and PostRun Hooks

+

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:

+
    +
  • PersistentPreRun
  • +
  • PreRun
  • +
  • Run
  • +
  • PostRun
  • +
  • PersistentPostRun
  • +
+

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:

+
package main
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+
+  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)
+    },
+  }
+
+  var 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()
+}
+

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]
+
+ + + + + + + +

Suggestions when “unknown command” happens

+

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:

+
$ hugo srever
+Error: unknown command "srever" for "hugo"
+
+Did you mean this?
+        server
+
+Run 'hugo --help' for usage.
+

Suggestions are automatically generated based on existing subcommands and use an implementation of Levenshtein distance. Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.

+

If you need to disable suggestions or tweak the string distance in your command, use:

+
command.DisableSuggestions = true
+

or

+
command.SuggestionsMinimumDistance = 1
+

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 +you don’t want aliases. Example:

+
$ kubectl remove
+Error: unknown command "remove" for "kubectl"
+
+Did you mean this?
+        delete
+
+Run 'kubectl help' for usage.
+
+ + + + + + + +

Generating documentation for your command

+

Cobra can generate documentation based on subcommands, flags, etc. +Read more about it in the docs generation documentation.

+ + + + + + + + +

Generating shell completions

+

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.

+ + + + + + + + +

Providing Active Help

+

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.

+ + + +
+
+ +
+
+ + + diff --git a/categories/index.xml b/categories/index.xml new file mode 100644 index 000000000..e282b7f25 --- /dev/null +++ b/categories/index.xml @@ -0,0 +1,10 @@ + + + + Categories on Cobra documentation + https://spf13.github.io/cobra/categories/ + Recent content in Categories on Cobra documentation + Hugo -- gohugo.io + en + + diff --git a/completions/index.html b/completions/index.html new file mode 100644 index 000000000..506d9ef21 --- /dev/null +++ b/completions/index.html @@ -0,0 +1,1941 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NAV + + + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Active Help

+

Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.

+

For example,

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/    internal/    scripts/    pkg/     testdata/
+

Hint: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.

+ + + + + + + + +

Supported shells

+

Active Help is currently only supported for the following shells:

+
    +
  • Bash (using bash completion V2 only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
  • +
  • Zsh
  • +
+ + + + + + + + +

Adding Active Help messages

+

As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to Shell Completions.

+

Adding Active Help is done through the use of the cobra.AppendActiveHelp(...) function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.

+ + + + + + + + +

Active Help for nouns

+

Adding Active Help when completing a noun is done within the ValidArgsFunction(...) of a command. Please notice the use of cobra.AppendActiveHelp(...) in the following example:

+
cmd := &cobra.Command{
+	Use:   "add [NAME] [URL]",
+	Short: "add a chart repository",
+	Args:  require.ExactArgs(2),
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return addRepo(args)
+	},
+	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var comps []string
+		if len(args) == 0 {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		} else if len(args) == 1 {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		} else {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+		return comps, cobra.ShellCompDirectiveNoFileComp
+	},
+}
+

The example above defines the completions (none, in this specific example) as well as the Active Help messages for the helm repo add command. It yields the following behavior:

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+

Hint: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.

+ + + + + + + + +

Active Help for flags

+

Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:

+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		if len(args) != 2 {
+			return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+		}
+		return compVersionFlag(args[1], toComplete)
+	})
+

The example above prints an Active Help message when not enough information was given by the user to complete the --version flag.

+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1  2.0.2  2.0.3
+
+ + + + + + + +

User control of Active Help

+

You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.

+

The way to configure Active Help is to use the program’s Active Help environment +variable. That variable is named <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of your +program in uppercase with any - replaced by an _. The variable should be set by the user to whatever +Active Help configuration values are supported by the program.

+

For example, say helm has chosen to support three levels for Active Help: on, off, local. Then a user +would set the desired behavior to local by doing export HELM_ACTIVE_HELP=local in their shell.

+

For simplicity, when in cmd.ValidArgsFunction(...) or a flag’s completion function, the program should read the +Active Help configuration using the cobra.GetActiveHelpConfig(cmd) function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly).

+

For example:

+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+	var comps []string
+	if len(args) == 0 {
+		if activeHelpLevel != "off"  {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		}
+	} else if len(args) == 1 {
+		if activeHelpLevel != "off" {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		}
+	} else {
+		if activeHelpLevel == "local" {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+	}
+	return comps, cobra.ShellCompDirectiveNoFileComp
+},
+

Note 1: If the <PROGRAM>_ACTIVE_HELP environment variable is set to the string “0”, Cobra will automatically disable all Active Help output (even if some output was specified by the program using the cobra.AppendActiveHelp(...) function). Using “0” can simplify your code in situations where you want to blindly disable Active Help without having to call cobra.GetActiveHelpConfig(cmd) explicitly.

+

Note 2: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable COBRA_ACTIVE_HELP to “0”. In this case cobra.GetActiveHelpConfig(cmd) will return “0” no matter what the variable <PROGRAM>_ACTIVE_HELP is set to.

+

Note 3: If the user does not set <PROGRAM>_ACTIVE_HELP or COBRA_ACTIVE_HELP (which will be a common case), the default value for the Active Help configuration returned by cobra.GetActiveHelpConfig(cmd) will be the empty string.

+ + + + + + + + +

Active Help with Cobra’s default completion command

+

Cobra provides a default completion command for programs that wish to use it. +When using the default completion command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users.

+ + + + + + + + +

Debugging Active Help

+

Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra’s hidden __complete command. Please refer to debugging shell completion for details.

+

When debugging with the __complete command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named <PROGRAM>_ACTIVE_HELP where any - is replaced by an _. For example, we can test deactivating some Active Help as shown below:

+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+ + + + + + + + + +

Generating Bash Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Bash legacy dynamic completions

+

For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution.

+

Note: Cobra’s default completion command uses bash completion V2. If you are currently using Cobra’s legacy dynamic completion solution, you should not use the default completion command but continue using your own.

+

The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions.

+

Some code that works in kubernetes:

+
const (
+        bash_completion_func = `__kubectl_parse_get()
+{
+    local kubectl_output out
+    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
+        out=($(echo "${kubectl_output}" | awk '{print $1}'))
+        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
+    fi
+}
+
+__kubectl_get_resource()
+{
+    if [[ ${#nouns[@]} -eq 0 ]]; then
+        return 1
+    fi
+    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
+    if [[ $? -eq 0 ]]; then
+        return 0
+    fi
+}
+
+__kubectl_custom_func() {
+    case ${last_command} in
+        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
+            __kubectl_get_resource
+            return
+            ;;
+        *)
+            ;;
+    esac
+}
+`)
+

And then I set that in my command definition:

+
cmds := &cobra.Command{
+	Use:   "kubectl",
+	Short: "kubectl controls the Kubernetes cluster manager",
+	Long: `kubectl controls the Kubernetes cluster manager.
+
+Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
+	Run: runHelp,
+	BashCompletionFunction: bash_completion_func,
+}
+

The BashCompletionFunction option is really only valid/useful on the root command. Doing the above will cause __kubectl_custom_func() (__<command-use>_custom_func()) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like kubectl get pod [mypod]. If you type kubectl get pod [tab][tab] the __kubectl_customc_func() will run because the cobra.Command only understood “kubectl” and “get.” __kubectl_custom_func() will see that the cobra.Command is “kubectl_get” and will thus call another helper __kubectl_get_resource(). __kubectl_get_resource will look at the ’nouns’ collected. In our example the only noun will be pod. So it will call __kubectl_parse_get pod. __kubectl_parse_get will actually call out to kubernetes and get any pods. It will then set COMPREPLY to valid pods!

+

Similarly, for flags:

+
	annotation := make(map[string][]string)
+	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
+
+	flag := &pflag.Flag{
+		Name:        "namespace",
+		Usage:       usage,
+		Annotations: annotation,
+	}
+	cmd.Flags().AddFlag(flag)
+

In addition add the __kubectl_get_namespaces implementation in the BashCompletionFunction +value, e.g.:

+
__kubectl_get_namespaces()
+{
+    local template
+    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
+    local kubectl_out
+    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
+        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
+    fi
+}
+
+ + + + + + + + + +

Generating Fish Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating PowerShell Completions For Your Own cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating Zsh Completion For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Zsh completions standardization

+

Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced.

+ + + + + + + + +

Deprecation summary

+

See further below for more details on these deprecations.

+
    +
  • cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored.
  • +
  • cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction with ShellCompDirectiveFilterFileExt.
    • +
    +
  • +
  • cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction.
    • +
    +
  • +
+ + + + + + + + +

Behavioral changes

+

Noun completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use ValidArgsFunction with ShellCompDirectiveNoFileComp to turn off file completion on a per-argument basis
Completion of flag names without the - prefix having been typedFlag names are only completed if the user has typed the first -
cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) used to turn on file completion on a per-argument position basisFile completion for all arguments by default; cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored
cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) used to turn on file completion with glob filtering on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored; use ValidArgsFunction with ShellCompDirectiveFilterFileExt for file extension filtering (not full glob filtering)
cmd.MarkZshCompPositionalArgumentWords(pos, words[]) used to provide completion choices on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored; use ValidArgsFunction to achieve the same behavior
+

Flag-value completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use RegisterFlagCompletionFunc() with ShellCompDirectiveNoFileComp to turn off file completion
cmd.MarkFlagFilename(flag, []string{}) and similar used to turn on file completionFile completion by default; cmd.MarkFlagFilename(flag, []string{}) no longer needed in this context and silently ignored
cmd.MarkFlagFilename(flag, glob[]) used to turn on file completion with glob filtering (syntax of []string{"*.yaml", "*.yml"} incompatible with bash)Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells ([]string{"yaml", "yml"})
cmd.MarkFlagDirname(flag) only completes directories (zsh-specific)Has been added for all shells
Completion of a flag name does not repeat, unless flag is of type *Array or *Slice (not supported by bash)Retained for zsh and added to fish
Completion of a flag name does not provide the = form (unlike bash)Retained for zsh and added to fish
+

Improvements

+
    +
  • Custom completion support (ValidArgsFunction and RegisterFlagCompletionFunc())
  • +
  • File completion by default if no other completions found
  • +
  • Handling of required flags
  • +
  • File extension filtering no longer mutually exclusive with bash usage
  • +
  • Completion of directory names within another directory
  • +
  • Support for = form of flags
  • +
+ + + + + + + + + + +

Generating Man Pages For Your Own cobra.Command

+

Generating man pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	header := &doc.GenManHeader{
+		Title: "MINE",
+		Section: "3",
+	}
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a man page /tmp/test.3

+ + + + + + + + + + +

Generating Markdown Docs For Your Own cobra.Command

+

Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenMarkdownTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Markdown document /tmp/test.md

+ + + + + + + + +

Generate markdown docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenMarkdownTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate markdown docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenMarkdown instead of GenMarkdownTree

+
	out := new(bytes.Buffer)
+	err := doc.GenMarkdown(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the markdown doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + +

Customize the output

+

Both GenMarkdown and GenMarkdownTree have alternate versions with callbacks to get some control of the output:

+
func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Generating ReStructured Text Docs For Your Own cobra.Command

+

Generating ReST pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenReSTTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a ReST document /tmp/test.rst

+ + + + + + + + +

Generate ReST docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenReSTTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate ReST docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenReST instead of GenReSTTree

+
	out := new(bytes.Buffer)
+	err := doc.GenReST(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the ReST doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenReST and GenReSTTree have alternate versions with callbacks to get some control of the output:

+
func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+	//...
+}
+
func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where :ref: is used:

+
// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+    return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+
+ + + + + + + + + +

Generating Yaml Docs For Your Own cobra.Command

+

Generating yaml files from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Yaml document /tmp/test.yaml

+ + + + + + + + +

Generate yaml docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate yaml docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenYaml instead of GenYamlTree

+
	out := new(bytes.Buffer)
+	doc.GenYaml(cmd, out)
+

This will write the yaml doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenYaml and GenYamlTree have alternate versions with callbacks to get some control of the output:

+
func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Projects using Cobra

+ + + + + + + + + + + +

User Guide

+

While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure:

+
  ▾ appName/
+    ▾ cmd/
+        add.go
+        your.go
+        commands.go
+        here.go
+      main.go
+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Using the Cobra Generator

+

Cobra-CLI is its own program that will create your application and add any commands you want. +It’s the easiest way to incorporate Cobra into your application.

+

For complete details on using the Cobra generator, please refer to The Cobra-CLI Generator README

+ + + + + + + + +

Using the Cobra Library

+

To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit.

+ + + + + + + + +

Create rootCmd

+

Cobra doesn’t require any special constructors. Simply create your commands.

+

Ideally you place this in app/cmd/root.go:

+
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 https://gohugo.io/documentation/`,
+  Run: func(cmd *cobra.Command, args []string) {
+    // Do Stuff Here
+  },
+}
+
+func Execute() {
+  if err := rootCmd.Execute(); err != nil {
+    fmt.Fprintln(os.Stderr, err)
+    os.Exit(1)
+  }
+}
+

You will additionally define flags and handle configuration in your init() function.

+

For example cmd/root.go:

+
package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// Used for flags.
+	cfgFile     string
+	userLicense string
+
+	rootCmd = &cobra.Command{
+		Use:   "cobra-cli",
+		Short: "A generator for Cobra based Applications",
+		Long: `Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	}
+)
+
+// Execute executes the root command.
+func Execute() error {
+	return rootCmd.Execute()
+}
+
+func init() {
+	cobra.OnInitialize(initConfig)
+
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
+	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
+	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
+	viper.SetDefault("license", "apache")
+
+	rootCmd.AddCommand(addCmd)
+	rootCmd.AddCommand(initCmd)
+}
+
+func initConfig() {
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := os.UserHomeDir()
+		cobra.CheckErr(err)
+
+		// Search config in home directory with name ".cobra" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigType("yaml")
+		viper.SetConfigName(".cobra")
+	}
+
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
+}
+
+ + + + + + + +

Create your main.go

+

With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command.

+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Create additional commands

+

Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory.

+

If you wanted to create a version command you would create cmd/version.go and +populate it with the following:

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  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")
+  },
+}
+
+ + + + + + + +

Organizing subcommands

+

A command may have subcommands which in turn may have other subcommands. This is achieved by using +AddCommand. In some cases, especially in larger applications, each subcommand may be defined in +its own go package.

+

The suggested approach is for the parent command to use AddCommand to add its most immediate +subcommands. For example, consider the following directory structure:

+
├── cmd
+│   ├── root.go
+│   └── sub1
+│       ├── sub1.go
+│       └── sub2
+│           ├── leafA.go
+│           ├── leafB.go
+│           └── sub2.go
+└── main.go
+

In this case:

+
    +
  • The init function of root.go adds the command defined in sub1.go to the root command.
  • +
  • The init function of sub1.go adds the command defined in sub2.go to the sub1 command.
  • +
  • The init function of sub2.go adds the commands defined in leafA.go and leafB.go to the +sub2 command.
  • +
+

This approach ensures the subcommands are always included at compile time while avoiding cyclic +references.

+ + + + + + + + +

Returning and handling errors

+

If you wish to return an error to the caller of a command, RunE can be used.

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  rootCmd.AddCommand(tryCmd)
+}
+
+var tryCmd = &cobra.Command{
+  Use:   "try",
+  Short: "Try and possibly fail at something",
+  RunE: func(cmd *cobra.Command, args []string) error {
+    if err := someFunc(); err != nil {
+	return err
+    }
+    return nil
+  },
+}
+

The error can then be caught at the execute function call.

+ + + + + + + + +

Working with Flags

+

Flags provide modifiers to control how the action command operates.

+ + + + + + + + +

Assign flags to a command

+

Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with.

+
var Verbose bool
+var Source string
+

There are two different approaches to assign a flag.

+ + + + + + + + +

Persistent Flags

+

A flag can be ‘persistent’, meaning that this flag will be available to the +command it’s assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root.

+
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
+
+ + + + + + + +

Local Flags

+

A flag can also be assigned locally, which will only apply to that specific command.

+
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+
+ + + + + + + +

Local Flag on Parent Commands

+

By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling Command.TraverseChildren, Cobra will +parse local flags on each command before executing the target command.

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

Bind Flags with Config

+

You can also bind your flags with viper:

+
var author string
+
+func init() {
+  rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
+  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+}
+

In this example, the persistent flag author is bound with viper. +Note: the variable author will not be set to the value from config, +when the --author flag is provided by user.

+

More in viper documentation.

+ + + + + + + + +

Required flags

+

Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required:

+
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkFlagRequired("region")
+

Or, for persistent flags:

+
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkPersistentFlagRequired("region")
+
+ + + + + + + +

Flag Groups

+

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 +Cobra can enforce that requirement:

+
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+

You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either --json or --yaml but never both:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

If you want to require at least one flag from a group to be present, you can use MarkFlagsOneRequired. +This can be combined with MarkFlagsMutuallyExclusive to enforce exactly one flag from a given group:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsOneRequired("json", "yaml")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

In these cases:

+
    +
  • both local and persistent flags can be used +
      +
    • NOTE: the group is only enforced on commands where every flag is defined
    • +
    +
  • +
  • a flag may appear in multiple groups
  • +
  • a group may contain any number of flags
  • +
+ + + + + + + + +

Positional and Custom Arguments

+

Validation of positional arguments can be specified using the Args field of Command. +The following validators are built in:

+
    +
  • Number of arguments: +
      +
    • NoArgs - report an error if there are any positional args.
    • +
    • ArbitraryArgs - accept any number of args.
    • +
    • MinimumNArgs(int) - report an error if less than N positional args are provided.
    • +
    • MaximumNArgs(int) - report an error if more than N positional args are provided.
    • +
    • ExactArgs(int) - report an error if there are not exactly N positional args.
    • +
    • RangeArgs(min, max) - report an error if the number of args is not between min and max.
    • +
    +
  • +
  • Content of the arguments: +
      +
    • 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.
    • +
    +
  • +
+

If Args is undefined or nil, it defaults to ArbitraryArgs.

+

Moreover, MatchAll(pargs ...PositionalArgs) enables combining existing checks with arbitrary other checks. +For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional +args that are not in the ValidArgs field of Command, you can call MatchAll on ExactArgs and OnlyValidArgs, as +shown below:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
+  Run: func(cmd *cobra.Command, args []string) {
+    fmt.Println("Hello, World!")
+  },
+}
+

It is possible to set any custom validator that satisfies func(cmd *cobra.Command, args []string) error. +For example:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: func(cmd *cobra.Command, args []string) error {
+    // Optionally run one of the validators provided by cobra
+    if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
+        return err
+    }
+    // Run the custom validation logic
+    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!")
+  },
+}
+
+ + + + + + + +

Example

+

In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a ‘Run’ for the ‘rootCmd’.

+

We have only defined one flag for a single command.

+

More documentation about flags is available at https://github.com/spf13/pflag

+
package main
+
+import (
+  "fmt"
+  "strings"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+  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("Echo: " + strings.Join(args, " "))
+    },
+  }
+
+  var cmdTimes = &cobra.Command{
+    Use:   "times [string to echo]",
+    Short: "Echo anything to the screen more times",
+    Long: `echo things multiple times back to the user by 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")
+
+  var rootCmd = &cobra.Command{Use: "app"}
+  rootCmd.AddCommand(cmdPrint, cmdEcho)
+  cmdEcho.AddCommand(cmdTimes)
+  rootCmd.Execute()
+}
+

For a more complete example of a larger application, please checkout Hugo.

+ + + + + + + + +

Help Command

+

Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs ‘app help’. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +‘create’ without any additional configuration; Cobra will work when ‘app help +create’ is called. Every command will automatically have the ‘–help’ flag added.

+ + + + + + + + +

Example

+

The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed.

+
$ cobra-cli help
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.
+
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra-cli [command] --help" for more information about a command.
+
+

Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want.

+ + + + + + + + +

Grouping commands in help

+

Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly +defined using AddGroup() on the parent command. Then a subcommand can be added to a group using the GroupID element +of that subcommand. The groups will appear in the help output in the same order as they are defined using different +calls to AddGroup(). If you use the generated help or completion commands, you can set their group ids using +SetHelpCommandGroupId() and SetCompletionCommandGroupId() on the root command, respectively.

+ + + + + + + + +

Defining your own help

+

You can provide your own Help command or your own template for the default command to use +with the following functions:

+
cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
+

The latter two will also apply to any children commands.

+ + + + + + + + +

Usage Message

+

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

+ + + + + + + + +

Example

+

You may recognize this from the help above. That’s because the default help +embeds the usage as part of its output.

+
$ cobra-cli --invalid
+Error: unknown flag: --invalid
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra [command] --help" for more information about a command.
+
+ + + + + + + + +

Defining your own usage

+

You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods:

+
cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
+
+ + + + + + + +

Version Flag

+

Cobra adds a top-level ‘–version’ flag if the Version field is set on the root command. +Running an application with the ‘–version’ flag will print the version to stdout using +the version template. The template can be customized using the +cmd.SetVersionTemplate(s string) function.

+ + + + + + + + +

PreRun and PostRun Hooks

+

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:

+
    +
  • PersistentPreRun
  • +
  • PreRun
  • +
  • Run
  • +
  • PostRun
  • +
  • PersistentPostRun
  • +
+

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:

+
package main
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+
+  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)
+    },
+  }
+
+  var 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()
+}
+

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]
+
+ + + + + + + +

Suggestions when “unknown command” happens

+

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:

+
$ hugo srever
+Error: unknown command "srever" for "hugo"
+
+Did you mean this?
+        server
+
+Run 'hugo --help' for usage.
+

Suggestions are automatically generated based on existing subcommands and use an implementation of Levenshtein distance. Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.

+

If you need to disable suggestions or tweak the string distance in your command, use:

+
command.DisableSuggestions = true
+

or

+
command.SuggestionsMinimumDistance = 1
+

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 +you don’t want aliases. Example:

+
$ kubectl remove
+Error: unknown command "remove" for "kubectl"
+
+Did you mean this?
+        delete
+
+Run 'kubectl help' for usage.
+
+ + + + + + + +

Generating documentation for your command

+

Cobra can generate documentation based on subcommands, flags, etc. +Read more about it in the docs generation documentation.

+ + + + + + + + +

Generating shell completions

+

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.

+ + + + + + + + +

Providing Active Help

+

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.

+ + + +
+
+ +
+
+ + + diff --git a/completions/index.xml b/completions/index.xml new file mode 100644 index 000000000..af6321252 --- /dev/null +++ b/completions/index.xml @@ -0,0 +1,50 @@ + + + + Cobra documentation + https://spf13.github.io/cobra/completions/ + Recent content on Cobra documentation + Hugo -- gohugo.io + en + + + https://spf13.github.io/cobra/completions/bash/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/bash/ + Generating Bash Completions For Your cobra.Command Please refer to Shell Completions for details. +Bash legacy dynamic completions For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. + + + + + https://spf13.github.io/cobra/completions/fish/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/fish/ + Generating Fish Completions For Your cobra.Command Please refer to Shell Completions for details. + + + + + https://spf13.github.io/cobra/completions/powershell/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/powershell/ + Generating PowerShell Completions For Your Own cobra.Command Please refer to Shell Completions for details. + + + + + https://spf13.github.io/cobra/completions/zsh/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/zsh/ + Generating Zsh Completion For Your cobra.Command Please refer to Shell Completions for details. +Zsh completions standardization Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced. +Deprecation summary See further below for more details on these deprecations. +cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored. cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. + + + + diff --git a/docgen/index.html b/docgen/index.html new file mode 100644 index 000000000..506d9ef21 --- /dev/null +++ b/docgen/index.html @@ -0,0 +1,1941 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NAV + + + +
+ + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Active Help

+

Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.

+

For example,

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/    internal/    scripts/    pkg/     testdata/
+

Hint: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.

+ + + + + + + + +

Supported shells

+

Active Help is currently only supported for the following shells:

+
    +
  • Bash (using bash completion V2 only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
  • +
  • Zsh
  • +
+ + + + + + + + +

Adding Active Help messages

+

As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to Shell Completions.

+

Adding Active Help is done through the use of the cobra.AppendActiveHelp(...) function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.

+ + + + + + + + +

Active Help for nouns

+

Adding Active Help when completing a noun is done within the ValidArgsFunction(...) of a command. Please notice the use of cobra.AppendActiveHelp(...) in the following example:

+
cmd := &cobra.Command{
+	Use:   "add [NAME] [URL]",
+	Short: "add a chart repository",
+	Args:  require.ExactArgs(2),
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return addRepo(args)
+	},
+	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var comps []string
+		if len(args) == 0 {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		} else if len(args) == 1 {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		} else {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+		return comps, cobra.ShellCompDirectiveNoFileComp
+	},
+}
+

The example above defines the completions (none, in this specific example) as well as the Active Help messages for the helm repo add command. It yields the following behavior:

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+

Hint: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.

+ + + + + + + + +

Active Help for flags

+

Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:

+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		if len(args) != 2 {
+			return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+		}
+		return compVersionFlag(args[1], toComplete)
+	})
+

The example above prints an Active Help message when not enough information was given by the user to complete the --version flag.

+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1  2.0.2  2.0.3
+
+ + + + + + + +

User control of Active Help

+

You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.

+

The way to configure Active Help is to use the program’s Active Help environment +variable. That variable is named <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of your +program in uppercase with any - replaced by an _. The variable should be set by the user to whatever +Active Help configuration values are supported by the program.

+

For example, say helm has chosen to support three levels for Active Help: on, off, local. Then a user +would set the desired behavior to local by doing export HELM_ACTIVE_HELP=local in their shell.

+

For simplicity, when in cmd.ValidArgsFunction(...) or a flag’s completion function, the program should read the +Active Help configuration using the cobra.GetActiveHelpConfig(cmd) function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly).

+

For example:

+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+	var comps []string
+	if len(args) == 0 {
+		if activeHelpLevel != "off"  {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		}
+	} else if len(args) == 1 {
+		if activeHelpLevel != "off" {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		}
+	} else {
+		if activeHelpLevel == "local" {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+	}
+	return comps, cobra.ShellCompDirectiveNoFileComp
+},
+

Note 1: If the <PROGRAM>_ACTIVE_HELP environment variable is set to the string “0”, Cobra will automatically disable all Active Help output (even if some output was specified by the program using the cobra.AppendActiveHelp(...) function). Using “0” can simplify your code in situations where you want to blindly disable Active Help without having to call cobra.GetActiveHelpConfig(cmd) explicitly.

+

Note 2: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable COBRA_ACTIVE_HELP to “0”. In this case cobra.GetActiveHelpConfig(cmd) will return “0” no matter what the variable <PROGRAM>_ACTIVE_HELP is set to.

+

Note 3: If the user does not set <PROGRAM>_ACTIVE_HELP or COBRA_ACTIVE_HELP (which will be a common case), the default value for the Active Help configuration returned by cobra.GetActiveHelpConfig(cmd) will be the empty string.

+ + + + + + + + +

Active Help with Cobra’s default completion command

+

Cobra provides a default completion command for programs that wish to use it. +When using the default completion command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users.

+ + + + + + + + +

Debugging Active Help

+

Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra’s hidden __complete command. Please refer to debugging shell completion for details.

+

When debugging with the __complete command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named <PROGRAM>_ACTIVE_HELP where any - is replaced by an _. For example, we can test deactivating some Active Help as shown below:

+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+ + + + + + + + + +

Generating Bash Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Bash legacy dynamic completions

+

For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution.

+

Note: Cobra’s default completion command uses bash completion V2. If you are currently using Cobra’s legacy dynamic completion solution, you should not use the default completion command but continue using your own.

+

The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions.

+

Some code that works in kubernetes:

+
const (
+        bash_completion_func = `__kubectl_parse_get()
+{
+    local kubectl_output out
+    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
+        out=($(echo "${kubectl_output}" | awk '{print $1}'))
+        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
+    fi
+}
+
+__kubectl_get_resource()
+{
+    if [[ ${#nouns[@]} -eq 0 ]]; then
+        return 1
+    fi
+    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
+    if [[ $? -eq 0 ]]; then
+        return 0
+    fi
+}
+
+__kubectl_custom_func() {
+    case ${last_command} in
+        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
+            __kubectl_get_resource
+            return
+            ;;
+        *)
+            ;;
+    esac
+}
+`)
+

And then I set that in my command definition:

+
cmds := &cobra.Command{
+	Use:   "kubectl",
+	Short: "kubectl controls the Kubernetes cluster manager",
+	Long: `kubectl controls the Kubernetes cluster manager.
+
+Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
+	Run: runHelp,
+	BashCompletionFunction: bash_completion_func,
+}
+

The BashCompletionFunction option is really only valid/useful on the root command. Doing the above will cause __kubectl_custom_func() (__<command-use>_custom_func()) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like kubectl get pod [mypod]. If you type kubectl get pod [tab][tab] the __kubectl_customc_func() will run because the cobra.Command only understood “kubectl” and “get.” __kubectl_custom_func() will see that the cobra.Command is “kubectl_get” and will thus call another helper __kubectl_get_resource(). __kubectl_get_resource will look at the ’nouns’ collected. In our example the only noun will be pod. So it will call __kubectl_parse_get pod. __kubectl_parse_get will actually call out to kubernetes and get any pods. It will then set COMPREPLY to valid pods!

+

Similarly, for flags:

+
	annotation := make(map[string][]string)
+	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
+
+	flag := &pflag.Flag{
+		Name:        "namespace",
+		Usage:       usage,
+		Annotations: annotation,
+	}
+	cmd.Flags().AddFlag(flag)
+

In addition add the __kubectl_get_namespaces implementation in the BashCompletionFunction +value, e.g.:

+
__kubectl_get_namespaces()
+{
+    local template
+    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
+    local kubectl_out
+    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
+        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
+    fi
+}
+
+ + + + + + + + + +

Generating Fish Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating PowerShell Completions For Your Own cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating Zsh Completion For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Zsh completions standardization

+

Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced.

+ + + + + + + + +

Deprecation summary

+

See further below for more details on these deprecations.

+
    +
  • cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored.
  • +
  • cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction with ShellCompDirectiveFilterFileExt.
    • +
    +
  • +
  • cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction.
    • +
    +
  • +
+ + + + + + + + +

Behavioral changes

+

Noun completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use ValidArgsFunction with ShellCompDirectiveNoFileComp to turn off file completion on a per-argument basis
Completion of flag names without the - prefix having been typedFlag names are only completed if the user has typed the first -
cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) used to turn on file completion on a per-argument position basisFile completion for all arguments by default; cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored
cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) used to turn on file completion with glob filtering on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored; use ValidArgsFunction with ShellCompDirectiveFilterFileExt for file extension filtering (not full glob filtering)
cmd.MarkZshCompPositionalArgumentWords(pos, words[]) used to provide completion choices on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored; use ValidArgsFunction to achieve the same behavior
+

Flag-value completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use RegisterFlagCompletionFunc() with ShellCompDirectiveNoFileComp to turn off file completion
cmd.MarkFlagFilename(flag, []string{}) and similar used to turn on file completionFile completion by default; cmd.MarkFlagFilename(flag, []string{}) no longer needed in this context and silently ignored
cmd.MarkFlagFilename(flag, glob[]) used to turn on file completion with glob filtering (syntax of []string{"*.yaml", "*.yml"} incompatible with bash)Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells ([]string{"yaml", "yml"})
cmd.MarkFlagDirname(flag) only completes directories (zsh-specific)Has been added for all shells
Completion of a flag name does not repeat, unless flag is of type *Array or *Slice (not supported by bash)Retained for zsh and added to fish
Completion of a flag name does not provide the = form (unlike bash)Retained for zsh and added to fish
+

Improvements

+
    +
  • Custom completion support (ValidArgsFunction and RegisterFlagCompletionFunc())
  • +
  • File completion by default if no other completions found
  • +
  • Handling of required flags
  • +
  • File extension filtering no longer mutually exclusive with bash usage
  • +
  • Completion of directory names within another directory
  • +
  • Support for = form of flags
  • +
+ + + + + + + + + + +

Generating Man Pages For Your Own cobra.Command

+

Generating man pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	header := &doc.GenManHeader{
+		Title: "MINE",
+		Section: "3",
+	}
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a man page /tmp/test.3

+ + + + + + + + + + +

Generating Markdown Docs For Your Own cobra.Command

+

Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenMarkdownTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Markdown document /tmp/test.md

+ + + + + + + + +

Generate markdown docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenMarkdownTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate markdown docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenMarkdown instead of GenMarkdownTree

+
	out := new(bytes.Buffer)
+	err := doc.GenMarkdown(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the markdown doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + +

Customize the output

+

Both GenMarkdown and GenMarkdownTree have alternate versions with callbacks to get some control of the output:

+
func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Generating ReStructured Text Docs For Your Own cobra.Command

+

Generating ReST pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenReSTTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a ReST document /tmp/test.rst

+ + + + + + + + +

Generate ReST docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenReSTTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate ReST docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenReST instead of GenReSTTree

+
	out := new(bytes.Buffer)
+	err := doc.GenReST(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the ReST doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenReST and GenReSTTree have alternate versions with callbacks to get some control of the output:

+
func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+	//...
+}
+
func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where :ref: is used:

+
// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+    return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+
+ + + + + + + + + +

Generating Yaml Docs For Your Own cobra.Command

+

Generating yaml files from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Yaml document /tmp/test.yaml

+ + + + + + + + +

Generate yaml docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate yaml docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenYaml instead of GenYamlTree

+
	out := new(bytes.Buffer)
+	doc.GenYaml(cmd, out)
+

This will write the yaml doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenYaml and GenYamlTree have alternate versions with callbacks to get some control of the output:

+
func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Projects using Cobra

+ + + + + + + + + + + +

User Guide

+

While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure:

+
  ▾ appName/
+    ▾ cmd/
+        add.go
+        your.go
+        commands.go
+        here.go
+      main.go
+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Using the Cobra Generator

+

Cobra-CLI is its own program that will create your application and add any commands you want. +It’s the easiest way to incorporate Cobra into your application.

+

For complete details on using the Cobra generator, please refer to The Cobra-CLI Generator README

+ + + + + + + + +

Using the Cobra Library

+

To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit.

+ + + + + + + + +

Create rootCmd

+

Cobra doesn’t require any special constructors. Simply create your commands.

+

Ideally you place this in app/cmd/root.go:

+
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 https://gohugo.io/documentation/`,
+  Run: func(cmd *cobra.Command, args []string) {
+    // Do Stuff Here
+  },
+}
+
+func Execute() {
+  if err := rootCmd.Execute(); err != nil {
+    fmt.Fprintln(os.Stderr, err)
+    os.Exit(1)
+  }
+}
+

You will additionally define flags and handle configuration in your init() function.

+

For example cmd/root.go:

+
package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// Used for flags.
+	cfgFile     string
+	userLicense string
+
+	rootCmd = &cobra.Command{
+		Use:   "cobra-cli",
+		Short: "A generator for Cobra based Applications",
+		Long: `Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	}
+)
+
+// Execute executes the root command.
+func Execute() error {
+	return rootCmd.Execute()
+}
+
+func init() {
+	cobra.OnInitialize(initConfig)
+
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
+	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
+	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
+	viper.SetDefault("license", "apache")
+
+	rootCmd.AddCommand(addCmd)
+	rootCmd.AddCommand(initCmd)
+}
+
+func initConfig() {
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := os.UserHomeDir()
+		cobra.CheckErr(err)
+
+		// Search config in home directory with name ".cobra" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigType("yaml")
+		viper.SetConfigName(".cobra")
+	}
+
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
+}
+
+ + + + + + + +

Create your main.go

+

With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command.

+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Create additional commands

+

Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory.

+

If you wanted to create a version command you would create cmd/version.go and +populate it with the following:

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  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")
+  },
+}
+
+ + + + + + + +

Organizing subcommands

+

A command may have subcommands which in turn may have other subcommands. This is achieved by using +AddCommand. In some cases, especially in larger applications, each subcommand may be defined in +its own go package.

+

The suggested approach is for the parent command to use AddCommand to add its most immediate +subcommands. For example, consider the following directory structure:

+
├── cmd
+│   ├── root.go
+│   └── sub1
+│       ├── sub1.go
+│       └── sub2
+│           ├── leafA.go
+│           ├── leafB.go
+│           └── sub2.go
+└── main.go
+

In this case:

+
    +
  • The init function of root.go adds the command defined in sub1.go to the root command.
  • +
  • The init function of sub1.go adds the command defined in sub2.go to the sub1 command.
  • +
  • The init function of sub2.go adds the commands defined in leafA.go and leafB.go to the +sub2 command.
  • +
+

This approach ensures the subcommands are always included at compile time while avoiding cyclic +references.

+ + + + + + + + +

Returning and handling errors

+

If you wish to return an error to the caller of a command, RunE can be used.

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  rootCmd.AddCommand(tryCmd)
+}
+
+var tryCmd = &cobra.Command{
+  Use:   "try",
+  Short: "Try and possibly fail at something",
+  RunE: func(cmd *cobra.Command, args []string) error {
+    if err := someFunc(); err != nil {
+	return err
+    }
+    return nil
+  },
+}
+

The error can then be caught at the execute function call.

+ + + + + + + + +

Working with Flags

+

Flags provide modifiers to control how the action command operates.

+ + + + + + + + +

Assign flags to a command

+

Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with.

+
var Verbose bool
+var Source string
+

There are two different approaches to assign a flag.

+ + + + + + + + +

Persistent Flags

+

A flag can be ‘persistent’, meaning that this flag will be available to the +command it’s assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root.

+
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
+
+ + + + + + + +

Local Flags

+

A flag can also be assigned locally, which will only apply to that specific command.

+
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+
+ + + + + + + +

Local Flag on Parent Commands

+

By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling Command.TraverseChildren, Cobra will +parse local flags on each command before executing the target command.

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

Bind Flags with Config

+

You can also bind your flags with viper:

+
var author string
+
+func init() {
+  rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
+  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+}
+

In this example, the persistent flag author is bound with viper. +Note: the variable author will not be set to the value from config, +when the --author flag is provided by user.

+

More in viper documentation.

+ + + + + + + + +

Required flags

+

Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required:

+
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkFlagRequired("region")
+

Or, for persistent flags:

+
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkPersistentFlagRequired("region")
+
+ + + + + + + +

Flag Groups

+

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 +Cobra can enforce that requirement:

+
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+

You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either --json or --yaml but never both:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

If you want to require at least one flag from a group to be present, you can use MarkFlagsOneRequired. +This can be combined with MarkFlagsMutuallyExclusive to enforce exactly one flag from a given group:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsOneRequired("json", "yaml")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

In these cases:

+
    +
  • both local and persistent flags can be used +
      +
    • NOTE: the group is only enforced on commands where every flag is defined
    • +
    +
  • +
  • a flag may appear in multiple groups
  • +
  • a group may contain any number of flags
  • +
+ + + + + + + + +

Positional and Custom Arguments

+

Validation of positional arguments can be specified using the Args field of Command. +The following validators are built in:

+
    +
  • Number of arguments: +
      +
    • NoArgs - report an error if there are any positional args.
    • +
    • ArbitraryArgs - accept any number of args.
    • +
    • MinimumNArgs(int) - report an error if less than N positional args are provided.
    • +
    • MaximumNArgs(int) - report an error if more than N positional args are provided.
    • +
    • ExactArgs(int) - report an error if there are not exactly N positional args.
    • +
    • RangeArgs(min, max) - report an error if the number of args is not between min and max.
    • +
    +
  • +
  • Content of the arguments: +
      +
    • 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.
    • +
    +
  • +
+

If Args is undefined or nil, it defaults to ArbitraryArgs.

+

Moreover, MatchAll(pargs ...PositionalArgs) enables combining existing checks with arbitrary other checks. +For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional +args that are not in the ValidArgs field of Command, you can call MatchAll on ExactArgs and OnlyValidArgs, as +shown below:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
+  Run: func(cmd *cobra.Command, args []string) {
+    fmt.Println("Hello, World!")
+  },
+}
+

It is possible to set any custom validator that satisfies func(cmd *cobra.Command, args []string) error. +For example:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: func(cmd *cobra.Command, args []string) error {
+    // Optionally run one of the validators provided by cobra
+    if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
+        return err
+    }
+    // Run the custom validation logic
+    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!")
+  },
+}
+
+ + + + + + + +

Example

+

In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a ‘Run’ for the ‘rootCmd’.

+

We have only defined one flag for a single command.

+

More documentation about flags is available at https://github.com/spf13/pflag

+
package main
+
+import (
+  "fmt"
+  "strings"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+  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("Echo: " + strings.Join(args, " "))
+    },
+  }
+
+  var cmdTimes = &cobra.Command{
+    Use:   "times [string to echo]",
+    Short: "Echo anything to the screen more times",
+    Long: `echo things multiple times back to the user by 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")
+
+  var rootCmd = &cobra.Command{Use: "app"}
+  rootCmd.AddCommand(cmdPrint, cmdEcho)
+  cmdEcho.AddCommand(cmdTimes)
+  rootCmd.Execute()
+}
+

For a more complete example of a larger application, please checkout Hugo.

+ + + + + + + + +

Help Command

+

Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs ‘app help’. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +‘create’ without any additional configuration; Cobra will work when ‘app help +create’ is called. Every command will automatically have the ‘–help’ flag added.

+ + + + + + + + +

Example

+

The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed.

+
$ cobra-cli help
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.
+
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra-cli [command] --help" for more information about a command.
+
+

Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want.

+ + + + + + + + +

Grouping commands in help

+

Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly +defined using AddGroup() on the parent command. Then a subcommand can be added to a group using the GroupID element +of that subcommand. The groups will appear in the help output in the same order as they are defined using different +calls to AddGroup(). If you use the generated help or completion commands, you can set their group ids using +SetHelpCommandGroupId() and SetCompletionCommandGroupId() on the root command, respectively.

+ + + + + + + + +

Defining your own help

+

You can provide your own Help command or your own template for the default command to use +with the following functions:

+
cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
+

The latter two will also apply to any children commands.

+ + + + + + + + +

Usage Message

+

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

+ + + + + + + + +

Example

+

You may recognize this from the help above. That’s because the default help +embeds the usage as part of its output.

+
$ cobra-cli --invalid
+Error: unknown flag: --invalid
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra [command] --help" for more information about a command.
+
+ + + + + + + + +

Defining your own usage

+

You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods:

+
cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
+
+ + + + + + + +

Version Flag

+

Cobra adds a top-level ‘–version’ flag if the Version field is set on the root command. +Running an application with the ‘–version’ flag will print the version to stdout using +the version template. The template can be customized using the +cmd.SetVersionTemplate(s string) function.

+ + + + + + + + +

PreRun and PostRun Hooks

+

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:

+
    +
  • PersistentPreRun
  • +
  • PreRun
  • +
  • Run
  • +
  • PostRun
  • +
  • PersistentPostRun
  • +
+

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:

+
package main
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+
+  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)
+    },
+  }
+
+  var 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()
+}
+

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]
+
+ + + + + + + +

Suggestions when “unknown command” happens

+

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:

+
$ hugo srever
+Error: unknown command "srever" for "hugo"
+
+Did you mean this?
+        server
+
+Run 'hugo --help' for usage.
+

Suggestions are automatically generated based on existing subcommands and use an implementation of Levenshtein distance. Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.

+

If you need to disable suggestions or tweak the string distance in your command, use:

+
command.DisableSuggestions = true
+

or

+
command.SuggestionsMinimumDistance = 1
+

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 +you don’t want aliases. Example:

+
$ kubectl remove
+Error: unknown command "remove" for "kubectl"
+
+Did you mean this?
+        delete
+
+Run 'kubectl help' for usage.
+
+ + + + + + + +

Generating documentation for your command

+

Cobra can generate documentation based on subcommands, flags, etc. +Read more about it in the docs generation documentation.

+ + + + + + + + +

Generating shell completions

+

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.

+ + + + + + + + +

Providing Active Help

+

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.

+ + + +
+
+ +
+
+ + + diff --git a/docgen/index.xml b/docgen/index.xml new file mode 100644 index 000000000..c65285ce3 --- /dev/null +++ b/docgen/index.xml @@ -0,0 +1,53 @@ + + + + Cobra documentation + https://spf13.github.io/cobra/docgen/ + Recent content on Cobra documentation + Hugo -- gohugo.io + en + + + https://spf13.github.io/cobra/docgen/man/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/man/ + Generating Man Pages For Your Own cobra.Command Generating man pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } header := &amp;doc.GenManHeader{ Title: &#34;MINE&#34;, Section: &#34;3&#34;, } err := doc.GenManTree(cmd, header, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a man page /tmp/test. + + + + + https://spf13.github.io/cobra/docgen/md/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/md/ + Generating Markdown Docs For Your Own cobra.Command Generating Markdown pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenMarkdownTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a Markdown document /tmp/test.md +Generate markdown docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + + https://spf13.github.io/cobra/docgen/rest/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/rest/ + Generating ReStructured Text Docs For Your Own cobra.Command Generating ReST pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenReSTTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a ReST document /tmp/test.rst +Generate ReST docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + + https://spf13.github.io/cobra/docgen/yaml/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/yaml/ + Generating Yaml Docs For Your Own cobra.Command Generating yaml files from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenYamlTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a Yaml document /tmp/test.yaml +Generate yaml docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + diff --git a/fonts/slate.eot b/fonts/slate.eot new file mode 100644 index 0000000000000000000000000000000000000000..13c4839a1975d4c92d66753d75553f922743c6ef GIT binary patch literal 1876 zcmaJ?&2Jl35TEDWeRg&sP8)xqh$Kr)Yzaiu#`dnNaHtS!Xx9i53LF}#nAmmP`Xfq= z;s{Zte*qCEK;i~h4hYFPaA-x4sD#vVrBXQ{MIaD@1Ke8kn|8tnQ^fdI9N^x@? zd<=RUJW{D`U;b-v<0kYSA}zO8E|&DaCqF0BzlPme0}$TUZbAP8`m<~GR{K~75*dg= zcCEQu4DE@ZpmS=+>&5muJwb0nf0^x#V!izR7X1vpggLV7&CM3_1j&!tPMS_)mkgrN zC!rsJe5kniow8zt{RT+zltXle=pd}!=-!|+8X9a|iyqm&z#GOh#?Z4hMmoI$K1va6 zrUYgm&_U=R+`ZrJ0!LQ9E`42ef0@uHvC8U zo}w4%B?O&MCX$JGEG)w^HIqqa()pb0xK4IFpUb457c*fwDPqaQf|z%md}h1{#>ac0 zD>_@{@&c$_-fEYWRBE3yj7U8q4MTz%hA^cOxdwei%19MlXpM(P_)+e=@Rm}B>tXap zwoqO*DogaoKF+^`!zvX>{f10 zq*F6dk@0&Ok4=k2cHR|EKKaOn+_Q3KG-~~J-9n!;&D+d{W9=SQ|IqlDm9?y2uUl{( zi(0o$Q@Cby<g+B7U zE7gMM6{=S}Ps}C~lhg72%h#4X&vB-0d)je4Z)w>(?>M%-xE~jH;l@L}Lcyy(n4O9z z65lS`w&R>XbW_^$2bKN!lz(S%N3N!tcP>R={D&-^3rjyfS-aWi!AkH>sk+00G5&qW zC1%n(1Gmpd;5$IPUF_Lw@K%&WbbxEX?LgKcF9x!K$J`8LiMQ^#KsG5yOZ=|rBS1K&l2uG4tC&hwF_o-hDp_Le zTrgI}?0+pse + + +Generated by IcoMoon + + + + + + + + + + diff --git a/fonts/slate.ttf b/fonts/slate.ttf new file mode 100644 index 0000000000000000000000000000000000000000..ace9a46a7e1ed6b6ab3de2f30ef3e27c572f88d3 GIT binary patch literal 1720 zcmaJ>-D_KA7=PaL@t*V?ZMro%kz(6pV-rwZyCyk@Q7?wb>UJv9`gO6wj7^qiCTUqB zO%X@;7dX69!8^V6LWJzXiw!F%45qgVdLa}=5xvm6E&iVKo-9$jJ@CHI_viaTf`}a2 zC!H2wcyVDVd0amU$>&(FZ8pn0bm7yth{U7dH)`ef4)6r{E^wmO*t_`0^~*QG?-S|8 zt!lYq{5ky*k?|Sy{uTt*p8hrX-@re<)$DYS^+1t{800m!H_O^}@g4X@@W-3w?hZXf zuY!M;^{sNV`qeJ|2)=?Gg`Mqo2XzAEd#oqjAaRXMBJF+c79{T|EPkbe7-PE;5S;Q~ zaGL1Q(r@%{&}khDI-bPX!~GUGz-0@x9Aaiik?BxrHq?#(PnWnI%nYaReOv*$ZSm>?)ctla|1hAG;T1^YPnfOv{N&_J8ekcvoG^Cm?MLpzb znO-8ASEU{s)D{<<&JKz%JjTWAM|EWWzjHMajT;ECdZ?bsKw&|^tZONrkvOuIkI%De zUYTtG_26}0jYK0>4*B1QgBuPLXU?}t^*TiboK|r`R>P0_HD+(cdi{Ze{FKYDLBs0R~?v6B%Rx~Edo2aasT@IJ-vtfG(iE^ z$Awv_E5l{^C4s84a|;3+->t#z!u^V-9Nj!@+Ph(RslFP9tMyA^DCS*vdNzG<@yc2l z`u?ov&H8>AuC0gXeBbj{4$|U#n6XQ^x*FE+&d;P>_lp(J^Zj%8%oMl&cI_ZN6TKO{ zkvFp2-&{yO{TDd~50<`txN&oc<4*8TskuV~pXj~g5i{t$k=GYVU^@bQTx>a5uvcK? zADE$i`dge4A3((KH9;?{zv*7K*f>Jt^humckR5yQeHf=xv0R7Ti)jP&N=%#Ng5wPM z_VCv|5z{smX^sCCV+<0Gsc02b(JH2*RZK;zn2MJ0U5I^E%r-TsOdYDyD_EDQO?BF) z7OFc*Cuk9TtZz5Uo$8RKb(q)a%}C8|gD__z_YMNoV9|<#sst6tUZ*|mXK52w&tq|_ J6Wq-M;U6NW`v(93 literal 0 HcmV?d00001 diff --git a/fonts/slate.woff b/fonts/slate.woff new file mode 100644 index 0000000000000000000000000000000000000000..1e72e0ee0018119d7c814c2097cc60c0bcd05d84 GIT binary patch literal 1796 zcmaJ>&2Jl35TCanZ=GF;-Nqj%Qj#SmwgjS~vAs(b4i$%lc7v*fuR|jhlemtH?Nqf< z5&;$c3y8RZ#0{p83^QtGf$~^ZU#vdPL3b z4fcBr_DN>rKz!G#?&4f~pM4ZRM6a}~ts1aTadwIM%N_dh>UO7#K7YRFXF@YA68l_? z@xFm7>0K?wZ&VUvut!OxMlIIQ5*<0_&Hha~Yl49Y@PK@!7+CqFG*;eClSR)#j$=Xw zNnrjF9T`VX|4zRT99<||DqHk_nzSa(NzO5voBad{L?lOWoE4r?ZbRP(V_X@TZL>{} z(3A8mk}l-3xojrwNJr*pi-lsLQVxSKC{0w##ljO}){#>poy#tYg)pcTCk9|L<3To?f*omEO$b9ODUa}gVj!a zAvUB1l6OCpmTg;7PgnO)phbF-Xik@UVo+OLa3((}zVs*;Zywi?{r}GOL=0{q1ou!q ztD%;HAbGE?Z5HC#RzAMSTXWiN9ioS*i+Usm@#fI}eK@$`F!8DQHtAj`iEnm!UKH}P zNl{d*%%o>TwzLq6ppv_9BR_a$H<|Q)z2RXkyY6k4BJlQ)o4+xU@=Bif%MA~%sib$? zbw%hV*Y96nzi0MvpHdWZeO#D>x^i4rP!XsqKRYk5@ZB2RF5E9QWp(qg81F^VmBvaG ztu(Ggk(kS7r)DyTm#?ozQ4q}d{!9==(dt@sJ_vk&`7k5ChZ~1PD=Sgs?%Z@HoBe#* z_k-a4JvVKwyWWZ=q2@1#9uk~9EfrHBtA=!8%MC` zIGu@c6SyDi7WCym@ z2-w*rE$c_UfviKEL=Vy>={0bo+(i5#P1q3$6VB``hVMrCzU@B6vbqKcPy}m-BtQn- zkylU>byNe6DE>18g5d9bm%bZqa|qF=7&3(|U!AY)%Yg-vOsqKIq$w0D$r*3}ks4=+ z>U6?w2xMd=B$;zQ9v)F1K7KwfQ9|)<9nl&i?6-rchs{I8LC1eK^@#(|^QwB-{VeQz zoHLn@cwG?Yo(X!F(Q8iBOqSNs${h}C*?qJYLuZAnVXqx{ww|}Ux0`ca^V#hz?c7{r z7ldYbmk!M1m3G+IYC6(!VcCzqp&pJkZ#1@kw2W<^EJMqOM;^&dq6ELC*|pK!(cC0< zbZtF%BzLsuTw5O*+eg;dX0a+hcfI=gj8a~qWYJoMamHAo)!Qq|6&~9S8`{d0T?L&% z@$R=P6H0rTp6V+-Dlb>EB67JEMQ>kk%`y}{hvBC(RNEw)*%|U|4>SL+B=3rE@y*rw zR_bLZr&~XN?C;+yx2IilcDnrb?M)}An;DsTe@^rq$9L-UWNqY_oTyWyYisN3CMIh; z*C)b12exYgK^2c4S}J#2YJ+00rUlj%+LqQ7E%lldEc`K|1Bky)iLkwF{Wltvj!{A+PBEzhE3BX) zFBgqmj@&z?N1*=OK?z54T7is8FiA(N66oe`X+cKl>`n&&000000HC;3 zk^ug-#56-JW5JAtMV6Rgj#+|9A(7;@^`+^dWy@Alt7D86w|;R>QMs>d+47HJVfKhH aD;vc&%m&dlj4($-ipx}q&#}A+00017%3vV? literal 0 HcmV?d00001 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8d4918ce9ede2c8449ac2acfd13fec39edcb183d GIT binary patch literal 77987 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¥I-_1|EWkj9-eJ;T?4%5^0cn5 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 + + + + + + + + Cobra documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NAV + + + +
+ + + + + + + + + + + +
    + + +
+ + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Active Help

+

Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.

+

For example,

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/    internal/    scripts/    pkg/     testdata/
+

Hint: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.

+ + + + + + + + +

Supported shells

+

Active Help is currently only supported for the following shells:

+
    +
  • Bash (using bash completion V2 only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
  • +
  • Zsh
  • +
+ + + + + + + + +

Adding Active Help messages

+

As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to Shell Completions.

+

Adding Active Help is done through the use of the cobra.AppendActiveHelp(...) function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.

+ + + + + + + + +

Active Help for nouns

+

Adding Active Help when completing a noun is done within the ValidArgsFunction(...) of a command. Please notice the use of cobra.AppendActiveHelp(...) in the following example:

+
cmd := &cobra.Command{
+	Use:   "add [NAME] [URL]",
+	Short: "add a chart repository",
+	Args:  require.ExactArgs(2),
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return addRepo(args)
+	},
+	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var comps []string
+		if len(args) == 0 {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		} else if len(args) == 1 {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		} else {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+		return comps, cobra.ShellCompDirectiveNoFileComp
+	},
+}
+

The example above defines the completions (none, in this specific example) as well as the Active Help messages for the helm repo add command. It yields the following behavior:

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+

Hint: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.

+ + + + + + + + +

Active Help for flags

+

Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:

+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		if len(args) != 2 {
+			return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+		}
+		return compVersionFlag(args[1], toComplete)
+	})
+

The example above prints an Active Help message when not enough information was given by the user to complete the --version flag.

+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1  2.0.2  2.0.3
+
+ + + + + + + +

User control of Active Help

+

You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.

+

The way to configure Active Help is to use the program’s Active Help environment +variable. That variable is named <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of your +program in uppercase with any - replaced by an _. The variable should be set by the user to whatever +Active Help configuration values are supported by the program.

+

For example, say helm has chosen to support three levels for Active Help: on, off, local. Then a user +would set the desired behavior to local by doing export HELM_ACTIVE_HELP=local in their shell.

+

For simplicity, when in cmd.ValidArgsFunction(...) or a flag’s completion function, the program should read the +Active Help configuration using the cobra.GetActiveHelpConfig(cmd) function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly).

+

For example:

+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+	var comps []string
+	if len(args) == 0 {
+		if activeHelpLevel != "off"  {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		}
+	} else if len(args) == 1 {
+		if activeHelpLevel != "off" {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		}
+	} else {
+		if activeHelpLevel == "local" {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+	}
+	return comps, cobra.ShellCompDirectiveNoFileComp
+},
+

Note 1: If the <PROGRAM>_ACTIVE_HELP environment variable is set to the string “0”, Cobra will automatically disable all Active Help output (even if some output was specified by the program using the cobra.AppendActiveHelp(...) function). Using “0” can simplify your code in situations where you want to blindly disable Active Help without having to call cobra.GetActiveHelpConfig(cmd) explicitly.

+

Note 2: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable COBRA_ACTIVE_HELP to “0”. In this case cobra.GetActiveHelpConfig(cmd) will return “0” no matter what the variable <PROGRAM>_ACTIVE_HELP is set to.

+

Note 3: If the user does not set <PROGRAM>_ACTIVE_HELP or COBRA_ACTIVE_HELP (which will be a common case), the default value for the Active Help configuration returned by cobra.GetActiveHelpConfig(cmd) will be the empty string.

+ + + + + + + + +

Active Help with Cobra’s default completion command

+

Cobra provides a default completion command for programs that wish to use it. +When using the default completion command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users.

+ + + + + + + + +

Debugging Active Help

+

Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra’s hidden __complete command. Please refer to debugging shell completion for details.

+

When debugging with the __complete command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named <PROGRAM>_ACTIVE_HELP where any - is replaced by an _. For example, we can test deactivating some Active Help as shown below:

+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+ + + + + + + + + +

Generating Bash Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Bash legacy dynamic completions

+

For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution.

+

Note: Cobra’s default completion command uses bash completion V2. If you are currently using Cobra’s legacy dynamic completion solution, you should not use the default completion command but continue using your own.

+

The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions.

+

Some code that works in kubernetes:

+
const (
+        bash_completion_func = `__kubectl_parse_get()
+{
+    local kubectl_output out
+    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
+        out=($(echo "${kubectl_output}" | awk '{print $1}'))
+        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
+    fi
+}
+
+__kubectl_get_resource()
+{
+    if [[ ${#nouns[@]} -eq 0 ]]; then
+        return 1
+    fi
+    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
+    if [[ $? -eq 0 ]]; then
+        return 0
+    fi
+}
+
+__kubectl_custom_func() {
+    case ${last_command} in
+        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
+            __kubectl_get_resource
+            return
+            ;;
+        *)
+            ;;
+    esac
+}
+`)
+

And then I set that in my command definition:

+
cmds := &cobra.Command{
+	Use:   "kubectl",
+	Short: "kubectl controls the Kubernetes cluster manager",
+	Long: `kubectl controls the Kubernetes cluster manager.
+
+Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
+	Run: runHelp,
+	BashCompletionFunction: bash_completion_func,
+}
+

The BashCompletionFunction option is really only valid/useful on the root command. Doing the above will cause __kubectl_custom_func() (__<command-use>_custom_func()) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like kubectl get pod [mypod]. If you type kubectl get pod [tab][tab] the __kubectl_customc_func() will run because the cobra.Command only understood “kubectl” and “get.” __kubectl_custom_func() will see that the cobra.Command is “kubectl_get” and will thus call another helper __kubectl_get_resource(). __kubectl_get_resource will look at the ’nouns’ collected. In our example the only noun will be pod. So it will call __kubectl_parse_get pod. __kubectl_parse_get will actually call out to kubernetes and get any pods. It will then set COMPREPLY to valid pods!

+

Similarly, for flags:

+
	annotation := make(map[string][]string)
+	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
+
+	flag := &pflag.Flag{
+		Name:        "namespace",
+		Usage:       usage,
+		Annotations: annotation,
+	}
+	cmd.Flags().AddFlag(flag)
+

In addition add the __kubectl_get_namespaces implementation in the BashCompletionFunction +value, e.g.:

+
__kubectl_get_namespaces()
+{
+    local template
+    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
+    local kubectl_out
+    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
+        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
+    fi
+}
+
+ + + + + + + + + +

Generating Fish Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating PowerShell Completions For Your Own cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating Zsh Completion For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Zsh completions standardization

+

Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced.

+ + + + + + + + +

Deprecation summary

+

See further below for more details on these deprecations.

+
    +
  • cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored.
  • +
  • cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction with ShellCompDirectiveFilterFileExt.
    • +
    +
  • +
  • cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction.
    • +
    +
  • +
+ + + + + + + + +

Behavioral changes

+

Noun completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use ValidArgsFunction with ShellCompDirectiveNoFileComp to turn off file completion on a per-argument basis
Completion of flag names without the - prefix having been typedFlag names are only completed if the user has typed the first -
cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) used to turn on file completion on a per-argument position basisFile completion for all arguments by default; cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored
cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) used to turn on file completion with glob filtering on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored; use ValidArgsFunction with ShellCompDirectiveFilterFileExt for file extension filtering (not full glob filtering)
cmd.MarkZshCompPositionalArgumentWords(pos, words[]) used to provide completion choices on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored; use ValidArgsFunction to achieve the same behavior
+

Flag-value completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use RegisterFlagCompletionFunc() with ShellCompDirectiveNoFileComp to turn off file completion
cmd.MarkFlagFilename(flag, []string{}) and similar used to turn on file completionFile completion by default; cmd.MarkFlagFilename(flag, []string{}) no longer needed in this context and silently ignored
cmd.MarkFlagFilename(flag, glob[]) used to turn on file completion with glob filtering (syntax of []string{"*.yaml", "*.yml"} incompatible with bash)Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells ([]string{"yaml", "yml"})
cmd.MarkFlagDirname(flag) only completes directories (zsh-specific)Has been added for all shells
Completion of a flag name does not repeat, unless flag is of type *Array or *Slice (not supported by bash)Retained for zsh and added to fish
Completion of a flag name does not provide the = form (unlike bash)Retained for zsh and added to fish
+

Improvements

+
    +
  • Custom completion support (ValidArgsFunction and RegisterFlagCompletionFunc())
  • +
  • File completion by default if no other completions found
  • +
  • Handling of required flags
  • +
  • File extension filtering no longer mutually exclusive with bash usage
  • +
  • Completion of directory names within another directory
  • +
  • Support for = form of flags
  • +
+ + + + + + + + + + +

Generating Man Pages For Your Own cobra.Command

+

Generating man pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	header := &doc.GenManHeader{
+		Title: "MINE",
+		Section: "3",
+	}
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a man page /tmp/test.3

+ + + + + + + + + + +

Generating Markdown Docs For Your Own cobra.Command

+

Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenMarkdownTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Markdown document /tmp/test.md

+ + + + + + + + +

Generate markdown docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenMarkdownTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate markdown docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenMarkdown instead of GenMarkdownTree

+
	out := new(bytes.Buffer)
+	err := doc.GenMarkdown(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the markdown doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + +

Customize the output

+

Both GenMarkdown and GenMarkdownTree have alternate versions with callbacks to get some control of the output:

+
func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Generating ReStructured Text Docs For Your Own cobra.Command

+

Generating ReST pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenReSTTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a ReST document /tmp/test.rst

+ + + + + + + + +

Generate ReST docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenReSTTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate ReST docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenReST instead of GenReSTTree

+
	out := new(bytes.Buffer)
+	err := doc.GenReST(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the ReST doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenReST and GenReSTTree have alternate versions with callbacks to get some control of the output:

+
func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+	//...
+}
+
func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where :ref: is used:

+
// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+    return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+
+ + + + + + + + + +

Generating Yaml Docs For Your Own cobra.Command

+

Generating yaml files from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Yaml document /tmp/test.yaml

+ + + + + + + + +

Generate yaml docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate yaml docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenYaml instead of GenYamlTree

+
	out := new(bytes.Buffer)
+	doc.GenYaml(cmd, out)
+

This will write the yaml doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenYaml and GenYamlTree have alternate versions with callbacks to get some control of the output:

+
func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Projects using Cobra

+ + + + + + + + + + + +

User Guide

+

While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure:

+
  ▾ appName/
+    ▾ cmd/
+        add.go
+        your.go
+        commands.go
+        here.go
+      main.go
+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Using the Cobra Generator

+

Cobra-CLI is its own program that will create your application and add any commands you want. +It’s the easiest way to incorporate Cobra into your application.

+

For complete details on using the Cobra generator, please refer to The Cobra-CLI Generator README

+ + + + + + + + +

Using the Cobra Library

+

To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit.

+ + + + + + + + +

Create rootCmd

+

Cobra doesn’t require any special constructors. Simply create your commands.

+

Ideally you place this in app/cmd/root.go:

+
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 https://gohugo.io/documentation/`,
+  Run: func(cmd *cobra.Command, args []string) {
+    // Do Stuff Here
+  },
+}
+
+func Execute() {
+  if err := rootCmd.Execute(); err != nil {
+    fmt.Fprintln(os.Stderr, err)
+    os.Exit(1)
+  }
+}
+

You will additionally define flags and handle configuration in your init() function.

+

For example cmd/root.go:

+
package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// Used for flags.
+	cfgFile     string
+	userLicense string
+
+	rootCmd = &cobra.Command{
+		Use:   "cobra-cli",
+		Short: "A generator for Cobra based Applications",
+		Long: `Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	}
+)
+
+// Execute executes the root command.
+func Execute() error {
+	return rootCmd.Execute()
+}
+
+func init() {
+	cobra.OnInitialize(initConfig)
+
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
+	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
+	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
+	viper.SetDefault("license", "apache")
+
+	rootCmd.AddCommand(addCmd)
+	rootCmd.AddCommand(initCmd)
+}
+
+func initConfig() {
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := os.UserHomeDir()
+		cobra.CheckErr(err)
+
+		// Search config in home directory with name ".cobra" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigType("yaml")
+		viper.SetConfigName(".cobra")
+	}
+
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
+}
+
+ + + + + + + +

Create your main.go

+

With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command.

+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Create additional commands

+

Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory.

+

If you wanted to create a version command you would create cmd/version.go and +populate it with the following:

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  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")
+  },
+}
+
+ + + + + + + +

Organizing subcommands

+

A command may have subcommands which in turn may have other subcommands. This is achieved by using +AddCommand. In some cases, especially in larger applications, each subcommand may be defined in +its own go package.

+

The suggested approach is for the parent command to use AddCommand to add its most immediate +subcommands. For example, consider the following directory structure:

+
├── cmd
+│   ├── root.go
+│   └── sub1
+│       ├── sub1.go
+│       └── sub2
+│           ├── leafA.go
+│           ├── leafB.go
+│           └── sub2.go
+└── main.go
+

In this case:

+
    +
  • The init function of root.go adds the command defined in sub1.go to the root command.
  • +
  • The init function of sub1.go adds the command defined in sub2.go to the sub1 command.
  • +
  • The init function of sub2.go adds the commands defined in leafA.go and leafB.go to the +sub2 command.
  • +
+

This approach ensures the subcommands are always included at compile time while avoiding cyclic +references.

+ + + + + + + + +

Returning and handling errors

+

If you wish to return an error to the caller of a command, RunE can be used.

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  rootCmd.AddCommand(tryCmd)
+}
+
+var tryCmd = &cobra.Command{
+  Use:   "try",
+  Short: "Try and possibly fail at something",
+  RunE: func(cmd *cobra.Command, args []string) error {
+    if err := someFunc(); err != nil {
+	return err
+    }
+    return nil
+  },
+}
+

The error can then be caught at the execute function call.

+ + + + + + + + +

Working with Flags

+

Flags provide modifiers to control how the action command operates.

+ + + + + + + + +

Assign flags to a command

+

Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with.

+
var Verbose bool
+var Source string
+

There are two different approaches to assign a flag.

+ + + + + + + + +

Persistent Flags

+

A flag can be ‘persistent’, meaning that this flag will be available to the +command it’s assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root.

+
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
+
+ + + + + + + +

Local Flags

+

A flag can also be assigned locally, which will only apply to that specific command.

+
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+
+ + + + + + + +

Local Flag on Parent Commands

+

By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling Command.TraverseChildren, Cobra will +parse local flags on each command before executing the target command.

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

Bind Flags with Config

+

You can also bind your flags with viper:

+
var author string
+
+func init() {
+  rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
+  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+}
+

In this example, the persistent flag author is bound with viper. +Note: the variable author will not be set to the value from config, +when the --author flag is provided by user.

+

More in viper documentation.

+ + + + + + + + +

Required flags

+

Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required:

+
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkFlagRequired("region")
+

Or, for persistent flags:

+
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkPersistentFlagRequired("region")
+
+ + + + + + + +

Flag Groups

+

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 +Cobra can enforce that requirement:

+
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+

You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either --json or --yaml but never both:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

If you want to require at least one flag from a group to be present, you can use MarkFlagsOneRequired. +This can be combined with MarkFlagsMutuallyExclusive to enforce exactly one flag from a given group:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsOneRequired("json", "yaml")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

In these cases:

+
    +
  • both local and persistent flags can be used +
      +
    • NOTE: the group is only enforced on commands where every flag is defined
    • +
    +
  • +
  • a flag may appear in multiple groups
  • +
  • a group may contain any number of flags
  • +
+ + + + + + + + +

Positional and Custom Arguments

+

Validation of positional arguments can be specified using the Args field of Command. +The following validators are built in:

+
    +
  • Number of arguments: +
      +
    • NoArgs - report an error if there are any positional args.
    • +
    • ArbitraryArgs - accept any number of args.
    • +
    • MinimumNArgs(int) - report an error if less than N positional args are provided.
    • +
    • MaximumNArgs(int) - report an error if more than N positional args are provided.
    • +
    • ExactArgs(int) - report an error if there are not exactly N positional args.
    • +
    • RangeArgs(min, max) - report an error if the number of args is not between min and max.
    • +
    +
  • +
  • Content of the arguments: +
      +
    • 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.
    • +
    +
  • +
+

If Args is undefined or nil, it defaults to ArbitraryArgs.

+

Moreover, MatchAll(pargs ...PositionalArgs) enables combining existing checks with arbitrary other checks. +For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional +args that are not in the ValidArgs field of Command, you can call MatchAll on ExactArgs and OnlyValidArgs, as +shown below:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
+  Run: func(cmd *cobra.Command, args []string) {
+    fmt.Println("Hello, World!")
+  },
+}
+

It is possible to set any custom validator that satisfies func(cmd *cobra.Command, args []string) error. +For example:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: func(cmd *cobra.Command, args []string) error {
+    // Optionally run one of the validators provided by cobra
+    if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
+        return err
+    }
+    // Run the custom validation logic
+    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!")
+  },
+}
+
+ + + + + + + +

Example

+

In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a ‘Run’ for the ‘rootCmd’.

+

We have only defined one flag for a single command.

+

More documentation about flags is available at https://github.com/spf13/pflag

+
package main
+
+import (
+  "fmt"
+  "strings"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+  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("Echo: " + strings.Join(args, " "))
+    },
+  }
+
+  var cmdTimes = &cobra.Command{
+    Use:   "times [string to echo]",
+    Short: "Echo anything to the screen more times",
+    Long: `echo things multiple times back to the user by 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")
+
+  var rootCmd = &cobra.Command{Use: "app"}
+  rootCmd.AddCommand(cmdPrint, cmdEcho)
+  cmdEcho.AddCommand(cmdTimes)
+  rootCmd.Execute()
+}
+

For a more complete example of a larger application, please checkout Hugo.

+ + + + + + + + +

Help Command

+

Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs ‘app help’. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +‘create’ without any additional configuration; Cobra will work when ‘app help +create’ is called. Every command will automatically have the ‘–help’ flag added.

+ + + + + + + + +

Example

+

The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed.

+
$ cobra-cli help
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.
+
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra-cli [command] --help" for more information about a command.
+
+

Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want.

+ + + + + + + + +

Grouping commands in help

+

Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly +defined using AddGroup() on the parent command. Then a subcommand can be added to a group using the GroupID element +of that subcommand. The groups will appear in the help output in the same order as they are defined using different +calls to AddGroup(). If you use the generated help or completion commands, you can set their group ids using +SetHelpCommandGroupId() and SetCompletionCommandGroupId() on the root command, respectively.

+ + + + + + + + +

Defining your own help

+

You can provide your own Help command or your own template for the default command to use +with the following functions:

+
cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
+

The latter two will also apply to any children commands.

+ + + + + + + + +

Usage Message

+

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

+ + + + + + + + +

Example

+

You may recognize this from the help above. That’s because the default help +embeds the usage as part of its output.

+
$ cobra-cli --invalid
+Error: unknown flag: --invalid
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra [command] --help" for more information about a command.
+
+ + + + + + + + +

Defining your own usage

+

You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods:

+
cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
+
+ + + + + + + +

Version Flag

+

Cobra adds a top-level ‘–version’ flag if the Version field is set on the root command. +Running an application with the ‘–version’ flag will print the version to stdout using +the version template. The template can be customized using the +cmd.SetVersionTemplate(s string) function.

+ + + + + + + + +

PreRun and PostRun Hooks

+

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:

+
    +
  • PersistentPreRun
  • +
  • PreRun
  • +
  • Run
  • +
  • PostRun
  • +
  • PersistentPostRun
  • +
+

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:

+
package main
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+
+  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)
+    },
+  }
+
+  var 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()
+}
+

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]
+
+ + + + + + + +

Suggestions when “unknown command” happens

+

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:

+
$ hugo srever
+Error: unknown command "srever" for "hugo"
+
+Did you mean this?
+        server
+
+Run 'hugo --help' for usage.
+

Suggestions are automatically generated based on existing subcommands and use an implementation of Levenshtein distance. Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.

+

If you need to disable suggestions or tweak the string distance in your command, use:

+
command.DisableSuggestions = true
+

or

+
command.SuggestionsMinimumDistance = 1
+

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 +you don’t want aliases. Example:

+
$ kubectl remove
+Error: unknown command "remove" for "kubectl"
+
+Did you mean this?
+        delete
+
+Run 'kubectl help' for usage.
+
+ + + + + + + +

Generating documentation for your command

+

Cobra can generate documentation based on subcommands, flags, etc. +Read more about it in the docs generation documentation.

+ + + + + + + + +

Generating shell completions

+

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.

+ + + + + + + + +

Providing Active Help

+

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.

+ + + +
+
+ +
+
+ + + diff --git a/index.xml b/index.xml new file mode 100644 index 000000000..fecffa857 --- /dev/null +++ b/index.xml @@ -0,0 +1,124 @@ + + + + Cobra documentation + https://spf13.github.io/cobra/ + Recent content on Cobra documentation + Hugo -- gohugo.io + en + + + https://spf13.github.io/cobra/active_help/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/active_help/ + Active Help Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion. +For example, +bash-5.1$ helm repo add [tab] You must choose a name for the repo you are adding. + + + + + https://spf13.github.io/cobra/completions/bash/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/bash/ + Generating Bash Completions For Your cobra.Command Please refer to Shell Completions for details. +Bash legacy dynamic completions For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. + + + + + https://spf13.github.io/cobra/completions/fish/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/fish/ + Generating Fish Completions For Your cobra.Command Please refer to Shell Completions for details. + + + + + https://spf13.github.io/cobra/completions/powershell/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/powershell/ + Generating PowerShell Completions For Your Own cobra.Command Please refer to Shell Completions for details. + + + + + https://spf13.github.io/cobra/completions/zsh/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/completions/zsh/ + Generating Zsh Completion For Your cobra.Command Please refer to Shell Completions for details. +Zsh completions standardization Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced. +Deprecation summary See further below for more details on these deprecations. +cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored. cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. + + + + + https://spf13.github.io/cobra/docgen/man/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/man/ + Generating Man Pages For Your Own cobra.Command Generating man pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } header := &amp;doc.GenManHeader{ Title: &#34;MINE&#34;, Section: &#34;3&#34;, } err := doc.GenManTree(cmd, header, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a man page /tmp/test. + + + + + https://spf13.github.io/cobra/docgen/md/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/md/ + Generating Markdown Docs For Your Own cobra.Command Generating Markdown pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenMarkdownTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a Markdown document /tmp/test.md +Generate markdown docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + + https://spf13.github.io/cobra/docgen/rest/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/rest/ + Generating ReStructured Text Docs For Your Own cobra.Command Generating ReST pages from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenReSTTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a ReST document /tmp/test.rst +Generate ReST docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + + https://spf13.github.io/cobra/docgen/yaml/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/docgen/yaml/ + Generating Yaml Docs For Your Own cobra.Command Generating yaml files from a cobra command is incredibly easy. An example is as follows: +package main import ( &#34;log&#34; &#34;github.com/spf13/cobra&#34; &#34;github.com/spf13/cobra/doc&#34; ) func main() { cmd := &amp;cobra.Command{ Use: &#34;test&#34;, Short: &#34;my test program&#34;, } err := doc.GenYamlTree(cmd, &#34;/tmp&#34;) if err != nil { log.Fatal(err) } } That will get you a Yaml document /tmp/test.yaml +Generate yaml docs for the entire command tree This program can actually generate docs for the kubectl command in the kubernetes project + + + + + https://spf13.github.io/cobra/projects_using_cobra/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/projects_using_cobra/ + Projects using Cobra Allero Arewefastyet Arduino CLI Bleve Cilium CloudQuery CockroachDB Constellation Cosmos SDK Datree Delve Docker (distribution) Etcd Gardener Giant Swarm&rsquo;s gsctl Git Bump GitHub CLI GitHub Labeler Golangci-lint GopherJS GoReleaser Helm Hugo Infracost Istio Kool Kubernetes Kubescape KubeVirt Linkerd Mattermost-server Mercure Meroxa CLI Metal Stack CLI Moby (former Docker) Moldy Multi-gitter Nanobox/Nanopack nFPM Okteto OpenShift Ory Hydra Ory Kratos Pixie Polygon Edge Pouch ProjectAtomic (enterprise) Prototool Pulumi QRcp Random Rclone Scaleway CLI Sia Skaffold Tendermint Twitch CLI UpCloud CLI (upctl) Vitess VMware&rsquo;s Tanzu Community Edition &amp; Tanzu Framework Werf ZITADEL + + + + + https://spf13.github.io/cobra/user_guide/ + Mon, 01 Jan 0001 00:00:00 +0000 + + https://spf13.github.io/cobra/user_guide/ + User Guide While you are welcome to provide your own organization, typically a Cobra-based application will follow the following organizational structure: +▾ appName/ ▾ cmd/ add.go your.go commands.go here.go main.go In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. +package main import ( &#34;{pathToYourApp}/cmd&#34; ) func main() { cmd.Execute() } Using the Cobra Generator Cobra-CLI is its own program that will create your application and add any commands you want. + + + + diff --git a/js/index.9eb557de32bb57d26313bf5737edf1ddeb0953be47b26637ab73a984517149f3.js b/js/index.9eb557de32bb57d26313bf5737edf1ddeb0953be47b26637ab73a984517149f3.js new file mode 100644 index 000000000..136fb8e46 --- /dev/null +++ b/js/index.9eb557de32bb57d26313bf5737edf1ddeb0953be47b26637ab73a984517149f3.js @@ -0,0 +1,56 @@ +(()=>{var hn=Object.create;var Lt=Object.defineProperty;var pn=Object.getOwnPropertyDescriptor;var gn=Object.getOwnPropertyNames;var _n=Object.getPrototypeOf,vn=Object.prototype.hasOwnProperty;var yn=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var xn=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of gn(t))!vn.call(e,i)&&i!==r&&Lt(e,i,{get:()=>t[i],enumerable:!(n=pn(t,i))||n.enumerable});return e};var mn=(e,t,r)=>(r=e!=null?hn(_n(e)):{},xn(t||!e||!e.__esModule?Lt(r,"default",{value:e,enumerable:!0}):r,e));var It=yn((Rt,kt)=>{(function(){var e=function(t){var r=new e.Builder;return r.pipeline.add(e.trimmer,e.stopWordFilter,e.stemmer),r.searchPipeline.add(e.stemmer),t.call(r,r),r.build()};e.version="2.3.8";e.utils={},e.utils.warn=function(t){return function(r){t.console&&console.warn&&console.warn(r)}}(this),e.utils.asString=function(t){return t==null?"":t.toString()},e.utils.clone=function(t){if(t==null)return t;for(var r=Object.create(null),n=Object.keys(t),i=0;i0){var c=e.utils.clone(r)||{};c.position=[a,l],c.index=s.length,s.push(new e.Token(n.slice(a,o),c))}a=o+1}}return s},e.tokenizer.separator=/[\s\-]+/;e.Pipeline=function(){this._stack=[]},e.Pipeline.registeredFunctions=Object.create(null),e.Pipeline.registerFunction=function(t,r){r in this.registeredFunctions&&e.utils.warn("Overwriting existing registered function: "+r),t.label=r,e.Pipeline.registeredFunctions[t.label]=t},e.Pipeline.warnIfFunctionNotRegistered=function(t){var r=t.label&&t.label in this.registeredFunctions;r||e.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,t)},e.Pipeline.load=function(t){var r=new e.Pipeline;return t.forEach(function(n){var i=e.Pipeline.registeredFunctions[n];if(i)r.add(i);else throw new Error("Cannot load unregistered function: "+n)}),r},e.Pipeline.prototype.add=function(){var t=Array.prototype.slice.call(arguments);t.forEach(function(r){e.Pipeline.warnIfFunctionNotRegistered(r),this._stack.push(r)},this)},e.Pipeline.prototype.after=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(t);if(n==-1)throw new Error("Cannot find existingFn");n=n+1,this._stack.splice(n,0,r)},e.Pipeline.prototype.before=function(t,r){e.Pipeline.warnIfFunctionNotRegistered(r);var n=this._stack.indexOf(t);if(n==-1)throw new Error("Cannot find existingFn");this._stack.splice(n,0,r)},e.Pipeline.prototype.remove=function(t){var r=this._stack.indexOf(t);r!=-1&&this._stack.splice(r,1)},e.Pipeline.prototype.run=function(t){for(var r=this._stack.length,n=0;n1&&(ot&&(n=s),o!=t);)i=n-r,s=r+Math.floor(i/2),o=this.elements[s*2];if(o==t||o>t)return s*2;if(ou?c+=2:a==u&&(r+=n[l+1]*i[c+1],l+=2,c+=2);return r},e.Vector.prototype.similarity=function(t){return this.dot(t)/this.magnitude()||0},e.Vector.prototype.toArray=function(){for(var t=new Array(this.elements.length/2),r=1,n=0;r0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new e.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new e.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new e.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var c=s.str.charAt(0),d=s.str.charAt(1),g;d in s.node.edges?g=s.node.edges[d]:(g=new e.TokenSet,s.node.edges[d]=g),s.str.length==1&&(g.final=!0),i.push({node:g,editsRemaining:s.editsRemaining-1,str:c+s.str.slice(2)})}}}return n},e.TokenSet.fromString=function(t){for(var r=new e.TokenSet,n=r,i=0,s=t.length;i=t;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};e.Index=function(t){this.invertedIndex=t.invertedIndex,this.fieldVectors=t.fieldVectors,this.tokenSet=t.tokenSet,this.fields=t.fields,this.pipeline=t.pipeline},e.Index.prototype.search=function(t){return this.query(function(r){var n=new e.QueryParser(t,r);n.parse()})},e.Index.prototype.query=function(t){for(var r=new e.Query(this.fields),n=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=t},e.Builder.prototype.k1=function(t){this._k1=t},e.Builder.prototype.add=function(t,r){var n=t[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return e.QueryLexer.EOS;var t=this.str.charAt(this.pos);return this.pos+=1,t},e.QueryLexer.prototype.width=function(){return this.pos-this.start},e.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},e.QueryLexer.prototype.backup=function(){this.pos-=1},e.QueryLexer.prototype.acceptDigitRun=function(){var t,r;do t=this.next(),r=t.charCodeAt(0);while(r>47&&r<58);t!=e.QueryLexer.EOS&&this.backup()},e.QueryLexer.prototype.more=function(){return this.pos1&&(t.backup(),t.emit(e.QueryLexer.TERM)),t.ignore(),t.more())return e.QueryLexer.lexText},e.QueryLexer.lexEditDistance=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.EDIT_DISTANCE),e.QueryLexer.lexText},e.QueryLexer.lexBoost=function(t){return t.ignore(),t.acceptDigitRun(),t.emit(e.QueryLexer.BOOST),e.QueryLexer.lexText},e.QueryLexer.lexEOS=function(t){t.width()>0&&t.emit(e.QueryLexer.TERM)},e.QueryLexer.termSeparator=e.tokenizer.separator,e.QueryLexer.lexText=function(t){for(;;){var r=t.next();if(r==e.QueryLexer.EOS)return e.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){t.escapeCharacter();continue}if(r==":")return e.QueryLexer.lexField;if(r=="~")return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexEditDistance;if(r=="^")return t.backup(),t.width()>0&&t.emit(e.QueryLexer.TERM),e.QueryLexer.lexBoost;if(r=="+"&&t.width()===1||r=="-"&&t.width()===1)return t.emit(e.QueryLexer.PRESENCE),e.QueryLexer.lexText;if(r.match(e.QueryLexer.termSeparator))return e.QueryLexer.lexTerm}},e.QueryParser=function(t,r){this.lexer=new e.QueryLexer(t),this.query=r,this.currentClause={},this.lexemeIdx=0},e.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var t=e.QueryParser.parseClause;t;)t=t(this);return this.query},e.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},e.QueryParser.prototype.consumeLexeme=function(){var t=this.peekLexeme();return this.lexemeIdx+=1,t},e.QueryParser.prototype.nextClause=function(){var t=this.currentClause;this.query.clause(t),this.currentClause={}},e.QueryParser.parseClause=function(t){var r=t.peekLexeme();if(r!=null)switch(r.type){case e.QueryLexer.PRESENCE:return e.QueryParser.parsePresence;case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new e.QueryParseError(n,r.start,r.end)}},e.QueryParser.parsePresence=function(t){var r=t.consumeLexeme();if(r!=null){switch(r.str){case"-":t.currentClause.presence=e.Query.presence.PROHIBITED;break;case"+":t.currentClause.presence=e.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new e.QueryParseError(n,r.start,r.end)}var i=t.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new e.QueryParseError(n,r.start,r.end)}switch(i.type){case e.QueryLexer.FIELD:return e.QueryParser.parseField;case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new e.QueryParseError(n,i.start,i.end)}}},e.QueryParser.parseField=function(t){var r=t.consumeLexeme();if(r!=null){if(t.query.allFields.indexOf(r.str)==-1){var n=t.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new e.QueryParseError(i,r.start,r.end)}t.currentClause.fields=[r.str];var s=t.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new e.QueryParseError(i,r.start,r.end)}switch(s.type){case e.QueryLexer.TERM:return e.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new e.QueryParseError(i,s.start,s.end)}}},e.QueryParser.parseTerm=function(t){var r=t.consumeLexeme();if(r!=null){t.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(t.currentClause.usePipeline=!1);var n=t.peekLexeme();if(n==null){t.nextClause();return}switch(n.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new e.QueryParseError(i,n.start,n.end)}}},e.QueryParser.parseEditDistance=function(t){var r=t.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new e.QueryParseError(i,r.start,r.end)}t.currentClause.editDistance=n;var s=t.peekLexeme();if(s==null){t.nextClause();return}switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(i,s.start,s.end)}}},e.QueryParser.parseBoost=function(t){var r=t.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new e.QueryParseError(i,r.start,r.end)}t.currentClause.boost=n;var s=t.peekLexeme();if(s==null){t.nextClause();return}switch(s.type){case e.QueryLexer.TERM:return t.nextClause(),e.QueryParser.parseTerm;case e.QueryLexer.FIELD:return t.nextClause(),e.QueryParser.parseField;case e.QueryLexer.EDIT_DISTANCE:return e.QueryParser.parseEditDistance;case e.QueryLexer.BOOST:return e.QueryParser.parseBoost;case e.QueryLexer.PRESENCE:return t.nextClause(),e.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new e.QueryParseError(i,s.start,s.end)}}},function(t,r){typeof define=="function"&&define.amd?define(r):typeof Rt=="object"?kt.exports=r():t.lunr=r()}(this,function(){return e})})()});var He=function(){},bn=function(e,t){He("toggleCodeblockVisibility",e,t),document.querySelectorAll(`.highlight code.language-${e}`).forEach(r=>{let n=r.closest(".highlight");n.style.display=t?"block":"none"})};function Pt(){return{tabs:[],changeLanguage:function(e){He("changeLanguage",e);for(let t=0;t{this.changeLanguage(0)})}}}var k=mn(It());var we=class{constructor(t={contentSelector:".content",markClass:"da-highlight-mark"}){this.opts=t,this.nodeStack=[]}apply(t){let r=document.createTreeWalker(this.content(),NodeFilter.SHOW_TEXT,{acceptNode:i=>i.parentNode.classList.contains(this.opts.markClass)?NodeFilter.FILTER_REJECT:/\S/.test(i.data)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_REJECT},!1),n=[];for(;r.nextNode();){let i=r.currentNode;i.data.match(t)&&n.push(i)}n.forEach(i=>{let s=i.parentNode.cloneNode(!0);s.childNodes.forEach(o=>{if(o.nodeType!==Node.TEXT_NODE)return;let a=o.data.match(t);if(!a)return;let u=o.data.indexOf(a[0],a.index);if(u===-1)return;let l=document.createElement("mark");l.classList.add(this.opts.markClass);let c=o.splitText(u);c.splitText(a[0].length);let d=c.cloneNode(!0);l.appendChild(d),s.replaceChild(l,c)}),i.parentNode&&i.parentNode.parentNode&&(this.nodeStack.push({old:i.parentNode,new:s}),i.parentNode.parentNode.replaceChild(s,i.parentNode))})}remove(){for(;this.nodeStack.length;){let t=this.nodeStack.pop();t.new.parentNode.replaceChild(t.old,t.new)}}content(){return document.querySelector(this.opts.contentSelector)}};function wn(e,t){var r=[];for(e=e.nextElementSibling;e&&!e.matches(t);)r.push(e),e=e.nextElementSibling;return r}function Qt(){var e,t=function(i){var s=new k.Builder;return s.pipeline.add(k.trimmer,k.stopWordFilter,k.stemmer),s.searchPipeline.add(k.stemmer),i.call(s,s),s.build()};function r(){e=t(function(){this.ref("id"),this.field("title",{boost:10}),this.field("body"),this.pipeline.add(k.trimmer,k.stopWordFilter),document.querySelectorAll("h1, h2").forEach(i=>{let s="";wn(i,"h1, h2").forEach(o=>{s=s.concat(" ",o.textContent)}),this.add({id:i.id,title:i.textContent,body:s})})})}let n=new we;return{query:"",results:[],init:function(){return this.$nextTick(()=>{r(),this.$watch("query",()=>{this.search()})})},search:function(){n.remove();let i=e.search(this.query).filter(s=>s.score>1e-4);this.results=i.map(s=>{var o=document.getElementById(s.ref);return{title:o.innerText,id:s.ref}}),this.results.length>0&&n.apply(new RegExp(this.query,"i"))}}}var Ft=function(){},En=()=>document.querySelectorAll(".content h1, .content h2, .content h3"),Sn=function(e,t){let r=document.querySelector(".content"),n=r.offsetHeight,i=r.offsetTop,s=Math.round((t.offsetTop-i)/n*100);e.activeHeading.title=t.innerText,e.activeHeading.progress=s};function Mt(){let e=function(t,r){if(!t.sub)return!1;let n=!1;return t.sub.forEach(i=>{i.open=r(i),i.active=i.open,i.open=i.open||e(i,r),i.open&&(n=!0)}),t.active_parent=n,n=n||r(t),t.open=n,t.active=r(t),n};return{activeHeading:{title:"",progress:0},showHeading:!0,rows:[],load:function(t){this.rows=t},transitions:function(){return{"x-transition:enter.duration.500ms":"","x-transition:leave.duration.400ms":"","x-transition.scale.origin.top.left.80":""}},rowClass:function(t){return{"x-bind:class"(){return`toc-h${t.level}${t.active?" active":""}${t.active_parent?" active-parent":""}`}}},click:function(t){this.rows.forEach(r=>{e(r,n=>t===n)})},onScroll:function(){Ft("onScroll");let t=window.scrollY;En().forEach(r=>{r.offsetTop{e(i,s=>s.id===r.id)}),Sn(this,r)),window.innerHeight+t>=document.body.offsetHeight&&(this.activeHeading.progress=100)})}}}var Ye=!1,Je=!1,q=[];function Tn(e){On(e)}function On(e){q.includes(e)||q.push(e),Cn()}function qt(e){let t=q.indexOf(e);t!==-1&&q.splice(t,1)}function Cn(){!Je&&!Ye&&(Ye=!0,queueMicrotask(An))}function An(){Ye=!1,Je=!0;for(let e=0;ee.effect(t,{scheduler:r=>{Xe?Tn(r):r()}}),Ht=e.raw}function Nt(e){de=e}function Rn(e){let t=()=>{};return[n=>{let i=de(n);return e._x_effects||(e._x_effects=new Set,e._x_runEffects=()=>{e._x_effects.forEach(s=>s())}),e._x_effects.add(i),t=()=>{i!==void 0&&(e._x_effects.delete(i),Le(i))},i},()=>{t()}]}var Wt=[],Kt=[],Ut=[];function kn(e){Ut.push(e)}function Gt(e,t){typeof t=="function"?(e._x_cleanups||(e._x_cleanups=[]),e._x_cleanups.push(t)):(t=e,Kt.push(t))}function In(e){Wt.push(e)}function Yt(e,t,r){e._x_attributeCleanups||(e._x_attributeCleanups={}),e._x_attributeCleanups[t]||(e._x_attributeCleanups[t]=[]),e._x_attributeCleanups[t].push(r)}function Jt(e,t){e._x_attributeCleanups&&Object.entries(e._x_attributeCleanups).forEach(([r,n])=>{(t===void 0||t.includes(r))&&(n.forEach(i=>i()),delete e._x_attributeCleanups[r])})}var dt=new MutationObserver(gt),ht=!1;function Xt(){dt.observe(document,{subtree:!0,childList:!0,attributes:!0,attributeOldValue:!0}),ht=!0}function Zt(){Qn(),dt.disconnect(),ht=!1}var ue=[],We=!1;function Qn(){ue=ue.concat(dt.takeRecords()),ue.length&&!We&&(We=!0,queueMicrotask(()=>{Fn(),We=!1}))}function Fn(){gt(ue),ue.length=0}function A(e){if(!ht)return e();Zt();let t=e();return Xt(),t}var pt=!1,Oe=[];function Mn(){pt=!0}function Nn(){pt=!1,gt(Oe),Oe=[]}function gt(e){if(pt){Oe=Oe.concat(e);return}let t=[],r=[],n=new Map,i=new Map;for(let s=0;so.nodeType===1&&t.push(o)),e[s].removedNodes.forEach(o=>o.nodeType===1&&r.push(o))),e[s].type==="attributes")){let o=e[s].target,a=e[s].attributeName,u=e[s].oldValue,l=()=>{n.has(o)||n.set(o,[]),n.get(o).push({name:a,value:o.getAttribute(a)})},c=()=>{i.has(o)||i.set(o,[]),i.get(o).push(a)};o.hasAttribute(a)&&u===null?l():o.hasAttribute(a)?(c(),l()):c()}i.forEach((s,o)=>{Jt(o,s)}),n.forEach((s,o)=>{Wt.forEach(a=>a(o,s))});for(let s of r)if(!t.includes(s)&&(Kt.forEach(o=>o(s)),s._x_cleanups))for(;s._x_cleanups.length;)s._x_cleanups.pop()();t.forEach(s=>{s._x_ignoreSelf=!0,s._x_ignore=!0});for(let s of t)r.includes(s)||s.isConnected&&(delete s._x_ignoreSelf,delete s._x_ignore,Ut.forEach(o=>o(s)),s._x_ignore=!0,s._x_ignoreSelf=!0);t.forEach(s=>{delete s._x_ignoreSelf,delete s._x_ignore}),t=null,r=null,n=null,i=null}function er(e){return pe(J(e))}function he(e,t,r){return e._x_dataStack=[t,...J(r||e)],()=>{e._x_dataStack=e._x_dataStack.filter(n=>n!==t)}}function $t(e,t){let r=e._x_dataStack[0];Object.entries(t).forEach(([n,i])=>{r[n]=i})}function J(e){return e._x_dataStack?e._x_dataStack:typeof ShadowRoot=="function"&&e instanceof ShadowRoot?J(e.host):e.parentNode?J(e.parentNode):[]}function pe(e){let t=new Proxy({},{ownKeys:()=>Array.from(new Set(e.flatMap(r=>Object.keys(r)))),has:(r,n)=>e.some(i=>i.hasOwnProperty(n)),get:(r,n)=>(e.find(i=>{if(i.hasOwnProperty(n)){let s=Object.getOwnPropertyDescriptor(i,n);if(s.get&&s.get._x_alreadyBound||s.set&&s.set._x_alreadyBound)return!0;if((s.get||s.set)&&s.enumerable){let o=s.get,a=s.set,u=s;o=o&&o.bind(t),a=a&&a.bind(t),o&&(o._x_alreadyBound=!0),a&&(a._x_alreadyBound=!0),Object.defineProperty(i,n,{...u,get:o,set:a})}return!0}return!1})||{})[n],set:(r,n,i)=>{let s=e.find(o=>o.hasOwnProperty(n));return s?s[n]=i:e[e.length-1][n]=i,!0}});return t}function tr(e){let t=n=>typeof n=="object"&&!Array.isArray(n)&&n!==null,r=(n,i="")=>{Object.entries(Object.getOwnPropertyDescriptors(n)).forEach(([s,{value:o,enumerable:a}])=>{if(a===!1||o===void 0)return;let u=i===""?s:`${i}.${s}`;typeof o=="object"&&o!==null&&o._x_interceptor?n[s]=o.initialize(e,u,s):t(o)&&o!==n&&!(o instanceof Element)&&r(o,u)})};return r(e)}function rr(e,t=()=>{}){let r={initialValue:void 0,_x_interceptor:!0,initialize(n,i,s){return e(this.initialValue,()=>$n(n,i),o=>Ze(n,i,o),i,s)}};return t(r),n=>{if(typeof n=="object"&&n!==null&&n._x_interceptor){let i=r.initialize.bind(r);r.initialize=(s,o,a)=>{let u=n.initialize(s,o,a);return r.initialValue=u,i(s,o,a)}}else r.initialValue=n;return r}}function $n(e,t){return t.split(".").reduce((r,n)=>r[n],e)}function Ze(e,t,r){if(typeof t=="string"&&(t=t.split(".")),t.length===1)e[t[0]]=r;else{if(t.length===0)throw error;return e[t[0]]||(e[t[0]]={}),Ze(e[t[0]],t.slice(1),r)}}var nr={};function Q(e,t){nr[e]=t}function et(e,t){return Object.entries(nr).forEach(([r,n])=>{Object.defineProperty(e,`$${r}`,{get(){let[i,s]=lr(t);return i={interceptor:rr,...i},Gt(t,s),n(t,i)},enumerable:!1})}),{obj:e,cleanup:()=>{t=null}}}function jn(e,t,r,...n){try{return r(...n)}catch(i){fe(i,e,t)}}function fe(e,t,r=void 0){Object.assign(e,{el:t,expression:r}),console.warn(`Alpine Expression Error: ${e.message} + +${r?'Expression: "'+r+`" + +`:""}`,t),setTimeout(()=>{throw e},0)}var Te=!0;function Dn(e){let t=Te;Te=!1,e(),Te=t}function Y(e,t,r={}){let n;return L(e,t)(i=>n=i,r),n}function L(...e){return ir(...e)}var ir=sr;function Bn(e){ir=e}function sr(e,t){let r={},n=et(r,e).cleanup;Yt(e,"evaluator",n);let i=[r,...J(e)];if(typeof t=="function")return zn(i,t);let s=qn(i,t,e);return jn.bind(null,e,t,s)}function zn(e,t){return(r=()=>{},{scope:n={},params:i=[]}={})=>{let s=t.apply(pe([n,...e]),i);Ce(r,s)}}var Ke={};function Vn(e,t){if(Ke[e])return Ke[e];let r=Object.getPrototypeOf(async function(){}).constructor,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e,s=(()=>{try{return new r(["__self","scope"],`with (scope) { __self.result = ${n} }; __self.finished = true; return __self.result;`)}catch(o){return fe(o,t,e),Promise.resolve()}})();return Ke[e]=s,s}function qn(e,t,r){let n=Vn(t,r);return(i=()=>{},{scope:s={},params:o=[]}={})=>{n.result=void 0,n.finished=!1;let a=pe([s,...e]);if(typeof n=="function"){let u=n(n,a).catch(l=>fe(l,r,t));n.finished?(Ce(i,n.result,a,o,r),n.result=void 0):u.then(l=>{Ce(i,l,a,o,r)}).catch(l=>fe(l,r,t)).finally(()=>n.result=void 0)}}}function Ce(e,t,r,n,i){if(Te&&typeof t=="function"){let s=t.apply(r,n);s instanceof Promise?s.then(o=>Ce(e,o,r,n)).catch(o=>fe(o,i,t)):e(s)}else e(t)}var _t="x-";function te(e=""){return _t+e}function Hn(e){_t=e}var or={};function C(e,t){or[e]=t}function vt(e,t,r){if(t=Array.from(t),e._x_virtualDirectives){let s=Object.entries(e._x_virtualDirectives).map(([a,u])=>({name:a,value:u})),o=ar(s);s=s.map(a=>o.find(u=>u.name===a.name)?{name:`x-bind:${a.name}`,value:`"${a.value}"`}:a),t=t.concat(s)}let n={};return t.map(dr((s,o)=>n[s]=o)).filter(pr).map(Un(n,r)).sort(Gn).map(s=>Kn(e,s))}function ar(e){return Array.from(e).map(dr()).filter(t=>!pr(t))}var tt=!1,ae=new Map,ur=Symbol();function Wn(e){tt=!0;let t=Symbol();ur=t,ae.set(t,[]);let r=()=>{for(;ae.get(t).length;)ae.get(t).shift()();ae.delete(t)},n=()=>{tt=!1,r()};e(r),n()}function lr(e){let t=[],r=a=>t.push(a),[n,i]=Rn(e);return t.push(i),[{Alpine:ge,effect:n,cleanup:r,evaluateLater:L.bind(L,e),evaluate:Y.bind(Y,e)},()=>t.forEach(a=>a())]}function Kn(e,t){let r=()=>{},n=or[t.type]||r,[i,s]=lr(e);Yt(e,t.original,s);let o=()=>{e._x_ignore||e._x_ignoreSelf||(n.inline&&n.inline(e,t,i),n=n.bind(n,e,t,i),tt?ae.get(ur).push(n):n())};return o.runCleanups=s,o}var cr=(e,t)=>({name:r,value:n})=>(r.startsWith(e)&&(r=r.replace(e,t)),{name:r,value:n}),fr=e=>e;function dr(e=()=>{}){return({name:t,value:r})=>{let{name:n,value:i}=hr.reduce((s,o)=>o(s),{name:t,value:r});return n!==t&&e(n,t),{name:n,value:i}}}var hr=[];function yt(e){hr.push(e)}function pr({name:e}){return gr().test(e)}var gr=()=>new RegExp(`^${_t}([^:^.]+)\\b`);function Un(e,t){return({name:r,value:n})=>{let i=r.match(gr()),s=r.match(/:([a-zA-Z0-9\-:]+)/),o=r.match(/\.[^.\]]+(?=[^\]]*$)/g)||[],a=t||e[r]||r;return{type:i?i[1]:null,value:s?s[1]:null,modifiers:o.map(u=>u.replace(".","")),expression:n,original:a}}}var rt="DEFAULT",Ee=["ignore","ref","data","id","bind","init","for","mask","model","modelable","transition","show","if",rt,"teleport"];function Gn(e,t){let r=Ee.indexOf(e.type)===-1?rt:e.type,n=Ee.indexOf(t.type)===-1?rt:t.type;return Ee.indexOf(r)-Ee.indexOf(n)}function le(e,t,r={}){e.dispatchEvent(new CustomEvent(t,{detail:r,bubbles:!0,composed:!0,cancelable:!0}))}var nt=[],xt=!1;function _r(e=()=>{}){return queueMicrotask(()=>{xt||setTimeout(()=>{it()})}),new Promise(t=>{nt.push(()=>{e(),t()})})}function it(){for(xt=!1;nt.length;)nt.shift()()}function Yn(){xt=!0}function K(e,t){if(typeof ShadowRoot=="function"&&e instanceof ShadowRoot){Array.from(e.children).forEach(i=>K(i,t));return}let r=!1;if(t(e,()=>r=!0),r)return;let n=e.firstElementChild;for(;n;)K(n,t,!1),n=n.nextElementSibling}function X(e,...t){console.warn(`Alpine Warning: ${e}`,...t)}function Jn(){document.body||X("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` + + + + + + + + NAV + + + +
+ + + + + + + + + + + +
    + + +
+ + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Active Help

+

Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.

+

For example,

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/    internal/    scripts/    pkg/     testdata/
+

Hint: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.

+ + + + + + + + +

Supported shells

+

Active Help is currently only supported for the following shells:

+
    +
  • Bash (using bash completion V2 only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
  • +
  • Zsh
  • +
+ + + + + + + + +

Adding Active Help messages

+

As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to Shell Completions.

+

Adding Active Help is done through the use of the cobra.AppendActiveHelp(...) function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.

+ + + + + + + + +

Active Help for nouns

+

Adding Active Help when completing a noun is done within the ValidArgsFunction(...) of a command. Please notice the use of cobra.AppendActiveHelp(...) in the following example:

+
cmd := &cobra.Command{
+	Use:   "add [NAME] [URL]",
+	Short: "add a chart repository",
+	Args:  require.ExactArgs(2),
+	RunE: func(cmd *cobra.Command, args []string) error {
+		return addRepo(args)
+	},
+	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		var comps []string
+		if len(args) == 0 {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		} else if len(args) == 1 {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		} else {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+		return comps, cobra.ShellCompDirectiveNoFileComp
+	},
+}
+

The example above defines the completions (none, in this specific example) as well as the Active Help messages for the helm repo add command. It yields the following behavior:

+
bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+

Hint: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.

+ + + + + + + + +

Active Help for flags

+

Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:

+
_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+		if len(args) != 2 {
+			return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+		}
+		return compVersionFlag(args[1], toComplete)
+	})
+

The example above prints an Active Help message when not enough information was given by the user to complete the --version flag.

+
bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1  2.0.2  2.0.3
+
+ + + + + + + +

User control of Active Help

+

You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.

+

The way to configure Active Help is to use the program’s Active Help environment +variable. That variable is named <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of your +program in uppercase with any - replaced by an _. The variable should be set by the user to whatever +Active Help configuration values are supported by the program.

+

For example, say helm has chosen to support three levels for Active Help: on, off, local. Then a user +would set the desired behavior to local by doing export HELM_ACTIVE_HELP=local in their shell.

+

For simplicity, when in cmd.ValidArgsFunction(...) or a flag’s completion function, the program should read the +Active Help configuration using the cobra.GetActiveHelpConfig(cmd) function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly).

+

For example:

+
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+	activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+	var comps []string
+	if len(args) == 0 {
+		if activeHelpLevel != "off"  {
+			comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+		}
+	} else if len(args) == 1 {
+		if activeHelpLevel != "off" {
+			comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+		}
+	} else {
+		if activeHelpLevel == "local" {
+			comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+		}
+	}
+	return comps, cobra.ShellCompDirectiveNoFileComp
+},
+

Note 1: If the <PROGRAM>_ACTIVE_HELP environment variable is set to the string “0”, Cobra will automatically disable all Active Help output (even if some output was specified by the program using the cobra.AppendActiveHelp(...) function). Using “0” can simplify your code in situations where you want to blindly disable Active Help without having to call cobra.GetActiveHelpConfig(cmd) explicitly.

+

Note 2: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable COBRA_ACTIVE_HELP to “0”. In this case cobra.GetActiveHelpConfig(cmd) will return “0” no matter what the variable <PROGRAM>_ACTIVE_HELP is set to.

+

Note 3: If the user does not set <PROGRAM>_ACTIVE_HELP or COBRA_ACTIVE_HELP (which will be a common case), the default value for the Active Help configuration returned by cobra.GetActiveHelpConfig(cmd) will be the empty string.

+ + + + + + + + +

Active Help with Cobra’s default completion command

+

Cobra provides a default completion command for programs that wish to use it. +When using the default completion command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users.

+ + + + + + + + +

Debugging Active Help

+

Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra’s hidden __complete command. Please refer to debugging shell completion for details.

+

When debugging with the __complete command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named <PROGRAM>_ACTIVE_HELP where any - is replaced by an _. For example, we can test deactivating some Active Help as shown below:

+
$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+ + + + + + + + + +

Generating Bash Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Bash legacy dynamic completions

+

For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the ValidArgsFunction solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side ValidArgsFunction and RegisterFlagCompletionFunc(), as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution.

+

Note: Cobra’s default completion command uses bash completion V2. If you are currently using Cobra’s legacy dynamic completion solution, you should not use the default completion command but continue using your own.

+

The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions.

+

Some code that works in kubernetes:

+
const (
+        bash_completion_func = `__kubectl_parse_get()
+{
+    local kubectl_output out
+    if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then
+        out=($(echo "${kubectl_output}" | awk '{print $1}'))
+        COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) )
+    fi
+}
+
+__kubectl_get_resource()
+{
+    if [[ ${#nouns[@]} -eq 0 ]]; then
+        return 1
+    fi
+    __kubectl_parse_get ${nouns[${#nouns[@]} -1]}
+    if [[ $? -eq 0 ]]; then
+        return 0
+    fi
+}
+
+__kubectl_custom_func() {
+    case ${last_command} in
+        kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop)
+            __kubectl_get_resource
+            return
+            ;;
+        *)
+            ;;
+    esac
+}
+`)
+

And then I set that in my command definition:

+
cmds := &cobra.Command{
+	Use:   "kubectl",
+	Short: "kubectl controls the Kubernetes cluster manager",
+	Long: `kubectl controls the Kubernetes cluster manager.
+
+Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`,
+	Run: runHelp,
+	BashCompletionFunction: bash_completion_func,
+}
+

The BashCompletionFunction option is really only valid/useful on the root command. Doing the above will cause __kubectl_custom_func() (__<command-use>_custom_func()) to be called when the built in processor was unable to find a solution. In the case of kubernetes a valid command might look something like kubectl get pod [mypod]. If you type kubectl get pod [tab][tab] the __kubectl_customc_func() will run because the cobra.Command only understood “kubectl” and “get.” __kubectl_custom_func() will see that the cobra.Command is “kubectl_get” and will thus call another helper __kubectl_get_resource(). __kubectl_get_resource will look at the ’nouns’ collected. In our example the only noun will be pod. So it will call __kubectl_parse_get pod. __kubectl_parse_get will actually call out to kubernetes and get any pods. It will then set COMPREPLY to valid pods!

+

Similarly, for flags:

+
	annotation := make(map[string][]string)
+	annotation[cobra.BashCompCustom] = []string{"__kubectl_get_namespaces"}
+
+	flag := &pflag.Flag{
+		Name:        "namespace",
+		Usage:       usage,
+		Annotations: annotation,
+	}
+	cmd.Flags().AddFlag(flag)
+

In addition add the __kubectl_get_namespaces implementation in the BashCompletionFunction +value, e.g.:

+
__kubectl_get_namespaces()
+{
+    local template
+    template="{{ range .items  }}{{ .metadata.name }} {{ end }}"
+    local kubectl_out
+    if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
+        COMPREPLY=( $( compgen -W "${kubectl_out}[*]" -- "$cur" ) )
+    fi
+}
+
+ + + + + + + + + +

Generating Fish Completions For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating PowerShell Completions For Your Own cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + + + +

Generating Zsh Completion For Your cobra.Command

+

Please refer to Shell Completions for details.

+ + + + + + + + +

Zsh completions standardization

+

Cobra 1.1 standardized its zsh completion support to align it with its other shell completions. Although the API was kept backwards-compatible, some small changes in behavior were introduced.

+ + + + + + + + +

Deprecation summary

+

See further below for more details on these deprecations.

+
    +
  • cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) is no longer needed. It is therefore deprecated and silently ignored.
  • +
  • cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction with ShellCompDirectiveFilterFileExt.
    • +
    +
  • +
  • cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored. +
      +
    • Instead use ValidArgsFunction.
    • +
    +
  • +
+ + + + + + + + +

Behavioral changes

+

Noun completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use ValidArgsFunction with ShellCompDirectiveNoFileComp to turn off file completion on a per-argument basis
Completion of flag names without the - prefix having been typedFlag names are only completed if the user has typed the first -
cmd.MarkZshCompPositionalArgumentFile(pos, []string{}) used to turn on file completion on a per-argument position basisFile completion for all arguments by default; cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored
cmd.MarkZshCompPositionalArgumentFile(pos, glob[]) used to turn on file completion with glob filtering on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentFile() is deprecated and silently ignored; use ValidArgsFunction with ShellCompDirectiveFilterFileExt for file extension filtering (not full glob filtering)
cmd.MarkZshCompPositionalArgumentWords(pos, words[]) used to provide completion choices on a per-argument position basis (zsh-specific)cmd.MarkZshCompPositionalArgumentWords() is deprecated and silently ignored; use ValidArgsFunction to achieve the same behavior
+

Flag-value completion

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old behaviorNew behavior
No file completion by default (opposite of bash)File completion by default; use RegisterFlagCompletionFunc() with ShellCompDirectiveNoFileComp to turn off file completion
cmd.MarkFlagFilename(flag, []string{}) and similar used to turn on file completionFile completion by default; cmd.MarkFlagFilename(flag, []string{}) no longer needed in this context and silently ignored
cmd.MarkFlagFilename(flag, glob[]) used to turn on file completion with glob filtering (syntax of []string{"*.yaml", "*.yml"} incompatible with bash)Will continue to work, however, support for bash syntax is added and should be used instead so as to work for all shells ([]string{"yaml", "yml"})
cmd.MarkFlagDirname(flag) only completes directories (zsh-specific)Has been added for all shells
Completion of a flag name does not repeat, unless flag is of type *Array or *Slice (not supported by bash)Retained for zsh and added to fish
Completion of a flag name does not provide the = form (unlike bash)Retained for zsh and added to fish
+

Improvements

+
    +
  • Custom completion support (ValidArgsFunction and RegisterFlagCompletionFunc())
  • +
  • File completion by default if no other completions found
  • +
  • Handling of required flags
  • +
  • File extension filtering no longer mutually exclusive with bash usage
  • +
  • Completion of directory names within another directory
  • +
  • Support for = form of flags
  • +
+ + + + + + + + + + +

Generating Man Pages For Your Own cobra.Command

+

Generating man pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	header := &doc.GenManHeader{
+		Title: "MINE",
+		Section: "3",
+	}
+	err := doc.GenManTree(cmd, header, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a man page /tmp/test.3

+ + + + + + + + + + +

Generating Markdown Docs For Your Own cobra.Command

+

Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenMarkdownTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Markdown document /tmp/test.md

+ + + + + + + + +

Generate markdown docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenMarkdownTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate markdown docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenMarkdown instead of GenMarkdownTree

+
	out := new(bytes.Buffer)
+	err := doc.GenMarkdown(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the markdown doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + +

Customize the output

+

Both GenMarkdown and GenMarkdownTree have alternate versions with callbacks to get some control of the output:

+
func GenMarkdownTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenMarkdownCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Markdown file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Generating ReStructured Text Docs For Your Own cobra.Command

+

Generating ReST pages from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenReSTTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a ReST document /tmp/test.rst

+ + + + + + + + +

Generate ReST docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"log"
+	"io/ioutil"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenReSTTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate ReST docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenReST instead of GenReSTTree

+
	out := new(bytes.Buffer)
+	err := doc.GenReST(cmd, out)
+	if err != nil {
+		log.Fatal(err)
+	}
+

This will write the ReST doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenReST and GenReSTTree have alternate versions with callbacks to get some control of the output:

+
func GenReSTTreeCustom(cmd *Command, dir string, filePrepender func(string) string, linkHandler func(string, string) string) error {
+	//...
+}
+
func GenReSTCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string, string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered ReST file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered links to the commands, given a command name and reference. This is useful while converting rst to html or while generating documentation with tools like Sphinx where :ref: is used:

+
// Sphinx cross-referencing format
+linkHandler := func(name, ref string) string {
+    return fmt.Sprintf(":ref:`%s <%s>`", name, ref)
+}
+
+ + + + + + + + + +

Generating Yaml Docs For Your Own cobra.Command

+

Generating yaml files from a cobra command is incredibly easy. An example is as follows:

+
package main
+
+import (
+	"log"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	cmd := &cobra.Command{
+		Use:   "test",
+		Short: "my test program",
+	}
+	err := doc.GenYamlTree(cmd, "/tmp")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

That will get you a Yaml document /tmp/test.yaml

+ + + + + + + + +

Generate yaml docs for the entire command tree

+

This program can actually generate docs for the kubectl command in the kubernetes project

+
package main
+
+import (
+	"io/ioutil"
+	"log"
+	"os"
+
+	"k8s.io/kubernetes/pkg/kubectl/cmd"
+	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
+
+	"github.com/spf13/cobra/doc"
+)
+
+func main() {
+	kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
+	err := doc.GenYamlTree(kubectl, "./")
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+

This will generate a whole series of files, one for each command in the tree, in the directory specified (in this case “./”)

+ + + + + + + + +

Generate yaml docs for a single command

+

You may wish to have more control over the output, or only generate for a single command, instead of the entire command tree. If this is the case you may prefer to GenYaml instead of GenYamlTree

+
	out := new(bytes.Buffer)
+	doc.GenYaml(cmd, out)
+

This will write the yaml doc for ONLY “cmd” into the out, buffer.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Customize the output

+

Both GenYaml and GenYamlTree have alternate versions with callbacks to get some control of the output:

+
func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error {
+	//...
+}
+
func GenYamlCustom(cmd *Command, out *bytes.Buffer, linkHandler func(string) string) error {
+	//...
+}
+

The filePrepender will prepend the return value given the full filepath to the rendered Yaml file. A common use case is to add front matter to use the generated documentation with Hugo:

+
const fmTemplate = `---
+date: %s
+title: "%s"
+slug: %s
+url: %s
+---
+`
+
+filePrepender := func(filename string) string {
+	now := time.Now().Format(time.RFC3339)
+	name := filepath.Base(filename)
+	base := strings.TrimSuffix(name, path.Ext(name))
+	url := "/commands/" + strings.ToLower(base) + "/"
+	return fmt.Sprintf(fmTemplate, now, strings.Replace(base, "_", " ", -1), base, url)
+}
+

The linkHandler can be used to customize the rendered internal links to the commands, given a filename:

+
linkHandler := func(name string) string {
+	base := strings.TrimSuffix(name, path.Ext(name))
+	return "/commands/" + strings.ToLower(base) + "/"
+}
+
+ + + + + + + + + +

Projects using Cobra

+ + + + + + + + + + + +

User Guide

+

While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure:

+
  ▾ appName/
+    ▾ cmd/
+        add.go
+        your.go
+        commands.go
+        here.go
+      main.go
+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Using the Cobra Generator

+

Cobra-CLI is its own program that will create your application and add any commands you want. +It’s the easiest way to incorporate Cobra into your application.

+

For complete details on using the Cobra generator, please refer to The Cobra-CLI Generator README

+ + + + + + + + +

Using the Cobra Library

+

To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit.

+ + + + + + + + +

Create rootCmd

+

Cobra doesn’t require any special constructors. Simply create your commands.

+

Ideally you place this in app/cmd/root.go:

+
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 https://gohugo.io/documentation/`,
+  Run: func(cmd *cobra.Command, args []string) {
+    // Do Stuff Here
+  },
+}
+
+func Execute() {
+  if err := rootCmd.Execute(); err != nil {
+    fmt.Fprintln(os.Stderr, err)
+    os.Exit(1)
+  }
+}
+

You will additionally define flags and handle configuration in your init() function.

+

For example cmd/root.go:

+
package cmd
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
+)
+
+var (
+	// Used for flags.
+	cfgFile     string
+	userLicense string
+
+	rootCmd = &cobra.Command{
+		Use:   "cobra-cli",
+		Short: "A generator for Cobra based Applications",
+		Long: `Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.`,
+	}
+)
+
+// Execute executes the root command.
+func Execute() error {
+	return rootCmd.Execute()
+}
+
+func init() {
+	cobra.OnInitialize(initConfig)
+
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
+	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
+	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
+	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+	viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))
+	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
+	viper.SetDefault("license", "apache")
+
+	rootCmd.AddCommand(addCmd)
+	rootCmd.AddCommand(initCmd)
+}
+
+func initConfig() {
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := os.UserHomeDir()
+		cobra.CheckErr(err)
+
+		// Search config in home directory with name ".cobra" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigType("yaml")
+		viper.SetConfigName(".cobra")
+	}
+
+	viper.AutomaticEnv()
+
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
+}
+
+ + + + + + + +

Create your main.go

+

With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command.

+

In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra.

+
package main
+
+import (
+  "{pathToYourApp}/cmd"
+)
+
+func main() {
+  cmd.Execute()
+}
+
+ + + + + + + +

Create additional commands

+

Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory.

+

If you wanted to create a version command you would create cmd/version.go and +populate it with the following:

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  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")
+  },
+}
+
+ + + + + + + +

Organizing subcommands

+

A command may have subcommands which in turn may have other subcommands. This is achieved by using +AddCommand. In some cases, especially in larger applications, each subcommand may be defined in +its own go package.

+

The suggested approach is for the parent command to use AddCommand to add its most immediate +subcommands. For example, consider the following directory structure:

+
├── cmd
+│   ├── root.go
+│   └── sub1
+│       ├── sub1.go
+│       └── sub2
+│           ├── leafA.go
+│           ├── leafB.go
+│           └── sub2.go
+└── main.go
+

In this case:

+
    +
  • The init function of root.go adds the command defined in sub1.go to the root command.
  • +
  • The init function of sub1.go adds the command defined in sub2.go to the sub1 command.
  • +
  • The init function of sub2.go adds the commands defined in leafA.go and leafB.go to the +sub2 command.
  • +
+

This approach ensures the subcommands are always included at compile time while avoiding cyclic +references.

+ + + + + + + + +

Returning and handling errors

+

If you wish to return an error to the caller of a command, RunE can be used.

+
package cmd
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func init() {
+  rootCmd.AddCommand(tryCmd)
+}
+
+var tryCmd = &cobra.Command{
+  Use:   "try",
+  Short: "Try and possibly fail at something",
+  RunE: func(cmd *cobra.Command, args []string) error {
+    if err := someFunc(); err != nil {
+	return err
+    }
+    return nil
+  },
+}
+

The error can then be caught at the execute function call.

+ + + + + + + + +

Working with Flags

+

Flags provide modifiers to control how the action command operates.

+ + + + + + + + +

Assign flags to a command

+

Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with.

+
var Verbose bool
+var Source string
+

There are two different approaches to assign a flag.

+ + + + + + + + +

Persistent Flags

+

A flag can be ‘persistent’, meaning that this flag will be available to the +command it’s assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root.

+
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
+
+ + + + + + + +

Local Flags

+

A flag can also be assigned locally, which will only apply to that specific command.

+
localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+
+ + + + + + + +

Local Flag on Parent Commands

+

By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling Command.TraverseChildren, Cobra will +parse local flags on each command before executing the target command.

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

Bind Flags with Config

+

You can also bind your flags with viper:

+
var author string
+
+func init() {
+  rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
+  viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))
+}
+

In this example, the persistent flag author is bound with viper. +Note: the variable author will not be set to the value from config, +when the --author flag is provided by user.

+

More in viper documentation.

+ + + + + + + + +

Required flags

+

Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required:

+
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkFlagRequired("region")
+

Or, for persistent flags:

+
rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
+rootCmd.MarkPersistentFlagRequired("region")
+
+ + + + + + + +

Flag Groups

+

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 +Cobra can enforce that requirement:

+
rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+

You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either --json or --yaml but never both:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

If you want to require at least one flag from a group to be present, you can use MarkFlagsOneRequired. +This can be combined with MarkFlagsMutuallyExclusive to enforce exactly one flag from a given group:

+
rootCmd.Flags().BoolVar(&ofJson, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&ofYaml, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsOneRequired("json", "yaml")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+

In these cases:

+
    +
  • both local and persistent flags can be used +
      +
    • NOTE: the group is only enforced on commands where every flag is defined
    • +
    +
  • +
  • a flag may appear in multiple groups
  • +
  • a group may contain any number of flags
  • +
+ + + + + + + + +

Positional and Custom Arguments

+

Validation of positional arguments can be specified using the Args field of Command. +The following validators are built in:

+
    +
  • Number of arguments: +
      +
    • NoArgs - report an error if there are any positional args.
    • +
    • ArbitraryArgs - accept any number of args.
    • +
    • MinimumNArgs(int) - report an error if less than N positional args are provided.
    • +
    • MaximumNArgs(int) - report an error if more than N positional args are provided.
    • +
    • ExactArgs(int) - report an error if there are not exactly N positional args.
    • +
    • RangeArgs(min, max) - report an error if the number of args is not between min and max.
    • +
    +
  • +
  • Content of the arguments: +
      +
    • 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.
    • +
    +
  • +
+

If Args is undefined or nil, it defaults to ArbitraryArgs.

+

Moreover, MatchAll(pargs ...PositionalArgs) enables combining existing checks with arbitrary other checks. +For instance, if you want to report an error if there are not exactly N positional args OR if there are any positional +args that are not in the ValidArgs field of Command, you can call MatchAll on ExactArgs and OnlyValidArgs, as +shown below:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: cobra.MatchAll(cobra.ExactArgs(2), cobra.OnlyValidArgs),
+  Run: func(cmd *cobra.Command, args []string) {
+    fmt.Println("Hello, World!")
+  },
+}
+

It is possible to set any custom validator that satisfies func(cmd *cobra.Command, args []string) error. +For example:

+
var cmd = &cobra.Command{
+  Short: "hello",
+  Args: func(cmd *cobra.Command, args []string) error {
+    // Optionally run one of the validators provided by cobra
+    if err := cobra.MinimumNArgs(1)(cmd, args); err != nil {
+        return err
+    }
+    // Run the custom validation logic
+    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!")
+  },
+}
+
+ + + + + + + +

Example

+

In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a ‘Run’ for the ‘rootCmd’.

+

We have only defined one flag for a single command.

+

More documentation about flags is available at https://github.com/spf13/pflag

+
package main
+
+import (
+  "fmt"
+  "strings"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+  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("Echo: " + strings.Join(args, " "))
+    },
+  }
+
+  var cmdTimes = &cobra.Command{
+    Use:   "times [string to echo]",
+    Short: "Echo anything to the screen more times",
+    Long: `echo things multiple times back to the user by 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")
+
+  var rootCmd = &cobra.Command{Use: "app"}
+  rootCmd.AddCommand(cmdPrint, cmdEcho)
+  cmdEcho.AddCommand(cmdTimes)
+  rootCmd.Execute()
+}
+

For a more complete example of a larger application, please checkout Hugo.

+ + + + + + + + +

Help Command

+

Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs ‘app help’. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +‘create’ without any additional configuration; Cobra will work when ‘app help +create’ is called. Every command will automatically have the ‘–help’ flag added.

+ + + + + + + + +

Example

+

The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed.

+
$ cobra-cli help
+
+Cobra is a CLI library for Go that empowers applications.
+This application is a tool to generate the needed files
+to quickly create a Cobra application.
+
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra-cli [command] --help" for more information about a command.
+
+

Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want.

+ + + + + + + + +

Grouping commands in help

+

Cobra supports grouping of available commands in the help output. To group commands, each group must be explicitly +defined using AddGroup() on the parent command. Then a subcommand can be added to a group using the GroupID element +of that subcommand. The groups will appear in the help output in the same order as they are defined using different +calls to AddGroup(). If you use the generated help or completion commands, you can set their group ids using +SetHelpCommandGroupId() and SetCompletionCommandGroupId() on the root command, respectively.

+ + + + + + + + +

Defining your own help

+

You can provide your own Help command or your own template for the default command to use +with the following functions:

+
cmd.SetHelpCommand(cmd *Command)
+cmd.SetHelpFunc(f func(*Command, []string))
+cmd.SetHelpTemplate(s string)
+

The latter two will also apply to any children commands.

+ + + + + + + + +

Usage Message

+

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

+ + + + + + + + +

Example

+

You may recognize this from the help above. That’s because the default help +embeds the usage as part of its output.

+
$ cobra-cli --invalid
+Error: unknown flag: --invalid
+Usage:
+  cobra-cli [command]
+
+Available Commands:
+  add         Add a command to a Cobra Application
+  completion  Generate the autocompletion script for the specified shell
+  help        Help about any command
+  init        Initialize a Cobra Application
+
+Flags:
+  -a, --author string    author name for copyright attribution (default "YOUR NAME")
+      --config string    config file (default is $HOME/.cobra.yaml)
+  -h, --help             help for cobra-cli
+  -l, --license string   name of license for the project
+      --viper            use Viper for configuration
+
+Use "cobra [command] --help" for more information about a command.
+
+ + + + + + + + +

Defining your own usage

+

You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods:

+
cmd.SetUsageFunc(f func(*Command) error)
+cmd.SetUsageTemplate(s string)
+
+ + + + + + + +

Version Flag

+

Cobra adds a top-level ‘–version’ flag if the Version field is set on the root command. +Running an application with the ‘–version’ flag will print the version to stdout using +the version template. The template can be customized using the +cmd.SetVersionTemplate(s string) function.

+ + + + + + + + +

PreRun and PostRun Hooks

+

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:

+
    +
  • PersistentPreRun
  • +
  • PreRun
  • +
  • Run
  • +
  • PostRun
  • +
  • PersistentPostRun
  • +
+

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:

+
package main
+
+import (
+  "fmt"
+
+  "github.com/spf13/cobra"
+)
+
+func main() {
+
+  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)
+    },
+  }
+
+  var 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()
+}
+

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]
+
+ + + + + + + +

Suggestions when “unknown command” happens

+

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:

+
$ hugo srever
+Error: unknown command "srever" for "hugo"
+
+Did you mean this?
+        server
+
+Run 'hugo --help' for usage.
+

Suggestions are automatically generated based on existing subcommands and use an implementation of Levenshtein distance. Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.

+

If you need to disable suggestions or tweak the string distance in your command, use:

+
command.DisableSuggestions = true
+

or

+
command.SuggestionsMinimumDistance = 1
+

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 +you don’t want aliases. Example:

+
$ kubectl remove
+Error: unknown command "remove" for "kubectl"
+
+Did you mean this?
+        delete
+
+Run 'kubectl help' for usage.
+
+ + + + + + + +

Generating documentation for your command

+

Cobra can generate documentation based on subcommands, flags, etc. +Read more about it in the docs generation documentation.

+ + + + + + + + +

Generating shell completions

+

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.

+ + + + + + + + +

Providing Active Help

+

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.

+ + + +
+
+ +
+
+ + + diff --git a/tags/index.xml b/tags/index.xml new file mode 100644 index 000000000..990cb71f9 --- /dev/null +++ b/tags/index.xml @@ -0,0 +1,10 @@ + + + + Tags on Cobra documentation + https://spf13.github.io/cobra/tags/ + Recent content in Tags on Cobra documentation + Hugo -- gohugo.io + en + +