diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 4ed81359420..d97bb1ba8c0 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -484,7 +484,7 @@ }, { "ImportPath": "github.com/spf13/cobra", - "Rev": "69e5f196b5d30673deb07a2221d89cf62e4b74ae" + "Rev": "bba56042cf767e329430e7c7f68c3f9f640b4b8b" }, { "ImportPath": "github.com/spf13/pflag", diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/README.md b/Godeps/_workspace/src/github.com/spf13/cobra/README.md index 95e91324755..710b66eb29c 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/README.md +++ b/Godeps/_workspace/src/github.com/spf13/cobra/README.md @@ -348,6 +348,76 @@ Like help the function and template are over ridable through public methods. command.SetUsageTemplate(s string) +## PreRun or 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`. `PersistendPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherrited by children if they do not declare their own. These function are run in the following order: + +- `PersistentPreRun` +- `PreRun` +- `Run` +- `PostRun` +- `PersistenPostRun` + +And example of two commands which use all of these features is below. When the subcommand in executed it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun` + +```go +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 sub command", + 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.Print("\n") + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + _ = rootCmd.Execute() +} +``` + ## Generating markdown formatted documentation for your command Cobra can generate a markdown formatted document based on the subcommands, flags, etc. A simple example of how to do this for your command can be found in [Markdown Docs](md_docs.md) diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go index dee95b31cab..735d2f54c55 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.go @@ -22,7 +22,7 @@ func preamble(out *bytes.Buffer) { __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then - echo "$*" >> ${BASH_COMP_DEBUG_FILE} + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -93,6 +93,13 @@ __handle_reply() fi } +# The arguments should be in the form "ext1|ext2|extn" +__handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + __handle_flag() { __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" @@ -173,10 +180,9 @@ __handle_word() func postscript(out *bytes.Buffer, name string) { fmt.Fprintf(out, "__start_%s()\n", name) fmt.Fprintf(out, `{ - local cur prev words cword split + local cur prev words cword _init_completion -s || return - local completions_func local c=0 local flags=() local two_word_flags=() @@ -199,6 +205,9 @@ func postscript(out *bytes.Buffer, name string) { func writeCommands(cmd *Command, out *bytes.Buffer) { fmt.Fprintf(out, " commands=()\n") for _, c := range cmd.Commands() { + if len(c.Deprecated) > 0 { + continue + } fmt.Fprintf(out, " commands+=(%q)\n", c.Name()) } fmt.Fprintf(out, "\n") @@ -211,7 +220,7 @@ func writeFlagHandler(name string, annotations map[string][]string, out *bytes.B fmt.Fprintf(out, " flags_with_completion+=(%q)\n", name) ext := strings.Join(value, "|") - ext = "_filedir '@(" + ext + ")'" + ext = "__handle_filename_extension_flag " + ext fmt.Fprintf(out, " flags_completion+=(%q)\n", ext) } } @@ -291,6 +300,9 @@ func writeRequiredNoun(cmd *Command, out *bytes.Buffer) { func gen(cmd *Command, out *bytes.Buffer) { for _, c := range cmd.Commands() { + if len(c.Deprecated) > 0 { + continue + } gen(c, out) } commandName := cmd.CommandPath() diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md index e1a5d56d00b..f6707ff03b9 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions.md @@ -123,15 +123,18 @@ and you'll get something like In this example we use --filename= and expect to get a json or yaml file as the argument. To make this easier we annotate the --filename flag with valid filename extensions. ```go - annotations := make([]string, 3) - annotations[0] = "json" - annotations[1] = "yaml" - annotations[2] = "yml" - + annotations := []string{"json", "yaml", "yml"} annotation := make(map[string][]string) annotation[cobra.BashCompFilenameExt] = annotations - flag := &pflag.Flag{"filename", "f", usage, value, value.String(), false, annotation} + flag := &pflag.Flag{ + Name: "filename", + Shorthand: "f", + Usage: usage, + Value: value, + DefValue: value.String(), + Annotations: annotation, + } cmd.Flags().AddFlag(flag) ``` diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go index 12dc96049cd..ee632cf49a1 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/bash_completions_test.go @@ -11,6 +11,12 @@ import ( var _ = fmt.Println var _ = os.Stderr +func checkOmit(t *testing.T, found, unexpected string) { + if strings.Contains(found, unexpected) { + t.Errorf("Unexpected response.\nGot: %q\nBut should not have!\n", unexpected) + } +} + func check(t *testing.T, found, expected string) { if !strings.Contains(found, expected) { t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) @@ -28,7 +34,7 @@ COMPREPLY=( "hello" ) func TestBashCompletions(t *testing.T) { c := initializeWithRootCmd() cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdEcho, cmdPrint) + c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated) // custom completion function c.BashCompletionFunction = bash_completion_func @@ -70,5 +76,7 @@ func TestBashCompletions(t *testing.T) { // check for required nouns check(t, str, `must_have_one_noun+=("pods")`) // check for filename extention flags - check(t, str, `flags_completion+=("_filedir '@(json|yaml|yml)'")`) + check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`) + + checkOmit(t, str, cmdDeprecated.Name()) } diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go index 6feb8e56fb2..56746495a89 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/cobra_test.go @@ -13,6 +13,7 @@ var _ = fmt.Println var _ = os.Stderr var tp, te, tt, t1 []string +var rootPersPre, echoPre, echoPersPre, timesPersPre []string var flagb1, flagb2, flagb3, flagbr, flagbp bool var flags1, flags2a, flags2b, flags3 string var flagi1, flagi2, flagi3, flagir int @@ -38,6 +39,12 @@ var cmdEcho = &Command{ Short: "Echo anything to the screen", Long: `an utterly useless command for testing.`, Example: "Just run cobra-test echo", + PersistentPreRun: func(cmd *Command, args []string) { + echoPersPre = args + }, + PreRun: func(cmd *Command, args []string) { + echoPre = args + }, Run: func(cmd *Command, args []string) { te = args }, @@ -51,10 +58,22 @@ var cmdEchoSub = &Command{ }, } +var cmdDeprecated = &Command{ + Use: "deprecated [can't do anything here]", + Short: "A command which is deprecated", + Long: `an absolutely utterly useless command for testing deprecation!.`, + Deprecated: "Please use echo instead", + Run: func(cmd *Command, args []string) { + }, +} + var cmdTimes = &Command{ Use: "times [# times] [string to echo]", Short: "Echo anything to the screen more times", Long: `a slightly useless command for testing.`, + PersistentPreRun: func(cmd *Command, args []string) { + timesPersPre = args + }, Run: func(cmd *Command, args []string) { tt = args }, @@ -64,6 +83,9 @@ var cmdRootNoRun = &Command{ Use: "cobra-test", Short: "The root can run it's own function", Long: "The root description for help", + PersistentPreRun: func(cmd *Command, args []string) { + rootPersPre = args + }, } var cmdRootSameName = &Command{ @@ -140,6 +162,8 @@ func commandInit() { func initialize() *Command { tt, tp, te = nil, nil, nil + rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil + var c = cmdRootNoRun flagInit() commandInit() @@ -148,6 +172,7 @@ func initialize() *Command { func initializeWithSameName() *Command { tt, tp, te = nil, nil, nil + rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil var c = cmdRootSameName flagInit() commandInit() @@ -205,7 +230,7 @@ func fullTester(c *Command, input string) resulter { // Testing flag with invalid input c.SetOutput(buf) cmdEcho.AddCommand(cmdTimes) - c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun) + c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdDeprecated) c.SetArgs(strings.Split(input, " ")) err := c.Execute() @@ -812,3 +837,52 @@ func TestReplaceCommandWithRemove(t *testing.T) { t.Errorf("Replacing command should have been called but didn't\n") } } + +func TestDeprecatedSub(t *testing.T) { + c := fullSetupTest("deprecated") + + checkResultContains(t, c, cmdDeprecated.Deprecated) +} + +func TestPreRun(t *testing.T) { + noRRSetupTest("echo one two") + if echoPre == nil || echoPersPre == nil { + t.Error("PreRun or PersistentPreRun not called") + } + if rootPersPre != nil || timesPersPre != nil { + t.Error("Wrong *Pre functions called!") + } + + noRRSetupTest("echo times one two") + if timesPersPre == nil { + t.Error("PreRun or PersistentPreRun not called") + } + if echoPre != nil || echoPersPre != nil || rootPersPre != nil { + t.Error("Wrong *Pre functions called!") + } + + noRRSetupTest("print one two") + if rootPersPre == nil { + t.Error("Parent PersistentPreRun not called but should not have been") + } + if echoPre != nil || echoPersPre != nil || timesPersPre != nil { + t.Error("Wrong *Pre functions called!") + } +} + +// Check if cmdEchoSub gets PersistentPreRun from rootCmd even if is added last +func TestPeristentPreRunPropagation(t *testing.T) { + rootCmd := initialize() + + // First add the cmdEchoSub to cmdPrint + cmdPrint.AddCommand(cmdEchoSub) + // Now add cmdPrint to rootCmd + rootCmd.AddCommand(cmdPrint) + + rootCmd.SetArgs(strings.Split("print echosub lala", " ")) + rootCmd.Execute() + + if rootPersPre == nil || len(rootPersPre) == 0 || rootPersPre[0] != "lala" { + t.Error("RootCmd PersistentPreRun not called but should have been") + } +} diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/command.go b/Godeps/_workspace/src/github.com/spf13/cobra/command.go index ef802c6704f..978c4b09634 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/command.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/command.go @@ -48,15 +48,31 @@ type Command struct { ValidArgs []string // Custom functions used by the bash autocompletion generator BashCompletionFunction string + // Is this command deprecated and should print this string when used? + Deprecated string // Full set of flags flags *flag.FlagSet // Set of flags childrens of this command will inherit pflags *flag.FlagSet // Flags that are declared specifically by this command (not inherited). lflags *flag.FlagSet - // Run runs the command. - // The args are the arguments after the command name. + // The *Run functions are executed in the following order: + // * PersistentPreRun() + // * PreRun() + // * Run() + // * PostRun() + // * PersistentPostRun() + // All functions get the same args, the arguments after the command name + // PersistentPreRun: children of this command will inherit and execute + PersistentPreRun func(cmd *Command, args []string) + // PreRun: children of this command will not inherit. + PreRun func(cmd *Command, args []string) + // Run: Typically the actual work function. Most commands will only implement this Run func(cmd *Command, args []string) + // PostRun: run after the Run command. + PostRun func(cmd *Command, args []string) + // PersistentPostRun: children of this command will inherit and execute after PostRun + PersistentPostRun func(cmd *Command, args []string) // Commands is the list of commands supported by this program. commands []*Command // Parent Command for this command @@ -231,7 +247,7 @@ Examples: {{ .Example }} {{end}}{{ if .HasRunnableSubCommands}} -Available Commands: {{range .Commands}}{{if .Runnable}} +Available Commands: {{range .Commands}}{{if and (.Runnable) (not .Deprecated)}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}} {{end}} {{ if .HasLocalFlags}}Flags: @@ -239,7 +255,7 @@ Available Commands: {{range .Commands}}{{if .Runnable}} {{ if .HasInheritedFlags}}Global Flags: {{.InheritedFlags.FlagUsages}}{{end}}{{if or (.HasHelpSubCommands) (.HasRunnableSiblings)}} Additional help topics: -{{if .HasHelpSubCommands}}{{range .Commands}}{{if not .Runnable}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasRunnableSiblings }}{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }} +{{if .HasHelpSubCommands}}{{range .Commands}}{{if and (not .Runnable) (not .Deprecated)}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasRunnableSiblings }}{{range .Parent.Commands}}{{if and (not .Runnable) (not .Deprecated)}}{{if not (eq .Name $cmd.Name) }} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{end}} {{end}}{{ if .HasSubCommands }} Use "{{.Root.Name}} help [command]" for more information about a command. @@ -414,6 +430,10 @@ func (c *Command) execute(a []string) (err error) { return fmt.Errorf("Called Execute() on a nil Command") } + if len(c.Deprecated) > 0 { + c.Printf("Command %q is deprecated, %s\n", c.Name(), c.Deprecated) + } + err = c.ParseFlags(a) if err == flag.ErrHelp { c.Help() @@ -432,19 +452,40 @@ func (c *Command) execute(a []string) (err error) { c.Usage() r.SetOutput(out) return err - } else { - // If help is called, regardless of other flags, we print that. - // Print help also if c.Run is nil. - if c.helpFlagVal || !c.Runnable() { - c.Help() - return nil - } - - c.preRun() - argWoFlags := c.Flags().Args() - c.Run(c, argWoFlags) + } + // If help is called, regardless of other flags, we print that. + // Print help also if c.Run is nil. + if c.helpFlagVal || !c.Runnable() { + c.Help() return nil } + + c.preRun() + argWoFlags := c.Flags().Args() + + for p := c; p != nil; p = p.Parent() { + if p.PersistentPreRun != nil { + p.PersistentPreRun(c, argWoFlags) + break + } + } + if c.PreRun != nil { + c.PreRun(c, argWoFlags) + } + + c.Run(c, argWoFlags) + + if c.PostRun != nil { + c.PostRun(c, argWoFlags) + } + for p := c; p != nil; p = p.Parent() { + if p.PersistentPostRun != nil { + p.PersistentPostRun(c, argWoFlags) + break + } + } + + return nil } func (c *Command) preRun() { @@ -495,20 +536,9 @@ func (c *Command) Execute() (err error) { args = c.args } - if len(args) == 0 { - // Only the executable is called and the root is runnable, run it - if c.Runnable() { - err = c.execute([]string(nil)) - } else { - c.Help() - } - } else { - cmd, flags, e := c.Find(args) - if e != nil { - err = e - } else { - err = cmd.execute(flags) - } + cmd, flags, err := c.Find(args) + if err == nil { + err = cmd.execute(flags) } if err != nil { @@ -535,7 +565,9 @@ func (c *Command) initHelp() { Short: "Help about any command", Long: `Help provides help for any command in the application. Simply type ` + c.Name() + ` help [path to command] for full details.`, - Run: c.HelpFunc(), + Run: c.HelpFunc(), + PersistentPreRun: func(cmd *Command, args []string) {}, + PersistentPostRun: func(cmd *Command, args []string) {}, } } c.AddCommand(c.helpCommand) @@ -948,6 +980,13 @@ func (c *Command) mergePersistentFlags() { c.PersistentFlags().VisitAll(addtolocal) } rmerge = func(x *Command) { + if !x.HasParent() { + flag.CommandLine.VisitAll(func(f *flag.Flag) { + if x.PersistentFlags().Lookup(f.Name) == nil { + x.PersistentFlags().AddFlag(f) + } + }) + } if x.HasPersistentFlags() { x.PersistentFlags().VisitAll(func(f *flag.Flag) { if c.Flags().Lookup(f.Name) == nil { diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go index ab5188e7540..4a57ebd0c6e 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs.go @@ -85,6 +85,9 @@ func GenMarkdown(cmd *Command, out *bytes.Buffer) { sort.Sort(byName(children)) for _, child := range children { + if len(child.Deprecated) > 0 { + continue + } cname := name + " " + child.Name() link := cname + ".md" link = strings.Replace(link, " ", "_", -1) diff --git a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go index fd11ad321d5..defc9411525 100644 --- a/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go +++ b/Godeps/_workspace/src/github.com/spf13/cobra/md_docs_test.go @@ -14,7 +14,7 @@ var _ = os.Stderr func TestGenMdDoc(t *testing.T) { c := initializeWithRootCmd() // Need two commands to run the command alphabetical sort - cmdEcho.AddCommand(cmdTimes, cmdEchoSub) + cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated) c.AddCommand(cmdPrint, cmdEcho) cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) @@ -59,4 +59,9 @@ func TestGenMdDoc(t *testing.T) { 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) + } } diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index f9fffc64e35..a31410c85eb 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -4,7 +4,7 @@ __debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then - echo "$*" >> ${BASH_COMP_DEBUG_FILE} + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -75,6 +75,13 @@ __handle_reply() fi } +# The arguments should be in the form "ext1|ext2|extn" +__handle_filename_extension_flag() +{ + local ext="$1" + _filedir "@(${ext})" +} + __handle_flag() { __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" @@ -297,10 +304,10 @@ _kubectl_create() flags+=("--filename=") flags_with_completion+=("--filename") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") two_word_flags+=("-f") flags_with_completion+=("-f") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--help") flags+=("-h") @@ -322,10 +329,10 @@ _kubectl_update() flags+=("--filename=") flags_with_completion+=("--filename") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") two_word_flags+=("-f") flags_with_completion+=("-f") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--help") flags+=("-h") flags+=("--patch=") @@ -351,10 +358,10 @@ _kubectl_delete() flags+=("--cascade") flags+=("--filename=") flags_with_completion+=("--filename") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") two_word_flags+=("-f") flags_with_completion+=("-f") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--grace-period=") flags+=("--help") flags+=("-h") @@ -575,10 +582,10 @@ _kubectl_stop() flags+=("--all") flags+=("--filename=") flags_with_completion+=("--filename") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") two_word_flags+=("-f") flags_with_completion+=("-f") - flags_completion+=("_filedir '@(json|yaml|yml)'") + flags_completion+=("__handle_filename_extension_flag json|yaml|yml") flags+=("--grace-period=") flags+=("--help") flags+=("-h") @@ -942,10 +949,9 @@ _kubectl() __start_kubectl() { - local cur prev words cword split + local cur prev words cword _init_completion -s || return - local completions_func local c=0 local flags=() local two_word_flags=()