diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/bash_completions.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/bash_completions.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/bash_completions.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/bash_completions.go 2017-03-28 14:04:07.000000000 +0000 @@ -10,6 +10,7 @@ "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 @@ if err != nil { return err } - _, err = fmt.Fprint(out, ` + preamStr := ` __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then @@ -246,7 +247,8 @@ __handle_word } -`) +` + _, err = fmt.Fprint(out, preamStr) return err } @@ -566,6 +568,7 @@ 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 @@ 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/bash_completions.md golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/bash_completions.md --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/bash_completions.md 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/bash_completions.md 2017-03-28 14:04:07.000000000 +0000 @@ -18,7 +18,7 @@ } ``` -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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/cobra.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/cobra.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/cobra.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/cobra.go 2017-03-28 14:04:07.000000000 +0000 @@ -37,7 +37,8 @@ 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 diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/command.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/command.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/command.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/command.go 2017-03-28 14:04:07.000000000 +0000 @@ -57,6 +57,9 @@ 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 @@ -129,7 +132,7 @@ 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 @@ -141,32 +144,33 @@ 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 } // SetFlagErrorFunc sets a function to generate an error when flag parsing -// fails +// fails. func (c *Command) SetFlagErrorFunc(f func(*Command, error) error) { c.flagErrorFunc = f } -// Can be defined by Application +// 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 } @@ -183,10 +187,12 @@ } } +// 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) } @@ -265,6 +271,7 @@ return nil } +// UsageString return usage string. func (c *Command) UsageString() string { tmpOutput := c.output bb := new(bytes.Buffer) @@ -292,6 +299,7 @@ var minUsagePadding = 25 +// UsagePadding return padding for the usage. func (c *Command) UsagePadding() int { if c.parent == nil || minUsagePadding > c.parent.commandsMaxUseLen { return minUsagePadding @@ -301,7 +309,7 @@ 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 @@ -311,6 +319,7 @@ var minNamePadding = 11 +// NamePadding returns padding for the name. func (c *Command) NamePadding() int { if c.parent == nil || minNamePadding > c.parent.commandsMaxNameLen { return minNamePadding @@ -318,6 +327,7 @@ return c.parent.commandsMaxNameLen } +// UsageTemplate returns usage template for the command. func (c *Command) UsageTemplate() string { if c.usageTemplate != "" { return c.usageTemplate @@ -335,24 +345,25 @@ {{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 @@ -373,20 +384,18 @@ } } -// 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 } }) @@ -412,13 +421,13 @@ 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 @@ -447,7 +456,7 @@ 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 { @@ -515,6 +524,7 @@ return commandFound, a, nil } +// SuggestionsFor provides suggestions for the typedName. func (c *Command) SuggestionsFor(typedName string) []string { suggestions := []string{} for _, cmd := range c.commands { @@ -535,6 +545,7 @@ 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 @@ -550,6 +561,7 @@ traverse(c) } +// Root finds root command. func (c *Command) Root() *Command { var findRoot func(*Command) *Command @@ -674,7 +686,7 @@ 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 { @@ -682,8 +694,8 @@ 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() @@ -768,7 +780,7 @@ 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() @@ -776,10 +788,11 @@ }, } } + 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 @@ -902,7 +915,7 @@ 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()) @@ -957,7 +970,8 @@ 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. @@ -970,10 +984,12 @@ 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 } @@ -1006,11 +1022,12 @@ 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 @@ -1018,7 +1035,7 @@ // 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 } } @@ -1031,10 +1048,9 @@ // 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 } } @@ -1046,7 +1062,6 @@ // 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 { @@ -1070,7 +1085,7 @@ 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 { @@ -1170,44 +1185,44 @@ 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/debian/changelog golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/debian/changelog --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/debian/changelog 2017-01-01 19:32:53.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/debian/changelog 2017-03-28 14:27:29.000000000 +0000 @@ -1,3 +1,10 @@ +golang-github-spf13-cobra (0.0~git20170314.0.7be4bed-1) unstable; urgency=medium + + * New upstream version 0.0~git20170314.0.7be4bed + * Added Michael Lustfield to uploaders + + -- Michael Lustfield Tue, 28 Mar 2017 09:27:29 -0500 + golang-github-spf13-cobra (0.0~git20161229.0.1dd5ff2-1) unstable; urgency=medium [ Paul Tagliamonte ] diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/debian/control golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/debian/control --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/debian/control 2016-12-29 09:00:46.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/debian/control 2017-03-28 14:14:29.000000000 +0000 @@ -2,7 +2,9 @@ Section: devel Priority: extra Maintainer: Debian Go Packaging Team -Uploaders: Anthony Fok , Tim Potter +Uploaders: Anthony Fok , + Tim Potter , + Michael Lustfield Build-Depends: debhelper (>= 9), dh-golang, golang-any, diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/man_docs.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/man_docs.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/man_docs.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/man_docs.go 2017-03-28 14:04:07.000000000 +0000 @@ -49,7 +49,7 @@ 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 @@ 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/md_docs.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/md_docs.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/md_docs.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/md_docs.go 2017-03-28 14:04:07.000000000 +0000 @@ -119,7 +119,7 @@ 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 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/md_docs.md golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/md_docs.md --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/md_docs.md 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/md_docs.md 2017-03-28 14:04:07.000000000 +0000 @@ -32,15 +32,15 @@ "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, "./") } ``` diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/util.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/util.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/util.go 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/util.go 2017-03-28 14:04:07.000000000 +0000 @@ -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 @@ return true } for _, c := range cmd.Commands() { - if !c.IsAvailableCommand() || c.IsHelpCommand() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } return true @@ -31,6 +35,15 @@ 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs.go 2017-03-28 14:04:07.000000000 +0000 @@ -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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs.md golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs.md --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs.md 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs.md 2017-03-28 14:04:07.000000000 +0000 @@ -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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs_test.go golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs_test.go --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/doc/yaml_docs_test.go 1970-01-01 00:00:00.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/doc/yaml_docs_test.go 2017-03-28 14:04:07.000000000 +0000 @@ -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) + +} diff -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/README.md golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/README.md --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/README.md 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/README.md 2017-03-28 14:04:07.000000000 +0000 @@ -8,6 +8,7 @@ * [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) @@ -755,7 +756,7 @@ * 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 -Nru golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/.travis.yml golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/.travis.yml --- golang-github-spf13-cobra-0.0~git20161229.0.1dd5ff2/.travis.yml 2017-01-01 19:25:42.000000000 +0000 +++ golang-github-spf13-cobra-0.0~git20170314.0.7be4bed/.travis.yml 2017-03-28 14:04:07.000000000 +0000 @@ -5,8 +5,9 @@ - go: 1.4.3 env: NOVET=true # No bundled vet. - go: 1.5.4 - - go: 1.6.3 - - go: 1.7 + - go: 1.6.4 + - go: 1.7.5 + - go: 1.8 - go: tip allow_failures: - go: tip