add is set method to flag interface - refer #294

This commit is contained in:
Ajitem Sahasrabuddhe 2019-09-15 18:46:38 +05:30
parent 2746d8dee6
commit ef1ba861f7
No known key found for this signature in database
GPG Key ID: 782DEBC01D3967A5
23 changed files with 197 additions and 800 deletions

View File

@ -13,6 +13,7 @@
### Changed ### Changed
- `Context.FlagNames` now returns all flags in the context lineage - `Context.FlagNames` now returns all flags in the context lineage
- `Context.IsSet` now considers the full context lineage - `Context.IsSet` now considers the full context lineage
- Added `IsSet` method to the `Flag` interface which allows us to detect whether or not a flag has been set
### Removed ### Removed
- the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`. - the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`.

27
app.go
View File

@ -14,8 +14,6 @@ import (
var ( var (
changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
// unused variable. commented for now. will remove in future if agreed upon by everyone
//runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you."
@ -89,7 +87,7 @@ type App struct {
// render custom help text by setting this variable. // render custom help text by setting this variable.
CustomAppHelpTemplate string CustomAppHelpTemplate string
// Boolean to enable short-option handling so user can combine several // Boolean to enable short-option handling so user can combine several
// single-character bool arguements into one // single-character bool arguments into one
// i.e. foobar -o -v -> foobar -ov // i.e. foobar -o -v -> foobar -ov
UseShortOptionHandling bool UseShortOptionHandling bool
@ -182,11 +180,6 @@ func (a *App) Setup() {
} }
} }
//if a.EnableShellCompletion {
// a.appendFlag(GenerateCompletionFlag)
// a.appendFlag(InitCompletionFlag)
//}
if !a.HideVersion { if !a.HideVersion {
a.appendFlag(VersionFlag) a.appendFlag(VersionFlag)
} }
@ -246,14 +239,6 @@ func (a *App) Run(arguments []string) (err error) {
return nil return nil
} }
//if done, cerr := checkInitCompletion(context); done {
// if cerr != nil {
// err = cerr
// } else {
// return nil
// }
//}
if err != nil { if err != nil {
if a.OnUsageError != nil { if a.OnUsageError != nil {
err := a.OnUsageError(context, err, false) err := a.OnUsageError(context, err, false)
@ -361,17 +346,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
} }
a.Commands = newCmds a.Commands = newCmds
//<<<<<<< HEAD
// // append flags
// if a.EnableShellCompletion {
// a.appendFlag(GenerateCompletionFlag)
// }
//
// // parse flags
// set, err := flagSet(a.Name, a.Flags)
//=======
_, err = a.newFlagSet() _, err = a.newFlagSet()
//>>>>>>> master
if err != nil { if err != nil {
return err return err
} }

View File

@ -1993,6 +1993,10 @@ func (c *customBoolFlag) Apply(set *flag.FlagSet) error {
return nil return nil
} }
func (c *customBoolFlag) IsSet() bool {
return false
}
func TestCustomFlagsUnused(t *testing.T) { func TestCustomFlagsUnused(t *testing.T) {
app := &App{ app := &App{
Flags: []Flag{&customBoolFlag{"custom"}}, Flags: []Flag{&customBoolFlag{"custom"}},

View File

@ -1,11 +1,5 @@
package cli package cli
import "errors"
var (
argsRangeErr = errors.New("index out of range")
)
type Args interface { type Args interface {
// Get returns the nth argument, or else a blank string // Get returns the nth argument, or else a blank string
Get(n int) string Get(n int) string
@ -55,6 +49,6 @@ func (a *args) Present() bool {
func (a *args) Slice() []string { func (a *args) Slice() []string {
ret := make([]string, len(*a)) ret := make([]string, len(*a))
copy(ret, []string(*a)) copy(ret, *a)
return ret return ret
} }

View File

@ -59,13 +59,6 @@ type commandCategory struct {
commands []*Command commands []*Command
} }
func newCommandCategory(name string) *commandCategory {
return &commandCategory{
name: name,
commands: []*Command{},
}
}
func (c *commandCategory) Name() string { func (c *commandCategory) Name() string {
return c.name return c.name
} }

View File

@ -1,479 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function, unicode_literals
import argparse
import io
import logging
import os
import re
import sys
_DESCRIPTION = """\
Migrate arbitrary `.go` sources (mostly) from the v1 to v2 API.
"""
_MIGRATORS = []
def main(sysargs=sys.argv[:]):
parser = argparse.ArgumentParser(
description=_DESCRIPTION,
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('path', nargs='*',
type=os.path.abspath, default=os.getcwd())
parser.add_argument('-w', '--write', help='write changes back to file',
action='store_true', default=False)
parser.add_argument('-q', '--quiet', help='quiet down the logging',
action='store_true', default=False)
parser.add_argument('-D', '--debug', help='debug up the logging',
action='store_true',
default=(os.environ.get('DEBUG') != ''))
parser.add_argument('--selftest', help='run internal tests',
action='store_true', default=False)
args = parser.parse_args(sysargs[1:])
if args.selftest:
logging.basicConfig(
level=logging.WARN,
format='selftest: %(message)s'
)
test_migrators()
return 0
level = logging.FATAL if args.quiet else logging.INFO
level = logging.DEBUG if args.debug else level
logging.basicConfig(level=level, format='%(message)s')
paths = args.path
if len(paths) == 0:
paths = ['.']
for filepath in _find_candidate_files(paths):
updated_source = _update_filepath(filepath)
if args.write:
logging.info('Updating %s', filepath)
with io.open(filepath, 'w', encoding='utf-8') as outfile:
outfile.write(updated_source)
else:
logging.info('// Updated %s:', filepath)
print(updated_source)
return 0
def _find_candidate_files(paths):
for path in paths:
if not os.path.isdir(path):
yield path
continue
for curdir, dirs, files in os.walk(path):
for i, dirname in enumerate(dirs[:]):
if dirname.startswith('.'):
dirs.pop(i)
for filename in files:
if not filename.decode('utf-8').endswith('.go'):
continue
filepath = os.path.join(curdir, filename)
if not os.access(filepath, os.R_OK | os.W_OK):
continue
yield filepath
def _update_filepath(filepath):
with io.open(filepath, encoding='utf-8') as infile:
return _update_source(infile.read())
def _update_source(source):
for migrator, func in _MIGRATORS:
logging.debug('Running %s migrator', migrator)
source = func(source)
return source
def _subfmt(pattern, replfmt, source, flags=re.UNICODE):
def repl(match):
return replfmt.format(**match.groupdict())
return re.sub(pattern, repl, source, flags=flags)
def _migrator(func):
_MIGRATORS.append((func.__name__.strip('_'), func))
return func
@_migrator
def _slice_pointer_types(source):
return _subfmt(
'(?P<prefix>\\[\\])cli\\.(?P<type>Command|Author){',
'{prefix}*cli.{type}{{', source
)
@_migrator
def _pointer_type_literal(source):
return _subfmt(
'(?P<prefix>\\s+)cli\\.(?P<type>Command|Author){',
'{prefix}&cli.{type}{{', source
)
@_migrator
def _slice_types(source):
return _subfmt(
'&cli\\.(?P<type>IntSlice|StringSlice){(?P<args>[^}]*)}',
'cli.New{type}({args})', source, flags=re.DOTALL | re.UNICODE
)
@_migrator
def _flag_literals(source):
return _subfmt(
'(?P<prefix>\\s+)cli\\.(?P<type>\\w+)Flag{',
'{prefix}&cli.{type}Flag{{', source
)
@_migrator
def _v1_imports(source):
return re.sub(
'"(?:github\\.com|gopkg\\.in)/(?:codegangsta|urfave)/cli(?:\\.v1|)"',
'"gopkg.in/urfave/cli.v2"', source, flags=re.UNICODE
)
@_migrator
def _new_exit_error(source):
return re.sub('cli\\.NewExitError', 'cli.Exit', source, flags=re.UNICODE)
@_migrator
def _bool_t_flag(source):
return _subfmt(
'cli\\.BoolTFlag{(?P<args>[^}]*)}',
'cli.BoolFlag{{Value: true,{args}}}',
source, flags=re.DOTALL | re.UNICODE
)
@_migrator
def _context_args_len(source):
return _subfmt(
'len\\((?P<prefix>\\S+)\\.Args\\(\\)\\)',
'{prefix}.Args().Len()', source
)
@_migrator
def _context_args_index(source):
return _subfmt(
'\\.Args\\(\\)\\[(?P<index>\\d+)\\]',
'.Args().Get({index})', source
)
@_migrator
def _envvar_string(source):
return re.sub(
'EnvVar:(?P<ws>\\s+)"(?P<string>[^"]+)"',
_envvar_string_repl, source, flags=re.UNICODE
)
def _envvar_string_repl(match):
return 'EnvVars:{ws}[]string{{{value}}}'.format(
value=', '.join([
'"{}"'.format(s) for s in
re.split(
'\\s*,\\s*', match.groupdict()['string'],
flags=re.UNICODE
)
]),
**match.groupdict()
)
@_migrator
def _flag_name_stringly(source):
return re.sub(
'(?P<prefix>\\s+)Name:(?P<ws>\\s+)"(?P<string>[^"]+)"',
_flag_name_stringly_repl, source, flags=re.UNICODE
)
def _flag_name_stringly_repl(match):
revars = dict(match.groupdict())
string = revars['string']
parts = list(
reversed(
sorted(
filter(lambda s: len(s.strip()) > 0, [
part.strip() for part in string.split(',')
]), key=len
)
)
)
if len(parts) == 1:
return '{prefix}Name:{ws}"{string}"'.format(**revars)
return (
'{prefix}Name:{ws}"{name}", Aliases: []string{{{aliases}}}'
).format(
name=parts[0],
aliases=', '.join(['"{}"'.format(s) for s in parts[1:]]),
**revars
)
@_migrator
def _commands_opaque_type(source):
return _subfmt(
'cli\\.Commands(?P<suffix>[^B])',
'[]*cli.Command{suffix}',
source
)
@_migrator
def _flag_names(source):
return re.sub('\\.GetName\\(\\)', '.Names()[0]', source, flags=re.UNICODE)
@_migrator
def _app_categories(source):
source = _subfmt(
'(?P<prefix>range\\s+\\S+)\\.App\\.Categories\\(\\)',
'{prefix}.App.Categories.Categories()', source
)
return re.sub(
'\\.App\\.Categories\\(\\)', '.App.Categories',
source, flags=re.UNICODE
)
@_migrator
def _command_category_commands(source):
# XXX: brittle
return _subfmt(
'(?P<prefix>\\s+category\\.)Commands(?P<suffix>[^(])',
'{prefix}VisibleCommands(){suffix}', source
)
@_migrator
def _context_bool_t(source):
# XXX: probably brittle
return _subfmt(
'(?P<prefix>\\S+)(?:Global|)BoolT\\(',
'!{prefix}Bool(', source
)
@_migrator
def _context_global_methods(source):
return _subfmt(
'\\.Global(?P<method>'
'Bool|Duration|Float64|Generic|Int|IntSlice|String|StringSlice|'
'FlagNames|IsSet|Set'
')\\(',
'.{method}(', source
)
@_migrator
def _context_parent(source):
# XXX: brittle
return re.sub('\\.Parent\\(\\)', '.Lineage()[1]', source, flags=re.UNICODE)
@_migrator
def _app_init(source):
return re.sub(
'cli\\.NewApp\\(\\)', '(&cli.App{})', source, flags=re.UNICODE
)
@_migrator
def _bash_complete(source):
return re.sub(
'BashComplete:', 'ShellComplete:',
re.sub('\\.BashComplete', '.ShellComplete', source, flags=re.UNICODE))
@_migrator
def _enable_bash_completion(source):
return re.sub(
'\\.EnableBashCompletion', '.EnableShellCompletion', source, flags=re.UNICODE
)
@_migrator
def _bash_completion_flag(source):
return re.sub(
'cli\\.BashCompletionFlag', 'cli.GenerateCompletionFlag', source, flags=re.UNICODE
)
def test_migrators():
import difflib
for i, (source, expected) in enumerate(_MIGRATOR_TESTS):
actual = _update_source(source)
if expected != actual:
udiff = difflib.unified_diff(
expected.splitlines(), actual.splitlines(),
fromfile='a/source.go', tofile='b/source.go', lineterm=''
)
for line in udiff:
print(line)
raise AssertionError('migrated source does not match expected')
logging.warn('Test case %d/%d OK', i+1, len(_MIGRATOR_TESTS))
_MIGRATOR_TESTS = (
("""
\t\t\t&cli.StringSlice{"a", "b", "c"},
""", """
\t\t\tcli.NewStringSlice("a", "b", "c"),
"""),
("""
\t\tcli.IntFlag{
\t\t\tName: "yep",
\t\t\tValue: 3,
\t\t}
""", """
\t\t&cli.IntFlag{
\t\t\tName: "yep",
\t\t\tValue: 3,
\t\t}
"""),
("""
\t\tapp.Commands = []cli.Command{
\t\t\t{
\t\t\t\tName: "whatebbs",
\t\t\t},
\t\t}
""", """
\t\tapp.Commands = []*cli.Command{
\t\t\t{
\t\t\t\tName: "whatebbs",
\t\t\t},
\t\t}
"""),
("""
\t\tapp.Commands = []cli.Command{
\t\t\tcli.Command{
\t\t\t\tName: "whatebbs",
\t\t\t},
\t\t}
""", """
\t\tapp.Commands = []*cli.Command{
\t\t\t&cli.Command{
\t\t\t\tName: "whatebbs",
\t\t\t},
\t\t}
"""),
("""
\t"github.com/codegangsta/cli"
\t"github.com/urfave/cli"
\t"gopkg.in/codegangsta/cli"
\t"gopkg.in/codegangsta/cli.v1"
\t"gopkg.in/urfave/cli"
\t"gopkg.in/urfave/cli.v1"
""", """
\t"gopkg.in/urfave/cli.v2"
\t"gopkg.in/urfave/cli.v2"
\t"gopkg.in/urfave/cli.v2"
\t"gopkg.in/urfave/cli.v2"
\t"gopkg.in/urfave/cli.v2"
\t"gopkg.in/urfave/cli.v2"
"""),
("""
\t\t\t\treturn cli.NewExitError("foo whatebber", 9)
""", """
\t\t\t\treturn cli.Exit("foo whatebber", 9)
"""),
("""
\t\t\tapp.Flags = []cli.Flag{
\t\t\t\tcli.StringFlag{
\t\t\t\t\tName: "aha",
\t\t\t\t},
\t\t\t\tcli.BoolTFlag{
\t\t\t\t\tName: "blurp",
\t\t\t\t},
\t\t\t}
""", """
\t\t\tapp.Flags = []cli.Flag{
\t\t\t\t&cli.StringFlag{
\t\t\t\t\tName: "aha",
\t\t\t\t},
\t\t\t\t&cli.BoolFlag{Value: true,
\t\t\t\t\tName: "blurp",
\t\t\t\t},
\t\t\t}
"""),
("""
\t\t\tAction = func(c *cli.Context) error {
\t\t\t\tif c.Args()[4] == "meep" {
\t\t\t\t\treturn nil
\t\t\t\t}
\t\t\t\treturn errors.New("mope")
\t\t\t}
""", """
\t\t\tAction = func(c *cli.Context) error {
\t\t\t\tif c.Args().Get(4) == "meep" {
\t\t\t\t\treturn nil
\t\t\t\t}
\t\t\t\treturn errors.New("mope")
\t\t\t}
"""),
("""
\t\tapp.Flags = []cli.Flag{
\t\t\tcli.StringFlag{
\t\t\t\tName: "toots",
\t\t\t\tEnvVar: "TOOTS,TOOTERS",
\t\t\t},
\t\t}
""", """
\t\tapp.Flags = []cli.Flag{
\t\t\t&cli.StringFlag{
\t\t\t\tName: "toots",
\t\t\t\tEnvVars: []string{"TOOTS", "TOOTERS"},
\t\t\t},
\t\t}
"""),
("""
\t\tapp.Flags = []cli.Flag{
\t\t\tcli.StringFlag{
\t\t\t\tName: "t, tootles, toots",
\t\t\t},
\t\t}
""", """
\t\tapp.Flags = []cli.Flag{
\t\t\t&cli.StringFlag{
\t\t\t\tName: "tootles", Aliases: []string{"toots", "t"},
\t\t\t},
\t\t}
"""),
("""
\t\tapp := cli.NewApp()
\t\tapp.HideHelp = true
""", """
\t\tapp := (&cli.App{})
\t\tapp.HideHelp = true
""")
)
if __name__ == '__main__':
sys.exit(main())

View File

@ -7,7 +7,6 @@ import (
"fmt" "fmt"
"os" "os"
"os/signal" "os/signal"
"reflect"
"strings" "strings"
"syscall" "syscall"
) )
@ -91,23 +90,25 @@ func (c *Context) IsSet(name string) bool {
return false return false
} }
val := reflect.ValueOf(f) //val := reflect.ValueOf(f)
if val.Kind() == reflect.Ptr { //if val.Kind() == reflect.Ptr {
val = val.Elem() // val = val.Elem()
} //}
//
//filePathValue := val.FieldByName("FilePath")
//if !filePathValue.IsValid() {
// return false
//}
//
//envVarValues := val.FieldByName("EnvVars")
//if !envVarValues.IsValid() {
// return false
//}
//
//_, ok := flagFromEnvOrFile(envVarValues.Interface().([]string), filePathValue.Interface().(string))
//return ok
filePathValue := val.FieldByName("FilePath") return f.IsSet()
if !filePathValue.IsValid() {
return false
}
envVarValues := val.FieldByName("EnvVars")
if !envVarValues.IsValid() {
return false
}
_, ok := flagFromEnvOrFile(envVarValues.Interface().([]string), filePathValue.Interface().(string))
return ok
} }
return false return false

View File

@ -222,75 +222,6 @@ func TestContext_IsSet_fromEnv(t *testing.T) {
expect(t, uIsSet, false) expect(t, uIsSet, false)
} }
// XXX Corresponds to hack in context.IsSet for flags with EnvVar field
// TODO: Should be moved to `flag_test` in v2
//func TestContext_GlobalIsSet_fromEnv(t *testing.T) {
// var (
// timeoutIsSet, tIsSet bool
// noEnvVarIsSet, nIsSet bool
// passwordIsSet, pIsSet bool
// passwordValue string
// unparsableIsSet, uIsSet bool
// overrideIsSet, oIsSet bool
// overrideValue string
// )
//
// os.Clearenv()
// _ = os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
// _ = os.Setenv("APP_PASSWORD", "badpass")
// _ = os.Setenv("APP_OVERRIDE", "overridden")
// a := App{
// Flags: []Flag{
// Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
// StringFlag{Name: "password, p", EnvVar: "APP_PASSWORD"},
// Float64Flag{Name: "no-env-var, n"},
// Float64Flag{Name: "unparsable, u", EnvVar: "APP_UNPARSABLE"},
// StringFlag{Name: "overrides-default, o", Value: "default", EnvVar: "APP_OVERRIDE"},
// },
// Commands: []Command{
// {
// Name: "hello",
// Action: func(ctx *Context) error {
// timeoutIsSet = ctx.GlobalIsSet("timeout")
// tIsSet = ctx.GlobalIsSet("t")
// passwordIsSet = ctx.GlobalIsSet("password")
// pIsSet = ctx.GlobalIsSet("p")
// passwordValue = ctx.GlobalString("password")
// unparsableIsSet = ctx.GlobalIsSet("unparsable")
// uIsSet = ctx.GlobalIsSet("u")
// noEnvVarIsSet = ctx.GlobalIsSet("no-env-var")
// nIsSet = ctx.GlobalIsSet("n")
// overrideIsSet = ctx.GlobalIsSet("overrides-default")
// oIsSet = ctx.GlobalIsSet("o")
// overrideValue = ctx.GlobalString("overrides-default")
// return nil
// },
// },
// },
// }
// if err := a.Run([]string{"run", "hello"}); err != nil {
// t.Logf("error running Run(): %+v", err)
// }
// expect(t, timeoutIsSet, true)
// expect(t, tIsSet, true)
// expect(t, passwordIsSet, true)
// expect(t, pIsSet, true)
// expect(t, passwordValue, "badpass")
// expect(t, unparsableIsSet, false)
// expect(t, noEnvVarIsSet, false)
// expect(t, nIsSet, false)
// expect(t, overrideIsSet, true)
// expect(t, oIsSet, true)
// expect(t, overrideValue, "overridden")
//
// _ = os.Setenv("APP_UNPARSABLE", "foobar")
// if err := a.Run([]string{"run"}); err != nil {
// t.Logf("error running Run(): %+v", err)
// }
// expect(t, unparsableIsSet, false)
// expect(t, uIsSet, false)
//}
func TestContext_NumFlags(t *testing.T) { func TestContext_NumFlags(t *testing.T) {
set := flag.NewFlagSet("test", 0) set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc") set.Bool("myflag", false, "doc")
@ -323,8 +254,8 @@ func TestContext_LocalFlagNames(t *testing.T) {
parentSet.Bool("top-flag", true, "doc") parentSet.Bool("top-flag", true, "doc")
parentCtx := NewContext(nil, parentSet, nil) parentCtx := NewContext(nil, parentSet, nil)
ctx := NewContext(nil, set, parentCtx) ctx := NewContext(nil, set, parentCtx)
set.Parse([]string{"--one-flag", "--two-flag=foo"}) _ = set.Parse([]string{"--one-flag", "--two-flag=foo"})
parentSet.Parse([]string{"--top-flag"}) _ = parentSet.Parse([]string{"--top-flag"})
actualFlags := ctx.LocalFlagNames() actualFlags := ctx.LocalFlagNames()
sort.Strings(actualFlags) sort.Strings(actualFlags)
@ -340,8 +271,8 @@ func TestContext_FlagNames(t *testing.T) {
parentSet.Bool("top-flag", true, "doc") parentSet.Bool("top-flag", true, "doc")
parentCtx := NewContext(nil, parentSet, nil) parentCtx := NewContext(nil, parentSet, nil)
ctx := NewContext(nil, set, parentCtx) ctx := NewContext(nil, set, parentCtx)
set.Parse([]string{"--one-flag", "--two-flag=foo"}) _ = set.Parse([]string{"--one-flag", "--two-flag=foo"})
parentSet.Parse([]string{"--top-flag"}) _ = parentSet.Parse([]string{"--top-flag"})
actualFlags := ctx.FlagNames() actualFlags := ctx.FlagNames()
sort.Strings(actualFlags) sort.Strings(actualFlags)
@ -356,8 +287,8 @@ func TestContext_Lineage(t *testing.T) {
parentSet.Bool("top-flag", true, "doc") parentSet.Bool("top-flag", true, "doc")
parentCtx := NewContext(nil, parentSet, nil) parentCtx := NewContext(nil, parentSet, nil)
ctx := NewContext(nil, set, parentCtx) ctx := NewContext(nil, set, parentCtx)
set.Parse([]string{"--local-flag"}) _ = set.Parse([]string{"--local-flag"})
parentSet.Parse([]string{"--top-flag"}) _ = parentSet.Parse([]string{"--top-flag"})
lineage := ctx.Lineage() lineage := ctx.Lineage()
expect(t, len(lineage), 2) expect(t, len(lineage), 2)
@ -372,8 +303,8 @@ func TestContext_lookupFlagSet(t *testing.T) {
parentSet.Bool("top-flag", true, "doc") parentSet.Bool("top-flag", true, "doc")
parentCtx := NewContext(nil, parentSet, nil) parentCtx := NewContext(nil, parentSet, nil)
ctx := NewContext(nil, set, parentCtx) ctx := NewContext(nil, set, parentCtx)
set.Parse([]string{"--local-flag"}) _ = set.Parse([]string{"--local-flag"})
parentSet.Parse([]string{"--top-flag"}) _ = parentSet.Parse([]string{"--top-flag"})
fs := lookupFlagSet("top-flag", ctx) fs := lookupFlagSet("top-flag", ctx)
expect(t, fs, parentCtx.flagSet) expect(t, fs, parentCtx.flagSet)
@ -534,15 +465,17 @@ func TestCheckRequiredFlags(t *testing.T) {
for _, test := range tdata { for _, test := range tdata {
t.Run(test.testCase, func(t *testing.T) { t.Run(test.testCase, func(t *testing.T) {
// setup // setup
set := flag.NewFlagSet("test", 0)
for _, flags := range test.flags {
flags.Apply(set)
}
_ = set.Parse(test.parseInput)
if test.envVarInput[0] != "" { if test.envVarInput[0] != "" {
os.Clearenv() os.Clearenv()
_ = os.Setenv(test.envVarInput[0], test.envVarInput[1]) _ = os.Setenv(test.envVarInput[0], test.envVarInput[1])
} }
set := flag.NewFlagSet("test", 0)
for _, flags := range test.flags {
_ = flags.Apply(set)
}
_ = set.Parse(test.parseInput)
c := &Context{} c := &Context{}
ctx := NewContext(c.App, set, c) ctx := NewContext(c.App, set, c)
ctx.Command.Flags = test.flags ctx.Command.Flags = test.flags
@ -558,10 +491,12 @@ func TestCheckRequiredFlags(t *testing.T) {
t.Errorf("did not expected an error, but there was one: %s", err) t.Errorf("did not expected an error, but there was one: %s", err)
} }
for _, errString := range test.expectedErrorContents { for _, errString := range test.expectedErrorContents {
if err != nil {
if !strings.Contains(err.Error(), errString) { if !strings.Contains(err.Error(), errString) {
t.Errorf("expected error %q to contain %q, but it didn't!", err.Error(), errString) t.Errorf("expected error %q to contain %q, but it didn't!", err.Error(), errString)
} }
} }
}
}) })
} }
} }

35
flag.go
View File

@ -21,26 +21,6 @@ var (
commaWhitespace = regexp.MustCompile("[, ]+.*") commaWhitespace = regexp.MustCompile("[, ]+.*")
) )
// GenerateCompletionFlag enables completion for all commands and subcommands
//var GenerateCompletionFlag Flag = &BoolFlag{
// Name: "generate-completion",
// Hidden: true,
//}
//
//func genCompName() string {
// names := GenerateCompletionFlag.Names()
// if len(names) == 0 {
// return "generate-completion"
// }
// return names[0]
//}
//
//// InitCompletionFlag generates completion code
//var InitCompletionFlag = &StringFlag{
// Name: "init-completion",
// Usage: "generate completion code. Value must be 'bash' or 'zsh'",
//}
// BashCompletionFlag enables bash-completion for all commands and subcommands // BashCompletionFlag enables bash-completion for all commands and subcommands
var BashCompletionFlag Flag = &BoolFlag{ var BashCompletionFlag Flag = &BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
@ -92,16 +72,12 @@ func (f FlagsByName) Len() int {
} }
func (f FlagsByName) Less(i, j int) bool { func (f FlagsByName) Less(i, j int) bool {
//<<<<<<< HEAD
if len(f[j].Names()) == 0 { if len(f[j].Names()) == 0 {
return false return false
} else if len(f[i].Names()) == 0 { } else if len(f[i].Names()) == 0 {
return true return true
} }
return f[i].Names()[0] < f[j].Names()[0] return lexicographicLess(f[i].Names()[0], f[j].Names()[0])
//=======
// return lexicographicLess(f[i].GetName(), f[j].GetName())
//>>>>>>> master
} }
func (f FlagsByName) Swap(i, j int) { func (f FlagsByName) Swap(i, j int) {
@ -116,6 +92,7 @@ type Flag interface {
// Apply Flag settings to the given flag set // Apply Flag settings to the given flag set
Apply(*flag.FlagSet) error Apply(*flag.FlagSet) error
Names() []string Names() []string
IsSet() bool
} }
// RequiredFlag is an interface that allows us to mark flags as required // RequiredFlag is an interface that allows us to mark flags as required
@ -153,14 +130,6 @@ func flagSet(name string, flags []Flag) (*flag.FlagSet, error) {
return set, nil return set, nil
} }
func eachName(longName string, fn func(string)) {
parts := strings.Split(longName, ",")
for _, name := range parts {
name = strings.Trim(name, " ")
fn(name)
}
}
func visibleFlags(fl []Flag) []Flag { func visibleFlags(fl []Flag) []Flag {
var visible []Flag var visible []Flag
for _, f := range fl { for _, f := range fl {

View File

@ -18,6 +18,12 @@ type BoolFlag struct {
Value bool Value bool
DefaultText string DefaultText string
Destination *bool Destination *bool
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *BoolFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -57,10 +63,13 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" { if val != "" {
valBool, err := strconv.ParseBool(val) valBool, err := strconv.ParseBool(val)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %q as bool value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as bool value for flag %s: %s", val, f.Name, err)
} }
f.Value = valBool f.Value = valBool
f.HasBeenSet = true
} }
} }
@ -84,16 +93,6 @@ func (c *Context) Bool(name string) bool {
return false return false
} }
// GlobalBool looks up the value of a global BoolFlag, returns
// false if not found
//func (c *Context) GlobalBool(name string) bool {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupBool(name, fs)
// }
// return false
//}
// TODO: Fix Duplicate
func lookupBool(name string, set *flag.FlagSet) bool { func lookupBool(name string, set *flag.FlagSet) bool {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -18,6 +18,12 @@ type DurationFlag struct {
Value time.Duration Value time.Duration
DefaultText string DefaultText string
Destination *time.Duration Destination *time.Duration
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *DurationFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -57,10 +63,13 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" { if val != "" {
valDuration, err := time.ParseDuration(val) valDuration, err := time.ParseDuration(val)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %q as duration value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as duration value for flag %s: %s", val, f.Name, err)
} }
f.Value = valDuration f.Value = valDuration
f.HasBeenSet = true
} }
} }
@ -82,14 +91,6 @@ func (c *Context) Duration(name string) time.Duration {
} }
return 0 return 0
} }
// GlobalDuration looks up the value of a global DurationFlag, returns
// 0 if not found
//func (c *Context) GlobalDuration(name string) time.Duration {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupDuration(name, fs)
// }
// return 0
//}
func lookupDuration(name string, set *flag.FlagSet) time.Duration { func lookupDuration(name string, set *flag.FlagSet) time.Duration {
f := set.Lookup(name) f := set.Lookup(name)

View File

@ -18,6 +18,12 @@ type Float64Flag struct {
Value float64 Value float64
DefaultText string DefaultText string
Destination *float64 Destination *float64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Float64Flag)IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -57,10 +63,13 @@ func (f *Float64Flag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" { if val != "" {
valFloat, err := strconv.ParseFloat(val, 10) valFloat, err := strconv.ParseFloat(val, 10)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as float64 value for flag %s: %s", val, f.Name, err)
} }
f.Value = valFloat f.Value = valFloat
f.HasBeenSet = true
} }
} }
@ -84,15 +93,6 @@ func (c *Context) Float64(name string) float64 {
return 0 return 0
} }
// GlobalFloat64 looks up the value of a global Float64Flag, returns
// 0 if not found
//func (c *Context) GlobalFloat64(name string) float64 {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupFloat64(name, fs)
// }
// return 0
//}
func lookupFloat64(name string, set *flag.FlagSet) float64 { func lookupFloat64(name string, set *flag.FlagSet) float64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -74,6 +74,12 @@ type Float64SliceFlag struct {
Hidden bool Hidden bool
Value *Float64Slice Value *Float64Slice
DefaultText string DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Float64SliceFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -114,6 +120,7 @@ func (f *Float64SliceFlag) GetValue() string {
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error { func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
f.Value = &Float64Slice{} f.Value = &Float64Slice{}
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
@ -121,6 +128,9 @@ func (f *Float64SliceFlag) Apply(set *flag.FlagSet) error {
return fmt.Errorf("could not parse %q as float64 slice value for flag %s: %s", f.Value, f.Name, err) return fmt.Errorf("could not parse %q as float64 slice value for flag %s: %s", f.Value, f.Name, err)
} }
} }
f.HasBeenSet = true
}
} }
for _, name := range f.Names() { for _, name := range f.Names() {
@ -142,15 +152,6 @@ func (c *Context) Float64Slice(name string) []float64 {
return nil return nil
} }
// GlobalFloat64Slice looks up the value of a global Float64SliceFlag, returns
// nil if not found
//func (c *Context) GlobalFloat64Slice(name string) []int {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupFloat64Slice(name, fs)
// }
// return nil
//}
func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 { func lookupFloat64Slice(name string, set *flag.FlagSet) []float64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -23,6 +23,12 @@ type GenericFlag struct {
TakesFile bool TakesFile bool
Value Generic Value Generic
DefaultText string DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *GenericFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -64,9 +70,13 @@ func (f *GenericFlag) GetValue() string {
// 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 {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" {
if err := f.Value.Set(val); err != nil { if err := f.Value.Set(val); err != nil {
return fmt.Errorf("could not parse %q as value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as value for flag %s: %s", val, f.Name, err)
} }
f.HasBeenSet = true
}
} }
for _, name := range f.Names() { for _, name := range f.Names() {
@ -79,17 +89,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) error {
// Generic looks up the value of a local GenericFlag, returns // Generic looks up the value of a local GenericFlag, returns
// nil if not found // nil if not found
func (c *Context) Generic(name string) interface{} { func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet) if fs := lookupFlagSet(name, c); fs != nil {
return lookupGeneric(name, fs)
}
return nil
} }
// GlobalGeneric looks up the value of a global GenericFlag, returns
// nil if not found
//func (c *Context) GlobalGeneric(name string) interface{} {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupGeneric(name, fs)
// }
// return nil
//}
func lookupGeneric(name string, set *flag.FlagSet) interface{} { func lookupGeneric(name string, set *flag.FlagSet) interface{} {
f := set.Lookup(name) f := set.Lookup(name)

View File

@ -18,6 +18,12 @@ type IntFlag struct {
Value int Value int
DefaultText string DefaultText string
Destination *int Destination *int
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *IntFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -57,10 +63,13 @@ func (f *IntFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64) valInt, err := strconv.ParseInt(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
} }
f.Value = int(valInt) f.Value = int(valInt)
f.HasBeenSet = true
} }
} }
@ -84,15 +93,6 @@ func (c *Context) Int(name string) int {
return 0 return 0
} }
// GlobalInt looks up the value of a global IntFlag, returns
// 0 if not found
//func (c *Context) GlobalInt(name string) int {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupInt(name, fs)
// }
// return 0
//}
func lookupInt(name string, set *flag.FlagSet) int { func lookupInt(name string, set *flag.FlagSet) int {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -18,6 +18,12 @@ type Int64Flag struct {
Value int64 Value int64
DefaultText string DefaultText string
Destination *int64 Destination *int64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Int64Flag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -57,10 +63,13 @@ func (f *Int64Flag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
if val != "" { if val != "" {
valInt, err := strconv.ParseInt(val, 0, 64) valInt, err := strconv.ParseInt(val, 0, 64)
if err != nil { if err != nil {
return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int value for flag %s: %s", val, f.Name, err)
} }
f.Value = valInt f.Value = valInt
f.HasBeenSet = true
} }
} }
@ -84,15 +93,6 @@ func (c *Context) Int64(name string) int64 {
return 0 return 0
} }
// GlobalInt64 looks up the value of a global Int64Flag, returns
// 0 if not found
//func (c *Context) GlobalInt64(name string) int64 {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupInt64(name, fs)
// }
// return 0
//}
func lookupInt64(name string, set *flag.FlagSet) int64 { func lookupInt64(name string, set *flag.FlagSet) int64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -74,6 +74,12 @@ type Int64SliceFlag struct {
Hidden bool Hidden bool
Value *Int64Slice Value *Int64Slice
DefaultText string DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Int64SliceFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -121,6 +127,8 @@ func (f *Int64SliceFlag) Apply(set *flag.FlagSet) error {
return fmt.Errorf("could not parse %q as int64 slice value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int64 slice value for flag %s: %s", val, f.Name, err)
} }
} }
f.HasBeenSet = true
} }
for _, name := range f.Names() { for _, name := range f.Names() {
@ -142,15 +150,6 @@ func (c *Context) Int64Slice(name string) []int64 {
return nil return nil
} }
// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns
// nil if not found
//func (c *Context) GlobalInt64Slice(name string) []int {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupInt64Slice(name, fs)
// }
// return nil
//}
func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { func lookupInt64Slice(name string, set *flag.FlagSet) []int64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -85,6 +85,12 @@ type IntSliceFlag struct {
Hidden bool Hidden bool
Value *IntSlice Value *IntSlice
DefaultText string DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *IntSliceFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -132,6 +138,8 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) error {
return fmt.Errorf("could not parse %q as int slice value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as int slice value for flag %s: %s", val, f.Name, err)
} }
} }
f.HasBeenSet = true
} }
for _, name := range f.Names() { for _, name := range f.Names() {
@ -153,15 +161,6 @@ func (c *Context) IntSlice(name string) []int {
return nil return nil
} }
// GlobalIntSlice looks up the value of a global IntSliceFlag, returns
// nil if not found
//func (c *Context) GlobalIntSlice(name string) []int {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupIntSlice(name, fs)
// }
// return nil
//}
func lookupIntSlice(name string, set *flag.FlagSet) []int { func lookupIntSlice(name string, set *flag.FlagSet) []int {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -14,6 +14,12 @@ type PathFlag struct {
Value string Value string
DefaultText string DefaultText string
Destination *string Destination *string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *PathFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -52,6 +58,7 @@ func (f *PathFlag) GetValue() string {
func (f *PathFlag) Apply(set *flag.FlagSet) error { func (f *PathFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = val f.Value = val
f.HasBeenSet = true
} }
for _, name := range f.Names() { for _, name := range f.Names() {

View File

@ -15,52 +15,59 @@ type StringFlag struct {
Value string Value string
DefaultText string DefaultText string
Destination *string Destination *string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *StringFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
// (for usage defaults) // (for usage defaults)
func (s *StringFlag) String() string { func (f *StringFlag) String() string {
return FlagStringer(s) return FlagStringer(f)
} }
// Names returns the names of the flag // Names returns the names of the flag
func (s *StringFlag) Names() []string { func (f *StringFlag) Names() []string {
return flagNames(s) return flagNames(f)
} }
// IsRequired returns whether or not the flag is required // IsRequired returns whether or not the flag is required
func (s *StringFlag) IsRequired() bool { func (f *StringFlag) IsRequired() bool {
return s.Required return f.Required
} }
// TakesValue returns true of the flag takes a value, otherwise false // TakesValue returns true of the flag takes a value, otherwise false
func (s *StringFlag) TakesValue() bool { func (f *StringFlag) TakesValue() bool {
return true return true
} }
// GetUsage returns the usage string for the flag // GetUsage returns the usage string for the flag
func (s *StringFlag) GetUsage() string { func (f *StringFlag) GetUsage() string {
return s.Usage return f.Usage
} }
// 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 (s *StringFlag) GetValue() string { func (f *StringFlag) GetValue() string {
return s.Value return f.Value
} }
// Apply populates the flag given the flag set and environment // Apply populates the flag given the flag set and environment
func (s *StringFlag) Apply(set *flag.FlagSet) error { func (f *StringFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(s.EnvVars, s.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
s.Value = val f.Value = val
f.HasBeenSet = true
} }
for _, name := range s.Names() { for _, name := range f.Names() {
if s.Destination != nil { if f.Destination != nil {
set.StringVar(s.Destination, name, s.Value, s.Usage) set.StringVar(f.Destination, name, f.Value, f.Usage)
continue continue
} }
set.String(name, s.Value, s.Usage) set.String(name, f.Value, f.Usage)
} }
return nil return nil
@ -75,15 +82,6 @@ func (c *Context) String(name string) string {
return "" return ""
} }
// GlobalString looks up the value of a global StringFlag, returns
// "" if not found
//func (c *Context) GlobalString(name string) string {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupPath(name, fs)
// }
// return ""
//}
func lookupString(name string, set *flag.FlagSet) string { func lookupString(name string, set *flag.FlagSet) string {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -69,6 +69,12 @@ type StringSliceFlag struct {
TakesFile bool TakesFile bool
Value *StringSlice Value *StringSlice
DefaultText string DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *StringSliceFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -110,11 +116,14 @@ func (f *StringSliceFlag) GetValue() string {
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error { func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = &StringSlice{} f.Value = &StringSlice{}
for _, s := range strings.Split(val, ",") { for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil { if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err) return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err)
} }
} }
f.HasBeenSet = true
} }
for _, name := range f.Names() { for _, name := range f.Names() {
@ -136,15 +145,6 @@ func (c *Context) StringSlice(name string) []string {
return nil return nil
} }
// GlobalStringSlice looks up the value of a global StringSliceFlag, returns
// nil if not found
//func (c *Context) GlobalStringSlice(name string) []string {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupStringSlice(name, fs)
// }
// return nil
//}
func lookupStringSlice(name string, set *flag.FlagSet) []string { func lookupStringSlice(name string, set *flag.FlagSet) []string {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -18,6 +18,12 @@ type UintFlag struct {
Value uint Value uint
DefaultText string DefaultText string
Destination *uint Destination *uint
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *UintFlag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -56,6 +62,7 @@ func (f *UintFlag) Apply(set *flag.FlagSet) error {
} }
f.Value = uint(valInt) f.Value = uint(valInt)
f.HasBeenSet = true
} }
} }
@ -85,15 +92,6 @@ func (c *Context) Uint(name string) uint {
return 0 return 0
} }
// GlobalUint looks up the value of a global UintFlag, returns
// 0 if not found
//func (c *Context) GlobalUint(name string) uint {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupUint(name, fs)
// }
// return 0
//}
func lookupUint(name string, set *flag.FlagSet) uint { func lookupUint(name string, set *flag.FlagSet) uint {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {

View File

@ -18,6 +18,12 @@ type Uint64Flag struct {
Value uint64 Value uint64
DefaultText string DefaultText string
Destination *uint64 Destination *uint64
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *Uint64Flag) IsSet() bool {
return f.HasBeenSet
} }
// String returns a readable representation of this value // String returns a readable representation of this value
@ -56,6 +62,7 @@ func (f *Uint64Flag) Apply(set *flag.FlagSet) error {
} }
f.Value = valInt f.Value = valInt
f.HasBeenSet = true
} }
} }
@ -85,15 +92,6 @@ func (c *Context) Uint64(name string) uint64 {
return 0 return 0
} }
// GlobalUint64 looks up the value of a global Uint64Flag, returns
// 0 if not found
//func (c *Context) GlobalUint64(name string) uint64 {
// if fs := lookupGlobalFlagSet(name, c); fs != nil {
// return lookupUint64(name, fs)
// }
// return 0
//}
func lookupUint64(name string, set *flag.FlagSet) uint64 { func lookupUint64(name string, set *flag.FlagSet) uint64 {
f := set.Lookup(name) f := set.Lookup(name)
if f != nil { if f != nil {