From 5a7e463ef68de3cc5bcd1d5911a503a6e57133b9 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Tue, 18 Apr 2017 21:35:33 +0200 Subject: [PATCH] Update spf13/cobra --- vendor/manifest | 2 +- vendor/src/github.com/spf13/cobra/README.md | 22 ++- .../spf13/cobra/bash_completions.go | 12 +- .../spf13/cobra/bash_completions.md | 2 +- vendor/src/github.com/spf13/cobra/cobra.go | 5 +- .../src/github.com/spf13/cobra/cobra_test.go | 2 +- vendor/src/github.com/spf13/cobra/command.go | 172 +++++++++++------- .../github.com/spf13/cobra/command_test.go | 48 +++++ .../github.com/spf13/cobra/doc/man_docs.go | 6 +- .../github.com/spf13/cobra/doc/man_docs.md | 4 +- .../spf13/cobra/doc/man_examples_test.go | 4 +- .../src/github.com/spf13/cobra/doc/md_docs.go | 4 +- .../src/github.com/spf13/cobra/doc/md_docs.md | 7 +- vendor/src/github.com/spf13/cobra/doc/util.go | 17 +- .../github.com/spf13/cobra/doc/yaml_docs.go | 165 +++++++++++++++++ .../github.com/spf13/cobra/doc/yaml_docs.md | 103 +++++++++++ .../spf13/cobra/doc/yaml_docs_test.go | 88 +++++++++ 17 files changed, 572 insertions(+), 91 deletions(-) create mode 100644 vendor/src/github.com/spf13/cobra/doc/yaml_docs.go create mode 100644 vendor/src/github.com/spf13/cobra/doc/yaml_docs.md create mode 100644 vendor/src/github.com/spf13/cobra/doc/yaml_docs_test.go diff --git a/vendor/manifest b/vendor/manifest index caa0dfe31..5a328f4dc 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -64,7 +64,7 @@ { "importpath": "github.com/spf13/cobra", "repository": "https://github.com/spf13/cobra", - "revision": "9c28e4bbd74e5c3ed7aacbc552b2cab7cfdfe744", + "revision": "b6cb3958937245a12d4d7728be080a6c758f4136", "branch": "master" }, { diff --git a/vendor/src/github.com/spf13/cobra/README.md b/vendor/src/github.com/spf13/cobra/README.md index 5d2504b1c..0d5bbfb1f 100644 --- a/vendor/src/github.com/spf13/cobra/README.md +++ b/vendor/src/github.com/spf13/cobra/README.md @@ -8,6 +8,7 @@ Many of the most widely used Go projects are built using Cobra including: * [Hugo](http://gohugo.io) * [rkt](https://github.com/coreos/rkt) * [etcd](https://github.com/coreos/etcd) +* [Docker](https://github.com/docker/docker) * [Docker (distribution)](https://github.com/docker/distribution) * [OpenShift](https://www.openshift.com/) * [Delve](https://github.com/derekparker/delve) @@ -157,12 +158,17 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, ```go package main -import "{pathToYourApp}/cmd" +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) func main() { if err := cmd.RootCmd.Execute(); err != nil { fmt.Println(err) - os.Exit(-1) + os.Exit(1) } } ``` @@ -313,12 +319,17 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, ```go package main -import "{pathToYourApp}/cmd" +import ( + "fmt" + "os" + + "{pathToYourApp}/cmd" +) func main() { if err := cmd.RootCmd.Execute(); err != nil { fmt.Println(err) - os.Exit(-1) + os.Exit(1) } } ``` @@ -337,6 +348,7 @@ package cmd import ( "github.com/spf13/cobra" + "fmt" ) func init() { @@ -744,7 +756,7 @@ providing a way to handle the errors in one location. The current list of functi * PersistentPostRunE If you would like to silence the default `error` and `usage` output in favor of your own, you can set `SilenceUsage` -and `SilenceErrors` to `false` on the command. A child command respects these flags if they are set on the parent +and `SilenceErrors` to `true` on the command. A child command respects these flags if they are set on the parent command. **Example Usage using RunE:** diff --git a/vendor/src/github.com/spf13/cobra/bash_completions.go b/vendor/src/github.com/spf13/cobra/bash_completions.go index 7a5bd4d7d..a0d040279 100644 --- a/vendor/src/github.com/spf13/cobra/bash_completions.go +++ b/vendor/src/github.com/spf13/cobra/bash_completions.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/pflag" ) +// Annotations for Bash completion. const ( BashCompFilenameExt = "cobra_annotation_bash_completion_filename_extensions" BashCompCustom = "cobra_annotation_bash_completion_custom" @@ -22,7 +23,7 @@ func preamble(out io.Writer, name string) error { if err != nil { return err } - _, err = fmt.Fprint(out, ` + preamStr := ` __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then @@ -87,8 +88,8 @@ __handle_reply() local index flag flag="${cur%%=*}" __index_of_word "${flag}" "${flags_with_completion[@]}" + COMPREPLY=() if [[ ${index} -ge 0 ]]; then - COMPREPLY=() PREFIX="" cur="${cur#*=}" ${flags_completion[${index}]} @@ -224,7 +225,7 @@ __handle_command() fi c=$((c+1)) __debug "${FUNCNAME[0]}: looking for ${next_command}" - declare -F $next_command >/dev/null && $next_command + declare -F "$next_command" >/dev/null && $next_command } __handle_word() @@ -246,7 +247,8 @@ __handle_word() __handle_word } -`) +` + _, err = fmt.Fprint(out, preamStr) return err } @@ -566,6 +568,7 @@ func gen(cmd *Command, w io.Writer) error { return nil } +// GenBashCompletion generates bash completion file and writes to the passed writer. func (cmd *Command) GenBashCompletion(w io.Writer) error { if err := preamble(w, cmd.Name()); err != nil { return err @@ -585,6 +588,7 @@ func nonCompletableFlag(flag *pflag.Flag) bool { return flag.Hidden || len(flag.Deprecated) > 0 } +// GenBashCompletionFile generates bash completion file. func (cmd *Command) GenBashCompletionFile(filename string) error { outFile, err := os.Create(filename) if err != nil { diff --git a/vendor/src/github.com/spf13/cobra/bash_completions.md b/vendor/src/github.com/spf13/cobra/bash_completions.md index 6e3b71f13..7fa970fa2 100644 --- a/vendor/src/github.com/spf13/cobra/bash_completions.md +++ b/vendor/src/github.com/spf13/cobra/bash_completions.md @@ -18,7 +18,7 @@ func main() { } ``` -That will get you completions of subcommands and flags. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. +`out.sh` will get you completions of subcommands and flags. Copy it to `/etc/bash_completion.d/` as described [here](https://debian-administration.org/article/316/An_introduction_to_bash_completion_part_1) and reset your terminal to use autocompletion. If you make additional annotations to your code, you can get even more intelligent and flexible behavior. ## Creating your own custom functions diff --git a/vendor/src/github.com/spf13/cobra/cobra.go b/vendor/src/github.com/spf13/cobra/cobra.go index b39c715a5..25473a706 100644 --- a/vendor/src/github.com/spf13/cobra/cobra.go +++ b/vendor/src/github.com/spf13/cobra/cobra.go @@ -37,7 +37,8 @@ var templateFuncs = template.FuncMap{ var initializers []func() -// Automatic prefix matching can be a dangerous thing to automatically enable in CLI tools. +// EnablePrefixMatching allows to set automatic prefix matching. Automatic prefix matching can be a dangerous thing +// to automatically enable in CLI tools. // Set this to true to enable it. var EnablePrefixMatching = false @@ -51,7 +52,7 @@ func AddTemplateFunc(name string, tmplFunc interface{}) { templateFuncs[name] = tmplFunc } -// AddTemplateFuncs adds multiple template functions availalble to Usage and +// AddTemplateFuncs adds multiple template functions that are available to Usage and // Help template generation. func AddTemplateFuncs(tmplFuncs template.FuncMap) { for k, v := range tmplFuncs { diff --git a/vendor/src/github.com/spf13/cobra/cobra_test.go b/vendor/src/github.com/spf13/cobra/cobra_test.go index 699a2f63b..46887fd7d 100644 --- a/vendor/src/github.com/spf13/cobra/cobra_test.go +++ b/vendor/src/github.com/spf13/cobra/cobra_test.go @@ -612,7 +612,7 @@ func TestSubcommandExecuteC(t *testing.T) { Use: "echo message", Run: func(c *Command, args []string) { msg := strings.Join(args, " ") - c.Println(msg, msg) + c.Println(msg) }, } diff --git a/vendor/src/github.com/spf13/cobra/command.go b/vendor/src/github.com/spf13/cobra/command.go index 9ae98369f..f4cd95ca7 100644 --- a/vendor/src/github.com/spf13/cobra/command.go +++ b/vendor/src/github.com/spf13/cobra/command.go @@ -57,6 +57,9 @@ type Command struct { Deprecated string // Is this command hidden and should NOT show up in the list of available commands? Hidden bool + // Annotations are key/value pairs that can be used by applications to identify or + // group commands + Annotations map[string]string // Full set of flags flags *flag.FlagSet // Set of flags childrens of this command will inherit @@ -109,10 +112,11 @@ type Command struct { flagErrorBuf *bytes.Buffer - args []string // actual args parsed from flags - output *io.Writer // out writer if set in SetOutput(w) - usageFunc func(*Command) error // Usage can be defined by application - usageTemplate string // Can be defined by Application + args []string // actual args parsed from flags + output io.Writer // out writer if set in SetOutput(w) + usageFunc func(*Command) error // Usage can be defined by application + usageTemplate string // Can be defined by Application + flagErrorFunc func(*Command, error) error helpTemplate string // Can be defined by Application helpFunc func(*Command, []string) // Help can be defined by application helpCommand *Command // The help command @@ -128,7 +132,7 @@ type Command struct { DisableFlagParsing bool } -// os.Args[1:] by default, if desired, can be overridden +// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // particularly useful when testing. func (c *Command) SetArgs(a []string) { c.args = a @@ -137,29 +141,36 @@ func (c *Command) SetArgs(a []string) { // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. func (c *Command) SetOutput(output io.Writer) { - c.output = &output + c.output = output } -// Usage can be defined by application. +// SetUsageFunc sets usage function. Usage can be defined by application. func (c *Command) SetUsageFunc(f func(*Command) error) { c.usageFunc = f } -// Can be defined by Application. +// SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { c.usageTemplate = s } -// Can be defined by Application. +// SetFlagErrorFunc sets a function to generate an error when flag parsing +// fails. +func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { + c.flagErrorFunc = f +} + +// SetHelpFunc sets help function. Can be defined by Application. func (c *Command) SetHelpFunc(f func(*Command, []string)) { c.helpFunc = f } +// SetHelpCommand sets help command. func (c *Command) SetHelpCommand(cmd *Command) { c.helpCommand = cmd } -// Can be defined by Application. +// SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { c.helpTemplate = s } @@ -176,17 +187,19 @@ func (c *Command) SetGlobalNormalizationFunc(n func(f *flag.FlagSet, name string } } +// OutOrStdout returns output to stdout. func (c *Command) OutOrStdout() io.Writer { return c.getOut(os.Stdout) } +// OutOrStderr returns output to stderr func (c *Command) OutOrStderr() io.Writer { return c.getOut(os.Stderr) } func (c *Command) getOut(def io.Writer) io.Writer { if c.output != nil { - return *c.output + return c.output } if c.HasParent() { return c.parent.getOut(def) @@ -224,12 +237,8 @@ func (c *Command) Usage() error { // HelpFunc returns either the function set by SetHelpFunc for this command // or a parent, or it returns a function with default help behavior. func (c *Command) HelpFunc() func(*Command, []string) { - cmd := c - for cmd != nil { - if cmd.helpFunc != nil { - return cmd.helpFunc - } - cmd = cmd.parent + if helpFunc := c.checkHelpFunc(); helpFunc != nil { + return helpFunc } return func(*Command, []string) { c.mergePersistentFlags() @@ -240,6 +249,20 @@ func (c *Command) HelpFunc() func(*Command, []string) { } } +// checkHelpFunc checks if there is helpFunc in ancestors of c. +func (c *Command) checkHelpFunc() func(*Command, []string) { + if c == nil { + return nil + } + if c.helpFunc != nil { + return c.helpFunc + } + if c.HasParent() { + return c.parent.checkHelpFunc() + } + return nil +} + // Help puts out the help for the command. // Used when a user calls help [command]. // Can be defined by user by overriding HelpFunc. @@ -248,6 +271,7 @@ func (c *Command) Help() error { return nil } +// UsageString return usage string. func (c *Command) UsageString() string { tmpOutput := c.output bb := new(bytes.Buffer) @@ -257,8 +281,25 @@ func (c *Command) UsageString() string { return bb.String() } +// FlagErrorFunc returns either the function set by SetFlagErrorFunc for this +// command or a parent, or it returns a function which returns the original +// error. +func (c *Command) FlagErrorFunc() (f func(*Command, error) error) { + if c.flagErrorFunc != nil { + return c.flagErrorFunc + } + + if c.HasParent() { + return c.parent.FlagErrorFunc() + } + return func(c *Command, err error) error { + return err + } +} + var minUsagePadding = 25 +// UsagePadding return padding for the usage. func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding @@ -268,7 +309,7 @@ func (c *Command) UsagePadding() int { var minCommandPathPadding = 11 -// +// CommandPathPadding return padding for the command path. func (c *Command) CommandPathPadding() int { if c.parent == nil || minCommandPathPadding > c.parent.commandsMaxCommandPathLen { return minCommandPathPadding @@ -278,6 +319,7 @@ func (c *Command) CommandPathPadding() int { var minNamePadding = 11 +// NamePadding returns padding for the name. func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding @@ -285,6 +327,7 @@ func (c *Command) NamePadding() int { return c.parent.commandsMaxNameLen } +// UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { if c.usageTemplate != "" { return c.usageTemplate @@ -298,28 +341,28 @@ func (c *Command) UsageTemplate() string { {{ .CommandPath}} [command]{{end}}{{if gt .Aliases 0}} Aliases: - {{.NameAndAliases}} -{{end}}{{if .HasExample}} + {{.NameAndAliases}}{{end}}{{if .HasExample}} Examples: -{{ .Example }}{{end}}{{ if .HasAvailableSubCommands}} +{{ .Example }}{{end}}{{if .HasAvailableSubCommands}} -Available Commands:{{range .Commands}}{{if .IsAvailableCommand}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableLocalFlags}} +Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} Flags: -{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{ if .HasAvailableInheritedFlags}} +{{.LocalFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasAvailableInheritedFlags}} Global Flags: {{.InheritedFlags.FlagUsages | trimRightSpace}}{{end}}{{if .HasHelpSubCommands}} -Additional help topics:{{range .Commands}}{{if .IsHelpCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{ if .HasAvailableSubCommands }} +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} ` } +// HelpTemplate return help template for the command. func (c *Command) HelpTemplate() string { if c.helpTemplate != "" { return c.helpTemplate @@ -340,20 +383,18 @@ func (c *Command) resetChildrensParents() { } } -// Test if the named flag is a boolean flag. -func isBooleanFlag(name string, f *flag.FlagSet) bool { +func hasNoOptDefVal(name string, f *flag.FlagSet) bool { flag := f.Lookup(name) if flag == nil { return false } - return flag.Value.Type() == "bool" + return len(flag.NoOptDefVal) > 0 } -// Test if the named flag is a boolean flag. -func isBooleanShortFlag(name string, f *flag.FlagSet) bool { +func shortHasNoOptDefVal(name string, fs *flag.FlagSet) bool { result := false - f.VisitAll(func(f *flag.Flag) { - if f.Shorthand == name && f.Value.Type() == "bool" { + fs.VisitAll(func(flag *flag.Flag) { + if flag.Shorthand == name && len(flag.NoOptDefVal) > 0 { result = true } }) @@ -379,13 +420,13 @@ func stripFlags(args []string, c *Command) []string { inQuote = true case strings.HasPrefix(y, "--") && !strings.Contains(y, "="): // TODO: this isn't quite right, we should really check ahead for 'true' or 'false' - inFlag = !isBooleanFlag(y[2:], c.Flags()) - case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !isBooleanShortFlag(y[1:], c.Flags()): + inFlag = !hasNoOptDefVal(y[2:], c.Flags()) + case strings.HasPrefix(y, "-") && !strings.Contains(y, "=") && len(y) == 2 && !shortHasNoOptDefVal(y[1:], c.Flags()): inFlag = true case inFlag: inFlag = false case y == "": - // strip empty commands, as the go tests expect this to be ok.... + // strip empty commands, as the go tests expect this to be ok.... case !strings.HasPrefix(y, "-"): commands = append(commands, y) inFlag = false @@ -414,7 +455,7 @@ func argsMinusFirstX(args []string, x string) []string { return args } -// find the target command given the args and command tree +// Find the target command given the args and command tree // Meant to be run on the highest node. Only searches down. func (c *Command) Find(args []string) (*Command, []string, error) { if c == nil { @@ -482,6 +523,7 @@ func (c *Command) Find(args []string) (*Command, []string, error) { return commandFound, a, nil } +// SuggestionsFor provides suggestions for the typedName. func (c *Command) SuggestionsFor(typedName string) []string { suggestions := []string{} for _, cmd := range c.commands { @@ -502,6 +544,7 @@ func (c *Command) SuggestionsFor(typedName string) []string { return suggestions } +// VisitParents visits all parents of the command and invokes fn on each parent. func (c *Command) VisitParents(fn func(*Command)) { var traverse func(*Command) *Command @@ -517,6 +560,7 @@ func (c *Command) VisitParents(fn func(*Command)) { traverse(c) } +// Root finds root command. func (c *Command) Root() *Command { var findRoot func(*Command) *Command @@ -553,7 +597,7 @@ func (c *Command) execute(a []string) (err error) { err = c.ParseFlags(a) if err != nil { - return err + return c.FlagErrorFunc()(c, err) } // If help is called, regardless of other flags, return we want help // Also say we need help if the command isn't runnable. @@ -641,7 +685,7 @@ func (c *Command) errorMsgFromParse() string { return "" } -// Call execute to use the args (os.Args[1:] by default) +// Execute Call execute to use the args (os.Args[1:] by default) // and run through the command tree finding appropriate matches // for commands and then corresponding flags. func (c *Command) Execute() error { @@ -649,8 +693,8 @@ func (c *Command) Execute() error { return err } +// ExecuteC executes the command. func (c *Command) ExecuteC() (cmd *Command, err error) { - // Regardless of what command execute is called on, run on Root only if c.HasParent() { return c.Root().ExecuteC() @@ -712,6 +756,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { } func (c *Command) initHelpFlag() { + c.mergePersistentFlags() if c.Flags().Lookup("help") == nil { c.Flags().BoolP("help", "h", false, "help for "+c.Name()) } @@ -734,7 +779,7 @@ func (c *Command) initHelpCmd() { Run: func(c *Command, args []string) { cmd, _, e := c.Root().Find(args) if cmd == nil || e != nil { - c.Printf("Unknown help topic %#q.", args) + c.Printf("Unknown help topic %#q\n", args) c.Root().Usage() } else { cmd.Help() @@ -742,10 +787,11 @@ func (c *Command) initHelpCmd() { }, } } + c.RemoveCommand(c.helpCommand) c.AddCommand(c.helpCommand) } -// Used for testing. +// ResetCommands used for testing. func (c *Command) ResetCommands() { c.commands = nil c.helpCommand = nil @@ -868,7 +914,7 @@ func (c *Command) UseLine() string { return str + c.Use } -// For use in determining which flags have been assigned to which commands +// DebugFlags used to determine which flags have been assigned to which commands // and which persist. func (c *Command) DebugFlags() { c.Println("DebugFlags called on", c.Name()) @@ -923,7 +969,8 @@ func (c *Command) Name() string { if i >= 0 { name = name[:i] } - return name + c.name = name + return c.name } // HasAlias determines if a given string is an alias of the command. @@ -936,10 +983,12 @@ func (c *Command) HasAlias(s string) bool { return false } +// NameAndAliases returns string containing name and all aliases func (c *Command) NameAndAliases() string { return strings.Join(append([]string{c.Name()}, c.Aliases...), ", ") } +// HasExample determines if the command has example. func (c *Command) HasExample() bool { return len(c.Example) > 0 } @@ -972,11 +1021,12 @@ func (c *Command) IsAvailableCommand() bool { return false } -// IsHelpCommand determines if a command is a 'help' command; a help command is -// determined by the fact that it is NOT runnable/hidden/deprecated, and has no -// sub commands that are runnable/hidden/deprecated. -func (c *Command) IsHelpCommand() bool { - +// IsAdditionalHelpTopicCommand determines if a command is an additional +// help topic command; additional help topic command is determined by the +// fact that it is NOT runnable/hidden/deprecated, and has no sub commands that +// are runnable/hidden/deprecated. +// Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. +func (c *Command) IsAdditionalHelpTopicCommand() bool { // if a command is runnable, deprecated, or hidden it is not a 'help' command if c.Runnable() || len(c.Deprecated) != 0 || c.Hidden { return false @@ -984,7 +1034,7 @@ func (c *Command) IsHelpCommand() bool { // if any non-help sub commands are found, the command is not a 'help' command for _, sub := range c.commands { - if !sub.IsHelpCommand() { + if !sub.IsAdditionalHelpTopicCommand() { return false } } @@ -997,10 +1047,9 @@ func (c *Command) IsHelpCommand() bool { // that need to be shown in the usage/help default template under 'additional help // topics'. func (c *Command) HasHelpSubCommands() bool { - // return true on the first found available 'help' sub command for _, sub := range c.commands { - if sub.IsHelpCommand() { + if sub.IsAdditionalHelpTopicCommand() { return true } } @@ -1012,7 +1061,6 @@ func (c *Command) HasHelpSubCommands() bool { // HasAvailableSubCommands determines if a command has available sub commands that // need to be shown in the usage/help default template under 'available commands'. func (c *Command) HasAvailableSubCommands() bool { - // return true on the first found available (non deprecated/help/hidden) // sub command for _, sub := range c.commands { @@ -1036,7 +1084,7 @@ func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) f return c.globNormFunc } -// Flage returns the complete FlagSet that applies +// Flags returns the complete FlagSet that applies // to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { @@ -1136,44 +1184,44 @@ func (c *Command) ResetFlags() { c.pflags.SetOutput(c.flagErrorBuf) } -// Does the command contain any flags (local plus persistent from the entire structure). +// HasFlags checks if the command contains any flags (local plus persistent from the entire structure). func (c *Command) HasFlags() bool { return c.Flags().HasFlags() } -// Does the command contain persistent flags. +// HasPersistentFlags checks if the command contains persistent flags. func (c *Command) HasPersistentFlags() bool { return c.PersistentFlags().HasFlags() } -// Does the command has flags specifically declared locally. +// HasLocalFlags checks if the command has flags specifically declared locally. func (c *Command) HasLocalFlags() bool { return c.LocalFlags().HasFlags() } -// Does the command have flags inherited from its parent command. +// HasInheritedFlags checks if the command has flags inherited from its parent command. func (c *Command) HasInheritedFlags() bool { return c.InheritedFlags().HasFlags() } -// Does the command contain any flags (local plus persistent from the entire +// HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire // structure) which are not hidden or deprecated. func (c *Command) HasAvailableFlags() bool { return c.Flags().HasAvailableFlags() } -// Does the command contain persistent flags which are not hidden or deprecated. +// HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. func (c *Command) HasAvailablePersistentFlags() bool { return c.PersistentFlags().HasAvailableFlags() } -// Does the command has flags specifically declared locally which are not hidden +// HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden // or deprecated. func (c *Command) HasAvailableLocalFlags() bool { return c.LocalFlags().HasAvailableFlags() } -// Does the command have flags inherited from its parent command which are +// HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are // not hidden or deprecated. func (c *Command) HasAvailableInheritedFlags() bool { return c.InheritedFlags().HasAvailableFlags() diff --git a/vendor/src/github.com/spf13/cobra/command_test.go b/vendor/src/github.com/spf13/cobra/command_test.go index b0c17e29c..8b78ee346 100644 --- a/vendor/src/github.com/spf13/cobra/command_test.go +++ b/vendor/src/github.com/spf13/cobra/command_test.go @@ -1,6 +1,8 @@ package cobra import ( + "bytes" + "fmt" "os" "reflect" "testing" @@ -134,6 +136,20 @@ func Test_DisableFlagParsing(t *testing.T) { } } +func TestInitHelpFlagMergesFlags(t *testing.T) { + usage := "custom flag" + baseCmd := Command{Use: "testcmd"} + baseCmd.PersistentFlags().Bool("help", false, usage) + cmd := Command{Use: "do"} + baseCmd.AddCommand(&cmd) + + cmd.initHelpFlag() + actual := cmd.Flags().Lookup("help").Usage + if actual != usage { + t.Fatalf("Expected the help flag from the base command with usage '%s', but got the default with usage '%s'", usage, actual) + } +} + func TestCommandsAreSorted(t *testing.T) { EnableCommandSorting = true @@ -174,3 +190,35 @@ func TestEnableCommandSortingIsDisabled(t *testing.T) { EnableCommandSorting = true } + +func TestSetOutput(t *testing.T) { + cmd := &Command{} + cmd.SetOutput(nil) + if out := cmd.OutOrStdout(); out != os.Stdout { + t.Fatalf("expected setting output to nil to revert back to stdout, got %v", out) + } +} + +func TestFlagErrorFunc(t *testing.T) { + + cmd := &Command{ + Use: "print", + RunE: func(cmd *Command, args []string) error { + return nil + }, + } + expectedFmt := "This is expected: %s" + + cmd.SetFlagErrorFunc(func(c *Command, err error) error { + return fmt.Errorf(expectedFmt, err) + }) + cmd.SetArgs([]string{"--bogus-flag"}) + cmd.SetOutput(new(bytes.Buffer)) + + err := cmd.Execute() + + expected := fmt.Sprintf(expectedFmt, "unknown flag: --bogus-flag") + if err.Error() != expected { + t.Errorf("expected %v, got %v", expected, err.Error()) + } +} diff --git a/vendor/src/github.com/spf13/cobra/doc/man_docs.go b/vendor/src/github.com/spf13/cobra/doc/man_docs.go index 5798d0fbf..b9266c367 100644 --- a/vendor/src/github.com/spf13/cobra/doc/man_docs.go +++ b/vendor/src/github.com/spf13/cobra/doc/man_docs.go @@ -37,7 +37,7 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return GenManTreeFromOpts(cmd, GenManTreeOptions{ Header: header, Path: dir, - CommandSeparator: "_", + CommandSeparator: "-", }) } @@ -49,7 +49,7 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { header = &GenManHeader{} } for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenManTreeFromOpts(c, opts); err != nil { @@ -216,7 +216,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { children := cmd.Commands() sort.Sort(byName(children)) for _, c := range children { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } seealso := fmt.Sprintf("**%s-%s(%s)**", dashCommandName, c.Name(), header.Section) diff --git a/vendor/src/github.com/spf13/cobra/doc/man_docs.md b/vendor/src/github.com/spf13/cobra/doc/man_docs.md index 5fe957a35..d568d9a03 100644 --- a/vendor/src/github.com/spf13/cobra/doc/man_docs.md +++ b/vendor/src/github.com/spf13/cobra/doc/man_docs.md @@ -15,7 +15,7 @@ func main() { Use: "test", Short: "my test program", } - header := &cobra.GenManHeader{ + header := &doc.GenManHeader{ Title: "MINE", Section: "3", } @@ -23,4 +23,4 @@ func main() { } ``` -That will get you a man page `/tmp/test.1` +That will get you a man page `/tmp/test.3` diff --git a/vendor/src/github.com/spf13/cobra/doc/man_examples_test.go b/vendor/src/github.com/spf13/cobra/doc/man_examples_test.go index 3593853b0..db6604268 100644 --- a/vendor/src/github.com/spf13/cobra/doc/man_examples_test.go +++ b/vendor/src/github.com/spf13/cobra/doc/man_examples_test.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra/doc" ) -func ExampleCommand_GenManTree() { +func ExampleGenManTree() { cmd := &cobra.Command{ Use: "test", Short: "my test program", @@ -20,7 +20,7 @@ func ExampleCommand_GenManTree() { doc.GenManTree(cmd, header, "/tmp") } -func ExampleCommand_GenMan() { +func ExampleGenMan() { cmd := &cobra.Command{ Use: "test", Short: "my test program", diff --git a/vendor/src/github.com/spf13/cobra/doc/md_docs.go b/vendor/src/github.com/spf13/cobra/doc/md_docs.go index fa1363180..8d159c1d7 100644 --- a/vendor/src/github.com/spf13/cobra/doc/md_docs.go +++ b/vendor/src/github.com/spf13/cobra/doc/md_docs.go @@ -119,7 +119,7 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) sort.Sort(byName(children)) for _, child := range children { - if !child.IsAvailableCommand() || child.IsHelpCommand() { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { continue } cname := name + " " + child.Name() @@ -149,7 +149,7 @@ func GenMarkdownTree(cmd *cobra.Command, dir string) error { func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } if err := GenMarkdownTreeCustom(c, dir, filePrepender, linkHandler); err != nil { diff --git a/vendor/src/github.com/spf13/cobra/doc/md_docs.md b/vendor/src/github.com/spf13/cobra/doc/md_docs.md index 0c3b96e27..beec3e0e8 100644 --- a/vendor/src/github.com/spf13/cobra/doc/md_docs.md +++ b/vendor/src/github.com/spf13/cobra/doc/md_docs.md @@ -32,15 +32,15 @@ import ( "io/ioutil" "os" - kubectlcmd "k8s.io/kubernetes/pkg/kubectl/cmd" + "k8s.io/kubernetes/pkg/kubectl/cmd" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "github.com/spf13/cobra/doc" ) func main() { - cmd := kubectlcmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) - doc.GenMarkdownTree(cmd, "./") + kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) + doc.GenMarkdownTree(kubectl, "./") } ``` @@ -101,4 +101,3 @@ linkHandler := func(name string) string { return "/commands/" + strings.ToLower(base) + "/" } ``` - diff --git a/vendor/src/github.com/spf13/cobra/doc/util.go b/vendor/src/github.com/spf13/cobra/doc/util.go index a1c6b89ba..8d3dbecec 100644 --- a/vendor/src/github.com/spf13/cobra/doc/util.go +++ b/vendor/src/github.com/spf13/cobra/doc/util.go @@ -13,7 +13,11 @@ package doc -import "github.com/spf13/cobra" +import ( + "strings" + + "github.com/spf13/cobra" +) // Test to see if we have a reason to print See Also information in docs // Basically this is a test for a parent commend or a subcommand which is @@ -23,7 +27,7 @@ func hasSeeAlso(cmd *cobra.Command) bool { return true } for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } return true @@ -31,6 +35,15 @@ func hasSeeAlso(cmd *cobra.Command) bool { return false } +// Temporary workaround for yaml lib generating incorrect yaml with long strings +// that do not contain \n. +func forceMultiLine(s string) string { + if len(s) > 60 && !strings.Contains(s, "\n") { + s = s + "\n" + } + return s +} + type byName []*cobra.Command func (s byName) Len() int { return len(s) } diff --git a/vendor/src/github.com/spf13/cobra/doc/yaml_docs.go b/vendor/src/github.com/spf13/cobra/doc/yaml_docs.go new file mode 100644 index 000000000..ac8db89eb --- /dev/null +++ b/vendor/src/github.com/spf13/cobra/doc/yaml_docs.go @@ -0,0 +1,165 @@ +// Copyright 2016 French Ben. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package doc + +import ( + "fmt" + "io" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "gopkg.in/yaml.v2" +) + +type cmdOption struct { + Name string + Shorthand string `yaml:",omitempty"` + DefaultValue string `yaml:"default_value,omitempty"` + Usage string `yaml:",omitempty"` +} + +type cmdDoc struct { + Name string + Synopsis string `yaml:",omitempty"` + Description string `yaml:",omitempty"` + Options []cmdOption `yaml:",omitempty"` + InheritedOptions []cmdOption `yaml:"inherited_options,omitempty"` + Example string `yaml:",omitempty"` + SeeAlso []string `yaml:"see_also,omitempty"` +} + +// GenYamlTree creates yaml structured ref files for this command and all descendants +// in the directory given. This function may not work +// correctly if your command names have - in them. If you have `cmd` with two +// subcmds, `sub` and `sub-third`. And `sub` has a subcommand called `third` +// it is undefined which help output will be in the file `cmd-sub-third.1`. +func GenYamlTree(cmd *cobra.Command, dir string) error { + identity := func(s string) string { return s } + emptyStr := func(s string) string { return "" } + return GenYamlTreeCustom(cmd, dir, emptyStr, identity) +} + +// GenYamlTreeCustom creates yaml structured ref files +func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { + continue + } + if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil { + return err + } + } + + basename := strings.Replace(cmd.CommandPath(), " ", "_", -1) + ".yaml" + filename := filepath.Join(dir, basename) + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.WriteString(f, filePrepender(filename)); err != nil { + return err + } + if err := GenYamlCustom(cmd, f, linkHandler); err != nil { + return err + } + return nil +} + +// GenYaml creates yaml output +func GenYaml(cmd *cobra.Command, w io.Writer) error { + return GenYamlCustom(cmd, w, func(s string) string { return s }) +} + +// GenYamlCustom creates custom yaml output +func GenYamlCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { + yamlDoc := cmdDoc{} + yamlDoc.Name = cmd.CommandPath() + + yamlDoc.Synopsis = forceMultiLine(cmd.Short) + yamlDoc.Description = forceMultiLine(cmd.Long) + + if len(cmd.Example) > 0 { + yamlDoc.Example = cmd.Example + } + + flags := cmd.NonInheritedFlags() + if flags.HasFlags() { + yamlDoc.Options = genFlagResult(flags) + } + flags = cmd.InheritedFlags() + if flags.HasFlags() { + yamlDoc.InheritedOptions = genFlagResult(flags) + } + + if hasSeeAlso(cmd) { + result := []string{} + if cmd.HasParent() { + parent := cmd.Parent() + result = append(result, parent.CommandPath()+" - "+parent.Short) + } + children := cmd.Commands() + sort.Sort(byName(children)) + for _, child := range children { + if !child.IsAvailableCommand() || child.IsAdditionalHelpTopicCommand() { + continue + } + result = append(result, child.Name()+" - "+child.Short) + } + yamlDoc.SeeAlso = result + } + + final, err := yaml.Marshal(&yamlDoc) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if _, err := fmt.Fprintf(w, string(final)); err != nil { + return err + } + return nil +} + +func genFlagResult(flags *pflag.FlagSet) []cmdOption { + var result []cmdOption + + flags.VisitAll(func(flag *pflag.Flag) { + // Todo, when we mark a shorthand is deprecated, but specify an empty message. + // The flag.ShorthandDeprecated is empty as the shorthand is deprecated. + // Using len(flag.ShorthandDeprecated) > 0 can't handle this, others are ok. + if !(len(flag.ShorthandDeprecated) > 0) && len(flag.Shorthand) > 0 { + opt := cmdOption{ + flag.Name, + flag.Shorthand, + flag.DefValue, + forceMultiLine(flag.Usage), + } + result = append(result, opt) + } else { + opt := cmdOption{ + Name: flag.Name, + DefaultValue: forceMultiLine(flag.DefValue), + Usage: forceMultiLine(flag.Usage), + } + result = append(result, opt) + } + }) + + return result +} diff --git a/vendor/src/github.com/spf13/cobra/doc/yaml_docs.md b/vendor/src/github.com/spf13/cobra/doc/yaml_docs.md new file mode 100644 index 000000000..4d0c75a12 --- /dev/null +++ b/vendor/src/github.com/spf13/cobra/doc/yaml_docs.md @@ -0,0 +1,103 @@ +# Generating Yaml Docs For Your Own cobra.Command + +Generating yaml files from a cobra command is incredibly easy. An example is as follows: + +```go +package main + +import ( + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +func main() { + cmd := &cobra.Command{ + Use: "test", + Short: "my test program", + } + doc.GenYamlTree(cmd, "/tmp") +} +``` + +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 + +```go +package main + +import ( + "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) + doc.GenYamlTree(kubectl, "./") +} +``` + +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` + +```go + 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: + +```go +func GenYamlTreeCustom(cmd *Command, dir string, filePrepender, linkHandler func(string) string) error { + //... +} +``` + +```go +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](http://gohugo.io/): + +```go +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: + +```go +linkHandler := func(name string) string { + base := strings.TrimSuffix(name, path.Ext(name)) + return "/commands/" + strings.ToLower(base) + "/" +} +``` diff --git a/vendor/src/github.com/spf13/cobra/doc/yaml_docs_test.go b/vendor/src/github.com/spf13/cobra/doc/yaml_docs_test.go new file mode 100644 index 000000000..a41499e1f --- /dev/null +++ b/vendor/src/github.com/spf13/cobra/doc/yaml_docs_test.go @@ -0,0 +1,88 @@ +package doc + +import ( + "bytes" + "fmt" + "os" + "strings" + "testing" +) + +var _ = fmt.Println +var _ = os.Stderr + +func TestGenYamlDoc(t *testing.T) { + c := initializeWithRootCmd() + // Need two commands to run the command alphabetical sort + cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) + c.AddCommand(cmdPrint, cmdEcho) + cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) + + out := new(bytes.Buffer) + + // We generate on s subcommand so we have both subcommands and parents + if err := GenYaml(cmdEcho, out); err != nil { + t.Fatal(err) + } + found := out.String() + + // Our description + expected := cmdEcho.Long + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // Better have our example + expected = cmdEcho.Example + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // A local flag + expected = "boolone" + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // persistent flag on parent + expected = "rootflag" + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // We better output info about our parent + expected = cmdRootWithRun.Short + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + // And about subcommands + expected = cmdEchoSub.Short + if !strings.Contains(found, expected) { + t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) + } + + unexpected := cmdDeprecated.Short + if strings.Contains(found, unexpected) { + t.Errorf("Unexpected response.\nFound: %v\nBut should not have!!\n", unexpected) + } +} + +func TestGenYamlNoTag(t *testing.T) { + c := initializeWithRootCmd() + // Need two commands to run the command alphabetical sort + cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) + c.AddCommand(cmdPrint, cmdEcho) + c.DisableAutoGenTag = true + cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) + out := new(bytes.Buffer) + + if err := GenYaml(c, out); err != nil { + t.Fatal(err) + } + found := out.String() + + unexpected := "Auto generated" + checkStringOmits(t, found, unexpected) + +}