Merge pull request #1525 from urfave/v3-porting

Porting changes from `main` to `v3-dev-main` (circa 2022-10-09)
This commit is contained in:
Dan Buch 2022-10-16 14:08:16 -04:00 committed by GitHub
commit 25897ce4dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 623 additions and 364 deletions

View File

@ -43,9 +43,14 @@ jobs:
GFLAGS: -tags urfave_cli_no_docs GFLAGS: -tags urfave_cli_no_docs
- run: make check-binary-size - run: make check-binary-size
- run: make yamlfmt - run: make yamlfmt
- run: make diffcheck
- if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest' - if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
run: make generate
- run: make diffcheck
# TODO: switch once v3 is released {{
# - if: matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
- if: 'false'
run: make v2diff run: make v2diff
# }}
- if: success() && matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest' - if: success() && matrix.go == '1.19.x' && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v3 uses: codecov/codecov-action@v3
with: with:

View File

@ -7,7 +7,7 @@
GO_RUN_BUILD := go run internal/build/build.go GO_RUN_BUILD := go run internal/build/build.go
.PHONY: all .PHONY: all
all: generate vet test check-binary-size gfmrun yamlfmt v2diff all: generate vet test check-binary-size gfmrun yamlfmt
# NOTE: this is a special catch-all rule to run any of the commands # NOTE: this is a special catch-all rule to run any of the commands
# defined in internal/build/build.go with optional arguments passed # defined in internal/build/build.go with optional arguments passed

View File

@ -177,7 +177,7 @@ func ExampleApp_Run_commandHelp() {
// greet describeit - use it to see a description // greet describeit - use it to see a description
// //
// USAGE: // USAGE:
// greet describeit [command options] [arguments...] // greet describeit [arguments...]
// //
// DESCRIPTION: // DESCRIPTION:
// This is how we describe describeit the function // This is how we describe describeit the function
@ -956,6 +956,37 @@ func TestApp_UseShortOptionHandlingSubCommand_missing_value(t *testing.T) {
expect(t, err, errors.New("flag needs an argument: -n")) expect(t, err, errors.New("flag needs an argument: -n"))
} }
func TestApp_UseShortOptionAfterSliceFlag(t *testing.T) {
var one, two bool
var name string
var sliceValDest StringSlice
var sliceVal []string
expected := "expectedName"
app := newTestApp()
app.UseShortOptionHandling = true
app.Flags = []Flag{
&StringSliceFlag{Name: "env", Aliases: []string{"e"}, Destination: &sliceValDest},
&BoolFlag{Name: "one", Aliases: []string{"o"}},
&BoolFlag{Name: "two", Aliases: []string{"t"}},
&StringFlag{Name: "name", Aliases: []string{"n"}},
}
app.Action = func(c *Context) error {
sliceVal = c.StringSlice("env")
one = c.Bool("one")
two = c.Bool("two")
name = c.String("name")
return nil
}
_ = app.Run([]string{"", "-e", "foo", "-on", expected})
expect(t, sliceVal, []string{"foo"})
expect(t, sliceValDest.Value(), []string{"foo"})
expect(t, one, true)
expect(t, two, false)
expect(t, name, expected)
}
func TestApp_Float64Flag(t *testing.T) { func TestApp_Float64Flag(t *testing.T) {
var meters float64 var meters float64

2
cli.go
View File

@ -22,4 +22,4 @@
// } // }
package cli package cli
//go:generate go run cmd/urfave-cli-genflags/main.go //go:generate make -C cmd/urfave-cli-genflags run

View File

@ -1,6 +1,9 @@
GOIMPORTS_BIN ?= $(shell which goimports || true)
GOTEST_FLAGS ?= -v --coverprofile main.coverprofile --covermode count --cover github.com/urfave/cli/v2/cmd/urfave-cli-genflags GOTEST_FLAGS ?= -v --coverprofile main.coverprofile --covermode count --cover github.com/urfave/cli/v2/cmd/urfave-cli-genflags
GOBUILD_FLAGS ?= -x GOBUILD_FLAGS ?= -x
export GOIMPORTS_BIN
.PHONY: all .PHONY: all
all: test build smoke-test all: test build smoke-test
@ -19,3 +22,7 @@ smoke-test: build
.PHONY: show-cover .PHONY: show-cover
show-cover: show-cover:
go tool cover -func main.coverprofile go tool cover -func main.coverprofile
.PHONY: run
run: build
./urfave-cli-genflags

View File

@ -75,16 +75,6 @@ func (f *{{.TypeName}}) TakesValue() bool {
return "{{.TypeName }}" != "BoolFlag" return "{{.TypeName }}" != "BoolFlag"
} }
{{if .GenerateDefaultText}}
// GetDefaultText returns the default text for this flag
func (f *{{.TypeName}}) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
{{end}}
{{end}}{{/* /if .GenerateFlagInterface */}} {{end}}{{/* /if .GenerateFlagInterface */}}
{{end}}{{/* /range .SortedFlagTypes */}} {{end}}{{/* /range .SortedFlagTypes */}}

View File

@ -12,13 +12,13 @@ func Test{{.TypeName}}_SatisfiesFlagInterface(t *testing.T) {
} }
func Test{{.TypeName}}_SatisfiesRequiredFlagInterface(t *testing.T) { func Test{{.TypeName}}_SatisfiesRequiredFlagInterface(t *testing.T) {
var f {{$.UrfaveCLITestNamespace}}Flag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{} var f {{$.UrfaveCLITestNamespace}}RequiredFlag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
_ = f.IsRequired() _ = f.IsRequired()
} }
func Test{{.TypeName}}_SatisfiesVisibleFlagInterface(t *testing.T) { func Test{{.TypeName}}_SatisfiesVisibleFlagInterface(t *testing.T) {
var f {{$.UrfaveCLITestNamespace}}Flag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{} var f {{$.UrfaveCLITestNamespace}}VisibleFlag = &{{$.UrfaveCLITestNamespace}}{{.TypeName}}{}
_ = f.IsVisible() _ = f.IsVisible()
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
_ "embed" _ "embed"
"fmt"
"log" "log"
"os" "os"
"os/exec" "os/exec"
@ -37,6 +38,9 @@ var (
func sh(ctx context.Context, exe string, args ...string) (string, error) { func sh(ctx context.Context, exe string, args ...string) (string, error) {
cmd := exec.CommandContext(ctx, exe, args...) cmd := exec.CommandContext(ctx, exe, args...)
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
fmt.Fprintf(os.Stderr, "# ---> %s\n", cmd)
outBytes, err := cmd.Output() outBytes, err := cmd.Output()
return string(outBytes), err return string(outBytes), err
} }
@ -89,10 +93,19 @@ func main() {
Aliases: []string{"N"}, Aliases: []string{"N"},
Value: "cli.", Value: "cli.",
}, },
&cli.PathFlag{
Name: "goimports",
EnvVars: []string{"GOIMPORTS_BIN"},
Value: filepath.Join(top, ".local/bin/goimports"),
},
}, },
Action: runGenFlags, Action: runGenFlags,
} }
if err := os.Chdir(top); err != nil {
log.Fatal(err)
}
if err := app.RunContext(ctx, os.Args); err != nil { if err := app.RunContext(ctx, os.Args); err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -163,11 +176,11 @@ func runGenFlags(cCtx *cli.Context) error {
return err return err
} }
if _, err := sh(cCtx.Context, "goimports", "-w", cCtx.Path("generated-output")); err != nil { if _, err := sh(cCtx.Context, cCtx.Path("goimports"), "-w", cCtx.Path("generated-output")); err != nil {
return err return err
} }
if _, err := sh(cCtx.Context, "goimports", "-w", cCtx.Path("generated-test-output")); err != nil { if _, err := sh(cCtx.Context, cCtx.Path("goimports"), "-w", cCtx.Path("generated-test-output")); err != nil {
return err return err
} }

View File

@ -295,6 +295,17 @@ func (c *Command) startApp(ctx *Context) error {
return app.RunAsSubcommand(ctx) return app.RunAsSubcommand(ctx)
} }
// VisibleCommands returns a slice of the Commands with Hidden=false
func (c *Command) VisibleCommands() []*Command {
var ret []*Command
for _, command := range c.Subcommands {
if !command.Hidden {
ret = append(ret, command)
}
}
return ret
}
// VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain // VisibleFlagCategories returns a slice containing all the visible flag categories with the flags they contain
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory { func (c *Command) VisibleFlagCategories() []VisibleFlagCategory {
if c.flagCategories == nil { if c.flagCategories == nil {

View File

@ -422,3 +422,30 @@ func TestCommand_CanAddVFlagOnCommands(t *testing.T) {
err := app.Run([]string{"foo", "bar"}) err := app.Run([]string{"foo", "bar"})
expect(t, err, nil) expect(t, err, nil)
} }
func TestCommand_VisibleSubcCommands(t *testing.T) {
subc1 := &Command{
Name: "subc1",
Usage: "subc1 command1",
}
subc3 := &Command{
Name: "subc3",
Usage: "subc3 command2",
}
c := &Command{
Name: "bar",
Usage: "this is for testing",
Subcommands: []*Command{
subc1,
{
Name: "subc2",
Usage: "subc2 command2",
Hidden: true,
},
subc3,
},
}
expect(t, c.VisibleCommands(), []*Command{subc1, subc3})
}

29
flag.go
View File

@ -135,6 +135,14 @@ type DocGenerationFlag interface {
GetEnvVars() []string GetEnvVars() []string
} }
// DocGenerationSliceFlag extends DocGenerationFlag for slice-based flags.
type DocGenerationSliceFlag interface {
DocGenerationFlag
// IsSliceFlag returns true for flags that can be given multiple times.
IsSliceFlag() bool
}
// Countable is an interface to enable detection of flag values which support // Countable is an interface to enable detection of flag values which support
// repetitive flags // repetitive flags
type Countable interface { type Countable interface {
@ -332,24 +340,13 @@ func stringifyFlag(f Flag) string {
usageWithDefault := strings.TrimSpace(usage + defaultValueString) usageWithDefault := strings.TrimSpace(usage + defaultValueString)
return withEnvHint(df.GetEnvVars(), pn := prefixedNames(df.Names(), placeholder)
fmt.Sprintf("%s\t%s", prefixedNames(df.Names(), placeholder), usageWithDefault)) sliceFlag, ok := f.(DocGenerationSliceFlag)
} if ok && sliceFlag.IsSliceFlag() {
pn = pn + " [ " + pn + " ]"
func stringifySliceFlag(usage string, names, defaultVals []string) string {
placeholder, usage := unquoteUsage(usage)
if placeholder == "" {
placeholder = defaultPlaceholder
} }
defaultVal := "" return withEnvHint(df.GetEnvVars(), fmt.Sprintf("%s\t%s", pn, usageWithDefault))
if len(defaultVals) > 0 {
defaultVal = fmt.Sprintf(formatDefault("%s"), strings.Join(defaultVals, ", "))
}
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
pn := prefixedNames(names, placeholder)
return fmt.Sprintf("%s [ %s ]\t%s", pn, pn, usageWithDefault)
} }
func hasFlag(flags []Flag, fl Flag) bool { func hasFlag(flags []Flag, fl Flag) bool {

View File

@ -12,6 +12,14 @@ func (f *DurationFlag) GetValue() string {
return f.Value.String() return f.Value.String()
} }
// GetDefaultText returns the default text for this flag
func (f *DurationFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *DurationFlag) Apply(set *flag.FlagSet) error { func (f *DurationFlag) Apply(set *flag.FlagSet) error {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {

View File

@ -12,6 +12,14 @@ func (f *Float64Flag) GetValue() string {
return fmt.Sprintf("%v", f.Value) return fmt.Sprintf("%v", f.Value)
} }
// GetDefaultText returns the default text for this flag
func (f *Float64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *Float64Flag) Apply(set *flag.FlagSet) error { func (f *Float64Flag) Apply(set *flag.FlagSet) error {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {

View File

@ -83,16 +83,32 @@ func (f *Float64Slice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *Float64SliceFlag) String() string { func (f *Float64SliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *Float64SliceFlag) GetValue() string { func (f *Float64SliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", i), "0"), "."))
}
} }
return "" return strings.Join(defaultVals, ", ")
}
// GetDefaultText returns the default text for this flag
func (f *Float64SliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IsSliceFlag implements DocGenerationSliceFlag.
func (f *Float64SliceFlag) IsSliceFlag() bool {
return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -141,18 +157,6 @@ func (f *Float64SliceFlag) Get(ctx *Context) []float64 {
return ctx.Float64Slice(f.Name) return ctx.Float64Slice(f.Name)
} }
func (f *Float64SliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strings.TrimRight(strings.TrimRight(fmt.Sprintf("%f", i), "0"), "."))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *Float64SliceFlag) RunAction(c *Context) error { func (f *Float64SliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -20,6 +20,14 @@ func (f *GenericFlag) GetValue() string {
return "" return ""
} }
// GetDefaultText returns the default text for this flag
func (f *GenericFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply takes the flagset and calls Set on the generic flag with the value // Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag // provided by the user for parsing by the flag
func (f *GenericFlag) Apply(set *flag.FlagSet) error { func (f *GenericFlag) Apply(set *flag.FlagSet) error {
@ -34,6 +42,10 @@ func (f *GenericFlag) Apply(set *flag.FlagSet) error {
} }
for _, name := range f.Names() { for _, name := range f.Names() {
if f.Destination != nil {
set.Var(f.Destination, name, f.Usage)
continue
}
set.Var(f.Value, name, f.Usage) set.Var(f.Value, name, f.Usage)
} }

View File

@ -12,6 +12,14 @@ func (f *IntFlag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// GetDefaultText returns the default text for this flag
func (f *IntFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *IntFlag) Apply(set *flag.FlagSet) error { func (f *IntFlag) Apply(set *flag.FlagSet) error {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {

View File

@ -12,6 +12,14 @@ func (f *Int64Flag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// GetDefaultText returns the default text for this flag
func (f *Int64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *Int64Flag) Apply(set *flag.FlagSet) error { func (f *Int64Flag) Apply(set *flag.FlagSet) error {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found { if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {

View File

@ -84,16 +84,32 @@ func (i *Int64Slice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *Int64SliceFlag) String() string { func (f *Int64SliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *Int64SliceFlag) GetValue() string { func (f *Int64SliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
}
} }
return "" return strings.Join(defaultVals, ", ")
}
// GetDefaultText returns the default text for this flag
func (f *Int64SliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IsSliceFlag implements DocGenerationSliceFlag.
func (f *Int64SliceFlag) IsSliceFlag() bool {
return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -140,17 +156,6 @@ func (f *Int64SliceFlag) Get(ctx *Context) []int64 {
return ctx.Int64Slice(f.Name) return ctx.Int64Slice(f.Name)
} }
func (f *Int64SliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatInt(i, 10))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *Int64SliceFlag) RunAction(c *Context) error { func (f *Int64SliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -95,16 +95,32 @@ func (i *IntSlice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *IntSliceFlag) String() string { func (f *IntSliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *IntSliceFlag) GetValue() string { func (f *IntSliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.Itoa(i))
}
} }
return "" return strings.Join(defaultVals, ", ")
}
// GetDefaultText returns the default text for this flag
func (f *IntSliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IsSliceFlag implements DocGenerationSliceFlag.
func (f *IntSliceFlag) IsSliceFlag() bool {
return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -151,17 +167,6 @@ func (f *IntSliceFlag) Get(ctx *Context) []int {
return ctx.IntSlice(f.Name) return ctx.IntSlice(f.Name)
} }
func (f *IntSliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.Itoa(i))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *IntSliceFlag) RunAction(c *Context) error { func (f *IntSliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -74,16 +74,34 @@ func (s *StringSlice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *StringSliceFlag) String() string { func (f *StringSliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *StringSliceFlag) GetValue() string { func (f *StringSliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, s := range f.Value.Value() {
if len(s) > 0 {
defaultVals = append(defaultVals, strconv.Quote(s))
}
}
} }
return "" return strings.Join(defaultVals, ", ")
}
// GetDefaultText returns the default text for this flag
func (f *StringSliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IsSliceFlag implements DocGenerationSliceFlag.
func (f *StringSliceFlag) IsSliceFlag() bool {
return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -130,19 +148,6 @@ func (f *StringSliceFlag) Get(ctx *Context) []string {
return ctx.StringSlice(f.Name) return ctx.StringSlice(f.Name)
} }
func (f *StringSliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, s := range f.Value.Value() {
if len(s) > 0 {
defaultVals = append(defaultVals, strconv.Quote(s))
}
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *StringSliceFlag) RunAction(c *Context) error { func (f *StringSliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -225,7 +225,7 @@ func TestFlagsFromEnv(t *testing.T) {
f, ok := test.flag.(DocGenerationFlag) f, ok := test.flag.(DocGenerationFlag)
if !ok { if !ok {
t.Errorf("flag %v needs to implement DocGenerationFlag to retrieve env vars", test.flag) t.Errorf("flag %[1]q (%[1]T) needs to implement DocGenerationFlag to retrieve env vars", test.flag)
} }
envVarSlice := f.GetEnvVars() envVarSlice := f.GetEnvVars()
_ = os.Setenv(envVarSlice[0], test.input) _ = os.Setenv(envVarSlice[0], test.input)
@ -307,12 +307,12 @@ func TestFlagStringifying(t *testing.T) {
{ {
name: "float64-slice-flag", name: "float64-slice-flag",
fl: &Float64SliceFlag{Name: "pizzas"}, fl: &Float64SliceFlag{Name: "pizzas"},
expected: "--pizzas value\t", expected: "--pizzas value [ --pizzas value ]\t",
}, },
{ {
name: "float64-slice-flag-with-default-text", name: "float64-slice-flag-with-default-text",
fl: &Float64SliceFlag{Name: "pepperonis", DefaultText: "shaved"}, fl: &Float64SliceFlag{Name: "pepperonis", DefaultText: "shaved"},
expected: "--pepperonis value\t(default: shaved)", expected: "--pepperonis value [ --pepperonis value ]\t(default: shaved)",
}, },
{ {
name: "generic-flag", name: "generic-flag",
@ -337,7 +337,7 @@ func TestFlagStringifying(t *testing.T) {
{ {
name: "int-slice-flag", name: "int-slice-flag",
fl: &IntSliceFlag{Name: "pencils"}, fl: &IntSliceFlag{Name: "pencils"},
expected: "--pencils value\t", expected: "--pencils value [ --pencils value ]\t",
}, },
{ {
name: "int-slice-flag-with-default-text", name: "int-slice-flag-with-default-text",
@ -347,7 +347,7 @@ func TestFlagStringifying(t *testing.T) {
{ {
name: "uint-slice-flag", name: "uint-slice-flag",
fl: &UintSliceFlag{Name: "pencils"}, fl: &UintSliceFlag{Name: "pencils"},
expected: "--pencils value\t", expected: "--pencils value [ --pencils value ]\t",
}, },
{ {
name: "uint-slice-flag-with-default-text", name: "uint-slice-flag-with-default-text",
@ -367,22 +367,22 @@ func TestFlagStringifying(t *testing.T) {
{ {
name: "int64-slice-flag", name: "int64-slice-flag",
fl: &Int64SliceFlag{Name: "drawers"}, fl: &Int64SliceFlag{Name: "drawers"},
expected: "--drawers value\t", expected: "--drawers value [ --drawers value ]\t",
}, },
{ {
name: "int64-slice-flag-with-default-text", name: "int64-slice-flag-with-default-text",
fl: &Int64SliceFlag{Name: "handles", DefaultText: "-2"}, fl: &Int64SliceFlag{Name: "handles", DefaultText: "-2"},
expected: "--handles value\t(default: -2)", expected: "--handles value [ --handles value ]\t(default: -2)",
}, },
{ {
name: "uint64-slice-flag", name: "uint64-slice-flag",
fl: &Uint64SliceFlag{Name: "drawers"}, fl: &Uint64SliceFlag{Name: "drawers"},
expected: "--drawers value\t", expected: "--drawers value [ --drawers value ]\t",
}, },
{ {
name: "uint64-slice-flag-with-default-text", name: "uint64-slice-flag-with-default-text",
fl: &Uint64SliceFlag{Name: "handles", DefaultText: "-2"}, fl: &Uint64SliceFlag{Name: "handles", DefaultText: "-2"},
expected: "--handles value\t(default: -2)", expected: "--handles value [ --handles value ]\t(default: -2)",
}, },
{ {
name: "path-flag", name: "path-flag",
@ -407,12 +407,12 @@ func TestFlagStringifying(t *testing.T) {
{ {
name: "string-slice-flag", name: "string-slice-flag",
fl: &StringSliceFlag{Name: "meow-sounds"}, fl: &StringSliceFlag{Name: "meow-sounds"},
expected: "--meow-sounds value\t", expected: "--meow-sounds value [ --meow-sounds value ]\t",
}, },
{ {
name: "string-slice-flag-with-default-text", name: "string-slice-flag-with-default-text",
fl: &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"}, fl: &StringSliceFlag{Name: "moo-sounds", DefaultText: "awoo"},
expected: "--moo-sounds value\t(default: awoo)", expected: "--moo-sounds value [ --moo-sounds value ]\t(default: awoo)",
}, },
{ {
name: "timestamp-flag", name: "timestamp-flag",
@ -2724,6 +2724,53 @@ func TestParseGeneric(t *testing.T) {
}).Run([]string{"run", "-s", "10,20"}) }).Run([]string{"run", "-s", "10,20"})
} }
type genericType struct {
s []string
}
func (g *genericType) Set(value string) error {
g.s = strings.Split(value, "-")
return nil
}
func (g *genericType) String() string {
return strings.Join(g.s, "-")
}
func TestParseDestinationGeneric(t *testing.T) {
expectedString := "abc1-123d"
expectedGeneric := &genericType{[]string{"abc1", "123d"}}
dest := &genericType{}
_ = (&App{
Flags: []Flag{
&GenericFlag{
Name: "dest",
Destination: dest,
},
},
Action: func(ctx *Context) error {
if !reflect.DeepEqual(dest, expectedGeneric) {
t.Errorf(
"expected destination generic: %+v, actual: %+v",
expectedGeneric,
dest,
)
}
if dest.String() != expectedString {
t.Errorf(
"expected destination string: %s, actual: %s",
expectedString,
dest.String(),
)
}
return nil
},
}).Run([]string{"run", "--dest", expectedString})
}
func TestParseGenericFromEnv(t *testing.T) { func TestParseGenericFromEnv(t *testing.T) {
defer resetEnv(os.Environ()) defer resetEnv(os.Environ())
os.Clearenv() os.Clearenv()

View File

@ -81,6 +81,14 @@ func (f *TimestampFlag) GetValue() string {
return "" return ""
} }
// GetDefaultText returns the default text for this flag
func (f *TimestampFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *TimestampFlag) Apply(set *flag.FlagSet) error { func (f *TimestampFlag) Apply(set *flag.FlagSet) error {
if f.Layout == "" { if f.Layout == "" {

View File

@ -37,6 +37,14 @@ func (f *UintFlag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// GetDefaultText returns the default text for this flag
func (f *UintFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Get returns the flags value in the given Context. // Get returns the flags value in the given Context.
func (f *UintFlag) Get(ctx *Context) uint { func (f *UintFlag) Get(ctx *Context) uint {
return ctx.Uint(f.Name) return ctx.Uint(f.Name)

View File

@ -37,6 +37,14 @@ func (f *Uint64Flag) GetValue() string {
return fmt.Sprintf("%d", f.Value) return fmt.Sprintf("%d", f.Value)
} }
// GetDefaultText returns the default text for this flag
func (f *Uint64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Get returns the flags value in the given Context. // Get returns the flags value in the given Context.
func (f *Uint64Flag) Get(ctx *Context) uint64 { func (f *Uint64Flag) Get(ctx *Context) uint64 {
return ctx.Uint64(f.Name) return ctx.Uint64(f.Name)

View File

@ -88,31 +88,19 @@ func (i *Uint64Slice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *Uint64SliceFlag) String() string { func (f *Uint64SliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *Uint64SliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *Uint64SliceFlag) GetUsage() string {
return f.Usage
}
// GetCategory returns the category for the flag
func (f *Uint64SliceFlag) GetCategory() string {
return f.Category
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *Uint64SliceFlag) GetValue() string { func (f *Uint64SliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatUint(i, 10))
}
} }
return "" return strings.Join(defaultVals, ", ")
} }
// GetDefaultText returns the default text for this flag // GetDefaultText returns the default text for this flag
@ -123,9 +111,9 @@ func (f *Uint64SliceFlag) GetDefaultText() string {
return f.GetValue() return f.GetValue()
} }
// GetEnvVars returns the env vars for this flag // IsSliceFlag implements DocGenerationSliceFlag.
func (f *Uint64SliceFlag) GetEnvVars() []string { func (f *Uint64SliceFlag) IsSliceFlag() bool {
return f.EnvVars return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -172,17 +160,6 @@ func (f *Uint64SliceFlag) Get(ctx *Context) []uint64 {
return ctx.Uint64Slice(f.Name) return ctx.Uint64Slice(f.Name)
} }
func (f *Uint64SliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatUint(i, 10))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *Uint64SliceFlag) RunAction(c *Context) error { func (f *Uint64SliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -99,31 +99,19 @@ func (i *UintSlice) Get() interface{} {
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (f *UintSliceFlag) String() string { func (f *UintSliceFlag) String() string {
return withEnvHint(f.GetEnvVars(), f.stringify()) return FlagStringer(f)
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *UintSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *UintSliceFlag) GetUsage() string {
return f.Usage
}
// GetCategory returns the category for the flag
func (f *UintSliceFlag) GetCategory() string {
return f.Category
} }
// GetValue returns the flags value as string representation and an empty // GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all. // string if the flag takes no value at all.
func (f *UintSliceFlag) GetValue() string { func (f *UintSliceFlag) GetValue() string {
if f.Value != nil { var defaultVals []string
return f.Value.String() if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatUint(uint64(i), 10))
}
} }
return "" return strings.Join(defaultVals, ", ")
} }
// GetDefaultText returns the default text for this flag // GetDefaultText returns the default text for this flag
@ -134,9 +122,9 @@ func (f *UintSliceFlag) GetDefaultText() string {
return f.GetValue() return f.GetValue()
} }
// GetEnvVars returns the env vars for this flag // IsSliceFlag implements DocGenerationSliceFlag.
func (f *UintSliceFlag) GetEnvVars() []string { func (f *UintSliceFlag) IsSliceFlag() bool {
return f.EnvVars return true
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
@ -183,17 +171,6 @@ func (f *UintSliceFlag) Get(ctx *Context) []uint {
return ctx.UintSlice(f.Name) return ctx.UintSlice(f.Name)
} }
func (f *UintSliceFlag) stringify() string {
var defaultVals []string
if f.Value != nil && len(f.Value.Value()) > 0 {
for _, i := range f.Value.Value() {
defaultVals = append(defaultVals, strconv.FormatUint(uint64(i), 10))
}
}
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set // RunAction executes flag action if set
func (f *UintSliceFlag) RunAction(c *Context) error { func (f *UintSliceFlag) RunAction(c *Context) error {
if f.Action != nil { if f.Action != nil {

View File

@ -32,7 +32,7 @@ var (
SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate SuggestDidYouMeanTemplate string = suggestDidYouMeanTemplate
) )
var AppHelpTemplate = `NAME: var AppHelpTemplate = `NAME:
{{$v := offset .Name 6}}{{wrap .Name 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{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}} {{if .UsageText}}{{wrap .UsageText 3}}{{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}}
@ -41,52 +41,39 @@ VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}} {{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if len .Authors}} {{template "descriptionTemplate" .}}{{end}}
{{- if len .Authors}}
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}}
{{range $index, $author := .Authors}}{{if $index}}
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
GLOBAL OPTIONS:{{range .VisibleFlagCategories}} GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
GLOBAL OPTIONS: GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{wrap $option.String 6}}{{end}}{{end}}{{end}}{{if .Copyright}}
COPYRIGHT: COPYRIGHT:
{{wrap .Copyright 3}}{{end}} {{template "copyrightTemplate" .}}{{end}}
` `
AppHelpTemplate is the text template for the Default help topic. cli.go 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 uses text/template to render templates. You can render custom help text by
setting this variable. setting this variable.
var CommandHelpTemplate = `NAME: var CommandHelpTemplate = `NAME:
{{$v := offset .HelpName 6}}{{wrap .HelpName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} {{template "usageTemplate" .}}{{if .Category}}
CATEGORY: CATEGORY:
{{.Category}}{{end}}{{if .Description}} {{.Category}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if .VisibleFlagCategories}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
OPTIONS:{{range .VisibleFlagCategories}} OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}{{end}}{{end}}{{else}}{{if .VisibleFlags}}
OPTIONS: OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
{{range .VisibleFlags}}{{.}}{{end}}{{end}}{{end}}
`
CommandHelpTemplate is the text template for the command help topic. cli.go 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 uses text/template to render templates. You can render custom help text by
setting this variable. setting this variable.
@ -145,22 +132,19 @@ var OsExiter = os.Exit
os.Exit. os.Exit.
var SubcommandHelpTemplate = `NAME: var SubcommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
OPTIONS: OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{range .VisibleFlags}}{{.}}{{end}}{{end}}
` OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
SubcommandHelpTemplate is the text template for the subcommand help topic. SubcommandHelpTemplate is the text template for the subcommand help topic.
cli.go uses text/template to render templates. You can render custom help cli.go uses text/template to render templates. You can render custom help
text by setting this variable. text by setting this variable.
@ -586,6 +570,9 @@ func (c *Command) Run(ctx *Context) (err error)
Run invokes the command given the context, parses ctx.Args() to generate Run invokes the command given the context, parses ctx.Args() to generate
command-specific flags command-specific flags
func (c *Command) VisibleCommands() []*Command
VisibleCommands returns a slice of the Commands with Hidden=false
func (c *Command) VisibleFlagCategories() []VisibleFlagCategory func (c *Command) VisibleFlagCategories() []VisibleFlagCategory
VisibleFlagCategories returns a slice containing all the visible flag VisibleFlagCategories returns a slice containing all the visible flag
categories with the flags they contain categories with the flags they contain
@ -754,6 +741,14 @@ type DocGenerationFlag interface {
DocGenerationFlag is an interface that allows documentation generation for DocGenerationFlag is an interface that allows documentation generation for
the flag the flag
type DocGenerationSliceFlag interface {
DocGenerationFlag
// IsSliceFlag returns true for flags that can be given multiple times.
IsSliceFlag() bool
}
DocGenerationSliceFlag extends DocGenerationFlag for slice-based flags.
type DurationFlag struct { type DurationFlag struct {
Name string Name string
@ -1077,6 +1072,9 @@ func (f *Float64SliceFlag) IsRequired() bool
func (f *Float64SliceFlag) IsSet() bool func (f *Float64SliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *Float64SliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *Float64SliceFlag) IsVisible() bool func (f *Float64SliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -1312,6 +1310,9 @@ func (f *Int64SliceFlag) IsRequired() bool
func (f *Int64SliceFlag) IsSet() bool func (f *Int64SliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *Int64SliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *Int64SliceFlag) IsVisible() bool func (f *Int64SliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -1477,6 +1478,9 @@ func (f *IntSliceFlag) IsRequired() bool
func (f *IntSliceFlag) IsSet() bool func (f *IntSliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *IntSliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *IntSliceFlag) IsVisible() bool func (f *IntSliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -1817,6 +1821,9 @@ func (f *StringSliceFlag) IsRequired() bool
func (f *StringSliceFlag) IsSet() bool func (f *StringSliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *StringSliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *StringSliceFlag) IsVisible() bool func (f *StringSliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -2057,7 +2064,7 @@ func (f *Uint64SliceFlag) Get(ctx *Context) []uint64
Get returns the flags value in the given Context. Get returns the flags value in the given Context.
func (f *Uint64SliceFlag) GetCategory() string func (f *Uint64SliceFlag) GetCategory() string
GetCategory returns the category for the flag GetCategory returns the category of the flag
func (f *Uint64SliceFlag) GetDefaultText() string func (f *Uint64SliceFlag) GetDefaultText() string
GetDefaultText returns the default text for this flag GetDefaultText returns the default text for this flag
@ -2078,6 +2085,9 @@ func (f *Uint64SliceFlag) IsRequired() bool
func (f *Uint64SliceFlag) IsSet() bool func (f *Uint64SliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *Uint64SliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *Uint64SliceFlag) IsVisible() bool func (f *Uint64SliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -2091,7 +2101,7 @@ func (f *Uint64SliceFlag) String() string
String returns a readable representation of this value (for usage defaults) String returns a readable representation of this value (for usage defaults)
func (f *Uint64SliceFlag) TakesValue() bool func (f *Uint64SliceFlag) TakesValue() bool
TakesValue returns true of the flag takes a value, otherwise false TakesValue returns true if the flag takes a value, otherwise false
type UintFlag struct { type UintFlag struct {
Name string Name string
@ -2216,7 +2226,7 @@ func (f *UintSliceFlag) Get(ctx *Context) []uint
Get returns the flags value in the given Context. Get returns the flags value in the given Context.
func (f *UintSliceFlag) GetCategory() string func (f *UintSliceFlag) GetCategory() string
GetCategory returns the category for the flag GetCategory returns the category of the flag
func (f *UintSliceFlag) GetDefaultText() string func (f *UintSliceFlag) GetDefaultText() string
GetDefaultText returns the default text for this flag GetDefaultText returns the default text for this flag
@ -2237,6 +2247,9 @@ func (f *UintSliceFlag) IsRequired() bool
func (f *UintSliceFlag) IsSet() bool func (f *UintSliceFlag) IsSet() bool
IsSet returns whether or not the flag has been set through env or file IsSet returns whether or not the flag has been set through env or file
func (f *UintSliceFlag) IsSliceFlag() bool
IsSliceFlag implements DocGenerationSliceFlag.
func (f *UintSliceFlag) IsVisible() bool func (f *UintSliceFlag) IsVisible() bool
IsVisible returns true if the flag is not hidden, otherwise false IsVisible returns true if the flag is not hidden, otherwise false
@ -2250,7 +2263,7 @@ func (f *UintSliceFlag) String() string
String returns a readable representation of this value (for usage defaults) String returns a readable representation of this value (for usage defaults)
func (f *UintSliceFlag) TakesValue() bool func (f *UintSliceFlag) TakesValue() bool
TakesValue returns true of the flag takes a value, otherwise false TakesValue returns true if the flag takes a value, otherwise false
type VisibleFlag interface { type VisibleFlag interface {
Flag Flag

36
help.go
View File

@ -242,7 +242,11 @@ func ShowCommandHelp(ctx *Context, command string) error {
c.Subcommands = append(c.Subcommands, helpCommandDontUse) c.Subcommands = append(c.Subcommands, helpCommandDontUse)
} }
if !ctx.App.HideHelp && HelpFlag != nil { if !ctx.App.HideHelp && HelpFlag != nil {
c.appendFlag(HelpFlag) if c.flagCategories == nil {
c.flagCategories = newFlagCategoriesFromFlags([]Flag{HelpFlag})
} else {
c.flagCategories.AddFlag("", HelpFlag)
}
} }
templ := c.CustomHelpTemplate templ := c.CustomHelpTemplate
if templ == "" { if templ == "" {
@ -358,6 +362,17 @@ func printHelpCustom(out io.Writer, templ string, data interface{}, customFuncs
w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
t.New("helpNameTemplate").Parse(helpNameTemplate)
t.New("usageTemplate").Parse(usageTemplate)
t.New("descriptionTemplate").Parse(descriptionTemplate)
t.New("visibleCommandTemplate").Parse(visibleCommandTemplate)
t.New("copyrightTemplate").Parse(copyrightTemplate)
t.New("versionTemplate").Parse(versionTemplate)
t.New("visibleFlagCategoryTemplate").Parse(visibleFlagCategoryTemplate)
t.New("visibleFlagTemplate").Parse(visibleFlagTemplate)
t.New("visibleGlobalFlagCategoryTemplate").Parse(strings.Replace(visibleFlagCategoryTemplate, "OPTIONS", "GLOBAL OPTIONS", -1))
t.New("authorsTemplate").Parse(authorsTemplate)
t.New("visibleCommandCategoryTemplate").Parse(visibleCommandCategoryTemplate)
err := t.Execute(w, data) err := t.Execute(w, data)
if err != nil { if err != nil {
@ -468,25 +483,28 @@ func nindent(spaces int, v string) string {
} }
func wrap(input string, offset int, wrapAt int) string { func wrap(input string, offset int, wrapAt int) string {
var sb strings.Builder var ss []string
lines := strings.Split(input, "\n") lines := strings.Split(input, "\n")
padding := strings.Repeat(" ", offset) padding := strings.Repeat(" ", offset)
for i, line := range lines { for i, line := range lines {
if i != 0 { if line == "" {
sb.WriteString(padding) ss = append(ss, line)
} } else {
wrapped := wrapLine(line, offset, wrapAt, padding)
if i == 0 {
ss = append(ss, wrapped)
} else {
ss = append(ss, padding+wrapped)
sb.WriteString(wrapLine(line, offset, wrapAt, padding)) }
if i != len(lines)-1 {
sb.WriteString("\n")
} }
} }
return sb.String() return strings.Join(ss, "\n")
} }
func wrapLine(input string, offset int, wrapAt int, padding string) string { func wrapLine(input string, offset int, wrapAt int, padding string) string {

View File

@ -1213,6 +1213,13 @@ func TestDefaultCompleteWithFlags(t *testing.T) {
} }
} }
func TestWrap(t *testing.T) {
emptywrap := wrap("", 4, 16)
if emptywrap != "" {
t.Errorf("Wrapping empty line should return empty line. Got '%s'.", emptywrap)
}
}
func TestWrappedHelp(t *testing.T) { func TestWrappedHelp(t *testing.T) {
// Reset HelpPrinter after this test. // Reset HelpPrinter after this test.
@ -1276,7 +1283,7 @@ DESCRIPTION:
App.Description string long App.Description string long
enough that it should be enough that it should be
wrapped in this test wrapped in this test
with a newline with a newline
and an indented line and an indented line
@ -1294,8 +1301,8 @@ COPYRIGHT:
that it should be wrapped. that it should be wrapped.
Including newlines. Including newlines.
And also indented lines. And also indented lines.
And then another long line. And then another long line.
Blah blah blah does anybody Blah blah blah does anybody
ever read these things? ever read these things?
@ -1436,3 +1443,79 @@ OPTIONS:
output.String(), expected) output.String(), expected)
} }
} }
func TestWrappedHelpSubcommand(t *testing.T) {
// Reset HelpPrinter after this test.
defer func(old helpPrinter) {
HelpPrinter = old
}(HelpPrinter)
output := new(bytes.Buffer)
app := &App{
Name: "cli.test",
Writer: output,
Commands: []*Command{
{
Name: "bar",
Aliases: []string{"a"},
Usage: "add a task to the list",
UsageText: "this is an even longer way of describing adding a task to the list",
Description: "and a description long enough to wrap in this test case",
Action: func(c *Context) error {
return nil
},
Subcommands: []*Command{
{
Name: "grok",
Usage: "remove an existing template",
UsageText: "longer usage text goes here, la la la, hopefully this is long enough to wrap even more",
Action: func(c *Context) error {
return nil
},
Flags: []Flag{
&StringFlag{
Name: "test-f",
Usage: "my test usage",
},
},
},
},
},
},
}
HelpPrinter = func(w io.Writer, templ string, data interface{}) {
funcMap := map[string]interface{}{
"wrapAt": func() int {
return 30
},
}
HelpPrinterCustom(w, templ, data, funcMap)
}
_ = app.Run([]string{"foo", "bar", "help", "grok"})
expected := `NAME:
cli.test bar grok - remove
an
existing
template
USAGE:
longer usage text goes
here, la la la, hopefully
this is long enough to wrap
even more
OPTIONS:
--help, -h show help (default: false)
--test-f value my test usage
`
if output.String() != expected {
t.Errorf("Unexpected wrapping, got:\n%s\nexpected: %s",
output.String(), expected)
}
}

View File

@ -46,7 +46,10 @@ func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComple
} }
// swap current argument with the split version // swap current argument with the split version
args = append(args[:i], append(shortOpts, args[i+1:]...)...) // do not include args that parsed correctly so far as it would
// trigger Value.Set() on those args and would result in
// duplicates for slice type flags
args = append(shortOpts, args[i+1:]...)
argsWereSplit = true argsWereSplit = true
break break
} }
@ -56,13 +59,6 @@ func parseIter(set *flag.FlagSet, ip iterativeParser, args []string, shellComple
if !argsWereSplit { if !argsWereSplit {
return err return err
} }
// Since custom parsing failed, replace the flag set before retrying
newSet, err := ip.newFlagSet()
if err != nil {
return err
}
*set = *newSet
} }
} }

View File

@ -1,10 +1,38 @@
package cli package cli
var helpNameTemplate = `{{$v := offset .HelpName 6}}{{wrap .HelpName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}}`
var usageTemplate = `{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}`
var descriptionTemplate = `{{wrap .Description 3}}`
var authorsTemplate = `{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
{{range $index, $author := .Authors}}{{if $index}}
{{end}}{{$author}}{{end}}`
var visibleCommandTemplate = `{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}`
var visibleCommandCategoryTemplate = `{{range .VisibleCategories}}{{if .Name}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{template "visibleCommandTemplate" .}}{{end}}{{end}}`
var visibleFlagCategoryTemplate = `{{range .VisibleFlagCategories}}
{{if .Name}}{{.Name}}
{{end}}{{$flglen := len .Flags}}{{range $i, $e := .Flags}}{{if eq (subtract $flglen $i) 1}}{{$e}}
{{else}}{{$e}}
{{end}}{{end}}{{end}}`
var visibleFlagTemplate = `{{range $index, $option := .VisibleFlags}}{{if $index}}{{end}}
{{wrap $option.String 6}}{{end}}`
var versionTemplate = `{{if .Version}}{{if not .HideVersion}}
VERSION:
{{.Version}}{{end}}{{end}}`
var copyrightTemplate = `{{wrap .Copyright 3}}`
// AppHelpTemplate is the text template for the Default help topic. // AppHelpTemplate is the text template for the Default help topic.
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
var AppHelpTemplate = `NAME: var AppHelpTemplate = `NAME:
{{$v := offset .Name 6}}{{wrap .Name 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{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}} {{if .UsageText}}{{wrap .UsageText 3}}{{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}}
@ -13,73 +41,57 @@ VERSION:
{{.Version}}{{end}}{{end}}{{if .Description}} {{.Version}}{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if len .Authors}} {{template "descriptionTemplate" .}}{{end}}
{{- if len .Authors}}
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: AUTHOR{{template "authorsTemplate" .}}{{end}}{{if .VisibleCommands}}
{{range $index, $author := .Authors}}{{if $index}}
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{template "visibleCommandCategoryTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{end}}{{if .VisibleFlagCategories}}
GLOBAL OPTIONS:{{range .VisibleFlagCategories}} GLOBAL OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}
{{end}}{{end}}{{else}}{{if .VisibleFlags}}
GLOBAL OPTIONS: GLOBAL OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}{{if .Copyright}}
{{range $index, $option := .VisibleFlags}}{{if $index}}
{{end}}{{wrap $option.String 6}}{{end}}{{end}}{{end}}{{if .Copyright}}
COPYRIGHT: COPYRIGHT:
{{wrap .Copyright 3}}{{end}} {{template "copyrightTemplate" .}}{{end}}
` `
// CommandHelpTemplate is the text template for the command help topic. // CommandHelpTemplate is the text template for the command help topic.
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
var CommandHelpTemplate = `NAME: var CommandHelpTemplate = `NAME:
{{$v := offset .HelpName 6}}{{wrap .HelpName 3}}{{if .Usage}} - {{wrap .Usage $v}}{{end}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} {{template "usageTemplate" .}}{{if .Category}}
CATEGORY: CATEGORY:
{{.Category}}{{end}}{{if .Description}} {{.Category}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}}{{if .VisibleFlagCategories}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
OPTIONS:{{range .VisibleFlagCategories}} OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{if .Name}}{{.Name}}
{{end}}{{range .Flags}}{{.}}{{end}}{{end}}{{else}}{{if .VisibleFlags}}
OPTIONS: OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
{{range .VisibleFlags}}{{.}}{{end}}{{end}}{{end}}
`
// SubcommandHelpTemplate is the text template for the subcommand help topic. // SubcommandHelpTemplate is the text template for the subcommand help topic.
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME: var SubcommandHelpTemplate = `NAME:
{{.HelpName}} - {{.Usage}} {{template "helpNameTemplate" .}}
USAGE: USAGE:
{{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}} {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{wrap .Description 3}}{{end}} {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
COMMANDS:{{range .VisibleCategories}}{{if .Name}} COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
{{.Name}}:{{range .VisibleCommands}}
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{else}}{{ $cv := offsetCommands .VisibleCommands 5}}{{range .VisibleCommands}}
{{$s := join .Names ", "}}{{$s}}{{ $sp := subtract $cv (offset $s 3) }}{{ indent $sp ""}}{{wrap .Usage $cv}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
OPTIONS: OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
{{range .VisibleFlags}}{{.}}{{end}}{{end}}
` OPTIONS:{{template "visibleFlagTemplate" .}}{{end}}`
var MarkdownDocTemplate = `{{if gt .SectionNum 0}}% {{ .App.Name }} {{ .SectionNum }} var MarkdownDocTemplate = `{{if gt .SectionNum 0}}% {{ .App.Name }} {{ .SectionNum }}

View File

@ -66,14 +66,6 @@ func (f *Float64SliceFlag) TakesValue() bool {
return "Float64SliceFlag" != "BoolFlag" return "Float64SliceFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *Float64SliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// GenericFlag is a flag with type Generic // GenericFlag is a flag with type Generic
type GenericFlag struct { type GenericFlag struct {
Name string Name string
@ -143,14 +135,6 @@ func (f *GenericFlag) TakesValue() bool {
return "GenericFlag" != "BoolFlag" return "GenericFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *GenericFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Int64SliceFlag is a flag with type *Int64Slice // Int64SliceFlag is a flag with type *Int64Slice
type Int64SliceFlag struct { type Int64SliceFlag struct {
Name string Name string
@ -213,14 +197,6 @@ func (f *Int64SliceFlag) TakesValue() bool {
return "Int64SliceFlag" != "BoolFlag" return "Int64SliceFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *Int64SliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IntSliceFlag is a flag with type *IntSlice // IntSliceFlag is a flag with type *IntSlice
type IntSliceFlag struct { type IntSliceFlag struct {
Name string Name string
@ -283,14 +259,6 @@ func (f *IntSliceFlag) TakesValue() bool {
return "IntSliceFlag" != "BoolFlag" return "IntSliceFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *IntSliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// PathFlag is a flag with type Path // PathFlag is a flag with type Path
type PathFlag struct { type PathFlag struct {
Name string Name string
@ -424,14 +392,6 @@ func (f *StringSliceFlag) TakesValue() bool {
return "StringSliceFlag" != "BoolFlag" return "StringSliceFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *StringSliceFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// TimestampFlag is a flag with type *Timestamp // TimestampFlag is a flag with type *Timestamp
type TimestampFlag struct { type TimestampFlag struct {
Name string Name string
@ -503,14 +463,6 @@ func (f *TimestampFlag) TakesValue() bool {
return "TimestampFlag" != "BoolFlag" return "TimestampFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *TimestampFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Uint64SliceFlag is a flag with type *Uint64Slice // Uint64SliceFlag is a flag with type *Uint64Slice
type Uint64SliceFlag struct { type Uint64SliceFlag struct {
Name string Name string
@ -553,6 +505,26 @@ func (f *Uint64SliceFlag) IsVisible() bool {
return !f.Hidden return !f.Hidden
} }
// GetCategory returns the category of the flag
func (f *Uint64SliceFlag) GetCategory() string {
return f.Category
}
// GetUsage returns the usage string for the flag
func (f *Uint64SliceFlag) GetUsage() string {
return f.Usage
}
// GetEnvVars returns the env vars for this flag
func (f *Uint64SliceFlag) GetEnvVars() []string {
return f.EnvVars
}
// TakesValue returns true if the flag takes a value, otherwise false
func (f *Uint64SliceFlag) TakesValue() bool {
return "Uint64SliceFlag" != "BoolFlag"
}
// UintSliceFlag is a flag with type *UintSlice // UintSliceFlag is a flag with type *UintSlice
type UintSliceFlag struct { type UintSliceFlag struct {
Name string Name string
@ -595,6 +567,26 @@ func (f *UintSliceFlag) IsVisible() bool {
return !f.Hidden return !f.Hidden
} }
// GetCategory returns the category of the flag
func (f *UintSliceFlag) GetCategory() string {
return f.Category
}
// GetUsage returns the usage string for the flag
func (f *UintSliceFlag) GetUsage() string {
return f.Usage
}
// GetEnvVars returns the env vars for this flag
func (f *UintSliceFlag) GetEnvVars() []string {
return f.EnvVars
}
// TakesValue returns true if the flag takes a value, otherwise false
func (f *UintSliceFlag) TakesValue() bool {
return "UintSliceFlag" != "BoolFlag"
}
// BoolFlag is a flag with type bool // BoolFlag is a flag with type bool
type BoolFlag struct { type BoolFlag struct {
Name string Name string
@ -731,14 +723,6 @@ func (f *Float64Flag) TakesValue() bool {
return "Float64Flag" != "BoolFlag" return "Float64Flag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *Float64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// IntFlag is a flag with type int // IntFlag is a flag with type int
type IntFlag struct { type IntFlag struct {
Name string Name string
@ -808,14 +792,6 @@ func (f *IntFlag) TakesValue() bool {
return "IntFlag" != "BoolFlag" return "IntFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *IntFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Int64Flag is a flag with type int64 // Int64Flag is a flag with type int64
type Int64Flag struct { type Int64Flag struct {
Name string Name string
@ -885,14 +861,6 @@ func (f *Int64Flag) TakesValue() bool {
return "Int64Flag" != "BoolFlag" return "Int64Flag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *Int64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// StringFlag is a flag with type string // StringFlag is a flag with type string
type StringFlag struct { type StringFlag struct {
Name string Name string
@ -1029,14 +997,6 @@ func (f *DurationFlag) TakesValue() bool {
return "DurationFlag" != "BoolFlag" return "DurationFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *DurationFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// UintFlag is a flag with type uint // UintFlag is a flag with type uint
type UintFlag struct { type UintFlag struct {
Name string Name string
@ -1106,14 +1066,6 @@ func (f *UintFlag) TakesValue() bool {
return "UintFlag" != "BoolFlag" return "UintFlag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *UintFlag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// Uint64Flag is a flag with type uint64 // Uint64Flag is a flag with type uint64
type Uint64Flag struct { type Uint64Flag struct {
Name string Name string
@ -1183,12 +1135,4 @@ func (f *Uint64Flag) TakesValue() bool {
return "Uint64Flag" != "BoolFlag" return "Uint64Flag" != "BoolFlag"
} }
// GetDefaultText returns the default text for this flag
func (f *Uint64Flag) GetDefaultText() string {
if f.DefaultText != "" {
return f.DefaultText
}
return f.GetValue()
}
// vim:ro // vim:ro

View File

@ -167,6 +167,18 @@ func TestUint64SliceFlag_SatisfiesFlagInterface(t *testing.T) {
_ = f.Names() _ = f.Names()
} }
func TestUint64SliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
var f cli.RequiredFlag = &cli.Uint64SliceFlag{}
_ = f.IsRequired()
}
func TestUint64SliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
var f cli.VisibleFlag = &cli.Uint64SliceFlag{}
_ = f.IsVisible()
}
func TestUintSliceFlag_SatisfiesFlagInterface(t *testing.T) { func TestUintSliceFlag_SatisfiesFlagInterface(t *testing.T) {
var f cli.Flag = &cli.UintSliceFlag{} var f cli.Flag = &cli.UintSliceFlag{}
@ -174,6 +186,18 @@ func TestUintSliceFlag_SatisfiesFlagInterface(t *testing.T) {
_ = f.Names() _ = f.Names()
} }
func TestUintSliceFlag_SatisfiesRequiredFlagInterface(t *testing.T) {
var f cli.RequiredFlag = &cli.UintSliceFlag{}
_ = f.IsRequired()
}
func TestUintSliceFlag_SatisfiesVisibleFlagInterface(t *testing.T) {
var f cli.VisibleFlag = &cli.UintSliceFlag{}
_ = f.IsVisible()
}
func TestBoolFlag_SatisfiesFlagInterface(t *testing.T) { func TestBoolFlag_SatisfiesFlagInterface(t *testing.T) {
var f cli.Flag = &cli.BoolFlag{} var f cli.Flag = &cli.BoolFlag{}