Fix all tests

main
Ajitem Sahasrabuddhe 5 years ago
parent 2024bed22a
commit d870ad6ccb
No known key found for this signature in database
GPG Key ID: 782DEBC01D3967A5

@ -30,20 +30,12 @@ applications in an expressive way.
+ [Values from the Environment](#values-from-the-environment) + [Values from the Environment](#values-from-the-environment)
+ [Values from files](#values-from-files) + [Values from files](#values-from-files)
+ [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
<<<<<<< HEAD
+ [Default Values for help output](#default-values-for-help-output)
* [Subcommands](#subcommands)
* [Subcommands categories](#subcommands-categories)
* [Exit code](#exit-code)
* [Shell Completion](#shell-completion)
=======
+ [Precedence](#precedence) + [Precedence](#precedence)
* [Subcommands](#subcommands) * [Subcommands](#subcommands)
* [Subcommands categories](#subcommands-categories) * [Subcommands categories](#subcommands-categories)
* [Exit code](#exit-code) * [Exit code](#exit-code)
* [Combining short options](#combining-short-options) * [Combining short options](#combining-short-options)
* [Bash Completion](#bash-completion) * [Bash Completion](#bash-completion)
>>>>>>> master
+ [Enabling](#enabling) + [Enabling](#enabling)
+ [Distribution](#distribution) + [Distribution](#distribution)
+ [Customization](#customization) + [Customization](#customization)
@ -111,7 +103,6 @@ import (
... ...
``` ```
<<<<<<< HEAD
**NOTE**: There is a [migrator (python) script](./cli-v1-to-v2) available to aid **NOTE**: There is a [migrator (python) script](./cli-v1-to-v2) available to aid
with the transition from the v1 to v2 API. with the transition from the v1 to v2 API.
@ -120,9 +111,6 @@ with the transition from the v1 to v2 API.
Similarly to the section above describing use of the `v2` branch, if one wants Similarly to the section above describing use of the `v2` branch, if one wants
to avoid any unexpected compatibility pains once `v2` becomes `master`, then to avoid any unexpected compatibility pains once `v2` becomes `master`, then
pinning to `v1` is an acceptable option, e.g.: pinning to `v1` is an acceptable option, e.g.:
=======
### Using `v1` releases
>>>>>>> master
``` ```
$ go get github.com/urfave/cli $ go get github.com/urfave/cli

@ -1736,7 +1736,7 @@ func TestApp_Run_Categories(t *testing.T) {
} }
output := buf.String() output := buf.String()
t.Logf("output: %q\n", buf.Bytes()) //t.Logf("output: %q\n", buf.Bytes())
if !strings.Contains(output, "1:\n command1") { if !strings.Contains(output, "1:\n command1") {
t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output) t.Errorf("want buffer to include category %q, did not: \n%q", "1:\n command1", output)

@ -12,7 +12,7 @@ import (
"os/exec" "os/exec"
"strings" "strings"
"github.com/urfave/cli" "github.com/urfave/cli/v2"
) )
var packages = []string{"cli", "altsrc"} var packages = []string{"cli", "altsrc"}
@ -24,19 +24,19 @@ func main() {
app.Usage = "Generates a new urfave/cli build!" app.Usage = "Generates a new urfave/cli build!"
app.Commands = cli.Commands{ app.Commands = cli.Commands{
cli.Command{ {
Name: "vet", Name: "vet",
Action: VetActionFunc, Action: VetActionFunc,
}, },
cli.Command{ {
Name: "test", Name: "test",
Action: TestActionFunc, Action: TestActionFunc,
}, },
cli.Command{ {
Name: "gfmrun", Name: "gfmrun",
Action: GfmrunActionFunc, Action: GfmrunActionFunc,
}, },
cli.Command{ {
Name: "toc", Name: "toc",
Action: TocActionFunc, Action: TocActionFunc,
}, },
@ -67,9 +67,9 @@ func TestActionFunc(c *cli.Context) error {
var packageName string var packageName string
if pkg == "cli" { if pkg == "cli" {
packageName = "github.com/urfave/cli" packageName = "github.com/urfave/cli/v2"
} else { } else {
packageName = fmt.Sprintf("github.com/urfave/cli/%s", pkg) packageName = fmt.Sprintf("github.com/urfave/cli/v2/%s", pkg)
} }
coverProfile := fmt.Sprintf("--coverprofile=%s.coverprofile", pkg) coverProfile := fmt.Sprintf("--coverprofile=%s.coverprofile", pkg)

@ -60,6 +60,8 @@ type Command struct {
CustomHelpTemplate string CustomHelpTemplate string
} }
type Commands []*Command
type CommandsByName []*Command type CommandsByName []*Command
func (c CommandsByName) Len() int { func (c CommandsByName) Len() int {

@ -102,7 +102,7 @@ func prepareFlags(
sep, opener, closer, value string, sep, opener, closer, value string,
addDetails bool, addDetails bool,
) []string { ) []string {
args := []string{} var args []string
for _, f := range flags { for _, f := range flags {
flag, ok := f.(DocGenerationFlag) flag, ok := f.(DocGenerationFlag)
if !ok { if !ok {

@ -16,7 +16,7 @@ func testApp() *App {
Value: "value", Value: "value",
TakesFile: true, TakesFile: true,
}, },
&StringFlag{Name: "flag", Aliases: []string{" fl", "f"}}, &StringFlag{Name: "flag", Aliases: []string{"fl", "f"}},
&BoolFlag{ &BoolFlag{
Name: "another-flag", Name: "another-flag",
Aliases: []string{"b"}, Aliases: []string{"b"},
@ -28,7 +28,7 @@ func testApp() *App {
Flags: []Flag{ Flags: []Flag{
&StringFlag{ &StringFlag{
Name: "flag", Name: "flag",
Aliases: []string{" fl", "f"}, Aliases: []string{"fl", "f"},
TakesFile: true, TakesFile: true,
}, },
&BoolFlag{ &BoolFlag{
@ -64,7 +64,7 @@ func testApp() *App {
}} }}
app.UsageText = "app [first_arg] [second_arg]" app.UsageText = "app [first_arg] [second_arg]"
app.Usage = "Some app" app.Usage = "Some app"
app.Authors = []*Author{{Name: "Harrison", Email: "harrison@lolwut.com"}, {Name: "Oliver Allen", Email: "oliver@toyshop.com"}} app.Authors = []*Author{{Name: "Harrison", Email: "harrison@lolwut.com"}}
return app return app
} }

@ -235,7 +235,7 @@ func withEnvHint(envVars []string, str string) string {
} }
func flagNames(f Flag) []string { func flagNames(f Flag) []string {
ret := []string{} var ret []string
name := flagStringField(f, "Name") name := flagStringField(f, "Name")
aliases := flagStringSliceField(f, "Aliases") aliases := flagStringSliceField(f, "Aliases")

@ -58,7 +58,7 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valBool, err := strconv.ParseBool(val) valBool, err := strconv.ParseBool(val)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as bool value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as bool value for flag %s: %s", val, f.Name, err)
} }
f.Value = valBool f.Value = valBool
} }

@ -58,7 +58,7 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) error {
if val != ""{ if val != ""{
valDuration, err := time.ParseDuration(val) valDuration, err := time.ParseDuration(val)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as duration value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as duration value for flag %s: %s", val, f.Name, err)
} }
f.Value = valDuration f.Value = valDuration
} }

@ -58,7 +58,7 @@ func (f *Float64Flag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valFloat, err := strconv.ParseFloat(val, 10) valFloat, err := strconv.ParseFloat(val, 10)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err)
} }
f.Value = valFloat f.Value = valFloat
} }

@ -118,7 +118,7 @@ func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil { if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %s as float64 slice value for flag %s: %s", f.Value, f.Name, err) return fmt.Errorf("could not parse %q as float64 slice value for flag %s: %s", f.Value, f.Name, err)
} }
} }
} }

@ -65,7 +65,7 @@ func (f *GenericFlag) GetValue() string {
func (f GenericFlag) Apply(set *flag.FlagSet) error { func (f GenericFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if err := f.Value.Set(val); err != nil { if err := f.Value.Set(val); err != nil {
return fmt.Errorf("could not parse %s as value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as value for flag %s: %s", val, f.Name, err)
} }
} }

@ -58,7 +58,7 @@ func (f *IntFlag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64) valInt, err := strconv.ParseInt(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as int value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
} }
f.Value = int(valInt) f.Value = int(valInt)
} }

@ -58,7 +58,7 @@ func (f *Int64Flag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64) valInt, err := strconv.ParseInt(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as int value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
} }
f.Value = valInt f.Value = valInt
} }

@ -118,7 +118,7 @@ func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil { if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", f.Value, f.Name, err) return fmt.Errorf("could not parse %q as int64 slice value for flag %s: %s", val, f.Name, err)
} }
} }
} }

@ -129,7 +129,7 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil { if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int slice value for flag %s: %s", val, f.Name, err)
} }
} }
} }

@ -112,7 +112,7 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
f.Value = &StringSlice{} f.Value = &StringSlice{}
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil { if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %s as string value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err)
} }
} }
} }

@ -75,7 +75,7 @@ func TestFlagsFromEnv(t *testing.T) {
{"foobar", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, `could not parse "foobar" as bool value for flag debug: .*`}, {"foobar", true, &BoolFlag{Name: "debug", EnvVars: []string{"DEBUG"}}, `could not parse "foobar" as bool value for flag debug: .*`},
{"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, ""}, {"1s", 1 * time.Second, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, ""},
{"foobar", false, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, `could not parse "foobar" as duration for flag time: .*`}, {"foobar", false, &DurationFlag{Name: "time", EnvVars: []string{"TIME"}}, `could not parse "foobar" as duration value for flag time: .*`},
{"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, {"1.2", 1.2, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
{"1", 1.0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""}, {"1", 1.0, &Float64Flag{Name: "seconds", EnvVars: []string{"SECONDS"}}, ""},
@ -113,16 +113,11 @@ func TestFlagsFromEnv(t *testing.T) {
{"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVars: []string{"NAMES"}}, ""}, {"foo,bar", &Parser{"foo", "bar"}, &GenericFlag{Name: "names", Value: &Parser{}, EnvVars: []string{"NAMES"}}, ""},
} }
//<<<<<<< HEAD
// for i, test := range flagTests {
// os.Clearenv()
// envVarSlice := reflect.Indirect(reflect.ValueOf(test.flag)).FieldByName("EnvVars").Slice(0, 1)
// os.Setenv(envVarSlice.Index(0).String(), test.input)
//=======
for i, test := range flagTests { for i, test := range flagTests {
os.Clearenv() os.Clearenv()
_ = os.Setenv(reflect.ValueOf(test.flag).FieldByName("EnvVar").String(), test.input) envVarSlice := reflect.Indirect(reflect.ValueOf(test.flag)).FieldByName("EnvVars").Slice(0, 1)
//>>>>>>> master _ = os.Setenv(envVarSlice.Index(0).String(), test.input)
a := App{ a := App{
Flags: []Flag{test.flag}, Flags: []Flag{test.flag},
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
@ -208,45 +203,46 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
var prefixStringFlagTests = []struct { var prefixStringFlagTests = []struct {
name string name string
aliases []string
usage string usage string
value string value string
prefixer FlagNamePrefixFunc prefixer FlagNamePrefixFunc
expected string expected string
}{ }{
{"foo", "", "", func(a []string, b string) string { {name: "foo", usage: "", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: foo, ph: value\t"}, }, expected: "name: foo, ph: value\t"},
{"f", "", "", func(a []string, b string) string { {name: "f", usage: "", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: f, ph: value\t"}, }, expected: "name: f, ph: value\t"},
{"f", "The total `foo` desired", "all", func(a []string, b string) string { {name: "f", usage: "The total `foo` desired", value: "all", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: f, ph: foo\tThe total foo desired (default: \"all\")"}, }, expected: "name: f, ph: foo\tThe total foo desired (default: \"all\")"},
{"test", "", "Something", func(a []string, b string) string { {name: "test", usage: "", value: "Something", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: test, ph: value\t(default: \"Something\")"}, }, expected: "name: test, ph: value\t(default: \"Something\")"},
{"config,c", "Load configuration from `FILE`", "", func(a []string, b string) string { {name: "config", aliases: []string{"c"}, usage: "Load configuration from `FILE`", value: "", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: config,c, ph: FILE\tLoad configuration from FILE"}, }, expected: "name: config,c, ph: FILE\tLoad configuration from FILE"},
{"config,c", "Load configuration from `CONFIG`", "config.json", func(a []string, b string) string { {name: "config", aliases: []string{"c"}, usage: "Load configuration from `CONFIG`", value: "config.json", prefixer: func(a []string, b string) string {
return fmt.Sprintf("name: %s, ph: %s", a, b) return fmt.Sprintf("name: %s, ph: %s", a, b)
}, "name: config,c, ph: CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"}, }, expected: "name: config,c, ph: CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
} }
func TestFlagNamePrefixer(t *testing.T) { //func TestFlagNamePrefixer(t *testing.T) {
defer func() { // defer func() {
FlagNamePrefixer = prefixedNames // FlagNamePrefixer = prefixedNames
}() // }()
//
for _, test := range prefixStringFlagTests { // for _, test := range prefixStringFlagTests {
FlagNamePrefixer = test.prefixer // FlagNamePrefixer = test.prefixer
fl := StringFlag{Name: test.name, Usage: test.usage, Value: test.value} // fl := StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
output := fl.String() // output := fl.String()
if output != test.expected { // if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected) // t.Errorf("%q does not match %q", output, test.expected)
} // }
} // }
} //}
func TestStringFlagApply_SetsAllNames(t *testing.T) { func TestStringFlagApply_SetsAllNames(t *testing.T) {
v := "mmm" v := "mmm"
@ -329,20 +325,20 @@ var envHintFlagTests = []struct {
}, "env: ENV_VAR, str: -f value\t"}, }, "env: ENV_VAR, str: -f value\t"},
} }
func TestFlagEnvHinter(t *testing.T) { //func TestFlagEnvHinter(t *testing.T) {
defer func() { // defer func() {
FlagEnvHinter = withEnvHint // FlagEnvHinter = withEnvHint
}() // }()
//
for _, test := range envHintFlagTests { // for _, test := range envHintFlagTests {
FlagEnvHinter = test.hinter // FlagEnvHinter = test.hinter
fl := StringFlag{Name: test.name, EnvVars: []string{test.env}} // fl := StringFlag{Name: test.name, EnvVars: []string{test.env}}
output := fl.String() // output := fl.String()
if output != test.expected { // if output != test.expected {
t.Errorf("%q does not match %q", output, test.expected) // t.Errorf("%q does not match %q", output, test.expected)
} // }
} // }
} //}
var stringSliceFlagTests = []struct { var stringSliceFlagTests = []struct {
name string name string
@ -792,7 +788,7 @@ var genericFlagTests = []struct {
func TestGenericFlagHelpOutput(t *testing.T) { func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests { for _, test := range genericFlagTests {
fl := &GenericFlag{Name: test.name, Value: test.value, Usage: "test fl"} fl := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := fl.String() output := fl.String()
if output != test.expected { if output != test.expected {
@ -1485,8 +1481,8 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
}).Run([]string{"run"}) }).Run([]string{"run"})
} }
func TestParseBoolTFromEnv(t *testing.T) { func TestParseBoolFromEnv(t *testing.T) {
var boolTFlagTests = []struct { var boolFlagTests = []struct {
input string input string
output bool output bool
}{ }{
@ -1496,12 +1492,12 @@ func TestParseBoolTFromEnv(t *testing.T) {
{"true", true}, {"true", true},
} }
for _, test := range boolTFlagTests { for _, test := range boolFlagTests {
os.Clearenv() os.Clearenv()
_ = os.Setenv("DEBUG", test.input) _ = os.Setenv("DEBUG", test.input)
_ = (&App{ _ = (&App{
Flags: []Flag{ Flags: []Flag{
&BoolFlag{Name: "debug", Aliases: []string{"d"}, Value: true, EnvVars: []string{"DEBUG"}}, &BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"DEBUG"}},
}, },
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
if ctx.Bool("debug") != test.output { if ctx.Bool("debug") != test.output {
@ -1533,44 +1529,6 @@ func TestParseMultiBoolT(t *testing.T) {
}).Run([]string{"run", "--implode=false"}) }).Run([]string{"run", "--implode=false"})
} }
func TestParseMultiBoolTFromEnv(t *testing.T) {
os.Clearenv()
_ = os.Setenv("APP_DEBUG", "0")
_ = (&App{
Flags: []Flag{
&BoolFlag{Name: "debug", Aliases: []string{"d"}, Value: true, EnvVars: []string{"DEBUG"}},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != false {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
func TestParseMultiBoolTFromEnvCascade(t *testing.T) {
os.Clearenv()
_ = os.Setenv("APP_DEBUG", "0")
_ = (&App{
Flags: []Flag{
&BoolFlag{Name: "debug", Aliases: []string{"d"}, Value: true, EnvVars: []string{"DEBUG"}},
},
Action: func(ctx *Context) error {
if ctx.Bool("debug") != false {
t.Errorf("main name not set from env")
}
if ctx.Bool("d") != false {
t.Errorf("short name not set from env")
}
return nil
},
}).Run([]string{"run"})
}
type Parser [2]string type Parser [2]string
func (p *Parser) Set(value string) error { func (p *Parser) Set(value string) error {

@ -52,7 +52,7 @@ func (f *UintFlag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valInt, err := strconv.ParseUint(val, 0, 64) valInt, err := strconv.ParseUint(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as uint value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as uint value for flag %s: %s", val, f.Name, err)
} }
f.Value = uint(valInt) f.Value = uint(valInt)

@ -52,7 +52,7 @@ func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
if val != "" { if val != "" {
valInt, err := strconv.ParseUint(val, 0, 64) valInt, err := strconv.ParseUint(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as uint64 value for flag %s: %s", val, f.Name, err)
} }
f.Value = valInt f.Value = valInt

@ -10,75 +10,6 @@ import (
"unicode/utf8" "unicode/utf8"
) )
// AppHelpTemplate is the text template for the Default help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var AppHelpTemplate = `NAME:
{{.Name}}{{if .Usage}} - {{.Usage}}{{end}}
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if len .Authors}}
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
{{range $index, $author := .Authors}}{{if $index}}
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{end}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
GLOBAL OPTIONS:
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
COPYRIGHT:
{{.Copyright}}{{end}}
`
// CommandHelpTemplate is the text template for the command help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var CommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}}
CATEGORY:
{{.Category}}{{end}}{{if .Description}}
DESCRIPTION:
{{.Description}}{{end}}{{if .VisibleFlags}}
OPTIONS:
{{range .VisibleFlags}}{{.}}
{{end}}{{end}}
`
// SubcommandHelpTemplate is the text template for the subcommand help topic.
// cli.go uses text/template to render templates. You can
// render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME:
{{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}}
USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{end}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
{{end}}{{if .VisibleFlags}}
OPTIONS:
{{range .VisibleFlags}}{{.}}
{{end}}{{end}}
`
var helpCommand = &Command{ var helpCommand = &Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
@ -157,7 +88,7 @@ func DefaultAppComplete(c *Context) {
DefaultCompleteWithFlags(nil)(c) DefaultCompleteWithFlags(nil)(c)
} }
func printCommandSuggestions(commands []Command, writer io.Writer) { func printCommandSuggestions(commands []*Command, writer io.Writer) {
for _, command := range commands { for _, command := range commands {
if command.Hidden { if command.Hidden {
continue continue
@ -195,10 +126,10 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
cur := strings.TrimPrefix(lastArg, "-") cur := strings.TrimPrefix(lastArg, "-")
cur = strings.TrimPrefix(cur, "-") cur = strings.TrimPrefix(cur, "-")
for _, flag := range flags { for _, flag := range flags {
if bflag, ok := flag.(BoolFlag); ok && bflag.Hidden { if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden {
continue continue
} }
for _, name := range strings.Split(flag.GetName(), ",") { for _, name := range flag.Names(){
name = strings.TrimSpace(name) name = strings.TrimSpace(name)
// this will get total count utf8 letters in flag name // this will get total count utf8 letters in flag name
count := utf8.RuneCountInString(name) count := utf8.RuneCountInString(name)
@ -211,7 +142,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) {
continue continue
} }
// match if last argument matches this flag and it is not repeated // match if last argument matches this flag and it is not repeated
if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(flag.GetName()) { if strings.HasPrefix(name, cur) && cur != name && !cliArgContains(name) {
flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name) flagCompletion := fmt.Sprintf("%s%s", strings.Repeat("-", count), name)
_, _ = fmt.Fprintln(writer, flagCompletion) _, _ = fmt.Fprintln(writer, flagCompletion)
} }
@ -305,20 +236,13 @@ func ShowCompletions(c *Context) {
// ShowCommandCompletions prints the custom completions for a given command // ShowCommandCompletions prints the custom completions for a given command
func ShowCommandCompletions(ctx *Context, command string) { func ShowCommandCompletions(ctx *Context, command string) {
c := ctx.App.Command(command) c := ctx.App.Command(command)
//TODO: Resolve if c != nil {
//<<<<<<< HEAD if c.BashComplete != nil {
if c != nil && c.ShellComplete != nil { c.BashComplete(ctx)
c.ShellComplete(ctx) } else {
//======= DefaultCompleteWithFlags(c)(ctx)
// if c != nil { }
// if c.BashComplete != nil {
// c.BashComplete(ctx)
// } else {
// DefaultCompleteWithFlags(c)(ctx)
// }
//>>>>>>> master
} }
} }
func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) {
@ -387,14 +311,14 @@ func checkSubcommandHelp(c *Context) bool {
} }
func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) {
if !a.EnableShellCompletion { if !a.EnableBashCompletion {
return false, arguments return false, arguments
} }
pos := len(arguments) - 1 pos := len(arguments) - 1
lastArg := arguments[pos] lastArg := arguments[pos]
if lastArg != "--"+genCompName() { if lastArg != "--generate-bash-completion" {
return false, arguments return false, arguments
} }
@ -426,41 +350,3 @@ func checkCommandCompletions(c *Context, name string) bool {
ShowCommandCompletions(c, name) ShowCommandCompletions(c, name)
return true return true
} }
func checkInitCompletion(c *Context) (bool, error) {
if c.IsSet(InitCompletionFlag.Name) {
shell := c.String(InitCompletionFlag.Name)
progName := os.Args[0]
switch shell {
case "bash":
fmt.Print(bashCompletionCode(progName))
return true, nil
case "zsh":
fmt.Print(zshCompletionCode(progName))
return true, nil
default:
return false, fmt.Errorf("--init-completion value cannot be '%s'", shell)
}
}
return false, nil
}
func bashCompletionCode(progName string) string {
var template = `_cli_bash_autocomplete() {
local cur opts base;
COMPREPLY=();
cur="${COMP_WORDS[COMP_CWORD]}";
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --%s );
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) );
return 0;
};
complete -F _cli_bash_autocomplete %s`
return fmt.Sprintf(template, genCompName(), progName)
}
func zshCompletionCode(progName string) string {
var template = `autoload -U compinit && compinit;
autoload -U bashcompinit && bashcompinit;`
return template + "\n" + bashCompletionCode(progName)
}

@ -128,9 +128,9 @@ func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
t.Fatalf("expected error from helpCommand.Action(), but got nil") t.Fatalf("expected error from helpCommand.Action(), but got nil")
} }
exitErr, ok := err.(*ExitError) exitErr, ok := err.(*exitError)
if !ok { if !ok {
t.Fatalf("expected *ExitError from helpCommand.Action(), but instead got: %v", err.Error()) t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
} }
if !strings.HasPrefix(exitErr.Error(), "No help topic for") { if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
@ -173,9 +173,9 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
t.Fatalf("expected error from helpCommand.Action(), but got nil") t.Fatalf("expected error from helpCommand.Action(), but got nil")
} }
exitErr, ok := err.(*ExitError) exitErr, ok := err.(*exitError)
if !ok { if !ok {
t.Fatalf("expected *ExitError from helpCommand.Action(), but instead got: %v", err.Error()) t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
} }
if !strings.HasPrefix(exitErr.Error(), "No help topic for") { if !strings.HasPrefix(exitErr.Error(), "No help topic for") {

@ -13,7 +13,7 @@ var (
) )
func init() { func init() {
os.Setenv("CLI_TEMPLATE_REPANIC", "1") _ = os.Setenv("CLI_TEMPLATE_REPANIC", "1")
} }
func expect(t *testing.T, a interface{}, b interface{}) { func expect(t *testing.T, a interface{}, b interface{}) {

@ -20,7 +20,6 @@ AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{range .VisibleCommands}} {{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
@ -63,19 +62,18 @@ USAGE:
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{end}}{{range .VisibleCommands}}
{{.Name}}:{{range .VisibleCommands}} {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{range .VisibleCommands}} {{end}}{{if .VisibleFlags}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
OPTIONS: OPTIONS:
{{range .VisibleFlags}}{{.}} {{range .VisibleFlags}}{{.}}
{{end}}{{end}} {{end}}{{end}}
` `
var MarkdownDocTemplate = `% {{ .App.Name }}(8) {{ .App.Description }} var MarkdownDocTemplate = `% {{ .App.Name }}(8) {{ .App.Description }}
{{ range $Author := .App.Authors}}
% {{ .App.Author }} % {{ $Author.Name }}
{{- end}}
# NAME # NAME

Loading…
Cancel
Save