Merge branch 'v2' into v2-completion

This commit is contained in:
lewo 2016-09-01 09:35:02 +02:00 committed by GitHub
commit 6aa0ab6903
23 changed files with 671 additions and 73 deletions

View File

@ -7,11 +7,11 @@ cache:
- node_modules
go:
- 1.2.2
- 1.3.3
- 1.4
- 1.5.4
- 1.6.2
- 1.2.x
- 1.3.x
- 1.4.2
- 1.5.x
- 1.6.x
- master
env: pip_install="pip install --user"
@ -20,17 +20,12 @@ matrix:
allow_failures:
- go: master
include:
- go: 1.6.2
- go: 1.6.x
os: osx
env: pip_install="sudo pip install"
before_script:
- $pip_install flake8
- go get github.com/urfave/gfmrun/...
- go get golang.org/x/tools/cmd/goimports || true
- if [ ! -f node_modules/.bin/markdown-toc ] ; then
npm install markdown-toc ;
fi
- mkdir -p ${GOPATH%%:*}/src/gopkg.in/urfave
- rm -rvf ${GOPATH%%:*}/src/gopkg.in/urfave/cli.v2
- rm -rvf ${GOPATH%%:*}/pkg/*/gopkg.in/urfave/cli.v2.a
@ -38,10 +33,4 @@ before_script:
script:
- flake8 runtests cli-v1-to-v2 generate-flag-types
- ./runtests gen
- ./runtests vet
- ./runtests test
- ./runtests gfmrun
- ./cli-v1-to-v2 --selftest
- ./runtests migrations
- ./runtests toc
- make all

View File

@ -35,6 +35,8 @@
## [Unreleased] - (1.x series)
### Added
- Flag type code generation via `go generate`
- Write to stderr and exit 1 if action returns non-nil error
- Added support for TOML to the `altsrc` loader
### Changed
- Raise minimum tested/supported Go version to 1.2+

37
GNUmakefile Normal file
View File

@ -0,0 +1,37 @@
default: test
deps:
go get golang.org/x/tools/cmd/goimports || true
go get github.com/urfave/gfmrun/... || true
go list ./... \
| xargs go list -f '{{ join .Deps "\n" }}{{ printf "\n" }}{{ join .TestImports "\n" }}' \
| grep -v github.com/urfave/cli \
| xargs go get
@if [ ! -f node_modules/.bin/markdown-toc ]; then \
npm install markdown-toc ; \
fi
gen: deps
./runtests gen
vet:
./runtests vet
gfmrun:
./runtests gfmrun
v1-to-v2:
./cli-v1-to-v2 --selftest
migrations:
./runtests migrations
toc:
./runtests toc
test: deps
./runtests test
all: gen vet test gfmrun v1-to-v2 migrations toc
.PHONY: default gen vet test gfmrun migrations toc v1-to-v2 deps all

View File

@ -31,7 +31,8 @@ applications in an expressive way.
+ [Placeholder Values](#placeholder-values)
+ [Alternate Names](#alternate-names)
+ [Values from the Environment](#values-from-the-environment)
+ [Values from alternate input sources (YAML and others)](#values-from-alternate-input-sources-yaml-and-others)
+ [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
+ [Default Values for help output](#default-values-for-help-output)
* [Subcommands](#subcommands)
* [Subcommands categories](#subcommands-categories)
* [Exit code](#exit-code)
@ -520,10 +521,14 @@ func main() {
}
```
#### Values from alternate input sources (YAML and others)
#### Values from alternate input sources (YAML, TOML, and others)
There is a separate package altsrc that adds support for getting flag values
from other input sources like YAML.
from other file input sources.
Currently supported input source formats:
* YAML
* TOML
In order to get values for a flag from an alternate input source the following
code would be added to wrap an existing cli.Flag like below:
@ -545,9 +550,9 @@ the yaml input source for any flags that are defined on that command. As a note
the "load" flag used would also have to be defined on the command flags in order
for this code snipped to work.
Currently only YAML and JSON files are supported but developers can add support
for other input sources by implementing the altsrc.InputSourceContext for their
given sources.
Currently only the aboved specified formats are supported but developers can
add support for other input sources by implementing the
altsrc.InputSourceContext for their given sources.
Here is a more complete sample of a command using YAML support:
@ -585,6 +590,48 @@ func main() {
}
```
#### Default Values for help output
Sometimes it's useful to specify a flag's default help-text value within the flag declaration. This can be useful if the default value for a flag is a computed value. The default value can be set via the `DefaultText` struct field.
For example this:
<!-- {
"args": ["&#45;&#45;help"],
"output": "&#45;&#45;port value"
} -->
```go
package main
import (
"os"
"gopkg.in/urfave/cli.v2"
)
func main() {
app := &cli.App{
Flags: []cli.Flag{
&cli.IntFlag{
Name: "port",
Usage: "Use a randomized port",
Value: 0,
DefaultText: "random",
},
},
}
app.Run(os.Args)
}
```
Will result in help output like:
```
--port value Use a randomized port (default: random)
```
### Subcommands
Subcommands can be defined for a more git-like command line app.

View File

@ -5,7 +5,7 @@ import (
"os"
"strconv"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
// FlagInputSourceExtension is an extension interface of cli.Flag that

View File

@ -3,7 +3,7 @@ package altsrc
import (
"flag"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
// WARNING: This file is generated!

View File

@ -8,7 +8,7 @@ import (
"testing"
"time"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
type testApplyInputSource struct {

View File

@ -3,7 +3,7 @@ package altsrc
import (
"time"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
// InputSourceContext is an interface used to allow

View File

@ -6,7 +6,7 @@ import (
"os"
"testing"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
const (

View File

@ -8,7 +8,7 @@ import (
"strings"
"time"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
// NewJSONSourceFromFlagFunc returns a func that takes a cli.Context

View File

@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
// MapInputSource implements InputSourceContext to return

310
altsrc/toml_command_test.go Normal file
View File

@ -0,0 +1,310 @@
// Disabling building of toml support in cases where golang is 1.0 or 1.1
// as the encoding library is not implemented or supported.
// +build go1.2
package altsrc
import (
"flag"
"io/ioutil"
"os"
"testing"
"gopkg.in/urfave/cli.v2"
)
func TestCommandTomFileTest(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
defer os.Remove("current.toml")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestGlobalEnvVarWins(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
defer os.Remove("current.toml")
os.Setenv("THE_TEST", "10")
defer os.Setenv("THE_TEST", "")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 10)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestGlobalEnvVarWinsNested(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
defer os.Remove("current.toml")
os.Setenv("THE_TEST", "10")
defer os.Setenv("THE_TEST", "")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 10)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestSpecifiedFlagWins(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
defer os.Remove("current.toml")
test := []string{"test-cmd", "--load", "current.toml", "--test", "7"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 7)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestSpecifiedFlagWinsNested(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte(`[top]
test = 15`), 0666)
defer os.Remove("current.toml")
test := []string{"test-cmd", "--load", "current.toml", "--top.test", "7"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 7)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestDefaultValueFileWins(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
defer os.Remove("current.toml")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileTestDefaultValueFileWinsNested(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
defer os.Remove("current.toml")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWins(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("test = 15"), 0666)
defer os.Remove("current.toml")
os.Setenv("THE_TEST", "11")
defer os.Setenv("THE_TEST", "")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 11)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}
func TestCommandTomlFileFlagHasDefaultGlobalEnvTomlSetGlobalEnvWinsNested(t *testing.T) {
app := (&cli.App{})
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.toml", []byte("[top]\ntest = 15"), 0666)
defer os.Remove("current.toml")
os.Setenv("THE_TEST", "11")
defer os.Setenv("THE_TEST", "")
test := []string{"test-cmd", "--load", "current.toml"}
set.Parse(test)
c := cli.NewContext(app, set, nil)
command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 11)
return nil
},
Flags: []cli.Flag{
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewTomlSourceFromFlagFunc("load"))
err := command.Run(c)
expect(t, err, nil)
}

113
altsrc/toml_file_loader.go Normal file
View File

@ -0,0 +1,113 @@
// Disabling building of toml support in cases where golang is 1.0 or 1.1
// as the encoding library is not implemented or supported.
// +build go1.2
package altsrc
import (
"fmt"
"reflect"
"github.com/BurntSushi/toml"
"gopkg.in/urfave/cli.v2"
)
type tomlMap struct {
Map map[interface{}]interface{}
}
func unmarshalMap(i interface{}) (ret map[interface{}]interface{}, err error) {
ret = make(map[interface{}]interface{})
m := i.(map[string]interface{})
for key, val := range m {
v := reflect.ValueOf(val)
switch v.Kind() {
case reflect.Bool:
ret[key] = val.(bool)
case reflect.String:
ret[key] = val.(string)
case reflect.Int:
ret[key] = int(val.(int))
case reflect.Int8:
ret[key] = int(val.(int8))
case reflect.Int16:
ret[key] = int(val.(int16))
case reflect.Int32:
ret[key] = int(val.(int32))
case reflect.Int64:
ret[key] = int(val.(int64))
case reflect.Uint:
ret[key] = int(val.(uint))
case reflect.Uint8:
ret[key] = int(val.(uint8))
case reflect.Uint16:
ret[key] = int(val.(uint16))
case reflect.Uint32:
ret[key] = int(val.(uint32))
case reflect.Uint64:
ret[key] = int(val.(uint64))
case reflect.Float32:
ret[key] = float64(val.(float32))
case reflect.Float64:
ret[key] = float64(val.(float64))
case reflect.Map:
if tmp, err := unmarshalMap(val); err == nil {
ret[key] = tmp
} else {
return nil, err
}
case reflect.Array:
fallthrough // [todo] - Support array type
default:
return nil, fmt.Errorf("Unsupported: type = %#v", v.Kind())
}
}
return ret, nil
}
func (self *tomlMap) UnmarshalTOML(i interface{}) error {
if tmp, err := unmarshalMap(i); err == nil {
self.Map = tmp
} else {
return err
}
return nil
}
type tomlSourceContext struct {
FilePath string
}
// NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath.
func NewTomlSourceFromFile(file string) (InputSourceContext, error) {
tsc := &tomlSourceContext{FilePath: file}
var results tomlMap = tomlMap{}
if err := readCommandToml(tsc.FilePath, &results); err != nil {
return nil, fmt.Errorf("Unable to load TOML file '%s': inner error: \n'%v'", tsc.FilePath, err.Error())
}
return &MapInputSource{valueMap: results.Map}, nil
}
// NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a provided flag name and source context.
func NewTomlSourceFromFlagFunc(flagFileName string) func(context *cli.Context) (InputSourceContext, error) {
return func(context *cli.Context) (InputSourceContext, error) {
filePath := context.String(flagFileName)
return NewTomlSourceFromFile(filePath)
}
}
func readCommandToml(filePath string, container interface{}) (err error) {
b, err := loadDataFrom(filePath)
if err != nil {
return err
}
err = toml.Unmarshal(b, container)
if err != nil {
return err
}
err = nil
return
}

View File

@ -11,7 +11,7 @@ import (
"os"
"testing"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
)
func TestCommandYamlFileTest(t *testing.T) {

View File

@ -12,7 +12,7 @@ import (
"net/url"
"os"
"github.com/urfave/cli"
"gopkg.in/urfave/cli.v2"
"gopkg.in/yaml.v2"
)

View File

@ -13,6 +13,19 @@ import (
"testing"
)
var (
lastExitCode = 0
fakeOsExiter = func(rc int) {
lastExitCode = rc
}
fakeErrWriter = &bytes.Buffer{}
)
func init() {
OsExiter = fakeOsExiter
ErrWriter = fakeErrWriter
}
type opCounts struct {
Total, ShellComplete, OnUsageError, Before, CommandNotFound, Action, After, SubCommand int
}

View File

@ -98,5 +98,11 @@ func HandleExitCoder(err error) {
for _, merr := range multiErr.Errors() {
HandleExitCoder(merr)
}
return
}
if err.Error() != "" {
fmt.Fprintln(ErrWriter, err)
}
OsExiter(1)
}

View File

@ -1,8 +1,8 @@
package cli
import (
"bytes"
"errors"
"os"
"testing"
)
@ -15,7 +15,7 @@ func TestHandleExitCoder_nil(t *testing.T) {
called = true
}
defer func() { OsExiter = os.Exit }()
defer func() { OsExiter = fakeOsExiter }()
HandleExitCoder(nil)
@ -32,7 +32,7 @@ func TestHandleExitCoder_ExitCoder(t *testing.T) {
called = true
}
defer func() { OsExiter = os.Exit }()
defer func() { OsExiter = fakeOsExiter }()
HandleExitCoder(Exit("galactic perimeter breach", 9))
@ -49,7 +49,7 @@ func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
called = true
}
defer func() { OsExiter = os.Exit }()
defer func() { OsExiter = fakeOsExiter }()
exitErr := Exit("galactic perimeter breach", 9)
err := newMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
@ -58,3 +58,49 @@ func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
expect(t, exitCode, 9)
expect(t, called, true)
}
func TestHandleExitCoder_ErrorWithMessage(t *testing.T) {
exitCode := 0
called := false
OsExiter = func(rc int) {
exitCode = rc
called = true
}
ErrWriter = &bytes.Buffer{}
defer func() {
OsExiter = fakeOsExiter
ErrWriter = fakeErrWriter
}()
err := errors.New("gourd havens")
HandleExitCoder(err)
expect(t, exitCode, 1)
expect(t, called, true)
expect(t, ErrWriter.(*bytes.Buffer).String(), "gourd havens\n")
}
func TestHandleExitCoder_ErrorWithoutMessage(t *testing.T) {
exitCode := 0
called := false
OsExiter = func(rc int) {
exitCode = rc
called = true
}
ErrWriter = &bytes.Buffer{}
defer func() {
OsExiter = fakeOsExiter
ErrWriter = fakeErrWriter
}()
err := errors.New("")
HandleExitCoder(err)
expect(t, exitCode, 1)
expect(t, called, true)
expect(t, ErrWriter.(*bytes.Buffer).String(), "")
}

View File

@ -736,7 +736,6 @@ func stringifyFlag(f Flag) string {
needsPlaceholder := false
defaultValueString := ""
val := fv.FieldByName("Value")
if val.IsValid() {
needsPlaceholder = val.Kind() != reflect.Bool
defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
@ -746,6 +745,12 @@ func stringifyFlag(f Flag) string {
}
}
helpText := fv.FieldByName("DefaultText")
if helpText.IsValid() && helpText.String() != "" {
needsPlaceholder = val.Kind() != reflect.Bool
defaultValueString = fmt.Sprintf(" (default: %s)", helpText.String())
}
if defaultValueString == " (default: )" {
defaultValueString = ""
}

View File

@ -16,6 +16,7 @@ type BoolFlag struct {
EnvVars []string
Hidden bool
Value bool
DefaultText string
Destination *bool
}
@ -59,6 +60,7 @@ type DurationFlag struct {
EnvVars []string
Hidden bool
Value time.Duration
DefaultText string
Destination *time.Duration
}
@ -102,6 +104,7 @@ type Float64Flag struct {
EnvVars []string
Hidden bool
Value float64
DefaultText string
Destination *float64
}
@ -139,12 +142,13 @@ func lookupFloat64(name string, set *flag.FlagSet) float64 {
// GenericFlag is a flag with type Generic
type GenericFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value Generic
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value Generic
DefaultText string
}
// String returns a readable representation of this value
@ -187,6 +191,7 @@ type Int64Flag struct {
EnvVars []string
Hidden bool
Value int64
DefaultText string
Destination *int64
}
@ -230,6 +235,7 @@ type IntFlag struct {
EnvVars []string
Hidden bool
Value int
DefaultText string
Destination *int
}
@ -267,12 +273,13 @@ func lookupInt(name string, set *flag.FlagSet) int {
// IntSliceFlag is a flag with type *IntSlice
type IntSliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *IntSlice
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *IntSlice
DefaultText string
}
// String returns a readable representation of this value
@ -309,12 +316,13 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int {
// Int64SliceFlag is a flag with type *Int64Slice
type Int64SliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *Int64Slice
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *Int64Slice
DefaultText string
}
// String returns a readable representation of this value
@ -351,12 +359,13 @@ func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
// Float64SliceFlag is a flag with type *Float64Slice
type Float64SliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *Float64Slice
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *Float64Slice
DefaultText string
}
// String returns a readable representation of this value
@ -399,6 +408,7 @@ type StringFlag struct {
EnvVars []string
Hidden bool
Value string
DefaultText string
Destination *string
}
@ -436,12 +446,13 @@ func lookupString(name string, set *flag.FlagSet) string {
// StringSliceFlag is a flag with type *StringSlice
type StringSliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *StringSlice
Name string
Aliases []string
Usage string
EnvVars []string
Hidden bool
Value *StringSlice
DefaultText string
}
// String returns a readable representation of this value
@ -484,6 +495,7 @@ type Uint64Flag struct {
EnvVars []string
Hidden bool
Value uint64
DefaultText string
Destination *uint64
}
@ -527,6 +539,7 @@ type UintFlag struct {
EnvVars []string
Hidden bool
Value uint
DefaultText string
Destination *uint
}

View File

@ -67,6 +67,16 @@ func TestStringFlagHelpOutput(t *testing.T) {
}
}
func TestStringFlagDefaultText(t *testing.T) {
flag := &StringFlag{Name: "foo", Aliases: nil, Usage: "amount of `foo` requested", Value: "none", DefaultText: "all of it"}
expected := "--foo foo\tamount of foo requested (default: all of it)"
output := flag.String()
if output != expected {
t.Errorf("%q does not match %q", output, expected)
}
}
func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
os.Clearenv()
os.Setenv("APP_FOO", "derp")
@ -482,7 +492,6 @@ func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
expect(t, v, float64(43.33333))
}
var float64SliceFlagTests = []struct {
name string
aliases []string
@ -523,8 +532,6 @@ func TestFloat64SliceFlagWithEnvVarHelpOutput(t *testing.T) {
}
}
var genericFlagTests = []struct {
name string
value Generic
@ -1100,7 +1107,6 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
a.Run([]string{"run"})
}
func TestParseMultiFloat64SliceFromEnv(t *testing.T) {
os.Clearenv()
os.Setenv("APP_INTERVALS", "0.1,-10.5")
@ -1141,7 +1147,6 @@ func TestParseMultiFloat64SliceFromEnvCascade(t *testing.T) {
}).Run([]string{"run"})
}
func TestParseMultiBool(t *testing.T) {
a := App{
Flags: []Flag{

View File

@ -145,6 +145,7 @@ def _write_cli_flag_types(outfile, types):
EnvVars []string
Hidden bool
Value {type}
DefaultText string
""".format(**typedef))
if typedef['dest']:
@ -193,6 +194,8 @@ def _write_altsrc_flag_types(outfile, types):
_fwrite(outfile, """\
package altsrc
import "gopkg.in/urfave/cli.v2"
// WARNING: This file is generated!
""")

View File

@ -61,6 +61,10 @@ def _test():
@_target
def _gfmrun():
go_version = check_output('go version'.split()).split()[2]
if go_version < 'go1.3':
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
return
_run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md'])
@ -71,6 +75,11 @@ def _vet():
@_target
def _migrations():
go_version = check_output('go version'.split()).split()[2]
if go_version < 'go1.3':
print('runtests: skip on {}'.format(go_version), file=sys.stderr)
return
migration_script = os.path.abspath(
os.environ.get('V1TOV2', './cli-v1-to-v2')
)