Use golangci-lint (#1044)
Use golangci-lint. Repair warnings and errors resulting from linting.
This commit is contained in:
parent
1d71ff0270
commit
652c755d37
48
.golangci.yml
Normal file
48
.golangci.yml
Normal 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
|
@ -1,7 +1,6 @@
|
||||
language: go
|
||||
|
||||
stages:
|
||||
- diff
|
||||
- test
|
||||
- build
|
||||
|
||||
@ -10,17 +9,17 @@ go:
|
||||
- 1.15.x
|
||||
- tip
|
||||
|
||||
env: GO111MODULE=on
|
||||
|
||||
before_install:
|
||||
- go get -u github.com/kyoh86/richgo
|
||||
- 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:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
include:
|
||||
- stage: diff
|
||||
go: 1.14.x
|
||||
script: make fmt
|
||||
- stage: build
|
||||
go: 1.14.x
|
||||
script: make cobra_generator
|
||||
|
18
Makefile
18
Makefile
@ -1,21 +1,29 @@
|
||||
BIN="./bin"
|
||||
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))
|
||||
$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
|
||||
endif
|
||||
|
||||
.PHONY: fmt vet test cobra_generator install_deps clean
|
||||
.PHONY: fmt lint test cobra_generator install_deps clean
|
||||
|
||||
default: all
|
||||
|
||||
all: fmt vet test cobra_generator
|
||||
all: fmt test cobra_generator
|
||||
|
||||
fmt:
|
||||
$(info ******************** checking formatting ********************)
|
||||
@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 ********************)
|
||||
richgo test -v ./...
|
||||
|
||||
@ -28,9 +36,5 @@ install_deps:
|
||||
$(info ******************** downloading dependencies ********************)
|
||||
go get -v ./...
|
||||
|
||||
vet:
|
||||
$(info ******************** vetting ********************)
|
||||
go vet ./...
|
||||
|
||||
clean:
|
||||
rm -rf $(BIN)
|
||||
|
@ -234,11 +234,6 @@ func init() {
|
||||
rootCmd.AddCommand(initCmd)
|
||||
}
|
||||
|
||||
func er(msg interface{}) {
|
||||
fmt.Println("Error:", msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile != "" {
|
||||
// Use config file from the flag.
|
||||
@ -246,9 +241,7 @@ func initConfig() {
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".cobra" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
|
@ -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) {
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("# bash completion for %-36s -*- shell-script -*-\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||
__%[1]s_debug()
|
||||
{
|
||||
if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
|
||||
@ -380,10 +380,10 @@ __%[1]s_handle_word()
|
||||
ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
|
||||
}
|
||||
|
||||
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(`{
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`{
|
||||
local cur prev words cword
|
||||
declare -A flaghash 2>/dev/null || :
|
||||
declare -A aliashash 2>/dev/null || :
|
||||
@ -410,33 +410,33 @@ func writePostscript(buf *bytes.Buffer, name string) {
|
||||
}
|
||||
|
||||
`, 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
|
||||
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")
|
||||
WriteStringAndCheck(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) {
|
||||
WriteStringAndCheck(buf, " commands=()\n")
|
||||
for _, c := range cmd.Commands() {
|
||||
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||
continue
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" commands+=(%q)\n", c.Name()))
|
||||
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 {
|
||||
switch key {
|
||||
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
|
||||
if len(value) > 0 {
|
||||
@ -444,17 +444,18 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
|
||||
} else {
|
||||
ext = "_filedir"
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", ext))
|
||||
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 {
|
||||
handlers := strings.Join(value, "; ")
|
||||
buf.WriteString(fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" flags_completion+=(%q)\n", handlers))
|
||||
} else {
|
||||
buf.WriteString(" flags_completion+=(:)\n")
|
||||
WriteStringAndCheck(buf, " flags_completion+=(:)\n")
|
||||
}
|
||||
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
|
||||
if len(value) == 1 {
|
||||
@ -462,46 +463,48 @@ func writeFlagHandler(buf *bytes.Buffer, name string, annotations map[string][]s
|
||||
} else {
|
||||
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
|
||||
format := " "
|
||||
if len(flag.NoOptDefVal) == 0 {
|
||||
format += "two_word_"
|
||||
}
|
||||
format += "flags+=(\"-%s\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, name))
|
||||
format += "flags+=(\"-%s" + cbn
|
||||
WriteStringAndCheck(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
|
||||
WriteStringAndCheck(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
|
||||
WriteStringAndCheck(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+=(\"--%[1]s\")\n"
|
||||
format := " local_nonpersistent_flags+=(\"--%[1]s" + cbn
|
||||
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 {
|
||||
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)
|
||||
buf.WriteString(` flags=()
|
||||
WriteStringAndCheck(buf, ` flags=()
|
||||
two_word_flags=()
|
||||
local_nonpersistent_flags=()
|
||||
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) {
|
||||
buf.WriteString(" must_have_one_flag=()\n")
|
||||
func writeRequiredFlag(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " must_have_one_flag=()\n")
|
||||
flags := cmd.NonInheritedFlags()
|
||||
flags.VisitAll(func(flag *pflag.Flag) {
|
||||
if nonCompletableFlag(flag) {
|
||||
@ -570,55 +573,55 @@ func writeRequiredFlag(buf *bytes.Buffer, cmd *Command) {
|
||||
if flag.Value.Type() != "bool" {
|
||||
format += "="
|
||||
}
|
||||
format += "\")\n"
|
||||
buf.WriteString(fmt.Sprintf(format, flag.Name))
|
||||
format += cbn
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(format, flag.Name))
|
||||
|
||||
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) {
|
||||
buf.WriteString(" must_have_one_noun=()\n")
|
||||
sort.Sort(sort.StringSlice(cmd.ValidArgs))
|
||||
func writeRequiredNouns(buf io.StringWriter, cmd *Command) {
|
||||
WriteStringAndCheck(buf, " must_have_one_noun=()\n")
|
||||
sort.Strings(cmd.ValidArgs)
|
||||
for _, value := range cmd.ValidArgs {
|
||||
// Remove any description that may be included following a tab character.
|
||||
// Descriptions are not supported by bash completion.
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
buf.WriteString(fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
||||
buf.WriteString(fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name()))
|
||||
}
|
||||
buf.WriteString(` fi`)
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, ` fi`)
|
||||
WriteStringAndCheck(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) {
|
||||
WriteStringAndCheck(buf, " noun_aliases=()\n")
|
||||
sort.Strings(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() {
|
||||
if !c.IsAvailableCommand() && c != cmd.helpCommand {
|
||||
continue
|
||||
@ -630,22 +633,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))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName))
|
||||
} 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))
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(" command_aliases=()\n")
|
||||
buf.WriteString("\n")
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(" last_command=%q\n", commandName))
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
WriteStringAndCheck(buf, " command_aliases=()\n")
|
||||
WriteStringAndCheck(buf, "\n")
|
||||
|
||||
writeCommands(buf, cmd)
|
||||
writeFlags(buf, cmd)
|
||||
writeRequiredFlag(buf, cmd)
|
||||
writeRequiredNouns(buf, cmd)
|
||||
writeArgAliases(buf, cmd)
|
||||
buf.WriteString("}\n\n")
|
||||
WriteStringAndCheck(buf, "}\n\n")
|
||||
}
|
||||
|
||||
// GenBashCompletion generates bash completion file and writes to the passed writer.
|
||||
|
@ -40,10 +40,9 @@ func checkRegex(t *testing.T, found, pattern string) {
|
||||
}
|
||||
|
||||
func runShellCheck(s string) error {
|
||||
excluded := []string{
|
||||
cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e",
|
||||
"SC2034", // PREFIX appears unused. Verify it or export it.
|
||||
}
|
||||
cmd := exec.Command("shellcheck", "-s", "bash", "-", "-e", strings.Join(excluded, ","))
|
||||
)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
|
||||
@ -52,7 +51,9 @@ func runShellCheck(s string) error {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
stdin.Write([]byte(s))
|
||||
_, err := stdin.Write([]byte(s))
|
||||
CheckErr(err)
|
||||
|
||||
stdin.Close()
|
||||
}()
|
||||
|
||||
@ -74,26 +75,26 @@ func TestBashCompletions(t *testing.T) {
|
||||
Run: emptyRun,
|
||||
}
|
||||
rootCmd.Flags().IntP("introot", "i", -1, "help message for flag introot")
|
||||
rootCmd.MarkFlagRequired("introot")
|
||||
assertNoErr(t, rootCmd.MarkFlagRequired("introot"))
|
||||
|
||||
// Filename.
|
||||
rootCmd.Flags().String("filename", "", "Enter a filename")
|
||||
rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml")
|
||||
assertNoErr(t, rootCmd.MarkFlagFilename("filename", "json", "yaml", "yml"))
|
||||
|
||||
// Persistent filename.
|
||||
rootCmd.PersistentFlags().String("persistent-filename", "", "Enter a filename")
|
||||
rootCmd.MarkPersistentFlagFilename("persistent-filename")
|
||||
rootCmd.MarkPersistentFlagRequired("persistent-filename")
|
||||
assertNoErr(t, rootCmd.MarkPersistentFlagFilename("persistent-filename"))
|
||||
assertNoErr(t, rootCmd.MarkPersistentFlagRequired("persistent-filename"))
|
||||
|
||||
// Filename extensions.
|
||||
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.MarkFlagCustom("custom", "__complete_custom")
|
||||
assertNoErr(t, 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"})
|
||||
assertNoErr(t, rootCmd.Flags().SetAnnotation("theme", BashCompSubdirsInDir, []string{"themes"}))
|
||||
|
||||
// For two word flags check
|
||||
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.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().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"})
|
||||
assertNoErr(t, echoCmd.Flags().SetAnnotation("config", BashCompSubdirsInDir, []string{"config"}))
|
||||
|
||||
printCmd := &Command{
|
||||
Use: "print [string to print]",
|
||||
@ -149,7 +150,7 @@ func TestBashCompletions(t *testing.T) {
|
||||
rootCmd.AddCommand(echoCmd, printCmd, deprecatedCmd, colonCmd)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenBashCompletion(buf)
|
||||
assertNoErr(t, rootCmd.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, "_root")
|
||||
@ -216,10 +217,10 @@ func TestBashCompletionHiddenFlag(t *testing.T) {
|
||||
|
||||
const flagName = "hiddenFlag"
|
||||
c.Flags().Bool(flagName, false, "")
|
||||
c.Flags().MarkHidden(flagName)
|
||||
assertNoErr(t, c.Flags().MarkHidden(flagName))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
c.GenBashCompletion(buf)
|
||||
assertNoErr(t, c.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
if strings.Contains(output, flagName) {
|
||||
@ -232,10 +233,10 @@ func TestBashCompletionDeprecatedFlag(t *testing.T) {
|
||||
|
||||
const flagName = "deprecated-flag"
|
||||
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)
|
||||
c.GenBashCompletion(buf)
|
||||
assertNoErr(t, c.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
if strings.Contains(output, flagName) {
|
||||
@ -250,7 +251,7 @@ func TestBashCompletionTraverseChildren(t *testing.T) {
|
||||
c.Flags().BoolP("bool-flag", "b", false, "bool flag")
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
c.GenBashCompletion(buf)
|
||||
assertNoErr(t, c.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
// check that local nonpersistent flag are not set since we have TraverseChildren set to true
|
||||
|
15
cobra.go
15
cobra.go
@ -19,6 +19,7 @@ package cobra
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -205,3 +206,17 @@ func stringInSlice(a string, list []string) bool {
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
@ -40,13 +40,11 @@ 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")
|
||||
cobra.CheckErr(fmt.Errorf("add needs a name for the command"))
|
||||
}
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
commandName := validateCmdName(args[0])
|
||||
command := &Command{
|
||||
@ -59,10 +57,7 @@ Example: cobra add server -> resulting in a new cmd/server.go`,
|
||||
},
|
||||
}
|
||||
|
||||
err = command.Create()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(command.Create())
|
||||
|
||||
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() {
|
||||
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.")
|
||||
cobra.CheckErr(addCmd.Flags().MarkDeprecated("package", "this operation has been removed."))
|
||||
}
|
||||
|
||||
// validateCmdName returns source without any dashes and underscore.
|
||||
|
@ -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)
|
||||
}
|
||||
assertNoErr(t, command.Project.Create())
|
||||
assertNoErr(t, command.Create())
|
||||
|
||||
generatedFile := fmt.Sprintf("%s/cmd/%s.go", command.AbsolutePath, command.CmdName)
|
||||
goldenFile := fmt.Sprintf("testdata/%s.go.golden", command.CmdName)
|
||||
|
@ -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.SetOut(new(bytes.Buffer))
|
||||
@ -58,27 +55,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
|
||||
}
|
||||
|
@ -14,14 +14,12 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var srcPaths []string
|
||||
@ -43,14 +41,12 @@ func init() {
|
||||
}
|
||||
|
||||
out, err := exec.Command(goExecutable, "env", "GOPATH").Output()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
toolchainGoPath := strings.TrimSpace(string(out))
|
||||
goPaths = filepath.SplitList(toolchainGoPath)
|
||||
if len(goPaths) == 0 {
|
||||
er("$GOPATH is not set")
|
||||
cobra.CheckErr("$GOPATH is not set")
|
||||
}
|
||||
}
|
||||
srcPaths = make([]string, 0, len(goPaths))
|
||||
@ -58,111 +54,3 @@ func init() {
|
||||
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")
|
||||
}
|
||||
|
9
cobra/cmd/helpers_test.go
Normal file
9
cobra/cmd/helpers_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package cmd
|
||||
|
||||
import "testing"
|
||||
|
||||
func assertNoErr(t *testing.T, e error) {
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
}
|
||||
}
|
@ -39,9 +39,7 @@ and the appropriate structure for a Cobra-based CLI application.
|
||||
Run: func(_ *cobra.Command, args []string) {
|
||||
|
||||
projectPath, err := initializeProject(args)
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
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() {
|
||||
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) {
|
||||
|
@ -59,7 +59,7 @@ func TestGoldenInitCmd(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
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)
|
||||
projectPath, err := initializeProject(tt.args)
|
||||
defer func() {
|
||||
|
@ -16,9 +16,11 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@ -92,7 +94,7 @@ func copyrightLine() string {
|
||||
func findLicense(name string) License {
|
||||
found := matchLicense(name)
|
||||
if found == "" {
|
||||
er("unknown license: " + name)
|
||||
cobra.CheckErr(fmt.Errorf("unknown license: " + name))
|
||||
}
|
||||
return Licenses[found]
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/cobra/cobra/tpl"
|
||||
)
|
||||
|
||||
@ -49,7 +50,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)
|
||||
cobra.CheckErr(os.Mkdir(fmt.Sprintf("%s/cmd", p.AbsolutePath), 0751))
|
||||
}
|
||||
rootFile, err := os.Create(fmt.Sprintf("%s/cmd/root.go", p.AbsolutePath))
|
||||
if err != nil {
|
||||
|
@ -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"))
|
||||
cobra.CheckErr(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")))
|
||||
cobra.CheckErr(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")))
|
||||
viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
|
||||
viper.SetDefault("license", "apache")
|
||||
|
||||
@ -63,9 +63,7 @@ func initConfig() {
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
er(err)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".cobra" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
|
16
cobra/cmd/testdata/root.go.golden
vendored
16
cobra/cmd/testdata/root.go.golden
vendored
@ -17,8 +17,8 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
@ -38,16 +38,13 @@ 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.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cobra.CheckErr(rootCmd.Execute())
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -72,10 +69,7 @@ func initConfig() {
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".testproject" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
@ -86,6 +80,6 @@ func initConfig() {
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,11 @@ package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"github.com/spf13/cobra"
|
||||
{{ if .Viper }}
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/viper"
|
||||
{{ end -}}
|
||||
"github.com/spf13/viper"{{ end }}
|
||||
)
|
||||
|
||||
{{ if .Viper -}}
|
||||
@ -48,16 +47,13 @@ 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.
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cobra.CheckErr(rootCmd.Execute())
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -86,10 +82,7 @@ func initConfig() {
|
||||
} else {
|
||||
// Find home directory.
|
||||
home, err := homedir.Dir()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cobra.CheckErr(err)
|
||||
|
||||
// Search config in home directory with name ".{{ .AppName }}" (without extension).
|
||||
viper.AddConfigPath(home)
|
||||
@ -100,7 +93,7 @@ func initConfig() {
|
||||
|
||||
// If a config file is found, read it in.
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
fmt.Println("Using config file:", viper.ConfigFileUsed())
|
||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
}
|
||||
{{- end }}
|
||||
|
@ -5,6 +5,12 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func assertNoErr(t *testing.T, e error) {
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddTemplateFunctions(t *testing.T) {
|
||||
AddTemplateFunc("t", func() bool { return true })
|
||||
AddTemplateFuncs(template.FuncMap{
|
||||
|
112
command.go
112
command.go
@ -84,9 +84,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
|
||||
@ -126,55 +123,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
|
||||
|
||||
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 []string
|
||||
// flagErrorBuf contains all error messages from pflag.
|
||||
@ -216,6 +164,60 @@ 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
|
||||
}
|
||||
|
||||
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
|
||||
@ -418,7 +420,7 @@ func (c *Command) UsageString() string {
|
||||
c.outWriter = bb
|
||||
c.errWriter = bb
|
||||
|
||||
c.Usage()
|
||||
CheckErr(c.Usage())
|
||||
|
||||
// Setting things back to normal
|
||||
c.outWriter = tmpOutput
|
||||
@ -1087,10 +1089,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()
|
||||
CheckErr(c.Root().Usage())
|
||||
} else {
|
||||
cmd.InitDefaultHelpFlag() // make possible 'help' flag to be shown
|
||||
cmd.Help()
|
||||
CheckErr(cmd.Help())
|
||||
}
|
||||
},
|
||||
}
|
||||
|
199
command_test.go
199
command_test.go
@ -58,6 +58,8 @@ func checkStringOmits(t *testing.T, got, expected string) {
|
||||
}
|
||||
}
|
||||
|
||||
const onetwo = "one two"
|
||||
|
||||
func TestSingleCommand(t *testing.T) {
|
||||
var rootCmdArgs []string
|
||||
rootCmd := &Command{
|
||||
@ -78,9 +80,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,9 +105,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,9 +243,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,9 +270,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
|
||||
@ -307,9 +305,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
|
||||
@ -338,9 +335,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,9 +364,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -406,9 +401,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,9 +435,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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,9 +638,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)
|
||||
@ -731,9 +723,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)
|
||||
@ -746,9 +737,9 @@ func TestPersistentFlagsOnChild(t *testing.T) {
|
||||
func TestRequiredFlags(t *testing.T) {
|
||||
c := &Command{Use: "c", Run: emptyRun}
|
||||
c.Flags().String("foo1", "", "")
|
||||
c.MarkFlagRequired("foo1")
|
||||
assertNoErr(t, c.MarkFlagRequired("foo1"))
|
||||
c.Flags().String("foo2", "", "")
|
||||
c.MarkFlagRequired("foo2")
|
||||
assertNoErr(t, c.MarkFlagRequired("foo2"))
|
||||
c.Flags().String("bar", "", "")
|
||||
|
||||
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) {
|
||||
parent := &Command{Use: "parent", Run: emptyRun}
|
||||
parent.PersistentFlags().String("foo1", "", "")
|
||||
parent.MarkPersistentFlagRequired("foo1")
|
||||
assertNoErr(t, parent.MarkPersistentFlagRequired("foo1"))
|
||||
parent.PersistentFlags().String("foo2", "", "")
|
||||
parent.MarkPersistentFlagRequired("foo2")
|
||||
assertNoErr(t, parent.MarkPersistentFlagRequired("foo2"))
|
||||
parent.Flags().String("foo3", "", "")
|
||||
|
||||
child := &Command{Use: "child", Run: emptyRun}
|
||||
child.Flags().String("bar1", "", "")
|
||||
child.MarkFlagRequired("bar1")
|
||||
assertNoErr(t, child.MarkFlagRequired("bar1"))
|
||||
child.Flags().String("bar2", "", "")
|
||||
child.MarkFlagRequired("bar2")
|
||||
assertNoErr(t, child.MarkFlagRequired("bar2"))
|
||||
child.Flags().String("bar3", "", "")
|
||||
|
||||
parent.AddCommand(child)
|
||||
@ -793,7 +784,7 @@ func TestPersistentRequiredFlagsWithDisableFlagParsing(t *testing.T) {
|
||||
parent := &Command{Use: "parent", Run: emptyRun}
|
||||
parent.PersistentFlags().Bool("foo", false, "")
|
||||
flag := parent.PersistentFlags().Lookup("foo")
|
||||
parent.MarkPersistentFlagRequired("foo")
|
||||
assertNoErr(t, parent.MarkPersistentFlagRequired("foo"))
|
||||
|
||||
child := &Command{Use: "child", Run: emptyRun}
|
||||
child.DisableFlagParsing = true
|
||||
@ -1299,20 +1290,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1380,44 +1370,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1741,7 +1729,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")
|
||||
assertNoErr(t, c.Flags().MarkDeprecated("deprecated", "This flag is deprecated"))
|
||||
|
||||
output, err := executeCommand(c, "c", "-d")
|
||||
if err != nil {
|
||||
@ -1868,7 +1856,6 @@ type calledAsTestcase struct {
|
||||
call string
|
||||
want string
|
||||
epm bool
|
||||
tc bool
|
||||
}
|
||||
|
||||
func (tc *calledAsTestcase) test(t *testing.T) {
|
||||
@ -1890,7 +1877,7 @@ func (tc *calledAsTestcase) test(t *testing.T) {
|
||||
parent.SetOut(output)
|
||||
parent.SetErr(output)
|
||||
|
||||
parent.Execute()
|
||||
_ = parent.Execute()
|
||||
|
||||
if called == nil {
|
||||
if tc.call != "" {
|
||||
@ -1908,18 +1895,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 {
|
||||
|
@ -527,13 +527,13 @@ func CompDebug(msg string, printToStdErr bool) {
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err == nil {
|
||||
defer f.Close()
|
||||
f.WriteString(msg)
|
||||
WriteStringAndCheck(f, msg)
|
||||
}
|
||||
}
|
||||
|
||||
if printToStdErr {
|
||||
// Must print to stderr for this not to be read by the completion script.
|
||||
fmt.Fprintf(os.Stderr, msg)
|
||||
fmt.Fprint(os.Stderr, msg)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -780,17 +780,17 @@ func TestRequiredFlagNameCompletionInGo(t *testing.T) {
|
||||
rootCmd.AddCommand(childCmd)
|
||||
|
||||
rootCmd.Flags().IntP("requiredFlag", "r", -1, "required flag")
|
||||
rootCmd.MarkFlagRequired("requiredFlag")
|
||||
assertNoErr(t, rootCmd.MarkFlagRequired("requiredFlag"))
|
||||
requiredFlag := rootCmd.Flags().Lookup("requiredFlag")
|
||||
|
||||
rootCmd.PersistentFlags().IntP("requiredPersistent", "p", -1, "required persistent")
|
||||
rootCmd.MarkPersistentFlagRequired("requiredPersistent")
|
||||
assertNoErr(t, rootCmd.MarkPersistentFlagRequired("requiredPersistent"))
|
||||
requiredPersistent := rootCmd.PersistentFlags().Lookup("requiredPersistent")
|
||||
|
||||
rootCmd.Flags().StringP("release", "R", "", "Release name")
|
||||
|
||||
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")
|
||||
|
||||
// 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.
|
||||
rootCmd.Flags().StringP("file", "f", "", "file flag")
|
||||
rootCmd.MarkFlagFilename("file")
|
||||
assertNoErr(t, rootCmd.MarkFlagFilename("file"))
|
||||
|
||||
// Single extension
|
||||
rootCmd.Flags().StringP("log", "l", "", "log flag")
|
||||
rootCmd.MarkFlagFilename("log", "log")
|
||||
assertNoErr(t, rootCmd.MarkFlagFilename("log", "log"))
|
||||
|
||||
// Multiple extensions
|
||||
rootCmd.Flags().StringP("yaml", "y", "", "yaml flag")
|
||||
rootCmd.MarkFlagFilename("yaml", "yaml", "yml")
|
||||
assertNoErr(t, rootCmd.MarkFlagFilename("yaml", "yaml", "yml"))
|
||||
|
||||
// Directly using annotation
|
||||
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
|
||||
// script to handle the file filtering
|
||||
@ -1086,15 +1086,15 @@ func TestFlagDirFilterCompletionInGo(t *testing.T) {
|
||||
|
||||
// Filter directories
|
||||
rootCmd.Flags().StringP("dir", "d", "", "dir flag")
|
||||
rootCmd.MarkFlagDirname("dir")
|
||||
assertNoErr(t, rootCmd.MarkFlagDirname("dir"))
|
||||
|
||||
// Filter directories within a directory
|
||||
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
|
||||
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
|
||||
// script to handle the directory filtering
|
||||
@ -1430,7 +1430,7 @@ func TestValidArgsFuncInBashScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenBashCompletion(buf)
|
||||
assertNoErr(t, rootCmd.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, "has_completion_function=1")
|
||||
@ -1445,7 +1445,7 @@ func TestNoValidArgsFuncInBashScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenBashCompletion(buf)
|
||||
assertNoErr(t, rootCmd.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
checkOmit(t, output, "has_completion_function=1")
|
||||
@ -1461,7 +1461,7 @@ func TestCompleteCmdInBashScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenBashCompletion(buf)
|
||||
assertNoErr(t, rootCmd.GenBashCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, ShellCompNoDescRequestCmd)
|
||||
@ -1477,7 +1477,7 @@ func TestCompleteNoDesCmdInZshScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenZshCompletionNoDesc(buf)
|
||||
assertNoErr(t, rootCmd.GenZshCompletionNoDesc(buf))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, ShellCompNoDescRequestCmd)
|
||||
@ -1493,7 +1493,7 @@ func TestCompleteCmdInZshScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenZshCompletion(buf)
|
||||
assertNoErr(t, rootCmd.GenZshCompletion(buf))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, ShellCompRequestCmd)
|
||||
@ -1506,7 +1506,7 @@ func TestFlagCompletionInGo(t *testing.T) {
|
||||
Run: emptyRun,
|
||||
}
|
||||
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{}
|
||||
for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
|
||||
if strings.HasPrefix(comp, toComplete) {
|
||||
@ -1514,9 +1514,9 @@ func TestFlagCompletionInGo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
return completions, ShellCompDirectiveDefault
|
||||
})
|
||||
}))
|
||||
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{}
|
||||
for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
|
||||
if strings.HasPrefix(comp, toComplete) {
|
||||
@ -1524,7 +1524,7 @@ func TestFlagCompletionInGo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
|
||||
})
|
||||
}))
|
||||
|
||||
// Test completing an empty string
|
||||
output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "--introot", "")
|
||||
@ -1703,7 +1703,7 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
|
||||
Run: emptyRun,
|
||||
}
|
||||
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{}
|
||||
for _, comp := range []string{"1\tThe first", "2\tThe second", "10\tThe tenth"} {
|
||||
if strings.HasPrefix(comp, toComplete) {
|
||||
@ -1711,9 +1711,9 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
return completions, ShellCompDirectiveDefault
|
||||
})
|
||||
}))
|
||||
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{}
|
||||
for _, comp := range []string{"file.yaml\tYAML format", "myfile.json\tJSON format", "file.xml\tXML format"} {
|
||||
if strings.HasPrefix(comp, toComplete) {
|
||||
@ -1721,7 +1721,7 @@ func TestFlagCompletionInGoWithDesc(t *testing.T) {
|
||||
}
|
||||
}
|
||||
return completions, ShellCompDirectiveNoSpace | ShellCompDirectiveNoFileComp
|
||||
})
|
||||
}))
|
||||
|
||||
// Test completing an empty string
|
||||
output, err := executeCommand(rootCmd, ShellCompRequestCmd, "--introot", "")
|
||||
|
@ -139,23 +139,23 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) 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" "%s" "%s"
|
||||
cobra.WriteStringAndCheck(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")
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf("%s \\- %s\n\n", dashedName, cmd.Short))
|
||||
cobra.WriteStringAndCheck(buf, "# SYNOPSIS\n")
|
||||
cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n\n", cmd.UseLine()))
|
||||
cobra.WriteStringAndCheck(buf, "# DESCRIPTION\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) {
|
||||
if len(flag.Deprecated) > 0 || flag.Hidden {
|
||||
return
|
||||
@ -179,22 +179,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))
|
||||
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()
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("# OPTIONS\n")
|
||||
cobra.WriteStringAndCheck(buf, "# OPTIONS\n")
|
||||
manPrintFlags(buf, flags)
|
||||
buf.WriteString("\n")
|
||||
cobra.WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
flags = command.InheritedFlags()
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
||||
cobra.WriteStringAndCheck(buf, "# OPTIONS INHERITED FROM PARENT COMMANDS\n")
|
||||
manPrintFlags(buf, flags)
|
||||
buf.WriteString("\n")
|
||||
cobra.WriteStringAndCheck(buf, "\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,12 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func assertNoErr(t *testing.T, e error) {
|
||||
if e != nil {
|
||||
t.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
func translate(in string) string {
|
||||
return strings.Replace(in, "-", "\\-", -1)
|
||||
}
|
||||
@ -133,7 +139,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")
|
||||
assertNoErr(t, c.Flags().MarkShorthandDeprecated("foo", "don't use it no more"))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
manPrintFlags(buf, c.Flags())
|
||||
|
@ -17,7 +17,7 @@ func ExampleGenManTree() {
|
||||
Title: "MINE",
|
||||
Section: "3",
|
||||
}
|
||||
doc.GenManTree(cmd, header, "/tmp")
|
||||
cobra.CheckErr(doc.GenManTree(cmd, header, "/tmp"))
|
||||
}
|
||||
|
||||
func ExampleGenMan() {
|
||||
@ -30,6 +30,6 @@ func ExampleGenMan() {
|
||||
Section: "3",
|
||||
}
|
||||
out := new(bytes.Buffer)
|
||||
doc.GenMan(cmd, header, out)
|
||||
cobra.CheckErr(doc.GenMan(cmd, header, out))
|
||||
fmt.Print(out.String())
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
"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
|
||||
nameForVar := name
|
||||
nameForVar = strings.Replace(nameForVar, "-", "_", -1)
|
||||
@ -18,8 +18,8 @@ func genFishComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
||||
if !includeDesc {
|
||||
compCmd = ShellCompNoDescRequestCmd
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
|
||||
buf.WriteString(fmt.Sprintf(`
|
||||
WriteStringAndCheck(buf, fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name))
|
||||
WriteStringAndCheck(buf, fmt.Sprintf(`
|
||||
function __%[1]s_debug
|
||||
set file "$BASH_COMP_DEBUG_FILE"
|
||||
if test -n "$file"
|
||||
|
@ -15,7 +15,7 @@ func TestCompleteNoDesCmdInFishScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenFishCompletion(buf, false)
|
||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, ShellCompNoDescRequestCmd)
|
||||
@ -31,7 +31,7 @@ func TestCompleteCmdInFishScript(t *testing.T) {
|
||||
rootCmd.AddCommand(child)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenFishCompletion(buf, true)
|
||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, true))
|
||||
output := buf.String()
|
||||
|
||||
check(t, output, ShellCompRequestCmd)
|
||||
@ -41,7 +41,7 @@ func TestCompleteCmdInFishScript(t *testing.T) {
|
||||
func TestProgWithDash(t *testing.T) {
|
||||
rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun}
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenFishCompletion(buf, false)
|
||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
||||
output := buf.String()
|
||||
|
||||
// Functions name should have replace the '-'
|
||||
@ -56,7 +56,7 @@ func TestProgWithDash(t *testing.T) {
|
||||
func TestProgWithColon(t *testing.T) {
|
||||
rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun}
|
||||
buf := new(bytes.Buffer)
|
||||
rootCmd.GenFishCompletion(buf, false)
|
||||
assertNoErr(t, rootCmd.GenFishCompletion(buf, false))
|
||||
output := buf.String()
|
||||
|
||||
// Functions name should have replace the ':'
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func genPowerShellComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
||||
func genPowerShellComp(buf io.StringWriter, name string, includeDesc bool) {
|
||||
compCmd := ShellCompRequestCmd
|
||||
if !includeDesc {
|
||||
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 {
|
||||
if ($env:BASH_COMP_DEBUG_FILE) {
|
||||
|
@ -99,8 +99,7 @@ cmd := &cobra.Command{
|
||||
Long: get_long,
|
||||
Example: get_example,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunGet(f, out, cmd, args)
|
||||
util.CheckErr(err)
|
||||
cobra.CheckErr(RunGet(f, out, cmd, args))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
}
|
||||
|
@ -70,12 +70,12 @@ func (c *Command) genZshCompletion(w io.Writer, includeDesc bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func genZshComp(buf *bytes.Buffer, name string, includeDesc bool) {
|
||||
func genZshComp(buf io.StringWriter, name string, includeDesc bool) {
|
||||
compCmd := ShellCompRequestCmd
|
||||
if !includeDesc {
|
||||
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 -*-
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user