From cac49a29fabc4f9d37ad229e75e438702154e4e5 Mon Sep 17 00:00:00 2001 From: umarcor Date: Wed, 2 Oct 2019 17:54:10 +0200 Subject: [PATCH] deprecate <1.12.x, use golangci-lint (#876) * deprecate go 1.10.x and 1.11.x * use golangci-lint in Travis CI * fix linting issues accordingly --- .circleci/config.yml | 9 +- .gitattributes | 1 + .gitignore | 3 + .golangci.yml | 25 +++ .travis.yml | 28 ++-- README.md | 242 +++++++++++++++--------------- bash_completions.go | 127 ++++++++-------- bash_completions_test.go | 32 ++-- cobra.go | 16 ++ cobra/cmd/add.go | 4 +- cobra/cmd/add_test.go | 6 +- cobra/cmd/golden_test.go | 27 ---- cobra/cmd/helpers.go | 110 +------------- cobra/cmd/init.go | 2 +- cobra/cmd/init_test.go | 4 +- cobra/cmd/licenses.go | 3 +- cobra/cmd/project.go | 2 +- cobra/cmd/root.go | 8 +- cobra/cmd/testdata/root.go.golden | 7 +- cobra/tpl/main.go | 12 +- command.go | 108 ++++++------- command_test.go | 201 +++++++++++-------------- doc/man_docs.go | 28 ++-- doc/man_docs_test.go | 2 +- doc/man_examples_test.go | 8 +- doc/util.go | 9 ++ fish_completions.go | 27 ++-- fish_completions_test.go | 16 +- go.mod | 1 - go.sum | 2 - powershell_completions_test.go | 2 +- zsh_completions_test.go | 28 ++-- 32 files changed, 496 insertions(+), 604 deletions(-) create mode 100644 .gitattributes create mode 100644 .golangci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 819446439..533542dfa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,7 @@ references: run: name: "All Commands" command: | + export GO111MODULE=on mkdir -p bin curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck chmod +x bin/shellcheck @@ -29,13 +30,6 @@ jobs: - run: name: "Check formatting" command: diff -u <(echo -n) <(gofmt -d -s .) - go-previous: - docker: - - image: circleci/golang:1.11 - working_directory: *workspace - steps: - - checkout - - *run_tests go-latest: docker: - image: circleci/golang:latest @@ -49,5 +43,4 @@ workflows: main: jobs: - go-current - - go-previous - go-latest diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..212566614 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto \ No newline at end of file diff --git a/.gitignore b/.gitignore index 208e7d741..40405ad07 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ cobra.test .idea/ *.iml + +# test-generated files +cobra/cmd/testproject diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000..8450df644 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,25 @@ +run: + deadline: 5m + +linters: + enable: + - deadcode + - errcheck + - gas + - goconst + - goimports + - golint + - govet + - ineffassign + - interfacer + - maligned + - megacheck + - structcheck + - unconvert + - varcheck + enable-all: false + disable-all: true +# presets: +# - bugs +# - unused + fast: false diff --git a/.travis.yml b/.travis.yml index 4904788cd..b91301f35 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,27 @@ language: go stages: - - diff + - lint - test go: - - 1.10.x - - 1.11.x - 1.12.x + - 1.13.x - tip -env: - - GO111MODULE=on - -matrix: - allow_failures: - - go: tip - include: - - stage: diff - go: 1.12.x - script: diff -u <(echo -n) <(gofmt -d -s .) +env: GO111MODULE=on before_install: go get -u github.com/kyoh86/richgo script: - richgo test -v ./... - go build - - if [ -z $NOVET ]; then - diff -u <(echo -n) <(go vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint'); - fi + +matrix: + allow_failures: + - go: tip + include: + - stage: lint + go: 1.13.x + before_install: go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.19.1 + script: golangci-lint run -v diff --git a/README.md b/README.md index f15c72170..80efbc962 100644 --- a/README.md +++ b/README.md @@ -87,20 +87,12 @@ Cobra is built on a structure of commands, arguments & flags. The best applications will read like sentences when used. Users will know how to use the application because they will natively understand how to use it. -The pattern to follow is -`APPNAME VERB NOUN --ADJECTIVE.` - or -`APPNAME COMMAND ARG --FLAG` +The pattern to follow is `APPNAME VERB NOUN --ADJECTIVE` or `APPNAME COMMAND ARG --FLAG`. A few good real world examples may better illustrate this point. -In the following example, 'server' is a command, and 'port' is a flag: - - hugo server --port=1313 - -In this command we are telling Git to clone the url bare. - - git clone URL --bare +In example `hugo server --port=1313`, 'server' is a command, and 'port' is a flag. +In `git clone URL --bare`, we are telling Git to clone the url bare. ## Commands @@ -215,7 +207,6 @@ package cmd import ( "fmt" - homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -256,12 +247,13 @@ func init() { } 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() + home, err := os.UserHomeDir() if err != nil { er(err) } @@ -290,11 +282,11 @@ In a Cobra app, typically the main.go file is very bare. It serves, one purpose, package main import ( - "{pathToYourApp}/cmd" + "{pathToYourApp}/cmd" ) func main() { - cmd.Execute() + cmd.Execute() } ``` @@ -310,22 +302,22 @@ populate it with the following: package cmd import ( - "fmt" + "fmt" - "github.com/spf13/cobra" + "github.com/spf13/cobra" ) 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") + }, } ``` @@ -372,8 +364,8 @@ parse local flags on each command before executing the target command. ```go command := cobra.Command{ - Use: "print [OPTIONS] [COMMANDS]", - TraverseChildren: true, + Use: "print [OPTIONS] [COMMANDS]", + TraverseChildren: true, } ``` @@ -384,8 +376,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")) } ``` @@ -427,21 +419,21 @@ Moreover, it is possible to set any custom validator that satisfies `func(cmd *c ```go var cmd = &cobra.Command{ - Short: "hello", - Args: func(cmd *cobra.Command, args []string) error { - // Optionally run one of the validators provided by cobra - if err := cobra.MinimumNArgs(1)(cmd args); err != nil { - return err - } - // Run the custom validation logic - 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!") - }, + Short: "hello", + Args: func(cmd *cobra.Command, args []string) error { + // Optionally run one of the validators provided by cobra + if err := cobra.MinimumNArgs(1)(cmd args); err != nil { + return err + } + // Run the custom validation logic + 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!") + }, } ``` @@ -460,56 +452,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. + 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, " ")) - }, - } + 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. + 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("Echo: " + strings.Join(args, " ")) - }, - } + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Echo: " + strings.Join(args, " ")) + }, + } - var cmdTimes = &cobra.Command{ - Use: "times [string to echo]", - Short: "Echo anything to the screen more times", - Long: `echo things multiple times back to the user by providing + var cmdTimes = &cobra.Command{ + Use: "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, " ")) - } - }, - } + Args: cobra.MinimumNArgs(1), + 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() } ``` @@ -521,7 +513,7 @@ Cobra automatically adds a help command to your application when you have subcom This will be called when a user runs 'app help'. Additionally, help will also support all other commands as input. Say, for instance, you have a command called 'create' without any additional configuration; Cobra will work when 'app help -create' is called. Every command will automatically have the '--help' flag added. +create' is called. Every command will automatically have the '--help' flag added. ### Example @@ -628,57 +620,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.Println() - rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) - rootCmd.Execute() + rootCmd.SetArgs([]string{""}) + rootCmd.Execute() + fmt.Println() + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + rootCmd.Execute() } ``` diff --git a/bash_completions.go b/bash_completions.go index 1e0e25cf6..5ca20155d 100644 --- a/bash_completions.go +++ b/bash_completions.go @@ -19,9 +19,9 @@ const ( BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" ) -func writePreamble(buf *bytes.Buffer, name string) { - buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) - buf.WriteString(fmt.Sprintf(` +func writePreamble(buf io.StringWriter, name string) { + WrStringAndCheck(buf, fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) + WrStringAndCheck(buf, fmt.Sprintf(` __%[1]s_debug() { if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then @@ -282,10 +282,10 @@ __%[1]s_handle_word() `, name)) } -func writePostscript(buf *bytes.Buffer, name string) { +func writePostscript(buf io.StringWriter, name string) { name = strings.Replace(name, ":", "__", -1) - buf.WriteString(fmt.Sprintf("__start_%s()\n", name)) - buf.WriteString(fmt.Sprintf(`{ + WrStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name)) + WrStringAndCheck(buf, fmt.Sprintf(`{ local cur prev words cword declare -A flaghash 2>/dev/null || : declare -A aliashash 2>/dev/null || : @@ -311,33 +311,33 @@ func writePostscript(buf *bytes.Buffer, name string) { } `, name)) - buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then + WrStringAndCheck(buf, fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then complete -o default -F __start_%s %s else complete -o default -o nospace -F __start_%s %s fi `, name, name, name, name)) - buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n") + WrStringAndCheck(buf, "# ex: ts=4 sw=4 et filetype=sh\n") } -func writeCommands(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" commands=()\n") +func writeCommands(buf io.StringWriter, cmd *Command) { + WrStringAndCheck(buf, " commands=()\n") for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue } - buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) + WrStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name())) writeCmdAliases(buf, c) } - buf.WriteString("\n") + WrStringAndCheck(buf, "\n") } -func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]string, cmd *Command) { +func writeFlagHandler(buf io.StringWriter, name string, annotations map[string][]string, cmd *Command) { for key, value := range annotations { switch key { case BashCompFilenameExt: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) > 0 { @@ -345,17 +345,18 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s } else { ext = "_filedir" } - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext)) case BashCompCustom: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + if len(value) > 0 { handlers := strings.Join(value, "; ") - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) } else { - buf.WriteString(" flags_completion+=(:)\n") + WrStringAndCheck(buf, " flags_completion+=(:)\n") } case BashCompSubdirsInDir: - buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) var ext string if len(value) == 1 { @@ -363,49 +364,51 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s } else { ext = "_filedir -d" } - buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) + WrStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext)) } } } -func writeShortFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { +const cbn = "\")\n" + +func writeShortFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) { name := flag.Shorthand format := " " if len(flag.NoOptDefVal) == 0 { format += "two_word_" } - format += "flags+=(\"-%s\")\n" - buf.WriteString(fmt.Sprintf(format, name)) + format += "flags+=(\"-%s" + cbn + WrStringAndCheck(buf, fmt.Sprintf(format, name)) writeFlagHandler(buf, "-"+name, flag.Annotations, cmd) } -func writeFlag(buf *bytes.Buffer, flag *pflag.Flag, cmd *Command) { +func writeFlag(buf io.StringWriter, flag *pflag.Flag, cmd *Command) { name := flag.Name format := " flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { format += "=" } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, name)) + format += cbn + WrStringAndCheck(buf, fmt.Sprintf(format, name)) if len(flag.NoOptDefVal) == 0 { - format = " two_word_flags+=(\"--%s\")\n" - buf.WriteString(fmt.Sprintf(format, name)) + format = " two_word_flags+=(\"--%s" + cbn + WrStringAndCheck(buf, fmt.Sprintf(format, name)) } writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) } -func writeLocalNonPersistentFlag(buf *bytes.Buffer, flag *pflag.Flag) { +func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) { name := flag.Name format := " local_nonpersistent_flags+=(\"--%s" if len(flag.NoOptDefVal) == 0 { format += "=" } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, name)) + format += cbn + WrStringAndCheck(buf, fmt.Sprintf(format, name)) } -func writeFlags(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(` flags=() +func writeFlags(buf io.StringWriter, cmd *Command) { + WrStringAndCheck(buf, ` flags=() two_word_flags=() local_nonpersistent_flags=() flags_with_completion=() @@ -435,11 +438,11 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) { } }) - buf.WriteString("\n") + WrStringAndCheck(buf, "\n") } -func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" must_have_one_flag=()\n") +func writeRequiredFlag(buf io.StringWriter, cmd *Command) { + WrStringAndCheck(buf, " must_have_one_flag=()\n") flags := cmd.NonInheritedFlags() flags.VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { @@ -452,49 +455,49 @@ func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { if flag.Value.Type() != "bool" { format += "=" } - format += "\")\n" - buf.WriteString(fmt.Sprintf(format, flag.Name)) + format += cbn + WrStringAndCheck(buf, fmt.Sprintf(format, flag.Name)) if len(flag.Shorthand) > 0 { - buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand)) + WrStringAndCheck(buf, fmt.Sprintf(" must_have_one_flag+=(\"-%s"+cbn, flag.Shorthand)) } } } }) } -func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" must_have_one_noun=()\n") - sort.Sort(sort.StringSlice(cmd.ValidArgs)) +func writeRequiredNouns(buf io.StringWriter, cmd *Command) { + WrStringAndCheck(buf, " must_have_one_noun=()\n") + sort.Strings(cmd.ValidArgs) for _, value := range cmd.ValidArgs { - buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) + WrStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) } } -func writeCmdAliases(buf *bytes.Buffer, cmd *Command) { +func writeCmdAliases(buf io.StringWriter, cmd *Command) { if len(cmd.Aliases) == 0 { return } - sort.Sort(sort.StringSlice(cmd.Aliases)) + sort.Strings(cmd.Aliases) - buf.WriteString(fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n")) + WrStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n")) for _, value := range cmd.Aliases { - buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value)) - buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) + WrStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value)) + WrStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) } - buf.WriteString(` fi`) - buf.WriteString("\n") + WrStringAndCheck(buf, ` fi`) + WrStringAndCheck(buf, "\n") } -func writeArgAliases(buf *bytes.Buffer, cmd *Command) { - buf.WriteString(" noun_aliases=()\n") - sort.Sort(sort.StringSlice(cmd.ArgAliases)) +func writeArgAliases(buf io.StringWriter, cmd *Command) { + WrStringAndCheck(buf, " noun_aliases=()\n") + sort.Strings(cmd.ArgAliases) for _, value := range cmd.ArgAliases { - buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value)) + WrStringAndCheck(buf, fmt.Sprintf(" noun_aliases+=(%q)\n", value)) } } -func gen(buf *bytes.Buffer, cmd *Command) { +func gen(buf io.StringWriter, cmd *Command) { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c == cmd.helpCommand { continue @@ -506,22 +509,22 @@ func gen(buf *bytes.Buffer, cmd *Command) { commandName = strings.Replace(commandName, ":", "__", -1) if cmd.Root() == cmd { - buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName)) + WrStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName)) } else { - buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) + WrStringAndCheck(buf, fmt.Sprintf("_%s()\n{\n", commandName)) } - buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) - buf.WriteString("\n") - buf.WriteString(" command_aliases=()\n") - buf.WriteString("\n") + WrStringAndCheck(buf, fmt.Sprintf(" last_command=%q\n", commandName)) + WrStringAndCheck(buf, "\n") + WrStringAndCheck(buf, " command_aliases=()\n") + WrStringAndCheck(buf, "\n") writeCommands(buf, cmd) writeFlags(buf, cmd) writeRequiredFlag(buf, cmd) writeRequiredNouns(buf, cmd) writeArgAliases(buf, cmd) - buf.WriteString("}\n\n") + WrStringAndCheck(buf, "}\n\n") } // GenBashCompletion generates bash completion file and writes to the passed writer. diff --git a/bash_completions_test.go b/bash_completions_test.go index 55b56f8af..d689a9439 100644 --- a/bash_completions_test.go +++ b/bash_completions_test.go @@ -52,7 +52,9 @@ func runShellCheck(s string) error { return err } go func() { - stdin.Write([]byte(s)) + _, err := stdin.Write([]byte(s)) + er(err) + stdin.Close() }() @@ -74,26 +76,26 @@ func TestBashCompletions(t *testing.T) { Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") - rootCmd.MarkFlagRequired("introot") + er(rootCmd.MarkFlagRequired("introot")) // Filename. rootCmd.Flags().String("filename", "", "Enter a filename") - rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml") + er(rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) // Persistent filename. rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") - rootCmd.MarkPersistentFlagFilename("persistent-filename") - rootCmd.MarkPersistentFlagRequired("persistent-filename") + er(rootCmd.MarkPersistentFlagFilename("persistent-filename")) + er(rootCmd.MarkPersistentFlagRequired("persistent-filename")) // Filename extensions. rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") - rootCmd.MarkFlagFilename("filename-ext") + er(rootCmd.MarkFlagFilename("filename-ext")) rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") - rootCmd.MarkFlagCustom("custom", "__complete_custom") + er(rootCmd.MarkFlagCustom("custom", "__complete_custom")) // Subdirectories in a given directory. rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") - rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) + er(rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"})) // For two word flags check rootCmd.Flags().StringP("two", "t", "", "this is two word flags") @@ -109,9 +111,9 @@ func TestBashCompletions(t *testing.T) { } echoCmd.Flags().String("filename", "", "Enter a filename") - echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml") + er(echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)") - echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"}) + er(echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"})) printCmd := &Command{ Use: "print [string to print]", @@ -149,7 +151,7 @@ func TestBashCompletions(t *testing.T) { rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) buf := new(bytes.Buffer) - rootCmd.GenBashCompletion(buf) + er(rootCmd.GenBashCompletion(buf)) output := buf.String() check(t, output, "_root") @@ -209,10 +211,10 @@ func TestBashCompletionHiddenFlag(t *testing.T) { const flagName = "hiddenFlag" c.Flags().Bool(flagName, false, "") - c.Flags().MarkHidden(flagName) + er(c.Flags().MarkHidden(flagName)) buf := new(bytes.Buffer) - c.GenBashCompletion(buf) + er(c.GenBashCompletion(buf)) output := buf.String() if strings.Contains(output, flagName) { @@ -225,10 +227,10 @@ func TestBashCompletionDeprecatedFlag(t *testing.T) { const flagName = "deprecated-flag" c.Flags().Bool(flagName, false, "") - c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead") + er(c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead")) buf := new(bytes.Buffer) - c.GenBashCompletion(buf) + er(c.GenBashCompletion(buf)) output := buf.String() if strings.Contains(output, flagName) { diff --git a/cobra.go b/cobra.go index d01becc8f..00183ad7e 100644 --- a/cobra.go +++ b/cobra.go @@ -19,6 +19,7 @@ package cobra import ( "fmt" "io" + "os" "reflect" "strconv" "strings" @@ -205,3 +206,18 @@ func stringInSlice(a string, list []string) bool { } return false } + +func er(msg interface{}) { + if msg != nil { + fmt.Println("Error:", msg) + os.Exit(1) + } +} + +// Er prints the msg and exits with error code 1, unless the msg is nil +func Er(msg interface{}) { er(msg) } + +func WrStringAndCheck(b io.StringWriter, s string) { + _, err := b.WriteString(s) + er(err) +} diff --git a/cobra/cmd/add.go b/cobra/cmd/add.go index 6645a755f..f8c294718 100644 --- a/cobra/cmd/add.go +++ b/cobra/cmd/add.go @@ -40,7 +40,7 @@ Example: cobra add server -> resulting in a new cmd/server.go`, Run: func(cmd *cobra.Command, args []string) { if len(args) < 1 { - er("add needs a name for the command") + er(fmt.Errorf("add needs a name for the command")) } wd, err := os.Getwd() @@ -72,7 +72,7 @@ Example: cobra add server -> resulting in a new cmd/server.go`, func init() { addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") - addCmd.Flags().MarkDeprecated("package", "this operation has been removed.") + er(addCmd.Flags().MarkDeprecated("package", "this operation has been removed.")) } // validateCmdName returns source without any dashes and underscore. diff --git a/cobra/cmd/add_test.go b/cobra/cmd/add_test.go index de92fcea6..2847a0649 100644 --- a/cobra/cmd/add_test.go +++ b/cobra/cmd/add_test.go @@ -14,10 +14,8 @@ func TestGoldenAddCmd(t *testing.T) { } defer os.RemoveAll(command.AbsolutePath) - command.Project.Create() - if err := command.Create(); err != nil { - t.Fatal(err) - } + er(command.Project.Create()) + er(command.Create()) generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName) goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName) diff --git a/cobra/cmd/golden_test.go b/cobra/cmd/golden_test.go index c030c6ab5..852ec4efe 100644 --- a/cobra/cmd/golden_test.go +++ b/cobra/cmd/golden_test.go @@ -3,14 +3,11 @@ package cmd import ( "bytes" "errors" - "flag" "fmt" "io/ioutil" "os/exec" ) -var update = flag.Bool("update", false, "update .golden files") - func init() { // Mute commands. addCmd.SetOutput(new(bytes.Buffer)) @@ -56,27 +53,3 @@ func compareFiles(pathA, pathB string) error { } return nil } - -// checkLackFiles checks if all elements of expected are in got. -func checkLackFiles(expected, got []string) error { - lacks := make([]string, 0, len(expected)) - for _, ev := range expected { - if !stringInStringSlice(ev, got) { - lacks = append(lacks, ev) - } - } - if len(lacks) > 0 { - return fmt.Errorf("Lack %v file(s): %v", len(lacks), lacks) - } - return nil -} - -// stringInStringSlice checks if s is an element of slice. -func stringInStringSlice(s string, slice []string) bool { - for _, v := range slice { - if s == v { - return true - } - } - return false -} diff --git a/cobra/cmd/helpers.go b/cobra/cmd/helpers.go index cd94b3e31..0f7c33ee5 100644 --- a/cobra/cmd/helpers.go +++ b/cobra/cmd/helpers.go @@ -14,14 +14,11 @@ package cmd import ( - "bytes" "fmt" - "io" "os" "os/exec" "path/filepath" "strings" - "text/template" ) var srcPaths []string @@ -60,109 +57,8 @@ func init() { } func er(msg interface{}) { - fmt.Println("Error:", msg) - os.Exit(1) -} - -// isEmpty checks if a given path is empty. -// Hidden files in path are ignored. -func isEmpty(path string) bool { - fi, err := os.Stat(path) - if err != nil { - er(err) - } - - if !fi.IsDir() { - return fi.Size() == 0 - } - - f, err := os.Open(path) - if err != nil { - er(err) - } - defer f.Close() - - names, err := f.Readdirnames(-1) - if err != nil && err != io.EOF { - er(err) - } - - for _, name := range names { - if len(name) > 0 && name[0] != '.' { - return false - } - } - return true -} - -// exists checks if a file or directory exists. -func exists(path string) bool { - if path == "" { - return false - } - _, err := os.Stat(path) - if err == nil { - return true - } - if !os.IsNotExist(err) { - er(err) - } - return false -} - -func executeTemplate(tmplStr string, data interface{}) (string, error) { - tmpl, err := template.New("").Funcs(template.FuncMap{"comment": commentifyString}).Parse(tmplStr) - if err != nil { - return "", err - } - - buf := new(bytes.Buffer) - err = tmpl.Execute(buf, data) - return buf.String(), err -} - -func writeStringToFile(path string, s string) error { - return writeToFile(path, strings.NewReader(s)) -} - -// writeToFile writes r to file with path only -// if file/directory on given path doesn't exist. -func writeToFile(path string, r io.Reader) error { - if exists(path) { - return fmt.Errorf("%v already exists", path) - } - - dir := filepath.Dir(path) - if dir != "" { - if err := os.MkdirAll(dir, 0777); err != nil { - return err - } - } - - file, err := os.Create(path) - if err != nil { - return err - } - defer file.Close() - - _, err = io.Copy(file, r) - return err -} - -// commentfyString comments every line of in. -func commentifyString(in string) string { - var newlines []string - lines := strings.Split(in, "\n") - for _, line := range lines { - if strings.HasPrefix(line, "//") { - newlines = append(newlines, line) - } else { - if line == "" { - newlines = append(newlines, "//") - } else { - newlines = append(newlines, "// "+line) - } - } + if msg != nil { + fmt.Println("Error:", msg) + os.Exit(1) } - return strings.Join(newlines, "\n") } diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go index dcf5ada4f..c982ea4d1 100644 --- a/cobra/cmd/init.go +++ b/cobra/cmd/init.go @@ -74,5 +74,5 @@ Init will not use an existing directory with contents.`, func init() { initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name") - initCmd.MarkFlagRequired("pkg-name") + er(initCmd.MarkFlagRequired("pkg-name")) } diff --git a/cobra/cmd/init_test.go b/cobra/cmd/init_test.go index 8ee391061..2047f5348 100644 --- a/cobra/cmd/init_test.go +++ b/cobra/cmd/init_test.go @@ -23,9 +23,7 @@ func TestGoldenInitCmd(t *testing.T) { project := getProject() defer os.RemoveAll(project.AbsolutePath) - if err := project.Create(); err != nil { - t.Fatal(err) - } + er(project.Create()) expectedFiles := []string{"LICENSE", "main.go", "cmd/root.go"} for _, f := range expectedFiles { diff --git a/cobra/cmd/licenses.go b/cobra/cmd/licenses.go index a070134dd..bb3048465 100644 --- a/cobra/cmd/licenses.go +++ b/cobra/cmd/licenses.go @@ -16,6 +16,7 @@ package cmd import ( + "fmt" "strings" "time" @@ -92,7 +93,7 @@ func copyrightLine() string { func findLicense(name string) License { found := matchLicense(name) if found == "" { - er("unknown license: " + name) + er(fmt.Errorf("unknown license: " + name)) } return Licenses[found] } diff --git a/cobra/cmd/project.go b/cobra/cmd/project.go index ecd783d03..304e9880f 100644 --- a/cobra/cmd/project.go +++ b/cobra/cmd/project.go @@ -49,7 +49,7 @@ func (p *Project) Create() error { // create cmd/root.go if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) { - os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751) + er(os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751)) } rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath)) if err != nil { diff --git a/cobra/cmd/root.go b/cobra/cmd/root.go index 97f404bbb..27c7ac2a4 100644 --- a/cobra/cmd/root.go +++ b/cobra/cmd/root.go @@ -15,8 +15,8 @@ package cmd import ( "fmt" + "os" - homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -47,8 +47,8 @@ func init() { rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") - viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) - viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) + er(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author"))) + er(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper"))) viper.SetDefault("author", "NAME HERE ") viper.SetDefault("license", "apache") @@ -62,7 +62,7 @@ func initConfig() { viper.SetConfigFile(cfgFile) } else { // Find home directory. - home, err := homedir.Dir() + home, err := os.UserHomeDir() if err != nil { er(err) } diff --git a/cobra/cmd/testdata/root.go.golden b/cobra/cmd/testdata/root.go.golden index 6a54a7837..9266b59a7 100644 --- a/cobra/cmd/testdata/root.go.golden +++ b/cobra/cmd/testdata/root.go.golden @@ -17,10 +17,9 @@ package cmd import ( "fmt" - "github.com/spf13/cobra" "os" - homedir "github.com/mitchellh/go-homedir" + "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -38,7 +37,7 @@ This application is a tool to generate the needed files to quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, + // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -71,7 +70,7 @@ func initConfig() { viper.SetConfigFile(cfgFile) } else { // Find home directory. - home, err := homedir.Dir() + home, err := os.UserHomeDir() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/cobra/tpl/main.go b/cobra/tpl/main.go index b5e2e1aeb..d80ba88ed 100644 --- a/cobra/tpl/main.go +++ b/cobra/tpl/main.go @@ -24,12 +24,10 @@ package cmd import ( "fmt" - "github.com/spf13/cobra" "os" -{{ if .Viper }} - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/viper" -{{ end -}} + + "github.com/spf13/cobra" + {{ if .Viper }}"github.com/spf13/viper"{{ end }} ) {{ if .Viper -}} @@ -48,7 +46,7 @@ This application is a tool to generate the needed files to quickly create a Cobra application.` + "`" + `, // Uncomment the following line if your bare application // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { }, + // Run: func(cmd *cobra.Command, args []string) { }, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -85,7 +83,7 @@ func initConfig() { viper.SetConfigFile(cfgFile) } else { // Find home directory. - home, err := homedir.Dir() + home, err := os.UserHomeDir() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/command.go b/command.go index 3297f34af..16d91098b 100644 --- a/command.go +++ b/command.go @@ -74,9 +74,6 @@ type Command struct { // Deprecated defines, if this command is deprecated and should print this string when used. Deprecated string - // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. - Hidden bool - // Annotations are key/value pairs that can be used by applications to identify or // group commands. Annotations map[string]string @@ -115,53 +112,6 @@ type Command struct { // PersistentPostRunE: PersistentPostRun but returns an error. PersistentPostRunE func(cmd *Command, args []string) error - // SilenceErrors is an option to quiet errors down stream. - SilenceErrors bool - - // SilenceUsage is an option to silence usage when an error occurs. - SilenceUsage bool - - // DisableFlagParsing disables the flag parsing. - // If this is true all flags will be passed to the command as arguments. - DisableFlagParsing bool - - // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") - // will be printed by generating docs for this command. - DisableAutoGenTag bool - - // DisableFlagsInUseLine will disable the addition of [flags] to the usage - // line of a command when printing help or generating docs - DisableFlagsInUseLine bool - - // DisableSuggestions disables the suggestions based on Levenshtein distance - // that go along with 'unknown command' messages. - DisableSuggestions bool - // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. - // Must be > 0. - SuggestionsMinimumDistance int - - // TraverseChildren parses flags on all parents before executing child command. - TraverseChildren bool - - //FParseErrWhitelist flag parse errors to be ignored - FParseErrWhitelist FParseErrWhitelist - - // commands is the list of commands supported by this program. - commands []*Command - // parent is a parent command for this command. - parent *Command - // Max lengths of commands' string lengths for use in padding. - commandsMaxUseLen int - commandsMaxCommandPathLen int - commandsMaxNameLen int - // commandsAreSorted defines, if command slice are sorted or not. - commandsAreSorted bool - // commandCalledAs is the name or alias value used to call this command. - commandCalledAs struct { - name string - called bool - } - // args is actual args parsed from flags. args []string // flagErrorBuf contains all error messages from pflag. @@ -203,6 +153,58 @@ type Command struct { outWriter io.Writer // errWriter is a writer defined by the user that replaces stderr errWriter io.Writer + + //FParseErrWhitelist flag parse errors to be ignored + FParseErrWhitelist FParseErrWhitelist + + // commandsAreSorted defines, if command slice are sorted or not. + commandsAreSorted bool + // commandCalledAs is the name or alias value used to call this command. + commandCalledAs struct { + name string + called bool + } + + // commands is the list of commands supported by this program. + commands []*Command + // parent is a parent command for this command. + parent *Command + // Max lengths of commands' string lengths for use in padding. + commandsMaxUseLen int + commandsMaxCommandPathLen int + commandsMaxNameLen int + + // TraverseChildren parses flags on all parents before executing child command. + TraverseChildren bool + + // Hidden defines, if this command is hidden and should NOT show up in the list of available commands. + Hidden bool + + // SilenceErrors is an option to quiet errors down stream. + SilenceErrors bool + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage bool + + // DisableFlagParsing disables the flag parsing. + // If this is true all flags will be passed to the command as arguments. + DisableFlagParsing bool + + // DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") + // will be printed by generating docs for this command. + DisableAutoGenTag bool + + // DisableFlagsInUseLine will disable the addition of [flags] to the usage + // line of a command when printing help or generating docs + DisableFlagsInUseLine bool + + // DisableSuggestions disables the suggestions based on Levenshtein distance + // that go along with 'unknown command' messages. + DisableSuggestions bool + + // SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. + // Must be > 0. + SuggestionsMinimumDistance int } // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden @@ -399,7 +401,7 @@ func (c *Command) UsageString() string { c.outWriter = bb c.errWriter = bb - c.Usage() + er(c.Usage()) // Setting things back to normal c.outWriter = tmpOutput @@ -1033,10 +1035,10 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`, cmd, _, e := c.Root().Find(args) if cmd == nil || e != nil { c.Printf("Unknown help topic %#q\n", args) - c.Root().Usage() + er(c.Root().Usage()) } else { cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown - cmd.Help() + er(cmd.Help()) } }, } diff --git a/command_test.go b/command_test.go index b26bd4abe..ee4cae2f4 100644 --- a/command_test.go +++ b/command_test.go @@ -38,11 +38,7 @@ func checkStringContains(t *testing.T, got, expected string) { } } -func checkStringOmits(t *testing.T, got, expected string) { - if strings.Contains(got, expected) { - t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) - } -} +const onetwo = "one two" func TestSingleCommand(t *testing.T) { var rootCmdArgs []string @@ -64,9 +60,8 @@ func TestSingleCommand(t *testing.T) { } got := strings.Join(rootCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got) + if got != onetwo { + t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } @@ -90,9 +85,8 @@ func TestChildCommand(t *testing.T) { } got := strings.Join(child1CmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got) + if got != onetwo { + t.Errorf("child1CmdArgs expected: %q, got: %q", onetwo, got) } } @@ -131,7 +125,7 @@ func TestSubcommandExecuteC(t *testing.T) { } if c.Name() != "child" { - t.Errorf(`invalid command returned from ExecuteC: expected "child"', got %q`, c.Name()) + t.Errorf(`invalid command returned from ExecuteC: expected "child"', got: %q`, c.Name()) } } @@ -173,9 +167,8 @@ func TestCommandAlias(t *testing.T) { } got := strings.Join(timesCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) + if got != onetwo { + t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got) } } @@ -201,9 +194,8 @@ func TestEnablePrefixMatching(t *testing.T) { } got := strings.Join(aCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("aCmdArgs expected: %q, got: %q", expected, got) + if got != onetwo { + t.Errorf("aCmdArgs expected: %q, got: %q", onetwo, got) } EnablePrefixMatching = false @@ -237,9 +229,8 @@ func TestAliasPrefixMatching(t *testing.T) { } got := strings.Join(timesCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got) + if got != onetwo { + t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got) } EnablePrefixMatching = false @@ -268,9 +259,8 @@ func TestChildSameName(t *testing.T) { } got := strings.Join(fooCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) + if got != onetwo { + t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got) } } @@ -298,9 +288,8 @@ func TestGrandChildSameName(t *testing.T) { } got := strings.Join(fooCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got) + if got != onetwo { + t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got) } } @@ -336,9 +325,8 @@ func TestFlagLong(t *testing.T) { } got := strings.Join(cArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("Expected arguments: %q, got %q", expected, got) + if got != onetwo { + t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } @@ -371,9 +359,8 @@ func TestFlagShort(t *testing.T) { } got := strings.Join(cArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("Expected arguments: %q, got %q", expected, got) + if got != onetwo { + t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } } @@ -575,9 +562,8 @@ func TestPersistentFlagsOnSameCommand(t *testing.T) { } got := strings.Join(rootCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("rootCmdArgs expected: %q, got %q", expected, got) + if got != onetwo { + t.Errorf("rootCmdArgs expected: %q, got %q", onetwo, got) } if flagValue != 7 { t.Errorf("flagValue expected: %v, got %v", 7, flagValue) @@ -661,9 +647,8 @@ func TestPersistentFlagsOnChild(t *testing.T) { } got := strings.Join(childCmdArgs, " ") - expected := "one two" - if got != expected { - t.Errorf("childCmdArgs expected: %q, got %q", expected, got) + if got != onetwo { + t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got) } if parentFlagValue != 8 { t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) @@ -676,9 +661,9 @@ func TestPersistentFlagsOnChild(t *testing.T) { func TestRequiredFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().String("foo1", "", "") - c.MarkFlagRequired("foo1") + er(c.MarkFlagRequired("foo1")) c.Flags().String("foo2", "", "") - c.MarkFlagRequired("foo2") + er(c.MarkFlagRequired("foo2")) c.Flags().String("bar", "", "") expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") @@ -694,16 +679,16 @@ func TestRequiredFlags(t *testing.T) { func TestPersistentRequiredFlags(t *testing.T) { parent := &Command{Use: "parent", Run: emptyRun} parent.PersistentFlags().String("foo1", "", "") - parent.MarkPersistentFlagRequired("foo1") + er(parent.MarkPersistentFlagRequired("foo1")) parent.PersistentFlags().String("foo2", "", "") - parent.MarkPersistentFlagRequired("foo2") + er(parent.MarkPersistentFlagRequired("foo2")) parent.Flags().String("foo3", "", "") child := &Command{Use: "child", Run: emptyRun} child.Flags().String("bar1", "", "") - child.MarkFlagRequired("bar1") + er(child.MarkFlagRequired("bar1")) child.Flags().String("bar2", "", "") - child.MarkFlagRequired("bar2") + er(child.MarkFlagRequired("bar2")) child.Flags().String("bar3", "", "") parent.AddCommand(child) @@ -1083,20 +1068,19 @@ func TestHooks(t *testing.T) { t.Errorf("Unexpected error: %v", err) } - if persPreArgs != "one two" { - t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs) - } - if preArgs != "one two" { - t.Errorf("Expected preArgs %q, got %q", "one two", preArgs) - } - if runArgs != "one two" { - t.Errorf("Expected runArgs %q, got %q", "one two", runArgs) - } - if postArgs != "one two" { - t.Errorf("Expected postArgs %q, got %q", "one two", postArgs) - } - if persPostArgs != "one two" { - t.Errorf("Expected persPostArgs %q, got %q", "one two", persPostArgs) + for _, v := range []struct { + name string + got string + }{ + {"persPreArgs", persPreArgs}, + {"preArgs", preArgs}, + {"runArgs", runArgs}, + {"postArgs", postArgs}, + {"persPostArgs", persPostArgs}, + } { + if v.got != onetwo { + t.Errorf("Expected %s %q, got %q", v.name, onetwo, v.got) + } } } @@ -1164,44 +1148,42 @@ func TestPersistentHooks(t *testing.T) { t.Errorf("Unexpected error: %v", err) } - // TODO: currently PersistenPreRun* defined in parent does not - // run if the matchin child subcommand has PersistenPreRun. - // If the behavior changes (https://github.com/spf13/cobra/issues/252) - // this test must be fixed. - if parentPersPreArgs != "" { - t.Errorf("Expected blank parentPersPreArgs, got %q", parentPersPreArgs) - } - if parentPreArgs != "" { - t.Errorf("Expected blank parentPreArgs, got %q", parentPreArgs) - } - if parentRunArgs != "" { - t.Errorf("Expected blank parentRunArgs, got %q", parentRunArgs) - } - if parentPostArgs != "" { - t.Errorf("Expected blank parentPostArgs, got %q", parentPostArgs) - } - // TODO: currently PersistenPostRun* defined in parent does not - // run if the matchin child subcommand has PersistenPostRun. - // If the behavior changes (https://github.com/spf13/cobra/issues/252) - // this test must be fixed. - if parentPersPostArgs != "" { - t.Errorf("Expected blank parentPersPostArgs, got %q", parentPersPostArgs) + for _, v := range []struct { + name string + got string + }{ + // TODO: currently PersistenPreRun* defined in parent does not + // run if the matchin child subcommand has PersistenPreRun. + // If the behavior changes (https://github.com/spf13/cobra/issues/252) + // this test must be fixed. + {"parentPersPreArgs", parentPersPreArgs}, + {"parentPreArgs", parentPreArgs}, + {"parentRunArgs", parentRunArgs}, + {"parentPostArgs", parentPostArgs}, + // TODO: currently PersistenPostRun* defined in parent does not + // run if the matchin child subcommand has PersistenPostRun. + // If the behavior changes (https://github.com/spf13/cobra/issues/252) + // this test must be fixed. + {"parentPersPostArgs", parentPersPostArgs}, + } { + if v.got != "" { + t.Errorf("Expected blank %s, got %q", v.name, v.got) + } } - if childPersPreArgs != "one two" { - t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) - } - if childPreArgs != "one two" { - t.Errorf("Expected childPreArgs %q, got %q", "one two", childPreArgs) - } - if childRunArgs != "one two" { - t.Errorf("Expected childRunArgs %q, got %q", "one two", childRunArgs) - } - if childPostArgs != "one two" { - t.Errorf("Expected childPostArgs %q, got %q", "one two", childPostArgs) - } - if childPersPostArgs != "one two" { - t.Errorf("Expected childPersPostArgs %q, got %q", "one two", childPersPostArgs) + for _, v := range []struct { + name string + got string + }{ + {"childPersPreArgs", childPersPreArgs}, + {"childPreArgs", childPreArgs}, + {"childRunArgs", childRunArgs}, + {"childPostArgs", childPostArgs}, + {"childPersPostArgs", childPersPostArgs}, + } { + if v.got != onetwo { + t.Errorf("Expected %s %q, got %q", v.name, onetwo, v.got) + } } } @@ -1484,7 +1466,7 @@ func TestMergeCommandLineToFlags(t *testing.T) { func TestUseDeprecatedFlags(t *testing.T) { c := &Command{Use: "c", Run: emptyRun} c.Flags().BoolP("deprecated", "d", false, "deprecated flag") - c.Flags().MarkDeprecated("deprecated", "This flag is deprecated") + er(c.Flags().MarkDeprecated("deprecated", "This flag is deprecated")) output, err := executeCommand(c, "c", "-d") if err != nil { @@ -1611,7 +1593,6 @@ type calledAsTestcase struct { call string want string epm bool - tc bool } func (tc *calledAsTestcase) test(t *testing.T) { @@ -1632,7 +1613,7 @@ func (tc *calledAsTestcase) test(t *testing.T) { output := new(bytes.Buffer) parent.SetOutput(output) - parent.Execute() + _ = parent.Execute() if called == nil { if tc.call != "" { @@ -1650,18 +1631,18 @@ func (tc *calledAsTestcase) test(t *testing.T) { func TestCalledAs(t *testing.T) { tests := map[string]calledAsTestcase{ - "find/no-args": {nil, "parent", "parent", false, false}, - "find/real-name": {[]string{"child1"}, "child1", "child1", false, false}, - "find/full-alias": {[]string{"that"}, "child2", "that", false, false}, - "find/part-no-prefix": {[]string{"thi"}, "", "", false, false}, - "find/part-alias": {[]string{"thi"}, "child1", "this", true, false}, - "find/conflict": {[]string{"th"}, "", "", true, false}, - "traverse/no-args": {nil, "parent", "parent", false, true}, - "traverse/real-name": {[]string{"child1"}, "child1", "child1", false, true}, - "traverse/full-alias": {[]string{"that"}, "child2", "that", false, true}, - "traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true}, - "traverse/part-alias": {[]string{"thi"}, "child1", "this", true, true}, - "traverse/conflict": {[]string{"th"}, "", "", true, true}, + "find/no-args": {nil, "parent", "parent", false}, + "find/real-name": {[]string{"child1"}, "child1", "child1", false}, + "find/full-alias": {[]string{"that"}, "child2", "that", false}, + "find/part-no-prefix": {[]string{"thi"}, "", "", false}, + "find/part-alias": {[]string{"thi"}, "child1", "this", true}, + "find/conflict": {[]string{"th"}, "", "", true}, + "traverse/no-args": {nil, "parent", "parent", false}, + "traverse/real-name": {[]string{"child1"}, "child1", "child1", false}, + "traverse/full-alias": {[]string{"that"}, "child2", "that", false}, + "traverse/part-no-prefix": {[]string{"thi"}, "", "", false}, + "traverse/part-alias": {[]string{"thi"}, "child1", "this", true}, + "traverse/conflict": {[]string{"th"}, "", "", true}, } for name, tc := range tests { diff --git a/doc/man_docs.go b/doc/man_docs.go index 8c7fba44a..817070f9e 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -139,25 +139,25 @@ func fillHeader(header *GenManHeader, name string) error { return nil } -func manPreamble(buf *bytes.Buffer, header *GenManHeader, cmd *cobra.Command, dashedName string) { +func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) { description := cmd.Long if len(description) == 0 { description = cmd.Short } - buf.WriteString(fmt.Sprintf(`%% %s(%s)%s + wrStringAndCheck(buf, fmt.Sprintf(`%% %s(%s)%s %% %s %% %s # NAME `, header.Title, header.Section, header.date, header.Source, header.Manual)) - buf.WriteString(fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short)) - buf.WriteString("# SYNOPSIS\n") - buf.WriteString(fmt.Sprintf("**%s**\n\n", cmd.UseLine())) - buf.WriteString("# DESCRIPTION\n") - buf.WriteString(description + "\n\n") + wrStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short)) + wrStringAndCheck(buf, "# SYNOPSIS\n") + wrStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine())) + wrStringAndCheck(buf, "# DESCRIPTION\n") + wrStringAndCheck(buf, description+"\n\n") } -func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) { +func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) { flags.VisitAll(func(flag *pflag.Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { return @@ -181,22 +181,22 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) { format += "]" } format += "\n\t%s\n\n" - buf.WriteString(fmt.Sprintf(format, flag.DefValue, flag.Usage)) + wrStringAndCheck(buf, fmt.Sprintf(format, flag.DefValue, flag.Usage)) }) } -func manPrintOptions(buf *bytes.Buffer, command *cobra.Command) { +func manPrintOptions(buf io.StringWriter, command *cobra.Command) { flags := command.NonInheritedFlags() if flags.HasAvailableFlags() { - buf.WriteString("# OPTIONS\n") + wrStringAndCheck(buf, "# OPTIONS\n") manPrintFlags(buf, flags) - buf.WriteString("\n") + wrStringAndCheck(buf, "\n") } flags = command.InheritedFlags() if flags.HasAvailableFlags() { - buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") + wrStringAndCheck(buf, "# OPTIONS INHERITED FROM PARENT COMMANDS\n") manPrintFlags(buf, flags) - buf.WriteString("\n") + wrStringAndCheck(buf, "\n") } } diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go index 2c400f5df..609afdc6e 100644 --- a/doc/man_docs_test.go +++ b/doc/man_docs_test.go @@ -131,7 +131,7 @@ func TestGenManSeeAlso(t *testing.T) { func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { c := &cobra.Command{} c.Flags().StringP("foo", "f", "default", "Foo flag") - c.Flags().MarkShorthandDeprecated("foo", "don't use it no more") + er(c.Flags().MarkShorthandDeprecated("foo", "don't use it no more")) buf := new(bytes.Buffer) manPrintFlags(buf, c.Flags()) diff --git a/doc/man_examples_test.go b/doc/man_examples_test.go index db6604268..58dee8a8c 100644 --- a/doc/man_examples_test.go +++ b/doc/man_examples_test.go @@ -8,6 +8,10 @@ import ( "github.com/spf13/cobra/doc" ) +func er(msg interface{}) { + cobra.Er(msg) +} + func ExampleGenManTree() { cmd := &cobra.Command{ Use: "test", @@ -17,7 +21,7 @@ func ExampleGenManTree() { Title: "MINE", Section: "3", } - doc.GenManTree(cmd, header, "/tmp") + er(doc.GenManTree(cmd, header, "/tmp")) } func ExampleGenMan() { @@ -30,6 +34,6 @@ func ExampleGenMan() { Section: "3", } out := new(bytes.Buffer) - doc.GenMan(cmd, header, out) + er(doc.GenMan(cmd, header, out)) fmt.Print(out.String()) } diff --git a/doc/util.go b/doc/util.go index 8d3dbecec..584780694 100644 --- a/doc/util.go +++ b/doc/util.go @@ -14,6 +14,7 @@ package doc import ( + "io" "strings" "github.com/spf13/cobra" @@ -49,3 +50,11 @@ type byName []*cobra.Command func (s byName) Len() int { return len(s) } func (s byName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byName) Less(i, j int) bool { return s[i].Name() < s[j].Name() } + +func er(msg interface{}) { + cobra.Er(msg) +} + +func wrStringAndCheck(b io.StringWriter, s string) { + cobra.WrStringAndCheck(b, s) +} diff --git a/fish_completions.go b/fish_completions.go index dac814008..cc73d29f1 100644 --- a/fish_completions.go +++ b/fish_completions.go @@ -20,12 +20,12 @@ func (c *Command) GenFishCompletion(w io.Writer) error { return err } -func writeFishPreamble(cmd *Command, buf *bytes.Buffer) { +func writeFishPreamble(cmd *Command, buf io.StringWriter) { subCommandNames := []string{} rangeCommands(cmd, func(subCmd *Command) { subCommandNames = append(subCommandNames, subCmd.Name()) }) - buf.WriteString(fmt.Sprintf(` + WrStringAndCheck(buf, fmt.Sprintf(` function __fish_%s_no_subcommand --description 'Test if %s has yet to be given the subcommand' for i in (commandline -opc) if contains -- $i %s @@ -65,17 +65,24 @@ end `, cmd.Name(), cmd.Name(), strings.Join(subCommandNames, " "), cmd.Name())) } -func writeFishCommandCompletion(rootCmd, cmd *Command, buf *bytes.Buffer) { +func writeFishCommandCompletion(rootCmd, cmd *Command, buf io.StringWriter) { rangeCommands(cmd, func(subCmd *Command) { condition := commandCompletionCondition(rootCmd, cmd) escapedDescription := strings.Replace(subCmd.Short, "'", "\\'", -1) - buf.WriteString(fmt.Sprintf("complete -c %s -f %s -a %s -d '%s'\n", rootCmd.Name(), condition, subCmd.Name(), escapedDescription)) + WrStringAndCheck(buf, fmt.Sprintf("complete -c %s -f %s -a %s -d '%s'\n", rootCmd.Name(), condition, subCmd.Name(), escapedDescription)) }) for _, validArg := range append(cmd.ValidArgs, cmd.ArgAliases...) { condition := commandCompletionCondition(rootCmd, cmd) - buf.WriteString( - fmt.Sprintf("complete -c %s -f %s -a %s -d '%s'\n", - rootCmd.Name(), condition, validArg, fmt.Sprintf("Positional Argument to %s", cmd.Name()))) + WrStringAndCheck( + buf, + fmt.Sprintf( + "complete -c %s -f %s -a %s -d '%s'\n", + rootCmd.Name(), + condition, + validArg, + fmt.Sprintf("Positional Argument to %s", cmd.Name()), + ), + ) } writeCommandFlagsCompletion(rootCmd, cmd, buf) rangeCommands(cmd, func(subCmd *Command) { @@ -83,7 +90,7 @@ func writeFishCommandCompletion(rootCmd, cmd *Command, buf *bytes.Buffer) { }) } -func writeCommandFlagsCompletion(rootCmd, cmd *Command, buf *bytes.Buffer) { +func writeCommandFlagsCompletion(rootCmd, cmd *Command, buf io.StringWriter) { cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { return @@ -98,14 +105,14 @@ func writeCommandFlagsCompletion(rootCmd, cmd *Command, buf *bytes.Buffer) { }) } -func writeCommandFlagCompletion(rootCmd, cmd *Command, buf *bytes.Buffer, flag *pflag.Flag) { +func writeCommandFlagCompletion(rootCmd, cmd *Command, buf io.StringWriter, flag *pflag.Flag) { shortHandPortion := "" if len(flag.Shorthand) > 0 { shortHandPortion = fmt.Sprintf("-s %s", flag.Shorthand) } condition := completionCondition(rootCmd, cmd) escapedUsage := strings.Replace(flag.Usage, "'", "\\'", -1) - buf.WriteString(fmt.Sprintf("complete -c %s -f %s %s %s -l %s -d '%s'\n", + WrStringAndCheck(buf, fmt.Sprintf("complete -c %s -f %s %s %s -l %s -d '%s'\n", rootCmd.Name(), condition, flagRequiresArgumentCompletion(flag), shortHandPortion, flag.Name, escapedUsage)) } diff --git a/fish_completions_test.go b/fish_completions_test.go index e5f9a4e1c..ff1fc13ba 100644 --- a/fish_completions_test.go +++ b/fish_completions_test.go @@ -13,22 +13,22 @@ func TestFishCompletions(t *testing.T) { Run: emptyRun, } rootCmd.Flags().IntP("introot", "i", -1, "help's message for flag introot") - rootCmd.MarkFlagRequired("introot") + er(rootCmd.MarkFlagRequired("introot")) // Filename. rootCmd.Flags().String("filename", "", "Enter a filename") - rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml") + er(rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) // Persistent filename. rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") - rootCmd.MarkPersistentFlagFilename("persistent-filename") - rootCmd.MarkPersistentFlagRequired("persistent-filename") + er(rootCmd.MarkPersistentFlagFilename("persistent-filename")) + er(rootCmd.MarkPersistentFlagRequired("persistent-filename")) // Filename extensions. rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") - rootCmd.MarkFlagFilename("filename-ext") + er(rootCmd.MarkFlagFilename("filename-ext")) rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") - rootCmd.MarkFlagCustom("custom", "__complete_custom") + er(rootCmd.MarkFlagCustom("custom", "__complete_custom")) // Subdirectories in a given directory. rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") @@ -43,7 +43,7 @@ func TestFishCompletions(t *testing.T) { } echoCmd.Flags().String("filename", "", "Enter a filename") - echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml") + er(echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml")) echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)") printCmd := &Command{ @@ -82,7 +82,7 @@ func TestFishCompletions(t *testing.T) { rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) buf := new(bytes.Buffer) - rootCmd.GenFishCompletion(buf) + er(rootCmd.GenFishCompletion(buf)) output := buf.String() // check for preamble helper functions diff --git a/go.mod b/go.mod index f7bf33eb5..f34dce192 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.12 require ( github.com/cpuguy83/go-md2man/v2 v2.0.0 github.com/inconshreveable/mousetrap v1.0.0 - github.com/mitchellh/go-homedir v1.1.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.1 gopkg.in/yaml.v2 v2.2.7 diff --git a/go.sum b/go.sum index b02796f41..729677853 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= diff --git a/powershell_completions_test.go b/powershell_completions_test.go index 29b609de0..0a8c837df 100644 --- a/powershell_completions_test.go +++ b/powershell_completions_test.go @@ -109,7 +109,7 @@ func TestPowerShellCompletion(t *testing.T) { for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { buf := new(bytes.Buffer) - tc.root.GenPowerShellCompletion(buf) + er(tc.root.GenPowerShellCompletion(buf)) output := buf.String() for _, expectedExpression := range tc.expectedExpressions { diff --git a/zsh_completions_test.go b/zsh_completions_test.go index e53fa886e..dc6571b4e 100644 --- a/zsh_completions_test.go +++ b/zsh_completions_test.go @@ -90,9 +90,9 @@ func TestGenZshCompletion(t *testing.T) { Run: emptyRun, } r.Flags().StringVarP(&file, "config", "c", file, "config file") - r.MarkFlagFilename("config") + er(r.MarkFlagFilename("config")) r.Flags().String("output", "", "output file") - r.MarkFlagFilename("output", "*.log", "*.txt") + er(r.MarkFlagFilename("output", "*.log", "*.txt")) return r }(), expectedExpressions: []string{ @@ -161,8 +161,8 @@ func TestGenZshCompletion(t *testing.T) { name: "argument completion for file with and without patterns", root: func() *Command { r := genTestCommand("root", true) - r.MarkZshCompPositionalArgumentFile(1, "*.log") - r.MarkZshCompPositionalArgumentFile(2) + er(r.MarkZshCompPositionalArgumentFile(1, "*.log")) + er(r.MarkZshCompPositionalArgumentFile(2)) return r }(), expectedExpressions: []string{ @@ -173,7 +173,7 @@ func TestGenZshCompletion(t *testing.T) { name: "argument zsh completion for words", root: func() *Command { r := genTestCommand("root", true) - r.MarkZshCompPositionalArgumentWords(1, "word1", "word2") + er(r.MarkZshCompPositionalArgumentWords(1, "word1", "word2")) return r }(), expectedExpressions: []string{ @@ -184,7 +184,7 @@ func TestGenZshCompletion(t *testing.T) { name: "argument completion for words with spaces", root: func() *Command { r := genTestCommand("root", true) - r.MarkZshCompPositionalArgumentWords(1, "single", "multiple words") + er(r.MarkZshCompPositionalArgumentWords(1, "single", "multiple words")) return r }(), expectedExpressions: []string{ @@ -207,7 +207,7 @@ func TestGenZshCompletion(t *testing.T) { root: func() *Command { r := genTestCommand("root", true) r.ValidArgs = []string{"word1", "word2"} - r.MarkZshCompPositionalArgumentFile(2) + er(r.MarkZshCompPositionalArgumentFile(2)) return r }(), expectedExpressions: []string{ @@ -220,8 +220,8 @@ func TestGenZshCompletion(t *testing.T) { r := genTestCommand("root", true) r.Flags().String("test", "", "test") r.PersistentFlags().String("ptest", "", "ptest") - r.MarkFlagDirname("test") - r.MarkPersistentFlagDirname("ptest") + er(r.MarkFlagDirname("test")) + er(r.MarkPersistentFlagDirname("ptest")) return r }(), expectedExpressions: []string{ @@ -237,7 +237,7 @@ func TestGenZshCompletion(t *testing.T) { t.Skip(tc.skip) } tc.root.Root().SetArgs(tc.invocationArgs) - tc.root.Execute() + _ = tc.root.Execute() buf := new(bytes.Buffer) if err := tc.root.GenZshCompletion(buf); err != nil { t.Error(err) @@ -311,11 +311,9 @@ func TestGenZshCompletionHidden(t *testing.T) { for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { - tc.root.Execute() + _ = tc.root.Execute() buf := new(bytes.Buffer) - if err := tc.root.GenZshCompletion(buf); err != nil { - t.Error(err) - } + er(tc.root.GenZshCompletion(buf)) output := buf.String() for _, expr := range tc.expectedExpressions { @@ -457,7 +455,7 @@ func constructLargeCommandHierarchy() *Command { s1.AddCommand(s1_1, s1_2, s1_3) s2.AddCommand(s2_1, s2_2, s2_3, s2_4, s2_5) r.AddCommand(s1, s2, s3) - r.Execute() + er(r.Execute()) return r }