vendor: update version of github.com/spf13/cobra for zsh support

This commit is contained in:
bpicode 2017-08-31 16:20:55 +01:00 committed by Nick Craig-Wood
parent 2c8d6e86cc
commit 7e93567b18
26 changed files with 683 additions and 278 deletions

6
Gopkg.lock generated
View file

@ -209,7 +209,7 @@
branch = "master" branch = "master"
name = "github.com/spf13/cobra" name = "github.com/spf13/cobra"
packages = [".","doc"] packages = [".","doc"]
revision = "715f41bd7a70b5111f898b71ab484da52ee6266d" revision = "2df9a531813370438a4d79bfc33e21f58063ed87"
[[projects]] [[projects]]
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
@ -230,10 +230,10 @@
revision = "ba9c9e33906f58169366275e3450db66139a31a9" revision = "ba9c9e33906f58169366275e3450db66139a31a9"
[[projects]] [[projects]]
branch = "master"
name = "github.com/yunify/qingstor-sdk-go" name = "github.com/yunify/qingstor-sdk-go"
packages = [".","config","logger","request","request/builder","request/data","request/errors","request/signer","request/unpacker","service","utils"] packages = [".","config","logger","request","request/builder","request/data","request/errors","request/signer","request/unpacker","service","utils"]
revision = "68ce7c233bde780b2bbe1e1cf018db8e2df86361" revision = "4749bc5ebe4857b353e55b49ebe91eed9a7f6cda"
version = "v2.2.6"
[[projects]] [[projects]]
branch = "master" branch = "master"

View file

@ -2,8 +2,8 @@ language: go
matrix: matrix:
include: include:
- go: 1.7.5 - go: 1.7.6
- go: 1.8.1 - go: 1.8.3
- go: tip - go: tip
allow_failures: allow_failures:
- go: tip - go: tip

View file

@ -117,14 +117,6 @@ Flag functionality is provided by the [pflag
library](https://github.com/spf13/pflag), a fork of the flag standard library library](https://github.com/spf13/pflag), a fork of the flag standard library
which maintains the same interface while adding POSIX compliance. which maintains the same interface while adding POSIX compliance.
## Usage
Cobra works by creating a set of commands and then organizing them into a tree.
The tree defines the structure of the application.
Once each command is defined with its corresponding flags, then the
tree is assigned to the commander which is finally executed.
# Installing # Installing
Using Cobra is easy. First, use `go get` to install the latest version Using Cobra is easy. First, use `go get` to install the latest version
of the library. This command will install the `cobra` generator executable of the library. This command will install the `cobra` generator executable
@ -159,17 +151,17 @@ In a Cobra app, typically the main.go file is very bare. It serves one purpose:
package main package main
import ( import (
"fmt" "fmt"
"os" "os"
"{pathToYourApp}/cmd" "{pathToYourApp}/cmd"
) )
func main() { func main() {
if err := cmd.RootCmd.Execute(); err != nil { if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
} }
``` ```
@ -285,14 +277,14 @@ Ideally you place this in app/cmd/root.go:
```go ```go
var RootCmd = &cobra.Command{ var RootCmd = &cobra.Command{
Use: "hugo", Use: "hugo",
Short: "Hugo is a very fast static site generator", Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go. love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`, Complete documentation is available at http://hugo.spf13.com`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here // Do Stuff Here
}, },
} }
``` ```
@ -302,54 +294,54 @@ For example cmd/root.go:
```go ```go
import ( import (
"fmt" "fmt"
"os" "os"
homedir "github.com/mitchellh/go-homedir" homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
func init() { func init() {
cobra.OnInitialize(initConfig) cobra.OnInitialize(initConfig)
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/") RootCmd.PersistentFlags().StringVarP(&projectBase, "projectbase", "b", "", "base project directory eg. github.com/spf13/")
RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution") RootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "Author name for copyright attribution")
RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)") RootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "Name of license for the project (can provide `licensetext` in config)")
RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration") RootCmd.PersistentFlags().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase")) viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper")) viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache") viper.SetDefault("license", "apache")
} }
func Execute() { func Execute() {
RootCmd.Execute() RootCmd.Execute()
} }
func initConfig() { func initConfig() {
// Don't forget to read config either from cfgFile or from home directory! // Don't forget to read config either from cfgFile or from home directory!
if cfgFile != "" { if cfgFile != "" {
// Use config file from the flag. // Use config file from the flag.
viper.SetConfigFile(cfgFile) viper.SetConfigFile(cfgFile)
} else { } else {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
// Search config in home directory with name ".cobra" (without extension). // Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)
viper.SetConfigName(".cobra") viper.SetConfigName(".cobra")
} }
if err := viper.ReadInConfig(); err != nil { if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err) fmt.Println("Can't read config:", err)
os.Exit(1) os.Exit(1)
} }
} }
``` ```
@ -364,17 +356,17 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose,
package main package main
import ( import (
"fmt" "fmt"
"os" "os"
"{pathToYourApp}/cmd" "{pathToYourApp}/cmd"
) )
func main() { func main() {
if err := cmd.RootCmd.Execute(); err != nil { if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
} }
``` ```
@ -390,21 +382,21 @@ populate it with the following:
package cmd package cmd
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"fmt" "fmt"
) )
func init() { func init() {
RootCmd.AddCommand(versionCmd) RootCmd.AddCommand(versionCmd)
} }
var versionCmd = &cobra.Command{ var versionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Print the version number of Hugo", Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's`, Long: `All software has versions. This is Hugo's`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")
}, },
} }
``` ```
@ -419,19 +411,6 @@ root, but commands can be attached at any level.
RootCmd.AddCommand(versionCmd) RootCmd.AddCommand(versionCmd)
``` ```
### Remove a command from its parent
Removing a command is not a common action in simple programs, but it allows 3rd
parties to customize an existing command tree.
In this example, we remove the existing `VersionCmd` command of an existing
root command, and we replace it with our own version:
```go
mainlib.RootCmd.RemoveCommand(mainlib.VersionCmd)
mainlib.RootCmd.AddCommand(versionCmd)
```
## Working with Flags ## Working with Flags
Flags provide modifiers to control how the action command operates. Flags provide modifiers to control how the action command operates.
@ -474,8 +453,8 @@ You can also bind your flags with [viper](https://github.com/spf13/viper):
var author string var author string
func init() { func init() {
RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author")) viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
} }
``` ```
@ -485,6 +464,41 @@ when the `--author` flag is not provided by user.
More in [viper documentation](https://github.com/spf13/viper#working-with-flags). More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
## Positional and Custom Arguments
Validation of positional arguments can be specified using the `Args` field
of `Command`.
The following validators are built in:
- `NoArgs` - the command will report an error if there are any positional args.
- `ArbitraryArgs` - the command will accept any args.
- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`.
- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args.
- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args.
- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
An example of setting the custom validator:
```go
var cmd = &cobra.Command{
Short: "hello",
Args: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("requires at least one arg")
}
if myapp.IsValidColor(args[0]) {
return nil
}
return fmt.Errorf("invalid color specified: %s", args[0])
},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hello, World!")
},
}
```
## Example ## Example
In the example below, we have defined three commands. Two are at the top level In the example below, we have defined three commands. Two are at the top level
@ -500,56 +514,56 @@ More documentation about flags is available at https://github.com/spf13/pflag
package main package main
import ( import (
"fmt" "fmt"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func main() { func main() {
var echoTimes int
var echoTimes int var cmdPrint = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdPrint = &cobra.Command{ var cmdEcho = &cobra.Command{
Use: "print [string to print]", Use: "echo [string to echo]",
Short: "Print anything to the screen", Short: "Echo anything to the screen",
Long: `print is for printing anything back to the screen. Long: `echo is for echoing anything back.
For many years people have printed back to the screen. Echo works a lot like print, except it has a child command.`,
`, Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " ")) fmt.Println("Print: " + strings.Join(args, " "))
}, },
} }
var cmdEcho = &cobra.Command{ var cmdTimes = &cobra.Command{
Use: "echo [string to echo]", Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen", Short: "Echo anything to the screen more times",
Long: `echo is for echoing anything back. Long: `echo things multiple times back to the user by providing
Echo works a lot like print, except it has a child command. a count and a string.`,
`, Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " ")) for i := 0; i < echoTimes; i++ {
}, fmt.Println("Echo: " + strings.Join(args, " "))
} }
},
}
var cmdTimes = &cobra.Command{ cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
Use: "times [# times] [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing
a count and a string.`,
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
var rootCmd = &cobra.Command{Use: "app"} cmdEcho.AddCommand(cmdTimes)
rootCmd.AddCommand(cmdPrint, cmdEcho) rootCmd.Execute()
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
} }
``` ```
@ -635,16 +649,16 @@ The default help command is
```go ```go
func (c *Command) initHelp() { func (c *Command) initHelp() {
if c.helpCommand == nil { if c.helpCommand == nil {
c.helpCommand = &Command{ c.helpCommand = &Command{
Use: "help [command]", Use: "help [command]",
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(),
} }
} }
c.AddCommand(c.helpCommand) c.AddCommand(c.helpCommand)
} }
``` ```
@ -652,9 +666,7 @@ You can provide your own command, function or template through the following met
```go ```go
command.SetHelpCommand(cmd *Command) command.SetHelpCommand(cmd *Command)
command.SetHelpFunc(f func(*Command, []string)) command.SetHelpFunc(f func(*Command, []string))
command.SetHelpTemplate(s string) command.SetHelpTemplate(s string)
``` ```
@ -720,8 +732,8 @@ The default usage function is:
```go ```go
return func(c *Command) error { return func(c *Command) error {
err := tmpl(c.Out(), c.UsageTemplate(), c) err := tmpl(c.Out(), c.UsageTemplate(), c)
return err return err
} }
``` ```
@ -749,57 +761,57 @@ An example of two commands which use all of these features is below. When the s
package main package main
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func main() { func main() {
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "root [sub]", Use: "root [sub]",
Short: "My root command", Short: "My root command",
PersistentPreRun: func(cmd *cobra.Command, args []string) { PersistentPreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd Run with args: %v\n", args) fmt.Printf("Inside rootCmd Run with args: %v\n", args)
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
}, },
PersistentPostRun: func(cmd *cobra.Command, args []string) { PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
}, },
} }
var subCmd = &cobra.Command{ var subCmd = &cobra.Command{
Use: "sub [no options!]", Use: "sub [no options!]",
Short: "My subcommand", Short: "My subcommand",
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PreRun with args: %v\n", args) fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
}, },
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd Run with args: %v\n", args) fmt.Printf("Inside subCmd Run with args: %v\n", args)
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PostRun with args: %v\n", args) fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
}, },
PersistentPostRun: func(cmd *cobra.Command, args []string) { PersistentPostRun: func(cmd *cobra.Command, args []string) {
fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
}, },
} }
rootCmd.AddCommand(subCmd) rootCmd.AddCommand(subCmd)
rootCmd.SetArgs([]string{""}) rootCmd.SetArgs([]string{""})
_ = rootCmd.Execute() rootCmd.Execute()
fmt.Print("\n") fmt.Println()
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
_ = rootCmd.Execute() rootCmd.Execute()
} }
``` ```
@ -825,28 +837,28 @@ command.
package main package main
import ( import (
"errors" "errors"
"log" "log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func main() { func main() {
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "hugo", Use: "hugo",
Short: "Hugo is a very fast static site generator", Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go. love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`, Complete documentation is available at http://hugo.spf13.com`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
// Do Stuff Here // Do Stuff Here
return errors.New("some random error") return errors.New("some random error")
}, },
} }
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }
``` ```
@ -902,16 +914,6 @@ Cobra can generate a man page based on the subcommands, flags, etc. A simple exa
Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md). Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible. Read more about it in [Bash Completions](bash_completions.md).
## Debugging
Cobra provides a DebugFlags method on a command which, when called, will print
out everything Cobra knows about the flags for each command.
### Example
```go
command.DebugFlags()
```
## Extensions ## Extensions

98
vendor/github.com/spf13/cobra/args.go generated vendored Normal file
View file

@ -0,0 +1,98 @@
package cobra
import (
"fmt"
)
type PositionalArgs func(cmd *Command, args []string) error
// Legacy arg validation has the following behaviour:
// - root commands with no subcommands can take arbitrary arguments
// - root commands with subcommands will do subcommand validity checking
// - subcommands will always accept arbitrary arguments
func legacyArgs(cmd *Command, args []string) error {
// no subcommand, always take args
if !cmd.HasSubCommands() {
return nil
}
// root command with subcommands, do subcommand checking
if !cmd.HasParent() && len(args) > 0 {
return fmt.Errorf("unknown command %q for %q%s", args[0], cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
return nil
}
// NoArgs returns an error if any args are included
func NoArgs(cmd *Command, args []string) error {
if len(args) > 0 {
return fmt.Errorf("unknown command %q for %q", args[0], cmd.CommandPath())
}
return nil
}
// OnlyValidArgs returns an error if any args are not in the list of ValidArgs
func OnlyValidArgs(cmd *Command, args []string) error {
if len(cmd.ValidArgs) > 0 {
for _, v := range args {
if !stringInSlice(v, cmd.ValidArgs) {
return fmt.Errorf("invalid argument %q for %q%s", v, cmd.CommandPath(), cmd.findSuggestions(args[0]))
}
}
}
return nil
}
func stringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
// ArbitraryArgs never returns an error
func ArbitraryArgs(cmd *Command, args []string) error {
return nil
}
// MinimumNArgs returns an error if there is not at least N args
func MinimumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < n {
return fmt.Errorf("requires at least %d arg(s), only received %d", n, len(args))
}
return nil
}
}
// MaximumNArgs returns an error if there are more than N args
func MaximumNArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) > n {
return fmt.Errorf("accepts at most %d arg(s), received %d", n, len(args))
}
return nil
}
}
// ExactArgs returns an error if there are not exactly n args
func ExactArgs(n int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) != n {
return fmt.Errorf("accepts %d arg(s), received %d", n, len(args))
}
return nil
}
}
// RangeArgs returns an error if the number of args is not within the expected range
func RangeArgs(min int, max int) PositionalArgs {
return func(cmd *Command, args []string) error {
if len(args) < min || len(args) > max {
return fmt.Errorf("accepts between %d and %d arg(s), received %d", min, max, len(args))
}
return nil
}
}

View file

@ -117,6 +117,8 @@ func TestBashCompletions(t *testing.T) {
// check for filename extension flags // check for filename extension flags
check(t, str, `flags_completion+=("_filedir")`) check(t, str, `flags_completion+=("_filedir")`)
// check for filename extension flags // check for filename extension flags
check(t, str, `must_have_one_noun+=("three")`)
// check for filename extention flags
check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`) check(t, str, `flags_completion+=("__handle_filename_extension_flag json|yaml|yml")`)
// check for custom flags // check for custom flags
check(t, str, `flags_completion+=("__complete_custom")`) check(t, str, `flags_completion+=("__complete_custom")`)

View file

@ -24,7 +24,7 @@ import (
func init() { func init() {
addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
addCmd.Flags().StringVarP(&parentName, "parent", "p", "RootCmd", "name of parent command for this command") addCmd.Flags().StringVarP(&parentName, "parent", "p", "RootCmd", "variable name of parent command for this command")
} }
var packageName, parentName string var packageName, parentName string
@ -121,7 +121,7 @@ func validateCmdName(source string) string {
func createCmdFile(license License, path, cmdName string) { func createCmdFile(license License, path, cmdName string) {
template := `{{comment .copyright}} template := `{{comment .copyright}}
{{comment .license}} {{if .license}}{{comment .license}}{{end}}
package {{.cmdPackage}} package {{.cmdPackage}}

View file

@ -6,6 +6,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/spf13/viper"
) )
// TestGoldenAddCmd initializes the project "github.com/spf13/testproject" // TestGoldenAddCmd initializes the project "github.com/spf13/testproject"
@ -16,11 +18,18 @@ import (
func TestGoldenAddCmd(t *testing.T) { func TestGoldenAddCmd(t *testing.T) {
projectName := "github.com/spf13/testproject" projectName := "github.com/spf13/testproject"
project := NewProject(projectName) project := NewProject(projectName)
// Initialize the project at first.
initializeProject(project)
defer os.RemoveAll(project.AbsPath()) defer os.RemoveAll(project.AbsPath())
viper.Set("author", "NAME HERE <EMAIL ADDRESS>")
viper.Set("license", "apache")
viper.Set("year", 2017)
defer viper.Set("author", nil)
defer viper.Set("license", nil)
defer viper.Set("year", nil)
// Initialize the project first.
initializeProject(project)
// Then add the "test" command. // Then add the "test" command.
cmdName := "test" cmdName := "test"
cmdPath := filepath.Join(project.CmdPath(), cmdName+".go") cmdPath := filepath.Join(project.CmdPath(), cmdName+".go")
@ -48,7 +57,7 @@ func TestGoldenAddCmd(t *testing.T) {
goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden") goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden")
switch relPath { switch relPath {
// Know directories. // Known directories.
case ".": case ".":
return nil return nil
// Known files. // Known files.

View file

@ -39,11 +39,11 @@ func compareFiles(pathA, pathB string) error {
// Don't execute diff if it can't be found. // Don't execute diff if it can't be found.
return nil return nil
} }
diffCmd := exec.Command(diffPath, pathA, pathB) diffCmd := exec.Command(diffPath, "-u", pathA, pathB)
diffCmd.Stdout = output diffCmd.Stdout = output
diffCmd.Stderr = output diffCmd.Stderr = output
output.WriteString("$ diff " + pathA + " " + pathB + "\n") output.WriteString("$ diff -u " + pathA + " " + pathB + "\n")
if err := diffCmd.Run(); err != nil { if err := diffCmd.Run(); err != nil {
output.WriteString("\n" + err.Error()) output.WriteString("\n" + err.Error())
} }

View file

@ -6,6 +6,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/spf13/viper"
) )
// TestGoldenInitCmd initializes the project "github.com/spf13/testproject" // TestGoldenInitCmd initializes the project "github.com/spf13/testproject"
@ -17,6 +19,13 @@ func TestGoldenInitCmd(t *testing.T) {
project := NewProject(projectName) project := NewProject(projectName)
defer os.RemoveAll(project.AbsPath()) defer os.RemoveAll(project.AbsPath())
viper.Set("author", "NAME HERE <EMAIL ADDRESS>")
viper.Set("license", "apache")
viper.Set("year", 2017)
defer viper.Set("author", nil)
defer viper.Set("license", nil)
defer viper.Set("year", nil)
os.Args = []string{"cobra", "init", projectName} os.Args = []string{"cobra", "init", projectName}
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
t.Fatal("Error by execution:", err) t.Fatal("Error by execution:", err)
@ -44,7 +53,7 @@ func TestGoldenInitCmd(t *testing.T) {
goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden") goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden")
switch relPath { switch relPath {
// Know directories. // Known directories.
case ".", "cmd": case ".", "cmd":
return nil return nil
// Known files. // Known files.

View file

@ -4,8 +4,7 @@ func initAgpl() {
Licenses["agpl"] = License{ Licenses["agpl"] = License{
Name: "GNU Affero General Public License", Name: "GNU Affero General Public License",
PossibleMatches: []string{"agpl", "affero gpl", "gnu agpl"}, PossibleMatches: []string{"agpl", "affero gpl", "gnu agpl"},
Header: `{{.copyright}} Header: `
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or

View file

@ -19,7 +19,8 @@ func initApache2() {
Licenses["apache"] = License{ Licenses["apache"] = License{
Name: "Apache 2.0", Name: "Apache 2.0",
PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"}, PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
Header: `Licensed under the Apache License, Version 2.0 (the "License"); Header: `
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at

View file

@ -20,8 +20,7 @@ func initBsdClause2() {
Name: "Simplified BSD License", Name: "Simplified BSD License",
PossibleMatches: []string{"freebsd", "simpbsd", "simple bsd", "2-clause bsd", PossibleMatches: []string{"freebsd", "simpbsd", "simple bsd", "2-clause bsd",
"2 clause bsd", "simplified bsd license"}, "2 clause bsd", "simplified bsd license"},
Header: ` Header: `All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:

View file

@ -19,8 +19,7 @@ func initBsdClause3() {
Licenses["bsd"] = License{ Licenses["bsd"] = License{
Name: "NewBSD", Name: "NewBSD",
PossibleMatches: []string{"bsd", "newbsd", "3 clause bsd", "3-clause bsd"}, PossibleMatches: []string{"bsd", "newbsd", "3 clause bsd", "3-clause bsd"},
Header: ` Header: `All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met: modification, are permitted provided that the following conditions are met:

View file

@ -19,20 +19,19 @@ func initGpl2() {
Licenses["gpl2"] = License{ Licenses["gpl2"] = License{
Name: "GNU General Public License 2.0", Name: "GNU General Public License 2.0",
PossibleMatches: []string{"gpl2", "gnu gpl2", "gplv2"}, PossibleMatches: []string{"gpl2", "gnu gpl2", "gplv2"},
Header: `{{.copyright}} Header: `
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is free software; you can redistribute it and/or This program is distributed in the hope that it will be useful,
modify it under the terms of the GNU General Public License but WITHOUT ANY WARRANTY; without even the implied warranty of
as published by the Free Software Foundation; either version 2 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
of the License, or (at your option) any later version. GNU General Public License for more details.
This program is distributed in the hope that it will be useful, You should have received a copy of the GNU Lesser General Public License
but WITHOUT ANY WARRANTY; without even the implied warranty of along with this program. If not, see <http://www.gnu.org/licenses/>.`,
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.`,
Text: ` GNU GENERAL PUBLIC LICENSE Text: ` GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991

View file

@ -19,8 +19,7 @@ func initGpl3() {
Licenses["gpl3"] = License{ Licenses["gpl3"] = License{
Name: "GNU General Public License 3.0", Name: "GNU General Public License 3.0",
PossibleMatches: []string{"gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"}, PossibleMatches: []string{"gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"},
Header: `{{.copyright}} Header: `
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or

View file

@ -4,8 +4,7 @@ func initLgpl() {
Licenses["lgpl"] = License{ Licenses["lgpl"] = License{
Name: "GNU Lesser General Public License", Name: "GNU Lesser General Public License",
PossibleMatches: []string{"lgpl", "lesser gpl", "gnu lgpl"}, PossibleMatches: []string{"lgpl", "lesser gpl", "gnu lgpl"},
Header: `{{.copyright}} Header: `
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or

View file

@ -17,7 +17,7 @@ package cmd
func initMit() { func initMit() {
Licenses["mit"] = License{ Licenses["mit"] = License{
Name: "Mit", Name: "MIT License",
PossibleMatches: []string{"mit"}, PossibleMatches: []string{"mit"},
Header: ` Header: `
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View file

@ -77,7 +77,11 @@ func getLicense() License {
func copyrightLine() string { func copyrightLine() string {
author := viper.GetString("author") author := viper.GetString("author")
year := time.Now().Format("2006")
year := viper.GetString("year") // For tests.
if year == "" {
year = time.Now().Format("2006")
}
return "Copyright © " + year + " " + author return "Copyright © " + year + " " + author
} }

View file

@ -40,7 +40,7 @@ func Execute() {
} }
func init() { func init() {
initViper() cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
@ -55,7 +55,7 @@ func init() {
rootCmd.AddCommand(initCmd) rootCmd.AddCommand(initCmd)
} }
func initViper() { func initConfig() {
if cfgFile != "" { if cfgFile != "" {
// Use config file from the flag. // Use config file from the flag.
viper.SetConfigFile(cfgFile) viper.SetConfigFile(cfgFile)

View file

@ -1,4 +1,5 @@
// Copyright © 2017 NAME HERE <EMAIL ADDRESS> // Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at

View file

@ -1,4 +1,5 @@
// Copyright © 2017 NAME HERE <EMAIL ADDRESS> // Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at

View file

@ -1,4 +1,5 @@
// Copyright © 2017 NAME HERE <EMAIL ADDRESS> // Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at

View file

@ -36,6 +36,7 @@ var cmdHidden = &Command{
var cmdPrint = &Command{ var cmdPrint = &Command{
Use: "print [string to print]", Use: "print [string to print]",
Args: MinimumNArgs(1),
Short: "Print anything to the screen", Short: "Print anything to the screen",
Long: `an absolutely utterly useless command for testing.`, Long: `an absolutely utterly useless command for testing.`,
Run: func(cmd *Command, args []string) { Run: func(cmd *Command, args []string) {
@ -75,6 +76,7 @@ var cmdDeprecated = &Command{
Deprecated: "Please use echo instead", Deprecated: "Please use echo instead",
Run: func(cmd *Command, args []string) { Run: func(cmd *Command, args []string) {
}, },
Args: NoArgs,
} }
var cmdTimes = &Command{ var cmdTimes = &Command{
@ -88,6 +90,8 @@ var cmdTimes = &Command{
Run: func(cmd *Command, args []string) { Run: func(cmd *Command, args []string) {
tt = args tt = args
}, },
Args: OnlyValidArgs,
ValidArgs: []string{"one", "two", "three", "four"},
} }
var cmdRootNoRun = &Command{ var cmdRootNoRun = &Command{
@ -105,6 +109,16 @@ var cmdRootSameName = &Command{
Long: "The root description for help", Long: "The root description for help",
} }
var cmdRootTakesArgs = &Command{
Use: "root-with-args [random args]",
Short: "The root can run it's own function and takes args!",
Long: "The root description for help, and some args",
Run: func(cmd *Command, args []string) {
tr = args
},
Args: ArbitraryArgs,
}
var cmdRootWithRun = &Command{ var cmdRootWithRun = &Command{
Use: "cobra-test", Use: "cobra-test",
Short: "The root can run its own function", Short: "The root can run its own function",
@ -458,6 +472,63 @@ func TestUsage(t *testing.T) {
checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]") checkResultOmits(t, x, cmdCustomFlags.Use+" [flags]")
} }
func TestRootTakesNoArgs(t *testing.T) {
c := initializeWithSameName()
c.AddCommand(cmdPrint, cmdEcho)
result := simpleTester(c, "illegal")
if result.Error == nil {
t.Fatal("Expected an error")
}
expectedError := `unknown command "illegal" for "print"`
if !strings.Contains(result.Error.Error(), expectedError) {
t.Errorf("exptected %v, got %v", expectedError, result.Error.Error())
}
}
func TestRootTakesArgs(t *testing.T) {
c := cmdRootTakesArgs
result := simpleTester(c, "legal")
if result.Error != nil {
t.Errorf("expected no error, but got %v", result.Error)
}
}
func TestSubCmdTakesNoArgs(t *testing.T) {
result := fullSetupTest("deprecated", "illegal")
if result.Error == nil {
t.Fatal("Expected an error")
}
expectedError := `unknown command "illegal" for "cobra-test deprecated"`
if !strings.Contains(result.Error.Error(), expectedError) {
t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
}
}
func TestSubCmdTakesArgs(t *testing.T) {
noRRSetupTest("echo", "times", "one", "two")
if strings.Join(tt, " ") != "one two" {
t.Error("Command didn't parse correctly")
}
}
func TestCmdOnlyValidArgs(t *testing.T) {
result := noRRSetupTest("echo", "times", "one", "two", "five")
if result.Error == nil {
t.Fatal("Expected an error")
}
expectedError := `invalid argument "five"`
if !strings.Contains(result.Error.Error(), expectedError) {
t.Errorf("expected %v, got %v", expectedError, result.Error.Error())
}
}
func TestFlagLong(t *testing.T) { func TestFlagLong(t *testing.T) {
noRRSetupTest("echo", "--intone=13", "something", "--", "here") noRRSetupTest("echo", "--intone=13", "something", "--", "here")
@ -672,9 +743,9 @@ func TestPersistentFlags(t *testing.T) {
} }
// persistentFlag should act like normal flag on its own command // persistentFlag should act like normal flag on its own command
fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "test", "here") fullSetupTest("echo", "times", "-s", "again", "-c", "-p", "one", "two")
if strings.Join(tt, " ") != "test here" { if strings.Join(tt, " ") != "one two" {
t.Errorf("flags didn't leave proper args remaining. %s given", tt) t.Errorf("flags didn't leave proper args remaining. %s given", tt)
} }
@ -1095,7 +1166,7 @@ func TestGlobalNormFuncPropagation(t *testing.T) {
rootCmd := initialize() rootCmd := initialize()
rootCmd.SetGlobalNormalizationFunc(normFunc) rootCmd.SetGlobalNormalizationFunc(normFunc)
if reflect.ValueOf(normFunc) != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()) { if reflect.ValueOf(normFunc).Pointer() != reflect.ValueOf(rootCmd.GlobalNormalizationFunc()).Pointer() {
t.Error("rootCmd seems to have a wrong normalization function") t.Error("rootCmd seems to have a wrong normalization function")
} }

View file

@ -54,6 +54,9 @@ type Command struct {
// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
ValidArgs []string ValidArgs []string
// Expected arguments
Args PositionalArgs
// ArgAliases is List of aliases for ValidArgs. // ArgAliases is List of aliases for ValidArgs.
// These are not suggested to the user in the bash completion, // These are not suggested to the user in the bash completion,
// but accepted if entered manually. // but accepted if entered manually.
@ -513,33 +516,29 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
} }
commandFound, a := innerfind(c, args) commandFound, a := innerfind(c, args)
argsWOflags := stripFlags(a, commandFound) if commandFound.Args == nil {
return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound))
// no subcommand, always take args
if !commandFound.HasSubCommands() {
return commandFound, a, nil
} }
// root command with subcommands, do subcommand checking
if commandFound == c && len(argsWOflags) > 0 {
suggestionsString := ""
if !c.DisableSuggestions {
if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2
}
if suggestions := c.SuggestionsFor(argsWOflags[0]); len(suggestions) > 0 {
suggestionsString += "\n\nDid you mean this?\n"
for _, s := range suggestions {
suggestionsString += fmt.Sprintf("\t%v\n", s)
}
}
}
return commandFound, a, fmt.Errorf("unknown command %q for %q%s", argsWOflags[0], commandFound.CommandPath(), suggestionsString)
}
return commandFound, a, nil return commandFound, a, nil
} }
func (c *Command) findSuggestions(arg string) string {
if c.DisableSuggestions {
return ""
}
if c.SuggestionsMinimumDistance <= 0 {
c.SuggestionsMinimumDistance = 2
}
suggestionsString := ""
if suggestions := c.SuggestionsFor(arg); len(suggestions) > 0 {
suggestionsString += "\n\nDid you mean this?\n"
for _, s := range suggestions {
suggestionsString += fmt.Sprintf("\t%v\n", s)
}
}
return suggestionsString
}
// SuggestionsFor provides suggestions for the typedName. // SuggestionsFor provides suggestions for the typedName.
func (c *Command) SuggestionsFor(typedName string) []string { func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{} suggestions := []string{}
@ -624,6 +623,10 @@ func (c *Command) execute(a []string) (err error) {
argWoFlags = a argWoFlags = a
} }
if err := c.ValidateArgs(argWoFlags); err != nil {
return err
}
for p := c; p != nil; p = p.Parent() { for p := c; p != nil; p = p.Parent() {
if p.PersistentPreRunE != nil { if p.PersistentPreRunE != nil {
if err := p.PersistentPreRunE(c, argWoFlags); err != nil { if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
@ -747,6 +750,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
return cmd, err return cmd, err
} }
func (c *Command) ValidateArgs(args []string) error {
if c.Args == nil {
return nil
}
return c.Args(c, args)
}
// InitDefaultHelpFlag adds default help flag to c. // InitDefaultHelpFlag adds default help flag to c.
// It is called automatically by executing the c or by calling help and usage. // It is called automatically by executing the c or by calling help and usage.
// If c already has help flag, it will do nothing. // If c already has help flag, it will do nothing.

114
vendor/github.com/spf13/cobra/zsh_completions.go generated vendored Normal file
View file

@ -0,0 +1,114 @@
package cobra
import (
"bytes"
"fmt"
"io"
"strings"
)
// GenZshCompletion generates a zsh completion file and writes to the passed writer.
func (cmd *Command) GenZshCompletion(w io.Writer) error {
buf := new(bytes.Buffer)
writeHeader(buf, cmd)
maxDepth := maxDepth(cmd)
writeLevelMapping(buf, maxDepth)
writeLevelCases(buf, maxDepth, cmd)
_, err := buf.WriteTo(w)
return err
}
func writeHeader(w io.Writer, cmd *Command) {
fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
}
func maxDepth(c *Command) int {
if len(c.Commands()) == 0 {
return 0
}
maxDepthSub := 0
for _, s := range c.Commands() {
subDepth := maxDepth(s)
if subDepth > maxDepthSub {
maxDepthSub = subDepth
}
}
return 1 + maxDepthSub
}
func writeLevelMapping(w io.Writer, numLevels int) {
fmt.Fprintln(w, `_arguments \`)
for i := 1; i <= numLevels; i++ {
fmt.Fprintf(w, ` '%d: :->level%d' \`, i, i)
fmt.Fprintln(w)
}
fmt.Fprintf(w, ` '%d: :%s'`, numLevels+1, "_files")
fmt.Fprintln(w)
}
func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
fmt.Fprintln(w, "case $state in")
defer fmt.Fprintln(w, "esac")
for i := 1; i <= maxDepth; i++ {
fmt.Fprintf(w, " level%d)\n", i)
writeLevel(w, root, i)
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func writeLevel(w io.Writer, root *Command, i int) {
fmt.Fprintf(w, " case $words[%d] in\n", i)
defer fmt.Fprintln(w, " esac")
commands := filterByLevel(root, i)
byParent := groupByParent(commands)
for p, c := range byParent {
names := names(c)
fmt.Fprintf(w, " %s)\n", p)
fmt.Fprintf(w, " _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
fmt.Fprintln(w, " ;;")
}
fmt.Fprintln(w, " *)")
fmt.Fprintln(w, " _arguments '*: :_files'")
fmt.Fprintln(w, " ;;")
}
func filterByLevel(c *Command, l int) []*Command {
cs := make([]*Command, 0)
if l == 0 {
cs = append(cs, c)
return cs
}
for _, s := range c.Commands() {
cs = append(cs, filterByLevel(s, l-1)...)
}
return cs
}
func groupByParent(commands []*Command) map[string][]*Command {
m := make(map[string][]*Command)
for _, c := range commands {
parent := c.Parent()
if parent == nil {
continue
}
m[parent.Name()] = append(m[parent.Name()], c)
}
return m
}
func names(commands []*Command) []string {
ns := make([]string, len(commands))
for i, c := range commands {
ns[i] = c.Name()
}
return ns
}

88
vendor/github.com/spf13/cobra/zsh_completions_test.go generated vendored Normal file
View file

@ -0,0 +1,88 @@
package cobra
import (
"bytes"
"strings"
"testing"
)
func TestZshCompletion(t *testing.T) {
tcs := []struct {
name string
root *Command
expectedExpressions []string
}{
{
name: "trivial",
root: &Command{Use: "trivialapp"},
expectedExpressions: []string{"#compdef trivial"},
},
{
name: "linear",
root: func() *Command {
r := &Command{Use: "linear"}
sub1 := &Command{Use: "sub1"}
r.AddCommand(sub1)
sub2 := &Command{Use: "sub2"}
sub1.AddCommand(sub2)
sub3 := &Command{Use: "sub3"}
sub2.AddCommand(sub3)
return r
}(),
expectedExpressions: []string{"sub1", "sub2", "sub3"},
},
{
name: "flat",
root: func() *Command {
r := &Command{Use: "flat"}
r.AddCommand(&Command{Use: "c1"})
r.AddCommand(&Command{Use: "c2"})
return r
}(),
expectedExpressions: []string{"(c1 c2)"},
},
{
name: "tree",
root: func() *Command {
r := &Command{Use: "tree"}
sub1 := &Command{Use: "sub1"}
r.AddCommand(sub1)
sub11 := &Command{Use: "sub11"}
sub12 := &Command{Use: "sub12"}
sub1.AddCommand(sub11)
sub1.AddCommand(sub12)
sub2 := &Command{Use: "sub2"}
r.AddCommand(sub2)
sub21 := &Command{Use: "sub21"}
sub22 := &Command{Use: "sub22"}
sub2.AddCommand(sub21)
sub2.AddCommand(sub22)
return r
}(),
expectedExpressions: []string{"(sub11 sub12)", "(sub21 sub22)"},
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
buf := new(bytes.Buffer)
tc.root.GenZshCompletion(buf)
completion := buf.String()
for _, expectedExpression := range tc.expectedExpressions {
if !strings.Contains(completion, expectedExpression) {
t.Errorf("expected completion to contain '%v' somewhere; got '%v'", expectedExpression, completion)
}
}
})
}
}