Use golangci-lint (#1044)

Use golangci-lint. Repair warnings and errors resulting from linting.
This commit is contained in:
Unai Martinez-Corral 2021-02-08 00:08:50 +00:00 committed by GitHub
parent 1d71ff0270
commit 652c755d37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 437 additions and 525 deletions

48
.golangci.yml Normal file
View File

@ -0,0 +1,48 @@
run:
deadline: 5m
linters:
disable-all: true
enable:
#- bodyclose
- deadcode
#- depguard
#- dogsled
#- dupl
- errcheck
#- exhaustive
#- funlen
- gas
#- gochecknoinits
- goconst
#- gocritic
#- gocyclo
#- gofmt
- goimports
- golint
#- gomnd
#- goprintffuncname
#- gosec
#- gosimple
- govet
- ineffassign
- interfacer
#- lll
- maligned
- megacheck
#- misspell
#- nakedret
#- noctx
#- nolintlint
#- rowserrcheck
#- scopelint
#- staticcheck
- structcheck
#- stylecheck
#- typecheck
- unconvert
#- unparam
#- unused
- varcheck
#- whitespace
fast: false

View File

@ -1,7 +1,6 @@
language: go language: go
stages: stages:
- diff
- test - test
- build - build
@ -10,17 +9,17 @@ go:
- 1.15.x - 1.15.x
- tip - tip
env: GO111MODULE=on
before_install: before_install:
- go get -u github.com/kyoh86/richgo - go get -u github.com/kyoh86/richgo
- go get -u github.com/mitchellh/gox - go get -u github.com/mitchellh/gox
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest
matrix: matrix:
allow_failures: allow_failures:
- go: tip - go: tip
include: include:
- stage: diff
go: 1.14.x
script: make fmt
- stage: build - stage: build
go: 1.14.x go: 1.14.x
script: make cobra_generator script: make cobra_generator

View File

@ -1,21 +1,29 @@
BIN="./bin" BIN="./bin"
SRC=$(shell find . -name "*.go") SRC=$(shell find . -name "*.go")
ifeq (, $(shell which golangci-lint))
$(warning "could not find golangci-lint in $(PATH), run: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh")
endif
ifeq (, $(shell which richgo)) ifeq (, $(shell which richgo))
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo") $(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
endif endif
.PHONY: fmt vet test cobra_generator install_deps clean .PHONY: fmt lint test cobra_generator install_deps clean
default: all default: all
all: fmt vet test cobra_generator all: fmt test cobra_generator
fmt: fmt:
$(info ******************** checking formatting ********************) $(info ******************** checking formatting ********************)
@test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1) @test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1)
test: install_deps vet lint:
$(info ******************** running lint tools ********************)
golangci-lint run -v
test: install_deps lint
$(info ******************** running tests ********************) $(info ******************** running tests ********************)
richgo test -v ./... richgo test -v ./...
@ -28,9 +36,5 @@ install_deps:
$(info ******************** downloading dependencies ********************) $(info ******************** downloading dependencies ********************)
go get -v ./... go get -v ./...
vet:
$(info ******************** vetting ********************)
go vet ./...
clean: clean:
rm -rf $(BIN) rm -rf $(BIN)

View File

@ -234,11 +234,6 @@ func init() {
rootCmd.AddCommand(initCmd) rootCmd.AddCommand(initCmd)
} }
func er(msg interface{}) {
fmt.Println("Error:", msg)
os.Exit(1)
}
func initConfig() { func initConfig() {
if cfgFile != "" { if cfgFile != "" {
// Use config file from the flag. // Use config file from the flag.
@ -246,9 +241,7 @@ func initConfig() {
} else { } else {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
if err != nil { cobra.CheckErr(err)
er(err)
}
// Search config in home directory with name ".cobra" (without extension). // Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)

View File

@ -19,9 +19,9 @@ const (
BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir" BashCompSubdirsInDir = "cobra_annotation_bash_completion_subdirs_in_dir"
) )
func writePreamble(buf *bytes.Buffer, name string) { func writePreamble(buf io.StringWriter, name string) {
buf.WriteString(fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name)) WriteStringAndCheck(buf, fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
buf.WriteString(fmt.Sprintf(` WriteStringAndCheck(buf, fmt.Sprintf(`
__%[1]s_debug() __%[1]s_debug()
{ {
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
@ -380,10 +380,10 @@ __%[1]s_handle_word()
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
} }
func writePostscript(buf *bytes.Buffer, name string) { func writePostscript(buf io.StringWriter, name string) {
name = strings.Replace(name, ":", "__", -1) name = strings.Replace(name, ":", "__", -1)
buf.WriteString(fmt.Sprintf("__start_%s()\n", name)) WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name))
buf.WriteString(fmt.Sprintf(`{ WriteStringAndCheck(buf, fmt.Sprintf(`{
local cur prev words cword local cur prev words cword
declare -A flaghash 2>/dev/null || : declare -A flaghash 2>/dev/null || :
declare -A aliashash 2>/dev/null || : declare -A aliashash 2>/dev/null || :
@ -410,33 +410,33 @@ func writePostscript(buf *bytes.Buffer, name string) {
} }
`, name)) `, name))
buf.WriteString(fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then WriteStringAndCheck(buf, fmt.Sprintf(`if [[ $(type -t compopt) = "builtin" ]]; then
complete -o default -F __start_%s %s complete -o default -F __start_%s %s
else else
complete -o default -o nospace -F __start_%s %s complete -o default -o nospace -F __start_%s %s
fi fi
`, name, name, name, name)) `, name, name, name, name))
buf.WriteString("# ex: ts=4 sw=4 et filetype=sh\n") WriteStringAndCheck(buf, "# ex: ts=4 sw=4 et filetype=sh\n")
} }
func writeCommands(buf *bytes.Buffer, cmd *Command) { func writeCommands(buf io.StringWriter, cmd *Command) {
buf.WriteString(" commands=()\n") WriteStringAndCheck(buf, " commands=()\n")
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() && c != cmd.helpCommand { if !c.IsAvailableCommand() && c != cmd.helpCommand {
continue continue
} }
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name())) WriteStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name()))
writeCmdAliases(buf, c) writeCmdAliases(buf, c)
} }
buf.WriteString("\n") WriteStringAndCheck(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 { for key, value := range annotations {
switch key { switch key {
case BashCompFilenameExt: case BashCompFilenameExt:
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
var ext string var ext string
if len(value) > 0 { if len(value) > 0 {
@ -444,17 +444,18 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
} else { } else {
ext = "_filedir" ext = "_filedir"
} }
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext))
case BashCompCustom: case BashCompCustom:
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
if len(value) > 0 { if len(value) > 0 {
handlers := strings.Join(value, "; ") handlers := strings.Join(value, "; ")
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers)) WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
} else { } else {
buf.WriteString(" flags_completion+=(:)\n") WriteStringAndCheck(buf, " flags_completion+=(:)\n")
} }
case BashCompSubdirsInDir: case BashCompSubdirsInDir:
buf.WriteString(fmt.Sprintf(" flags_with_completion+=(%q)\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(" flags_with_completion+=(%q)\n", name))
var ext string var ext string
if len(value) == 1 { if len(value) == 1 {
@ -462,46 +463,48 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
} else { } else {
ext = "_filedir -d" ext = "_filedir -d"
} }
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext)) WriteStringAndCheck(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 name := flag.Shorthand
format := " " format := " "
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
format += "two_word_" format += "two_word_"
} }
format += "flags+=(\"-%s\")\n" format += "flags+=(\"-%s" + cbn
buf.WriteString(fmt.Sprintf(format, name)) WriteStringAndCheck(buf, fmt.Sprintf(format, name))
writeFlagHandler(buf, "-"+name, flag.Annotations, cmd) 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 name := flag.Name
format := " flags+=(\"--%s" format := " flags+=(\"--%s"
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
format += "=" format += "="
} }
format += "\")\n" format += cbn
buf.WriteString(fmt.Sprintf(format, name)) WriteStringAndCheck(buf, fmt.Sprintf(format, name))
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
format = " two_word_flags+=(\"--%s\")\n" format = " two_word_flags+=(\"--%s" + cbn
buf.WriteString(fmt.Sprintf(format, name)) WriteStringAndCheck(buf, fmt.Sprintf(format, name))
} }
writeFlagHandler(buf, "--"+name, flag.Annotations, cmd) 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 name := flag.Name
format := " local_nonpersistent_flags+=(\"--%[1]s\")\n" format := " local_nonpersistent_flags+=(\"--%[1]s" + cbn
if len(flag.NoOptDefVal) == 0 { if len(flag.NoOptDefVal) == 0 {
format += " local_nonpersistent_flags+=(\"--%[1]s=\")\n" format += " local_nonpersistent_flags+=(\"--%[1]s=" + cbn
} }
buf.WriteString(fmt.Sprintf(format, name)) WriteStringAndCheck(buf, fmt.Sprintf(format, name))
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
buf.WriteString(fmt.Sprintf(" local_nonpersistent_flags+=(\"-%s\")\n", flag.Shorthand)) WriteStringAndCheck(buf, fmt.Sprintf(" local_nonpersistent_flags+=(\"-%s\")\n", flag.Shorthand))
} }
} }
@ -519,9 +522,9 @@ func prepareCustomAnnotationsForFlags(cmd *Command) {
} }
} }
func writeFlags(buf *bytes.Buffer, cmd *Command) { func writeFlags(buf io.StringWriter, cmd *Command) {
prepareCustomAnnotationsForFlags(cmd) prepareCustomAnnotationsForFlags(cmd)
buf.WriteString(` flags=() WriteStringAndCheck(buf, ` flags=()
two_word_flags=() two_word_flags=()
local_nonpersistent_flags=() local_nonpersistent_flags=()
flags_with_completion=() flags_with_completion=()
@ -553,11 +556,11 @@ func writeFlags(buf *bytes.Buffer, cmd *Command) {
} }
}) })
buf.WriteString("\n") WriteStringAndCheck(buf, "\n")
} }
func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) { func writeRequiredFlag(buf io.StringWriter, cmd *Command) {
buf.WriteString(" must_have_one_flag=()\n") WriteStringAndCheck(buf, " must_have_one_flag=()\n")
flags := cmd.NonInheritedFlags() flags := cmd.NonInheritedFlags()
flags.VisitAll(func(flag *pflag.Flag) { flags.VisitAll(func(flag *pflag.Flag) {
if nonCompletableFlag(flag) { if nonCompletableFlag(flag) {
@ -570,55 +573,55 @@ func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
if flag.Value.Type() != "bool" { if flag.Value.Type() != "bool" {
format += "=" format += "="
} }
format += "\")\n" format += cbn
buf.WriteString(fmt.Sprintf(format, flag.Name)) WriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name))
if len(flag.Shorthand) > 0 { if len(flag.Shorthand) > 0 {
buf.WriteString(fmt.Sprintf(" must_have_one_flag+=(\"-%s\")\n", flag.Shorthand)) WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_flag+=(\"-%s"+cbn, flag.Shorthand))
} }
} }
} }
}) })
} }
func writeRequiredNouns(buf *bytes.Buffer, cmd *Command) { func writeRequiredNouns(buf io.StringWriter, cmd *Command) {
buf.WriteString(" must_have_one_noun=()\n") WriteStringAndCheck(buf, " must_have_one_noun=()\n")
sort.Sort(sort.StringSlice(cmd.ValidArgs)) sort.Strings(cmd.ValidArgs)
for _, value := range cmd.ValidArgs { for _, value := range cmd.ValidArgs {
// Remove any description that may be included following a tab character. // Remove any description that may be included following a tab character.
// Descriptions are not supported by bash completion. // Descriptions are not supported by bash completion.
value = strings.Split(value, "\t")[0] value = strings.Split(value, "\t")[0]
buf.WriteString(fmt.Sprintf(" must_have_one_noun+=(%q)\n", value)) WriteStringAndCheck(buf, fmt.Sprintf(" must_have_one_noun+=(%q)\n", value))
} }
if cmd.ValidArgsFunction != nil { if cmd.ValidArgsFunction != nil {
buf.WriteString(" has_completion_function=1\n") WriteStringAndCheck(buf, " has_completion_function=1\n")
} }
} }
func writeCmdAliases(buf *bytes.Buffer, cmd *Command) { func writeCmdAliases(buf io.StringWriter, cmd *Command) {
if len(cmd.Aliases) == 0 { if len(cmd.Aliases) == 0 {
return 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")) WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
for _, value := range cmd.Aliases { for _, value := range cmd.Aliases {
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value)) WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value))
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
} }
buf.WriteString(` fi`) WriteStringAndCheck(buf, ` fi`)
buf.WriteString("\n") WriteStringAndCheck(buf, "\n")
} }
func writeArgAliases(buf *bytes.Buffer, cmd *Command) { func writeArgAliases(buf io.StringWriter, cmd *Command) {
buf.WriteString(" noun_aliases=()\n") WriteStringAndCheck(buf, " noun_aliases=()\n")
sort.Sort(sort.StringSlice(cmd.ArgAliases)) sort.Strings(cmd.ArgAliases)
for _, value := range cmd.ArgAliases { for _, value := range cmd.ArgAliases {
buf.WriteString(fmt.Sprintf(" noun_aliases+=(%q)\n", value)) WriteStringAndCheck(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() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() && c != cmd.helpCommand { if !c.IsAvailableCommand() && c != cmd.helpCommand {
continue continue
@ -630,22 +633,22 @@ func gen(buf *bytes.Buffer, cmd *Command) {
commandName = strings.Replace(commandName, ":", "__", -1) commandName = strings.Replace(commandName, ":", "__", -1)
if cmd.Root() == cmd { if cmd.Root() == cmd {
buf.WriteString(fmt.Sprintf("_%s_root_command()\n{\n", commandName)) WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName))
} else { } else {
buf.WriteString(fmt.Sprintf("_%s()\n{\n", commandName)) WriteStringAndCheck(buf, fmt.Sprintf("_%s()\n{\n", commandName))
} }
buf.WriteString(fmt.Sprintf(" last_command=%q\n", commandName)) WriteStringAndCheck(buf, fmt.Sprintf(" last_command=%q\n", commandName))
buf.WriteString("\n") WriteStringAndCheck(buf, "\n")
buf.WriteString(" command_aliases=()\n") WriteStringAndCheck(buf, " command_aliases=()\n")
buf.WriteString("\n") WriteStringAndCheck(buf, "\n")
writeCommands(buf, cmd) writeCommands(buf, cmd)
writeFlags(buf, cmd) writeFlags(buf, cmd)
writeRequiredFlag(buf, cmd) writeRequiredFlag(buf, cmd)
writeRequiredNouns(buf, cmd) writeRequiredNouns(buf, cmd)
writeArgAliases(buf, cmd) writeArgAliases(buf, cmd)
buf.WriteString("}\n\n") WriteStringAndCheck(buf, "}\n\n")
} }
// GenBashCompletion generates bash completion file and writes to the passed writer. // GenBashCompletion generates bash completion file and writes to the passed writer.

View File

@ -40,10 +40,9 @@ func checkRegex(t *testing.T, found, pattern string) {
} }
func runShellCheck(s string) error { func runShellCheck(s string) error {
excluded := []string{ cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e",
"SC2034", // PREFIX appears unused. Verify it or export it. "SC2034", // PREFIX appears unused. Verify it or export it.
} )
cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ","))
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@ -52,7 +51,9 @@ func runShellCheck(s string) error {
return err return err
} }
go func() { go func() {
stdin.Write([]byte(s)) _, err := stdin.Write([]byte(s))
CheckErr(err)
stdin.Close() stdin.Close()
}() }()
@ -74,26 +75,26 @@ func TestBashCompletions(t *testing.T) {
Run: emptyRun, Run: emptyRun,
} }
rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
rootCmd.MarkFlagRequired("introot") assertNoErr(t, rootCmd.MarkFlagRequired("introot"))
// Filename. // Filename.
rootCmd.Flags().String("filename", "", "Enter a filename") rootCmd.Flags().String("filename", "", "Enter a filename")
rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml") assertNoErr(t, rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml"))
// Persistent filename. // Persistent filename.
rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename") rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename")
rootCmd.MarkPersistentFlagFilename("persistent-filename") assertNoErr(t, rootCmd.MarkPersistentFlagFilename("persistent-filename"))
rootCmd.MarkPersistentFlagRequired("persistent-filename") assertNoErr(t, rootCmd.MarkPersistentFlagRequired("persistent-filename"))
// Filename extensions. // Filename extensions.
rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)") rootCmd.Flags().String("filename-ext", "", "Enter a filename (extension limited)")
rootCmd.MarkFlagFilename("filename-ext") assertNoErr(t, rootCmd.MarkFlagFilename("filename-ext"))
rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)") rootCmd.Flags().String("custom", "", "Enter a filename (extension limited)")
rootCmd.MarkFlagCustom("custom", "__complete_custom") assertNoErr(t, rootCmd.MarkFlagCustom("custom", "__complete_custom"))
// Subdirectories in a given directory. // Subdirectories in a given directory.
rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)") rootCmd.Flags().String("theme", "", "theme to use (located in /themes/THEMENAME/)")
rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}) assertNoErr(t, rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}))
// For two word flags check // For two word flags check
rootCmd.Flags().StringP("two", "t", "", "this is two word flags") rootCmd.Flags().StringP("two", "t", "", "this is two word flags")
@ -109,9 +110,9 @@ func TestBashCompletions(t *testing.T) {
} }
echoCmd.Flags().String("filename", "", "Enter a filename") echoCmd.Flags().String("filename", "", "Enter a filename")
echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml") assertNoErr(t, echoCmd.MarkFlagFilename("filename", "json", "yaml", "yml"))
echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)") echoCmd.Flags().String("config", "", "config to use (located in /config/PROFILE/)")
echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"}) assertNoErr(t, echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"}))
printCmd := &Command{ printCmd := &Command{
Use: "print [string to print]", Use: "print [string to print]",
@ -149,7 +150,7 @@ func TestBashCompletions(t *testing.T) {
rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd) rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenBashCompletion(buf) assertNoErr(t, rootCmd.GenBashCompletion(buf))
output := buf.String() output := buf.String()
check(t, output, "_root") check(t, output, "_root")
@ -216,10 +217,10 @@ func TestBashCompletionHiddenFlag(t *testing.T) {
const flagName = "hiddenFlag" const flagName = "hiddenFlag"
c.Flags().Bool(flagName, false, "") c.Flags().Bool(flagName, false, "")
c.Flags().MarkHidden(flagName) assertNoErr(t, c.Flags().MarkHidden(flagName))
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
c.GenBashCompletion(buf) assertNoErr(t, c.GenBashCompletion(buf))
output := buf.String() output := buf.String()
if strings.Contains(output, flagName) { if strings.Contains(output, flagName) {
@ -232,10 +233,10 @@ func TestBashCompletionDeprecatedFlag(t *testing.T) {
const flagName = "deprecated-flag" const flagName = "deprecated-flag"
c.Flags().Bool(flagName, false, "") c.Flags().Bool(flagName, false, "")
c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead") assertNoErr(t, c.Flags().MarkDeprecated(flagName, "use --not-deprecated instead"))
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
c.GenBashCompletion(buf) assertNoErr(t, c.GenBashCompletion(buf))
output := buf.String() output := buf.String()
if strings.Contains(output, flagName) { if strings.Contains(output, flagName) {
@ -250,7 +251,7 @@ func TestBashCompletionTraverseChildren(t *testing.T) {
c.Flags().BoolP("bool-flag", "b", false, "bool flag") c.Flags().BoolP("bool-flag", "b", false, "bool flag")
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
c.GenBashCompletion(buf) assertNoErr(t, c.GenBashCompletion(buf))
output := buf.String() output := buf.String()
// check that local nonpersistent flag are not set since we have TraverseChildren set to true // check that local nonpersistent flag are not set since we have TraverseChildren set to true

View File

@ -19,6 +19,7 @@ package cobra
import ( import (
"fmt" "fmt"
"io" "io"
"os"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -205,3 +206,17 @@ func stringInSlice(a string, list []string) bool {
} }
return false return false
} }
// CheckErr prints the msg with the prefix 'Error:' and exits with error code 1. If the msg is nil, it does nothing.
func CheckErr(msg interface{}) {
if msg != nil {
fmt.Fprintln(os.Stderr, "Error:", msg)
os.Exit(1)
}
}
// WriteStringAndCheck writes a string into a buffer, and checks if the error is not nil.
func WriteStringAndCheck(b io.StringWriter, s string) {
_, err := b.WriteString(s)
CheckErr(err)
}

View File

@ -40,13 +40,11 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 { if len(args) < 1 {
er("add needs a name for the command") cobra.CheckErr(fmt.Errorf("add needs a name for the command"))
} }
wd, err := os.Getwd() wd, err := os.Getwd()
if err != nil { cobra.CheckErr(err)
er(err)
}
commandName := validateCmdName(args[0]) commandName := validateCmdName(args[0])
command := &Command{ command := &Command{
@ -59,10 +57,7 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
}, },
} }
err = command.Create() cobra.CheckErr(command.Create())
if err != nil {
er(err)
}
fmt.Printf("%s created at %s\n", command.CmdName, command.AbsolutePath) fmt.Printf("%s created at %s\n", command.CmdName, command.AbsolutePath)
}, },
@ -72,7 +67,7 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
func init() { func init() {
addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)") addCmd.Flags().StringVarP(&packageName, "package", "t", "", "target package name (e.g. github.com/spf13/hugo)")
addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command") addCmd.Flags().StringVarP(&parentName, "parent", "p", "rootCmd", "variable name of parent command for this command")
addCmd.Flags().MarkDeprecated("package", "this operation has been removed.") cobra.CheckErr(addCmd.Flags().MarkDeprecated("package", "this operation has been removed."))
} }
// validateCmdName returns source without any dashes and underscore. // validateCmdName returns source without any dashes and underscore.

View File

@ -14,10 +14,8 @@ func TestGoldenAddCmd(t *testing.T) {
} }
defer os.RemoveAll(command.AbsolutePath) defer os.RemoveAll(command.AbsolutePath)
command.Project.Create() assertNoErr(t, command.Project.Create())
if err := command.Create(); err != nil { assertNoErr(t, command.Create())
t.Fatal(err)
}
generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName) generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName)
goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName) goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName)

View File

@ -3,14 +3,11 @@ package cmd
import ( import (
"bytes" "bytes"
"errors" "errors"
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os/exec" "os/exec"
) )
var update = flag.Bool("update", false, "update .golden files")
func init() { func init() {
// Mute commands. // Mute commands.
addCmd.SetOut(new(bytes.Buffer)) addCmd.SetOut(new(bytes.Buffer))
@ -58,27 +55,3 @@ func compareFiles(pathA, pathB string) error {
} }
return nil 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
}

View File

@ -14,14 +14,12 @@
package cmd package cmd
import ( import (
"bytes"
"fmt"
"io"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strings" "strings"
"text/template"
"github.com/spf13/cobra"
) )
var srcPaths []string var srcPaths []string
@ -43,14 +41,12 @@ func init() {
} }
out, err := exec.Command(goExecutable, "env", "GOPATH").Output() out, err := exec.Command(goExecutable, "env", "GOPATH").Output()
if err != nil { cobra.CheckErr(err)
er(err)
}
toolchainGoPath := strings.TrimSpace(string(out)) toolchainGoPath := strings.TrimSpace(string(out))
goPaths = filepath.SplitList(toolchainGoPath) goPaths = filepath.SplitList(toolchainGoPath)
if len(goPaths) == 0 { if len(goPaths) == 0 {
er("$GOPATH is not set") cobra.CheckErr("$GOPATH is not set")
} }
} }
srcPaths = make([]string, 0, len(goPaths)) srcPaths = make([]string, 0, len(goPaths))
@ -58,111 +54,3 @@ func init() {
srcPaths = append(srcPaths, filepath.Join(goPath, "src")) srcPaths = append(srcPaths, filepath.Join(goPath, "src"))
} }
} }
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)
}
}
}
return strings.Join(newlines, "\n")
}

View File

@ -0,0 +1,9 @@
package cmd
import "testing"
func assertNoErr(t *testing.T, e error) {
if e != nil {
t.Error(e)
}
}

View File

@ -39,9 +39,7 @@ and the appropriate structure for a Cobra-based CLI application.
Run: func(_ *cobra.Command, args []string) { Run: func(_ *cobra.Command, args []string) {
projectPath, err := initializeProject(args) projectPath, err := initializeProject(args)
if err != nil { cobra.CheckErr(err)
er(err)
}
fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath) fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath)
}, },
} }
@ -49,7 +47,7 @@ and the appropriate structure for a Cobra-based CLI application.
func init() { func init() {
initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name") initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name")
initCmd.MarkFlagRequired("pkg-name") cobra.CheckErr(initCmd.MarkFlagRequired("pkg-name"))
} }
func initializeProject(args []string) (string, error) { func initializeProject(args []string) (string, error) {

View File

@ -59,7 +59,7 @@ func TestGoldenInitCmd(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
initCmd.Flags().Set("pkg-name", tt.pkgName) assertNoErr(t, initCmd.Flags().Set("pkg-name", tt.pkgName))
viper.Set("useViper", true) viper.Set("useViper", true)
projectPath, err := initializeProject(tt.args) projectPath, err := initializeProject(tt.args)
defer func() { defer func() {

View File

@ -16,9 +16,11 @@
package cmd package cmd
import ( import (
"fmt"
"strings" "strings"
"time" "time"
"github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
) )
@ -92,7 +94,7 @@ func copyrightLine() string {
func findLicense(name string) License { func findLicense(name string) License {
found := matchLicense(name) found := matchLicense(name)
if found == "" { if found == "" {
er("unknown license: " + name) cobra.CheckErr(fmt.Errorf("unknown license: " + name))
} }
return Licenses[found] return Licenses[found]
} }

View File

@ -5,6 +5,7 @@ import (
"os" "os"
"text/template" "text/template"
"github.com/spf13/cobra"
"github.com/spf13/cobra/cobra/tpl" "github.com/spf13/cobra/cobra/tpl"
) )
@ -49,7 +50,7 @@ func (p *Project) Create() error {
// create cmd/root.go // create cmd/root.go
if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) { if _, err = os.Stat(fmt.Sprintf("%s/cmd", p.AbsolutePath)); os.IsNotExist(err) {
os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751) cobra.CheckErr(os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751))
} }
rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath)) rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath))
if err != nil { if err != nil {

View File

@ -47,8 +47,8 @@ func init() {
rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) cobra.CheckErr(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")))
viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) cobra.CheckErr(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")))
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>") viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
viper.SetDefault("license", "apache") viper.SetDefault("license", "apache")
@ -63,9 +63,7 @@ func initConfig() {
} else { } else {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
if err != nil { cobra.CheckErr(err)
er(err)
}
// Search config in home directory with name ".cobra" (without extension). // Search config in home directory with name ".cobra" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)

View File

@ -17,8 +17,8 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra"
"os" "os"
"github.com/spf13/cobra"
homedir "github.com/mitchellh/go-homedir" homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -44,10 +44,7 @@ to quickly create a Cobra application.`,
// Execute adds all child commands to the root command and sets flags appropriately. // Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd. // This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() { func Execute() {
if err := rootCmd.Execute(); err != nil { cobra.CheckErr(rootCmd.Execute())
fmt.Println(err)
os.Exit(1)
}
} }
func init() { func init() {
@ -72,10 +69,7 @@ func initConfig() {
} else { } else {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
if err != nil { cobra.CheckErr(err)
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".testproject" (without extension). // Search config in home directory with name ".testproject" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)
@ -86,6 +80,6 @@ func initConfig() {
// If a config file is found, read it in. // If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil { if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed()) fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
} }
} }

View File

@ -24,12 +24,11 @@ package cmd
import ( import (
"fmt" "fmt"
"github.com/spf13/cobra"
"os" "os"
"github.com/spf13/cobra"
{{ if .Viper }} {{ if .Viper }}
homedir "github.com/mitchellh/go-homedir" homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/viper" "github.com/spf13/viper"{{ end }}
{{ end -}}
) )
{{ if .Viper -}} {{ if .Viper -}}
@ -54,10 +53,7 @@ to quickly create a Cobra application.` + "`" + `,
// Execute adds all child commands to the root command and sets flags appropriately. // Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd. // This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() { func Execute() {
if err := rootCmd.Execute(); err != nil { cobra.CheckErr(rootCmd.Execute())
fmt.Println(err)
os.Exit(1)
}
} }
func init() { func init() {
@ -86,10 +82,7 @@ func initConfig() {
} else { } else {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
if err != nil { cobra.CheckErr(err)
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".{{ .AppName }}" (without extension). // Search config in home directory with name ".{{ .AppName }}" (without extension).
viper.AddConfigPath(home) viper.AddConfigPath(home)
@ -100,7 +93,7 @@ func initConfig() {
// If a config file is found, read it in. // If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil { if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed()) fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
} }
} }
{{- end }} {{- end }}

View File

@ -5,6 +5,12 @@ import (
"text/template" "text/template"
) )
func assertNoErr(t *testing.T, e error) {
if e != nil {
t.Error(e)
}
}
func TestAddTemplateFunctions(t *testing.T) { func TestAddTemplateFunctions(t *testing.T) {
AddTemplateFunc("t", func() bool { return true }) AddTemplateFunc("t", func() bool { return true })
AddTemplateFuncs(template.FuncMap{ AddTemplateFuncs(template.FuncMap{

View File

@ -84,9 +84,6 @@ type Command struct {
// Deprecated defines, if this command is deprecated and should print this string when used. // Deprecated defines, if this command is deprecated and should print this string when used.
Deprecated string 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 // Annotations are key/value pairs that can be used by applications to identify or
// group commands. // group commands.
Annotations map[string]string Annotations map[string]string
@ -126,55 +123,6 @@ type Command struct {
// PersistentPostRunE: PersistentPostRun but returns an error. // PersistentPostRunE: PersistentPostRun but returns an error.
PersistentPostRunE func(cmd *Command, args []string) 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
ctx context.Context
// 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 is actual args parsed from flags.
args []string args []string
// flagErrorBuf contains all error messages from pflag. // flagErrorBuf contains all error messages from pflag.
@ -216,6 +164,60 @@ type Command struct {
outWriter io.Writer outWriter io.Writer
// errWriter is a writer defined by the user that replaces stderr // errWriter is a writer defined by the user that replaces stderr
errWriter io.Writer 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
}
ctx context.Context
// 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
} }
// Context returns underlying command context. If command wasn't // Context returns underlying command context. If command wasn't
@ -418,7 +420,7 @@ func (c *Command) UsageString() string {
c.outWriter = bb c.outWriter = bb
c.errWriter = bb c.errWriter = bb
c.Usage() CheckErr(c.Usage())
// Setting things back to normal // Setting things back to normal
c.outWriter = tmpOutput c.outWriter = tmpOutput
@ -1087,10 +1089,10 @@ Simply type ` + c.Name() + ` help [path to command] for full details.`,
cmd, _, e := c.Root().Find(args) cmd, _, e := c.Root().Find(args)
if cmd == nil || e != nil { if cmd == nil || e != nil {
c.Printf("Unknown help topic %#q\n", args) c.Printf("Unknown help topic %#q\n", args)
c.Root().Usage() CheckErr(c.Root().Usage())
} else { } else {
cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
cmd.Help() CheckErr(cmd.Help())
} }
}, },
} }

View File

@ -58,6 +58,8 @@ func checkStringOmits(t *testing.T, got, expected string) {
} }
} }
const onetwo = "one two"
func TestSingleCommand(t *testing.T) { func TestSingleCommand(t *testing.T) {
var rootCmdArgs []string var rootCmdArgs []string
rootCmd := &Command{ rootCmd := &Command{
@ -78,9 +80,8 @@ func TestSingleCommand(t *testing.T) {
} }
got := strings.Join(rootCmdArgs, " ") got := strings.Join(rootCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("rootCmdArgs expected: %q, got: %q", expected, got)
} }
} }
@ -104,9 +105,8 @@ func TestChildCommand(t *testing.T) {
} }
got := strings.Join(child1CmdArgs, " ") got := strings.Join(child1CmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("child1CmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("child1CmdArgs expected: %q, got: %q", expected, got)
} }
} }
@ -145,7 +145,7 @@ func TestSubcommandExecuteC(t *testing.T) {
} }
if c.Name() != "child" { 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())
} }
} }
@ -243,9 +243,8 @@ func TestCommandAlias(t *testing.T) {
} }
got := strings.Join(timesCmdArgs, " ") got := strings.Join(timesCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got)
t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
} }
} }
@ -271,9 +270,8 @@ func TestEnablePrefixMatching(t *testing.T) {
} }
got := strings.Join(aCmdArgs, " ") got := strings.Join(aCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("aCmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("aCmdArgs expected: %q, got: %q", expected, got)
} }
EnablePrefixMatching = false EnablePrefixMatching = false
@ -307,9 +305,8 @@ func TestAliasPrefixMatching(t *testing.T) {
} }
got := strings.Join(timesCmdArgs, " ") got := strings.Join(timesCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("timesCmdArgs expected: %v, got: %v", onetwo, got)
t.Errorf("timesCmdArgs expected: %v, got: %v", expected, got)
} }
EnablePrefixMatching = false EnablePrefixMatching = false
@ -338,9 +335,8 @@ func TestChildSameName(t *testing.T) {
} }
got := strings.Join(fooCmdArgs, " ") got := strings.Join(fooCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got)
t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
} }
} }
@ -368,9 +364,8 @@ func TestGrandChildSameName(t *testing.T) {
} }
got := strings.Join(fooCmdArgs, " ") got := strings.Join(fooCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("fooCmdArgs expected: %v, got: %v", onetwo, got)
t.Errorf("fooCmdArgs expected: %v, got: %v", expected, got)
} }
} }
@ -406,9 +401,8 @@ func TestFlagLong(t *testing.T) {
} }
got := strings.Join(cArgs, " ") got := strings.Join(cArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("Expected arguments: %q, got %q", expected, got)
} }
} }
@ -441,9 +435,8 @@ func TestFlagShort(t *testing.T) {
} }
got := strings.Join(cArgs, " ") got := strings.Join(cArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("Expected arguments: %q, got %q", expected, got)
} }
} }
@ -645,9 +638,8 @@ func TestPersistentFlagsOnSameCommand(t *testing.T) {
} }
got := strings.Join(rootCmdArgs, " ") got := strings.Join(rootCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("rootCmdArgs expected: %q, got %q", onetwo, got)
t.Errorf("rootCmdArgs expected: %q, got %q", expected, got)
} }
if flagValue != 7 { if flagValue != 7 {
t.Errorf("flagValue expected: %v, got %v", 7, flagValue) t.Errorf("flagValue expected: %v, got %v", 7, flagValue)
@ -731,9 +723,8 @@ func TestPersistentFlagsOnChild(t *testing.T) {
} }
got := strings.Join(childCmdArgs, " ") got := strings.Join(childCmdArgs, " ")
expected := "one two" if got != onetwo {
if got != expected { t.Errorf("rootCmdArgs expected: %q, got: %q", onetwo, got)
t.Errorf("childCmdArgs expected: %q, got %q", expected, got)
} }
if parentFlagValue != 8 { if parentFlagValue != 8 {
t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue) t.Errorf("parentFlagValue expected: %v, got %v", 8, parentFlagValue)
@ -746,9 +737,9 @@ func TestPersistentFlagsOnChild(t *testing.T) {
func TestRequiredFlags(t *testing.T) { func TestRequiredFlags(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun} c := &Command{Use: "c", Run: emptyRun}
c.Flags().String("foo1", "", "") c.Flags().String("foo1", "", "")
c.MarkFlagRequired("foo1") assertNoErr(t, c.MarkFlagRequired("foo1"))
c.Flags().String("foo2", "", "") c.Flags().String("foo2", "", "")
c.MarkFlagRequired("foo2") assertNoErr(t, c.MarkFlagRequired("foo2"))
c.Flags().String("bar", "", "") c.Flags().String("bar", "", "")
expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2") expected := fmt.Sprintf("required flag(s) %q, %q not set", "foo1", "foo2")
@ -764,16 +755,16 @@ func TestRequiredFlags(t *testing.T) {
func TestPersistentRequiredFlags(t *testing.T) { func TestPersistentRequiredFlags(t *testing.T) {
parent := &Command{Use: "parent", Run: emptyRun} parent := &Command{Use: "parent", Run: emptyRun}
parent.PersistentFlags().String("foo1", "", "") parent.PersistentFlags().String("foo1", "", "")
parent.MarkPersistentFlagRequired("foo1") assertNoErr(t, parent.MarkPersistentFlagRequired("foo1"))
parent.PersistentFlags().String("foo2", "", "") parent.PersistentFlags().String("foo2", "", "")
parent.MarkPersistentFlagRequired("foo2") assertNoErr(t, parent.MarkPersistentFlagRequired("foo2"))
parent.Flags().String("foo3", "", "") parent.Flags().String("foo3", "", "")
child := &Command{Use: "child", Run: emptyRun} child := &Command{Use: "child", Run: emptyRun}
child.Flags().String("bar1", "", "") child.Flags().String("bar1", "", "")
child.MarkFlagRequired("bar1") assertNoErr(t, child.MarkFlagRequired("bar1"))
child.Flags().String("bar2", "", "") child.Flags().String("bar2", "", "")
child.MarkFlagRequired("bar2") assertNoErr(t, child.MarkFlagRequired("bar2"))
child.Flags().String("bar3", "", "") child.Flags().String("bar3", "", "")
parent.AddCommand(child) parent.AddCommand(child)
@ -793,7 +784,7 @@ func TestPersistentRequiredFlagsWithDisableFlagParsing(t *testing.T) {
parent := &Command{Use: "parent", Run: emptyRun} parent := &Command{Use: "parent", Run: emptyRun}
parent.PersistentFlags().Bool("foo", false, "") parent.PersistentFlags().Bool("foo", false, "")
flag := parent.PersistentFlags().Lookup("foo") flag := parent.PersistentFlags().Lookup("foo")
parent.MarkPersistentFlagRequired("foo") assertNoErr(t, parent.MarkPersistentFlagRequired("foo"))
child := &Command{Use: "child", Run: emptyRun} child := &Command{Use: "child", Run: emptyRun}
child.DisableFlagParsing = true child.DisableFlagParsing = true
@ -1299,20 +1290,19 @@ func TestHooks(t *testing.T) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
if persPreArgs != "one two" { for _, v := range []struct {
t.Errorf("Expected persPreArgs %q, got %q", "one two", persPreArgs) 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)
} }
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)
} }
} }
@ -1380,44 +1370,42 @@ func TestPersistentHooks(t *testing.T) {
t.Errorf("Unexpected error: %v", err) t.Errorf("Unexpected error: %v", err)
} }
for _, v := range []struct {
name string
got string
}{
// TODO: currently PersistenPreRun* defined in parent does not // TODO: currently PersistenPreRun* defined in parent does not
// run if the matchin child subcommand has PersistenPreRun. // run if the matchin child subcommand has PersistenPreRun.
// If the behavior changes (https://github.com/spf13/cobra/issues/252) // If the behavior changes (https://github.com/spf13/cobra/issues/252)
// this test must be fixed. // this test must be fixed.
if parentPersPreArgs != "" { {"parentPersPreArgs", parentPersPreArgs},
t.Errorf("Expected blank parentPersPreArgs, got %q", parentPersPreArgs) {"parentPreArgs", parentPreArgs},
} {"parentRunArgs", parentRunArgs},
if parentPreArgs != "" { {"parentPostArgs", parentPostArgs},
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 // TODO: currently PersistenPostRun* defined in parent does not
// run if the matchin child subcommand has PersistenPostRun. // run if the matchin child subcommand has PersistenPostRun.
// If the behavior changes (https://github.com/spf13/cobra/issues/252) // If the behavior changes (https://github.com/spf13/cobra/issues/252)
// this test must be fixed. // this test must be fixed.
if parentPersPostArgs != "" { {"parentPersPostArgs", parentPersPostArgs},
t.Errorf("Expected blank parentPersPostArgs, got %q", parentPersPostArgs) } {
if v.got != "" {
t.Errorf("Expected blank %s, got %q", v.name, v.got)
}
} }
if childPersPreArgs != "one two" { for _, v := range []struct {
t.Errorf("Expected childPersPreArgs %q, got %q", "one two", childPersPreArgs) 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)
} }
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)
} }
} }
@ -1741,7 +1729,7 @@ func TestMergeCommandLineToFlags(t *testing.T) {
func TestUseDeprecatedFlags(t *testing.T) { func TestUseDeprecatedFlags(t *testing.T) {
c := &Command{Use: "c", Run: emptyRun} c := &Command{Use: "c", Run: emptyRun}
c.Flags().BoolP("deprecated", "d", false, "deprecated flag") c.Flags().BoolP("deprecated", "d", false, "deprecated flag")
c.Flags().MarkDeprecated("deprecated", "This flag is deprecated") assertNoErr(t, c.Flags().MarkDeprecated("deprecated", "This flag is deprecated"))
output, err := executeCommand(c, "c", "-d") output, err := executeCommand(c, "c", "-d")
if err != nil { if err != nil {
@ -1868,7 +1856,6 @@ type calledAsTestcase struct {
call string call string
want string want string
epm bool epm bool
tc bool
} }
func (tc *calledAsTestcase) test(t *testing.T) { func (tc *calledAsTestcase) test(t *testing.T) {
@ -1890,7 +1877,7 @@ func (tc *calledAsTestcase) test(t *testing.T) {
parent.SetOut(output) parent.SetOut(output)
parent.SetErr(output) parent.SetErr(output)
parent.Execute() _ = parent.Execute()
if called == nil { if called == nil {
if tc.call != "" { if tc.call != "" {
@ -1908,18 +1895,18 @@ func (tc *calledAsTestcase) test(t *testing.T) {
func TestCalledAs(t *testing.T) { func TestCalledAs(t *testing.T) {
tests := map[string]calledAsTestcase{ tests := map[string]calledAsTestcase{
"find/no-args": {nil, "parent", "parent", false, false}, "find/no-args": {nil, "parent", "parent", false},
"find/real-name": {[]string{"child1"}, "child1", "child1", false, false}, "find/real-name": {[]string{"child1"}, "child1", "child1", false},
"find/full-alias": {[]string{"that"}, "child2", "that", false, false}, "find/full-alias": {[]string{"that"}, "child2", "that", false},
"find/part-no-prefix": {[]string{"thi"}, "", "", false, false}, "find/part-no-prefix": {[]string{"thi"}, "", "", false},
"find/part-alias": {[]string{"thi"}, "child1", "this", true, false}, "find/part-alias": {[]string{"thi"}, "child1", "this", true},
"find/conflict": {[]string{"th"}, "", "", true, false}, "find/conflict": {[]string{"th"}, "", "", true},
"traverse/no-args": {nil, "parent", "parent", false, true}, "traverse/no-args": {nil, "parent", "parent", false},
"traverse/real-name": {[]string{"child1"}, "child1", "child1", false, true}, "traverse/real-name": {[]string{"child1"}, "child1", "child1", false},
"traverse/full-alias": {[]string{"that"}, "child2", "that", false, true}, "traverse/full-alias": {[]string{"that"}, "child2", "that", false},
"traverse/part-no-prefix": {[]string{"thi"}, "", "", false, true}, "traverse/part-no-prefix": {[]string{"thi"}, "", "", false},
"traverse/part-alias": {[]string{"thi"}, "child1", "this", true, true}, "traverse/part-alias": {[]string{"thi"}, "child1", "this", true},
"traverse/conflict": {[]string{"th"}, "", "", true, true}, "traverse/conflict": {[]string{"th"}, "", "", true},
} }
for name, tc := range tests { for name, tc := range tests {

View File

@ -527,13 +527,13 @@ func CompDebug(msg string, printToStdErr bool) {
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err == nil { if err == nil {
defer f.Close() defer f.Close()
f.WriteString(msg) WriteStringAndCheck(f, msg)
} }
} }
if printToStdErr { if printToStdErr {
// Must print to stderr for this not to be read by the completion script. // Must print to stderr for this not to be read by the completion script.
fmt.Fprintf(os.Stderr, msg) fmt.Fprint(os.Stderr, msg)
} }
} }

View File

@ -780,17 +780,17 @@ func TestRequiredFlagNameCompletionInGo(t *testing.T) {
rootCmd.AddCommand(childCmd) rootCmd.AddCommand(childCmd)
rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag") rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag")
rootCmd.MarkFlagRequired("requiredFlag") assertNoErr(t, rootCmd.MarkFlagRequired("requiredFlag"))
requiredFlag := rootCmd.Flags().Lookup("requiredFlag") requiredFlag := rootCmd.Flags().Lookup("requiredFlag")
rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent") rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent")
rootCmd.MarkPersistentFlagRequired("requiredPersistent") assertNoErr(t, rootCmd.MarkPersistentFlagRequired("requiredPersistent"))
requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent") requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent")
rootCmd.Flags().StringP("release", "R", "", "Release name") rootCmd.Flags().StringP("release", "R", "", "Release name")
childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag") childCmd.Flags().BoolP("subRequired", "s", false, "sub required flag")
childCmd.MarkFlagRequired("subRequired") assertNoErr(t, childCmd.MarkFlagRequired("subRequired"))
childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag") childCmd.Flags().BoolP("subNotRequired", "n", false, "sub not required flag")
// Test that a required flag is suggested even without the - prefix // Test that a required flag is suggested even without the - prefix
@ -964,19 +964,19 @@ func TestFlagFileExtFilterCompletionInGo(t *testing.T) {
// No extensions. Should be ignored. // No extensions. Should be ignored.
rootCmd.Flags().StringP("file", "f", "", "file flag") rootCmd.Flags().StringP("file", "f", "", "file flag")
rootCmd.MarkFlagFilename("file") assertNoErr(t, rootCmd.MarkFlagFilename("file"))
// Single extension // Single extension
rootCmd.Flags().StringP("log", "l", "", "log flag") rootCmd.Flags().StringP("log", "l", "", "log flag")
rootCmd.MarkFlagFilename("log", "log") assertNoErr(t, rootCmd.MarkFlagFilename("log", "log"))
// Multiple extensions // Multiple extensions
rootCmd.Flags().StringP("yaml", "y", "", "yaml flag") rootCmd.Flags().StringP("yaml", "y", "", "yaml flag")
rootCmd.MarkFlagFilename("yaml", "yaml", "yml") assertNoErr(t, rootCmd.MarkFlagFilename("yaml", "yaml", "yml"))
// Directly using annotation // Directly using annotation
rootCmd.Flags().StringP("text", "t", "", "text flag") rootCmd.Flags().StringP("text", "t", "", "text flag")
rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"}) assertNoErr(t, rootCmd.Flags().SetAnnotation("text", BashCompFilenameExt, []string{"txt"}))
// Test that the completion logic returns the proper info for the completion // Test that the completion logic returns the proper info for the completion
// script to handle the file filtering // script to handle the file filtering
@ -1086,15 +1086,15 @@ func TestFlagDirFilterCompletionInGo(t *testing.T) {
// Filter directories // Filter directories
rootCmd.Flags().StringP("dir", "d", "", "dir flag") rootCmd.Flags().StringP("dir", "d", "", "dir flag")
rootCmd.MarkFlagDirname("dir") assertNoErr(t, rootCmd.MarkFlagDirname("dir"))
// Filter directories within a directory // Filter directories within a directory
rootCmd.Flags().StringP("subdir", "s", "", "subdir") rootCmd.Flags().StringP("subdir", "s", "", "subdir")
rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"}) assertNoErr(t, rootCmd.Flags().SetAnnotation("subdir", BashCompSubdirsInDir, []string{"themes"}))
// Multiple directory specification get ignored // Multiple directory specification get ignored
rootCmd.Flags().StringP("manydir", "m", "", "manydir") rootCmd.Flags().StringP("manydir", "m", "", "manydir")
rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"}) assertNoErr(t, rootCmd.Flags().SetAnnotation("manydir", BashCompSubdirsInDir, []string{"themes", "colors"}))
// Test that the completion logic returns the proper info for the completion // Test that the completion logic returns the proper info for the completion
// script to handle the directory filtering // script to handle the directory filtering
@ -1430,7 +1430,7 @@ func TestValidArgsFuncInBashScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenBashCompletion(buf) assertNoErr(t, rootCmd.GenBashCompletion(buf))
output := buf.String() output := buf.String()
check(t, output, "has_completion_function=1") check(t, output, "has_completion_function=1")
@ -1445,7 +1445,7 @@ func TestNoValidArgsFuncInBashScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenBashCompletion(buf) assertNoErr(t, rootCmd.GenBashCompletion(buf))
output := buf.String() output := buf.String()
checkOmit(t, output, "has_completion_function=1") checkOmit(t, output, "has_completion_function=1")
@ -1461,7 +1461,7 @@ func TestCompleteCmdInBashScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenBashCompletion(buf) assertNoErr(t, rootCmd.GenBashCompletion(buf))
output := buf.String() output := buf.String()
check(t, output, ShellCompNoDescRequestCmd) check(t, output, ShellCompNoDescRequestCmd)
@ -1477,7 +1477,7 @@ func TestCompleteNoDesCmdInZshScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenZshCompletionNoDesc(buf) assertNoErr(t, rootCmd.GenZshCompletionNoDesc(buf))
output := buf.String() output := buf.String()
check(t, output, ShellCompNoDescRequestCmd) check(t, output, ShellCompNoDescRequestCmd)
@ -1493,7 +1493,7 @@ func TestCompleteCmdInZshScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenZshCompletion(buf) assertNoErr(t, rootCmd.GenZshCompletion(buf))
output := buf.String() output := buf.String()
check(t, output, ShellCompRequestCmd) check(t, output, ShellCompRequestCmd)
@ -1506,7 +1506,7 @@ func TestFlagCompletionInGo(t *testing.T) {
Run: emptyRun, Run: emptyRun,
} }
rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
completions := []string{} completions := []string{}
for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
if strings.HasPrefix(comp, toComplete) { if strings.HasPrefix(comp, toComplete) {
@ -1514,9 +1514,9 @@ func TestFlagCompletionInGo(t *testing.T) {
} }
} }
return completions, ShellCompDirectiveDefault return completions, ShellCompDirectiveDefault
}) }))
rootCmd.Flags().String("filename", "", "Enter a filename") rootCmd.Flags().String("filename", "", "Enter a filename")
rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
completions := []string{} completions := []string{}
for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
if strings.HasPrefix(comp, toComplete) { if strings.HasPrefix(comp, toComplete) {
@ -1524,7 +1524,7 @@ func TestFlagCompletionInGo(t *testing.T) {
} }
} }
return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
}) }))
// Test completing an empty string // Test completing an empty string
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "") output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "")
@ -1703,7 +1703,7 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
Run: emptyRun, Run: emptyRun,
} }
rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot") rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("introot", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
completions := []string{} completions := []string{}
for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} { for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
if strings.HasPrefix(comp, toComplete) { if strings.HasPrefix(comp, toComplete) {
@ -1711,9 +1711,9 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
} }
} }
return completions, ShellCompDirectiveDefault return completions, ShellCompDirectiveDefault
}) }))
rootCmd.Flags().String("filename", "", "Enter a filename") rootCmd.Flags().String("filename", "", "Enter a filename")
rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { assertNoErr(t, rootCmd.RegisterFlagCompletionFunc("filename", func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
completions := []string{} completions := []string{}
for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} { for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
if strings.HasPrefix(comp, toComplete) { if strings.HasPrefix(comp, toComplete) {
@ -1721,7 +1721,7 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
} }
} }
return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
}) }))
// Test completing an empty string // Test completing an empty string
output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "") output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")

View File

@ -139,23 +139,23 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error {
return nil 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 description := cmd.Long
if len(description) == 0 { if len(description) == 0 {
description = cmd.Short description = cmd.Short
} }
buf.WriteString(fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s" cobra.WriteStringAndCheck(buf, fmt.Sprintf(`%% "%s" "%s" "%s" "%s" "%s"
# NAME # NAME
`, header.Title, header.Section, header.date, header.Source, header.Manual)) `, header.Title, header.Section, header.date, header.Source, header.Manual))
buf.WriteString(fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short)) cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
buf.WriteString("# SYNOPSIS\n") cobra.WriteStringAndCheck(buf, "# SYNOPSIS\n")
buf.WriteString(fmt.Sprintf("**%s**\n\n", cmd.UseLine())) cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
buf.WriteString("# DESCRIPTION\n") cobra.WriteStringAndCheck(buf, "# DESCRIPTION\n")
buf.WriteString(description + "\n\n") cobra.WriteStringAndCheck(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) { flags.VisitAll(func(flag *pflag.Flag) {
if len(flag.Deprecated) > 0 || flag.Hidden { if len(flag.Deprecated) > 0 || flag.Hidden {
return return
@ -179,22 +179,22 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
format += "]" format += "]"
} }
format += "\n\t%s\n\n" format += "\n\t%s\n\n"
buf.WriteString(fmt.Sprintf(format, flag.DefValue, flag.Usage)) cobra.WriteStringAndCheck(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() flags := command.NonInheritedFlags()
if flags.HasAvailableFlags() { if flags.HasAvailableFlags() {
buf.WriteString("# OPTIONS\n") cobra.WriteStringAndCheck(buf, "# OPTIONS\n")
manPrintFlags(buf, flags) manPrintFlags(buf, flags)
buf.WriteString("\n") cobra.WriteStringAndCheck(buf, "\n")
} }
flags = command.InheritedFlags() flags = command.InheritedFlags()
if flags.HasAvailableFlags() { if flags.HasAvailableFlags() {
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n") cobra.WriteStringAndCheck(buf, "# OPTIONS INHERITED FROM PARENT COMMANDS\n")
manPrintFlags(buf, flags) manPrintFlags(buf, flags)
buf.WriteString("\n") cobra.WriteStringAndCheck(buf, "\n")
} }
} }

View File

@ -13,6 +13,12 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
func assertNoErr(t *testing.T, e error) {
if e != nil {
t.Error(e)
}
}
func translate(in string) string { func translate(in string) string {
return strings.Replace(in, "-", "\\-", -1) return strings.Replace(in, "-", "\\-", -1)
} }
@ -133,7 +139,7 @@ func TestGenManSeeAlso(t *testing.T) {
func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { func TestManPrintFlagsHidesShortDeperecated(t *testing.T) {
c := &cobra.Command{} c := &cobra.Command{}
c.Flags().StringP("foo", "f", "default", "Foo flag") c.Flags().StringP("foo", "f", "default", "Foo flag")
c.Flags().MarkShorthandDeprecated("foo", "don't use it no more") assertNoErr(t, c.Flags().MarkShorthandDeprecated("foo", "don't use it no more"))
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
manPrintFlags(buf, c.Flags()) manPrintFlags(buf, c.Flags())

View File

@ -17,7 +17,7 @@ func ExampleGenManTree() {
Title: "MINE", Title: "MINE",
Section: "3", Section: "3",
} }
doc.GenManTree(cmd, header, "/tmp") cobra.CheckErr(doc.GenManTree(cmd, header, "/tmp"))
} }
func ExampleGenMan() { func ExampleGenMan() {
@ -30,6 +30,6 @@ func ExampleGenMan() {
Section: "3", Section: "3",
} }
out := new(bytes.Buffer) out := new(bytes.Buffer)
doc.GenMan(cmd, header, out) cobra.CheckErr(doc.GenMan(cmd, header, out))
fmt.Print(out.String()) fmt.Print(out.String())
} }

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) { func genFishComp(buf io.StringWriter, name string, includeDesc bool) {
// Variables should not contain a '-' or ':' character // Variables should not contain a '-' or ':' character
nameForVar := name nameForVar := name
nameForVar = strings.Replace(nameForVar, "-", "_", -1) nameForVar = strings.Replace(nameForVar, "-", "_", -1)
@ -18,8 +18,8 @@ func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
if !includeDesc { if !includeDesc {
compCmd = ShellCompNoDescRequestCmd compCmd = ShellCompNoDescRequestCmd
} }
buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name)) WriteStringAndCheck(buf, fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
buf.WriteString(fmt.Sprintf(` WriteStringAndCheck(buf, fmt.Sprintf(`
function __%[1]s_debug function __%[1]s_debug
set file "$BASH_COMP_DEBUG_FILE" set file "$BASH_COMP_DEBUG_FILE"
if test -n "$file" if test -n "$file"

View File

@ -15,7 +15,7 @@ func TestCompleteNoDesCmdInFishScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenFishCompletion(buf, false) assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
output := buf.String() output := buf.String()
check(t, output, ShellCompNoDescRequestCmd) check(t, output, ShellCompNoDescRequestCmd)
@ -31,7 +31,7 @@ func TestCompleteCmdInFishScript(t *testing.T) {
rootCmd.AddCommand(child) rootCmd.AddCommand(child)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenFishCompletion(buf, true) assertNoErr(t, rootCmd.GenFishCompletion(buf, true))
output := buf.String() output := buf.String()
check(t, output, ShellCompRequestCmd) check(t, output, ShellCompRequestCmd)
@ -41,7 +41,7 @@ func TestCompleteCmdInFishScript(t *testing.T) {
func TestProgWithDash(t *testing.T) { func TestProgWithDash(t *testing.T) {
rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun} rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenFishCompletion(buf, false) assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
output := buf.String() output := buf.String()
// Functions name should have replace the '-' // Functions name should have replace the '-'
@ -56,7 +56,7 @@ func TestProgWithDash(t *testing.T) {
func TestProgWithColon(t *testing.T) { func TestProgWithColon(t *testing.T) {
rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun} rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
rootCmd.GenFishCompletion(buf, false) assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
output := buf.String() output := buf.String()
// Functions name should have replace the ':' // Functions name should have replace the ':'

View File

@ -10,12 +10,12 @@ import (
"os" "os"
) )
func genPowerShellComp(buf *bytes.Buffer, name string, includeDesc bool) { func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {
compCmd := ShellCompRequestCmd compCmd := ShellCompRequestCmd
if !includeDesc { if !includeDesc {
compCmd = ShellCompNoDescRequestCmd compCmd = ShellCompNoDescRequestCmd
} }
buf.WriteString(fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*- WriteStringAndCheck(buf, fmt.Sprintf(`# powershell completion for %-36[1]s -*- shell-script -*-
function __%[1]s_debug { function __%[1]s_debug {
if ($env:BASH_COMP_DEBUG_FILE) { if ($env:BASH_COMP_DEBUG_FILE) {

View File

@ -99,8 +99,7 @@ cmd := &cobra.Command{
Long: get_long, Long: get_long,
Example: get_example, Example: get_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
err := RunGet(f, out, cmd, args) cobra.CheckErr(RunGet(f, out, cmd, args))
util.CheckErr(err)
}, },
ValidArgs: validArgs, ValidArgs: validArgs,
} }

View File

@ -70,12 +70,12 @@ func (c *Command) genZshCompletion(w io.Writer, includeDesc bool) error {
return err return err
} }
func genZshComp(buf *bytes.Buffer, name string, includeDesc bool) { func genZshComp(buf io.StringWriter, name string, includeDesc bool) {
compCmd := ShellCompRequestCmd compCmd := ShellCompRequestCmd
if !includeDesc { if !includeDesc {
compCmd = ShellCompNoDescRequestCmd compCmd = ShellCompNoDescRequestCmd
} }
buf.WriteString(fmt.Sprintf(`#compdef _%[1]s %[1]s WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s
# zsh completion for %-36[1]s -*- shell-script -*- # zsh completion for %-36[1]s -*- shell-script -*-