1
mirror of https://github.com/rclone/rclone synced 2024-11-26 04:07:22 +01:00

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

View File

@ -2,8 +2,8 @@ language: go
matrix:
include:
- go: 1.7.5
- go: 1.8.1
- go: 1.7.6
- go: 1.8.3
- go: tip
allow_failures:
- 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
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
Using Cobra is easy. First, use `go get` to install the latest version
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
import (
"fmt"
"os"
"fmt"
"os"
"{pathToYourApp}/cmd"
"{pathToYourApp}/cmd"
)
func main() {
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
```
@ -285,14 +277,14 @@ Ideally you place this in app/cmd/root.go:
```go
var RootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
}
```
@ -302,54 +294,54 @@ For example cmd/root.go:
```go
import (
"fmt"
"os"
"fmt"
"os"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
func init() {
cobra.OnInitialize(initConfig)
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().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().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache")
cobra.OnInitialize(initConfig)
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().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().Bool("viper", true, "Use Viper for configuration")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
viper.BindPFlag("projectbase", RootCmd.PersistentFlags().Lookup("projectbase"))
viper.BindPFlag("useViper", RootCmd.PersistentFlags().Lookup("viper"))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache")
}
func Execute() {
RootCmd.Execute()
RootCmd.Execute()
}
func initConfig() {
// Don't forget to read config either from cfgFile or from home directory!
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cobra")
}
// Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".cobra")
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
os.Exit(1)
}
if err := viper.ReadInConfig(); err != nil {
fmt.Println("Can't read config:", err)
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
import (
"fmt"
"os"
"fmt"
"os"
"{pathToYourApp}/cmd"
"{pathToYourApp}/cmd"
)
func main() {
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
```
@ -390,21 +382,21 @@ populate it with the following:
package cmd
import (
"github.com/spf13/cobra"
"fmt"
"github.com/spf13/cobra"
"fmt"
)
func init() {
RootCmd.AddCommand(versionCmd)
RootCmd.AddCommand(versionCmd)
}
var versionCmd = &cobra.Command{
Use: "version",
Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Hugo Static Site Generator v0.9 -- HEAD")
},
Use: "version",
Short: "Print the version number of Hugo",
Long: `All software has versions. This is Hugo's`,
Run: func(cmd *cobra.Command, args []string) {
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)
```
### 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
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
func init() {
RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
viper.BindPFlag("author", RootCmd.PersistentFlags().Lookup("author"))
RootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution")
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).
## 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
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
import (
"fmt"
"strings"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/cobra"
)
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{
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.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdTimes = &cobra.Command{
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.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
var cmdTimes = &cobra.Command{
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")
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}
```
@ -635,16 +649,16 @@ The default help command is
```go
func (c *Command) initHelp() {
if c.helpCommand == nil {
c.helpCommand = &Command{
Use: "help [command]",
Short: "Help about any command",
Long: `Help provides help for any command in the application.
if c.helpCommand == nil {
c.helpCommand = &Command{
Use: "help [command]",
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(),
}
}
c.AddCommand(c.helpCommand)
Run: c.HelpFunc(),
}
}
c.AddCommand(c.helpCommand)
}
```
@ -652,9 +666,7 @@ You can provide your own command, function or template through the following met
```go
command.SetHelpCommand(cmd *Command)
command.SetHelpFunc(f func(*Command, []string))
command.SetHelpTemplate(s string)
```
@ -720,8 +732,8 @@ The default usage function is:
```go
return func(c *Command) error {
err := tmpl(c.Out(), c.UsageTemplate(), c)
return err
err := tmpl(c.Out(), c.UsageTemplate(), c)
return err
}
```
@ -749,57 +761,57 @@ An example of two commands which use all of these features is below. When the s
package main
import (
"fmt"
"fmt"
"github.com/spf13/cobra"
"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 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 subcommand",
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)
},
}
var subCmd = &cobra.Command{
Use: "sub [no options!]",
Short: "My subcommand",
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.AddCommand(subCmd)
rootCmd.SetArgs([]string{""})
_ = rootCmd.Execute()
fmt.Print("\n")
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
_ = rootCmd.Execute()
rootCmd.SetArgs([]string{""})
rootCmd.Execute()
fmt.Println()
rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
rootCmd.Execute()
}
```
@ -825,28 +837,28 @@ command.
package main
import (
"errors"
"log"
"errors"
"log"
"github.com/spf13/cobra"
"github.com/spf13/cobra"
)
func main() {
var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
RunE: func(cmd *cobra.Command, args []string) error {
// Do Stuff Here
return errors.New("some random error")
},
}
var rootCmd = &cobra.Command{
Use: "hugo",
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
Complete documentation is available at http://hugo.spf13.com`,
RunE: func(cmd *cobra.Command, args []string) error {
// Do Stuff Here
return errors.New("some random error")
},
}
if err := rootCmd.Execute(); err != nil {
log.Fatal(err)
}
if err := rootCmd.Execute(); err != nil {
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).
## 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

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(t, str, `flags_completion+=("_filedir")`)
// 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 for custom flags
check(t, str, `flags_completion+=("__complete_custom")`)

View File

@ -24,7 +24,7 @@ import (
func init() {
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
@ -121,7 +121,7 @@ func validateCmdName(source string) string {
func createCmdFile(license License, path, cmdName string) {
template := `{{comment .copyright}}
{{comment .license}}
{{if .license}}{{comment .license}}{{end}}
package {{.cmdPackage}}

View File

@ -6,6 +6,8 @@ import (
"os"
"path/filepath"
"testing"
"github.com/spf13/viper"
)
// TestGoldenAddCmd initializes the project "github.com/spf13/testproject"
@ -16,11 +18,18 @@ import (
func TestGoldenAddCmd(t *testing.T) {
projectName := "github.com/spf13/testproject"
project := NewProject(projectName)
// Initialize the project at first.
initializeProject(project)
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.
cmdName := "test"
cmdPath := filepath.Join(project.CmdPath(), cmdName+".go")
@ -48,7 +57,7 @@ func TestGoldenAddCmd(t *testing.T) {
goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden")
switch relPath {
// Know directories.
// Known directories.
case ".":
return nil
// Known files.

View File

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

View File

@ -6,6 +6,8 @@ import (
"os"
"path/filepath"
"testing"
"github.com/spf13/viper"
)
// TestGoldenInitCmd initializes the project "github.com/spf13/testproject"
@ -17,6 +19,13 @@ func TestGoldenInitCmd(t *testing.T) {
project := NewProject(projectName)
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}
if err := rootCmd.Execute(); err != nil {
t.Fatal("Error by execution:", err)
@ -44,7 +53,7 @@ func TestGoldenInitCmd(t *testing.T) {
goldenPath := filepath.Join("testdata", filepath.Base(path)+".golden")
switch relPath {
// Know directories.
// Known directories.
case ".", "cmd":
return nil
// Known files.

View File

@ -4,8 +4,7 @@ func initAgpl() {
Licenses["agpl"] = License{
Name: "GNU Affero General Public License",
PossibleMatches: []string{"agpl", "affero gpl", "gnu agpl"},
Header: `{{.copyright}}
Header: `
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
the Free Software Foundation, either version 3 of the License, or

View File

@ -19,7 +19,8 @@ func initApache2() {
Licenses["apache"] = License{
Name: "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 obtain a copy of the License at

View File

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

View File

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

View File

@ -19,20 +19,19 @@ func initGpl2() {
Licenses["gpl2"] = License{
Name: "GNU General Public License 2.0",
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
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 distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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/>.`,
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
Version 2, June 1991

View File

@ -19,8 +19,7 @@ func initGpl3() {
Licenses["gpl3"] = License{
Name: "GNU General Public License 3.0",
PossibleMatches: []string{"gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"},
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 3 of the License, or

View File

@ -4,8 +4,7 @@ func initLgpl() {
Licenses["lgpl"] = License{
Name: "GNU Lesser General Public License",
PossibleMatches: []string{"lgpl", "lesser gpl", "gnu lgpl"},
Header: `{{.copyright}}
Header: `
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
the Free Software Foundation, either version 3 of the License, or

View File

@ -17,7 +17,7 @@ package cmd
func initMit() {
Licenses["mit"] = License{
Name: "Mit",
Name: "MIT License",
PossibleMatches: []string{"mit"},
Header: `
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 {
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
}

View File

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

View File

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

View File

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

View File

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

View File

@ -36,6 +36,7 @@ var cmdHidden = &Command{
var cmdPrint = &Command{
Use: "print [string to print]",
Args: MinimumNArgs(1),
Short: "Print anything to the screen",
Long: `an absolutely utterly useless command for testing.`,
Run: func(cmd *Command, args []string) {
@ -75,6 +76,7 @@ var cmdDeprecated = &Command{
Deprecated: "Please use echo instead",
Run: func(cmd *Command, args []string) {
},
Args: NoArgs,
}
var cmdTimes = &Command{
@ -88,6 +90,8 @@ var cmdTimes = &Command{
Run: func(cmd *Command, args []string) {
tt = args
},
Args: OnlyValidArgs,
ValidArgs: []string{"one", "two", "three", "four"},
}
var cmdRootNoRun = &Command{
@ -105,6 +109,16 @@ var cmdRootSameName = &Command{
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{
Use: "cobra-test",
Short: "The root can run its own function",
@ -458,6 +472,63 @@ func TestUsage(t *testing.T) {
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) {
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
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)
}
@ -1095,7 +1166,7 @@ func TestGlobalNormFuncPropagation(t *testing.T) {
rootCmd := initialize()
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")
}

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 []string
// Expected arguments
Args PositionalArgs
// ArgAliases is List of aliases for ValidArgs.
// These are not suggested to the user in the bash completion,
// but accepted if entered manually.
@ -513,33 +516,29 @@ func (c *Command) Find(args []string) (*Command, []string, error) {
}
commandFound, a := innerfind(c, args)
argsWOflags := stripFlags(a, commandFound)
// no subcommand, always take args
if !commandFound.HasSubCommands() {
return commandFound, a, nil
if commandFound.Args == nil {
return commandFound, a, legacyArgs(commandFound, stripFlags(a, commandFound))
}
// 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
}
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.
func (c *Command) SuggestionsFor(typedName string) []string {
suggestions := []string{}
@ -624,6 +623,10 @@ func (c *Command) execute(a []string) (err error) {
argWoFlags = a
}
if err := c.ValidateArgs(argWoFlags); err != nil {
return err
}
for p := c; p != nil; p = p.Parent() {
if p.PersistentPreRunE != nil {
if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
@ -747,6 +750,13 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
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.
// It is called automatically by executing the c or by calling help and usage.
// 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)
}
}
})
}
}