Merge pull request #7776 from eparis/minor-bash-fixes

Cobra update and bash completions fix
This commit is contained in:
Jeff Lowdermilk 2015-05-05 17:12:39 -07:00
commit 221553b147
10 changed files with 276 additions and 56 deletions

2
Godeps/Godeps.json generated
View File

@ -484,7 +484,7 @@
}, },
{ {
"ImportPath": "github.com/spf13/cobra", "ImportPath": "github.com/spf13/cobra",
"Rev": "69e5f196b5d30673deb07a2221d89cf62e4b74ae" "Rev": "bba56042cf767e329430e7c7f68c3f9f640b4b8b"
}, },
{ {
"ImportPath": "github.com/spf13/pflag", "ImportPath": "github.com/spf13/pflag",

View File

@ -348,6 +348,76 @@ Like help the function and template are over ridable through public methods.
command.SetUsageTemplate(s string) 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 ## 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) 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)

View File

@ -22,7 +22,7 @@ func preamble(out *bytes.Buffer) {
__debug() __debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> ${BASH_COMP_DEBUG_FILE} echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
fi fi
} }
@ -93,6 +93,13 @@ __handle_reply()
fi fi
} }
# The arguments should be in the form "ext1|ext2|extn"
__handle_filename_extension_flag()
{
local ext="$1"
_filedir "@(${ext})"
}
__handle_flag() __handle_flag()
{ {
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
@ -173,10 +180,9 @@ __handle_word()
func postscript(out *bytes.Buffer, name string) { func postscript(out *bytes.Buffer, name string) {
fmt.Fprintf(out, "__start_%s()\n", name) fmt.Fprintf(out, "__start_%s()\n", name)
fmt.Fprintf(out, `{ fmt.Fprintf(out, `{
local cur prev words cword split local cur prev words cword
_init_completion -s || return _init_completion -s || return
local completions_func
local c=0 local c=0
local flags=() local flags=()
local two_word_flags=() local two_word_flags=()
@ -199,6 +205,9 @@ func postscript(out *bytes.Buffer, name string) {
func writeCommands(cmd *Command, out *bytes.Buffer) { func writeCommands(cmd *Command, out *bytes.Buffer) {
fmt.Fprintf(out, " commands=()\n") fmt.Fprintf(out, " commands=()\n")
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if len(c.Deprecated) > 0 {
continue
}
fmt.Fprintf(out, " commands+=(%q)\n", c.Name()) fmt.Fprintf(out, " commands+=(%q)\n", c.Name())
} }
fmt.Fprintf(out, "\n") 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) fmt.Fprintf(out, " flags_with_completion+=(%q)\n", name)
ext := strings.Join(value, "|") ext := strings.Join(value, "|")
ext = "_filedir '@(" + ext + ")'" ext = "__handle_filename_extension_flag " + ext
fmt.Fprintf(out, " flags_completion+=(%q)\n", 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) { func gen(cmd *Command, out *bytes.Buffer) {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if len(c.Deprecated) > 0 {
continue
}
gen(c, out) gen(c, out)
} }
commandName := cmd.CommandPath() commandName := cmd.CommandPath()

View File

@ -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. 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 ```go
annotations := make([]string, 3) annotations := []string{"json", "yaml", "yml"}
annotations[0] = "json"
annotations[1] = "yaml"
annotations[2] = "yml"
annotation := make(map[string][]string) annotation := make(map[string][]string)
annotation[cobra.BashCompFilenameExt] = annotations 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) cmd.Flags().AddFlag(flag)
``` ```

View File

@ -11,6 +11,12 @@ import (
var _ = fmt.Println var _ = fmt.Println
var _ = os.Stderr 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) { func check(t *testing.T, found, expected string) {
if !strings.Contains(found, expected) { if !strings.Contains(found, expected) {
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) 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) { func TestBashCompletions(t *testing.T) {
c := initializeWithRootCmd() c := initializeWithRootCmd()
cmdEcho.AddCommand(cmdTimes) cmdEcho.AddCommand(cmdTimes)
c.AddCommand(cmdEcho, cmdPrint) c.AddCommand(cmdEcho, cmdPrint, cmdDeprecated)
// custom completion function // custom completion function
c.BashCompletionFunction = bash_completion_func c.BashCompletionFunction = bash_completion_func
@ -70,5 +76,7 @@ func TestBashCompletions(t *testing.T) {
// check for required nouns // check for required nouns
check(t, str, `must_have_one_noun+=("pods")`) check(t, str, `must_have_one_noun+=("pods")`)
// check for filename extention flags // 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())
} }

View File

@ -13,6 +13,7 @@ var _ = fmt.Println
var _ = os.Stderr var _ = os.Stderr
var tp, te, tt, t1 []string var tp, te, tt, t1 []string
var rootPersPre, echoPre, echoPersPre, timesPersPre []string
var flagb1, flagb2, flagb3, flagbr, flagbp bool var flagb1, flagb2, flagb3, flagbr, flagbp bool
var flags1, flags2a, flags2b, flags3 string var flags1, flags2a, flags2b, flags3 string
var flagi1, flagi2, flagi3, flagir int var flagi1, flagi2, flagi3, flagir int
@ -38,6 +39,12 @@ var cmdEcho = &Command{
Short: "Echo anything to the screen", Short: "Echo anything to the screen",
Long: `an utterly useless command for testing.`, Long: `an utterly useless command for testing.`,
Example: "Just run cobra-test echo", 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) { Run: func(cmd *Command, args []string) {
te = args 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{ var cmdTimes = &Command{
Use: "times [# times] [string to echo]", Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen more times", Short: "Echo anything to the screen more times",
Long: `a slightly useless command for testing.`, Long: `a slightly useless command for testing.`,
PersistentPreRun: func(cmd *Command, args []string) {
timesPersPre = args
},
Run: func(cmd *Command, args []string) { Run: func(cmd *Command, args []string) {
tt = args tt = args
}, },
@ -64,6 +83,9 @@ var cmdRootNoRun = &Command{
Use: "cobra-test", Use: "cobra-test",
Short: "The root can run it's own function", Short: "The root can run it's own function",
Long: "The root description for help", Long: "The root description for help",
PersistentPreRun: func(cmd *Command, args []string) {
rootPersPre = args
},
} }
var cmdRootSameName = &Command{ var cmdRootSameName = &Command{
@ -140,6 +162,8 @@ func commandInit() {
func initialize() *Command { func initialize() *Command {
tt, tp, te = nil, nil, nil tt, tp, te = nil, nil, nil
rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
var c = cmdRootNoRun var c = cmdRootNoRun
flagInit() flagInit()
commandInit() commandInit()
@ -148,6 +172,7 @@ func initialize() *Command {
func initializeWithSameName() *Command { func initializeWithSameName() *Command {
tt, tp, te = nil, nil, nil tt, tp, te = nil, nil, nil
rootPersPre, echoPre, echoPersPre, timesPersPre = nil, nil, nil, nil
var c = cmdRootSameName var c = cmdRootSameName
flagInit() flagInit()
commandInit() commandInit()
@ -205,7 +230,7 @@ func fullTester(c *Command, input string) resulter {
// Testing flag with invalid input // Testing flag with invalid input
c.SetOutput(buf) c.SetOutput(buf)
cmdEcho.AddCommand(cmdTimes) cmdEcho.AddCommand(cmdTimes)
c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun) c.AddCommand(cmdPrint, cmdEcho, cmdSubNoRun, cmdDeprecated)
c.SetArgs(strings.Split(input, " ")) c.SetArgs(strings.Split(input, " "))
err := c.Execute() err := c.Execute()
@ -812,3 +837,52 @@ func TestReplaceCommandWithRemove(t *testing.T) {
t.Errorf("Replacing command should have been called but didn't\n") 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")
}
}

View File

@ -48,15 +48,31 @@ type Command struct {
ValidArgs []string ValidArgs []string
// Custom functions used by the bash autocompletion generator // Custom functions used by the bash autocompletion generator
BashCompletionFunction string BashCompletionFunction string
// Is this command deprecated and should print this string when used?
Deprecated string
// Full set of flags // Full set of flags
flags *flag.FlagSet flags *flag.FlagSet
// Set of flags childrens of this command will inherit // Set of flags childrens of this command will inherit
pflags *flag.FlagSet pflags *flag.FlagSet
// Flags that are declared specifically by this command (not inherited). // Flags that are declared specifically by this command (not inherited).
lflags *flag.FlagSet lflags *flag.FlagSet
// Run runs the command. // The *Run functions are executed in the following order:
// The args are the arguments after the command name. // * 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) 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 is the list of commands supported by this program.
commands []*Command commands []*Command
// Parent Command for this command // Parent Command for this command
@ -231,7 +247,7 @@ Examples:
{{ .Example }} {{ .Example }}
{{end}}{{ if .HasRunnableSubCommands}} {{end}}{{ if .HasRunnableSubCommands}}
Available Commands: {{range .Commands}}{{if .Runnable}} Available Commands: {{range .Commands}}{{if and (.Runnable) (not .Deprecated)}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}} {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}
{{end}} {{end}}
{{ if .HasLocalFlags}}Flags: {{ if .HasLocalFlags}}Flags:
@ -239,7 +255,7 @@ Available Commands: {{range .Commands}}{{if .Runnable}}
{{ if .HasInheritedFlags}}Global Flags: {{ if .HasInheritedFlags}}Global Flags:
{{.InheritedFlags.FlagUsages}}{{end}}{{if or (.HasHelpSubCommands) (.HasRunnableSiblings)}} {{.InheritedFlags.FlagUsages}}{{end}}{{if or (.HasHelpSubCommands) (.HasRunnableSiblings)}}
Additional help topics: 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}} {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{end}}
{{end}}{{ if .HasSubCommands }} {{end}}{{ if .HasSubCommands }}
Use "{{.Root.Name}} help [command]" for more information about a command. 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") 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) err = c.ParseFlags(a)
if err == flag.ErrHelp { if err == flag.ErrHelp {
c.Help() c.Help()
@ -432,19 +452,40 @@ func (c *Command) execute(a []string) (err error) {
c.Usage() c.Usage()
r.SetOutput(out) r.SetOutput(out)
return err return err
} else { }
// If help is called, regardless of other flags, we print that. // If help is called, regardless of other flags, we print that.
// Print help also if c.Run is nil. // Print help also if c.Run is nil.
if c.helpFlagVal || !c.Runnable() { if c.helpFlagVal || !c.Runnable() {
c.Help() c.Help()
return nil
}
c.preRun()
argWoFlags := c.Flags().Args()
c.Run(c, argWoFlags)
return nil 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() { func (c *Command) preRun() {
@ -495,20 +536,9 @@ func (c *Command) Execute() (err error) {
args = c.args args = c.args
} }
if len(args) == 0 { cmd, flags, err := c.Find(args)
// Only the executable is called and the root is runnable, run it if err == nil {
if c.Runnable() { err = cmd.execute(flags)
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)
}
} }
if err != nil { if err != nil {
@ -535,7 +565,9 @@ func (c *Command) initHelp() {
Short: "Help about any command", Short: "Help about any command",
Long: `Help provides help for any command in the application. Long: `Help provides help for any command in the application.
Simply type ` + c.Name() + ` help [path to command] for full details.`, 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) c.AddCommand(c.helpCommand)
@ -948,6 +980,13 @@ func (c *Command) mergePersistentFlags() {
c.PersistentFlags().VisitAll(addtolocal) c.PersistentFlags().VisitAll(addtolocal)
} }
rmerge = func(x *Command) { 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() { if x.HasPersistentFlags() {
x.PersistentFlags().VisitAll(func(f *flag.Flag) { x.PersistentFlags().VisitAll(func(f *flag.Flag) {
if c.Flags().Lookup(f.Name) == nil { if c.Flags().Lookup(f.Name) == nil {

View File

@ -85,6 +85,9 @@ func GenMarkdown(cmd *Command, out *bytes.Buffer) {
sort.Sort(byName(children)) sort.Sort(byName(children))
for _, child := range children { for _, child := range children {
if len(child.Deprecated) > 0 {
continue
}
cname := name + " " + child.Name() cname := name + " " + child.Name()
link := cname + ".md" link := cname + ".md"
link = strings.Replace(link, " ", "_", -1) link = strings.Replace(link, " ", "_", -1)

View File

@ -14,7 +14,7 @@ var _ = os.Stderr
func TestGenMdDoc(t *testing.T) { func TestGenMdDoc(t *testing.T) {
c := initializeWithRootCmd() c := initializeWithRootCmd()
// Need two commands to run the command alphabetical sort // Need two commands to run the command alphabetical sort
cmdEcho.AddCommand(cmdTimes, cmdEchoSub) cmdEcho.AddCommand(cmdTimes, cmdEchoSub, cmdDeprecated)
c.AddCommand(cmdPrint, cmdEcho) c.AddCommand(cmdPrint, cmdEcho)
cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp) cmdRootWithRun.PersistentFlags().StringVarP(&flags2a, "rootflag", "r", "two", strtwoParentHelp)
@ -59,4 +59,9 @@ func TestGenMdDoc(t *testing.T) {
if !strings.Contains(found, expected) { if !strings.Contains(found, expected) {
t.Errorf("Unexpected response.\nExpecting to contain: \n %q\nGot:\n %q\n", expected, found) 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)
}
} }

View File

@ -4,7 +4,7 @@
__debug() __debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
echo "$*" >> ${BASH_COMP_DEBUG_FILE} echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
fi fi
} }
@ -75,6 +75,13 @@ __handle_reply()
fi fi
} }
# The arguments should be in the form "ext1|ext2|extn"
__handle_filename_extension_flag()
{
local ext="$1"
_filedir "@(${ext})"
}
__handle_flag() __handle_flag()
{ {
__debug "${FUNCNAME}: c is $c words[c] is ${words[c]}" __debug "${FUNCNAME}: c is $c words[c] is ${words[c]}"
@ -297,10 +304,10 @@ _kubectl_create()
flags+=("--filename=") flags+=("--filename=")
flags_with_completion+=("--filename") flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f") two_word_flags+=("-f")
flags_with_completion+=("-f") flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
@ -322,10 +329,10 @@ _kubectl_update()
flags+=("--filename=") flags+=("--filename=")
flags_with_completion+=("--filename") flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f") two_word_flags+=("-f")
flags_with_completion+=("-f") flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
flags+=("--patch=") flags+=("--patch=")
@ -351,10 +358,10 @@ _kubectl_delete()
flags+=("--cascade") flags+=("--cascade")
flags+=("--filename=") flags+=("--filename=")
flags_with_completion+=("--filename") flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f") two_word_flags+=("-f")
flags_with_completion+=("-f") flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--grace-period=") flags+=("--grace-period=")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
@ -575,10 +582,10 @@ _kubectl_stop()
flags+=("--all") flags+=("--all")
flags+=("--filename=") flags+=("--filename=")
flags_with_completion+=("--filename") flags_with_completion+=("--filename")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
two_word_flags+=("-f") two_word_flags+=("-f")
flags_with_completion+=("-f") flags_with_completion+=("-f")
flags_completion+=("_filedir '@(json|yaml|yml)'") flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
flags+=("--grace-period=") flags+=("--grace-period=")
flags+=("--help") flags+=("--help")
flags+=("-h") flags+=("-h")
@ -942,10 +949,9 @@ _kubectl()
__start_kubectl() __start_kubectl()
{ {
local cur prev words cword split local cur prev words cword
_init_completion -s || return _init_completion -s || return
local completions_func
local c=0 local c=0
local flags=() local flags=()
local two_word_flags=() local two_word_flags=()