Remove all Context.Global* methods
and change the behavior of the non-Global variants to always search up the context lineage. Closes #385
This commit is contained in:
parent
cab5c58774
commit
bef835d455
11
CHANGELOG.md
11
CHANGELOG.md
@ -5,6 +5,12 @@
|
|||||||
## 2.0.0 - (unreleased 2.x series)
|
## 2.0.0 - (unreleased 2.x series)
|
||||||
### Added
|
### Added
|
||||||
- `NewStringSlice` and `NewIntSlice` for creating their related types
|
- `NewStringSlice` and `NewIntSlice` for creating their related types
|
||||||
|
- `Context.Lineage` to get all contexts from current up to global
|
||||||
|
- `Context.LocalFlagNames` to get the flag names from *only* the current context
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `Context.FlagNames` now returns all flags in the context lineage
|
||||||
|
- `Context.IsSet` now considers the full context lineage
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`.
|
- the ability to specify `&StringSlice{...string}` or `&IntSlice{...int}`.
|
||||||
@ -17,6 +23,11 @@
|
|||||||
arguments](https://github.com/codegangsta/cli/issues/355) when the user
|
arguments](https://github.com/codegangsta/cli/issues/355) when the user
|
||||||
attempted to mix flags and arguments. Given the trade-offs we removed support
|
attempted to mix flags and arguments. Given the trade-offs we removed support
|
||||||
for this reordering.
|
for this reordering.
|
||||||
|
- All `Context.Global*` methods, as the non-global versions now traverse up
|
||||||
|
the context lineage automatically.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `Context.BoolT` now returns `true` when not found
|
||||||
|
|
||||||
## [Unreleased] - (1.x series)
|
## [Unreleased] - (1.x series)
|
||||||
### Added
|
### Added
|
||||||
|
@ -1,13 +1,23 @@
|
|||||||
package altsrc
|
package altsrc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
wd, _ = os.Getwd()
|
||||||
|
)
|
||||||
|
|
||||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||||
if !reflect.DeepEqual(b, a) {
|
_, fn, line, _ := runtime.Caller(1)
|
||||||
t.Errorf("Expected %#v (type %v) - Got %#v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(a, b) {
|
||||||
|
t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
229
context.go
229
context.go
@ -28,129 +28,76 @@ func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
|
|||||||
|
|
||||||
// Int looks up the value of a local int flag, returns 0 if no int flag exists
|
// Int looks up the value of a local int flag, returns 0 if no int flag exists
|
||||||
func (c *Context) Int(name string) int {
|
func (c *Context) Int(name string) int {
|
||||||
return lookupInt(name, c.flagSet)
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
}
|
|
||||||
|
|
||||||
// Duration looks up the value of a local time.Duration flag, returns 0 if no
|
|
||||||
// time.Duration flag exists
|
|
||||||
func (c *Context) Duration(name string) time.Duration {
|
|
||||||
return lookupDuration(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float64 looks up the value of a local float64 flag, returns 0 if no float64
|
|
||||||
// flag exists
|
|
||||||
func (c *Context) Float64(name string) float64 {
|
|
||||||
return lookupFloat64(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bool looks up the value of a local bool flag, returns false if no bool flag exists
|
|
||||||
func (c *Context) Bool(name string) bool {
|
|
||||||
return lookupBool(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolT looks up the value of a local boolT flag, returns false if no bool flag exists
|
|
||||||
func (c *Context) BoolT(name string) bool {
|
|
||||||
return lookupBoolT(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// String looks up the value of a local string flag, returns "" if no string flag exists
|
|
||||||
func (c *Context) String(name string) string {
|
|
||||||
return lookupString(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringSlice looks up the value of a local string slice flag, returns nil if no
|
|
||||||
// string slice flag exists
|
|
||||||
func (c *Context) StringSlice(name string) []string {
|
|
||||||
return lookupStringSlice(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntSlice looks up the value of a local int slice flag, returns nil if no int
|
|
||||||
// slice flag exists
|
|
||||||
func (c *Context) IntSlice(name string) []int {
|
|
||||||
return lookupIntSlice(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic looks up the value of a local generic flag, returns nil if no generic
|
|
||||||
// flag exists
|
|
||||||
func (c *Context) Generic(name string) interface{} {
|
|
||||||
return lookupGeneric(name, c.flagSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalInt looks up the value of a global int flag, returns 0 if no int flag exists
|
|
||||||
func (c *Context) GlobalInt(name string) int {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupInt(name, fs)
|
return lookupInt(name, fs)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalFloat64 looks up the value of a global float64 flag, returns float64(0)
|
// Duration looks up the value of a local time.Duration flag, returns 0 if no
|
||||||
// if no float64 flag exists
|
// time.Duration flag exists
|
||||||
func (c *Context) GlobalFloat64(name string) float64 {
|
func (c *Context) Duration(name string) time.Duration {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
return lookupFloat64(name, fs)
|
|
||||||
}
|
|
||||||
return float64(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalDuration looks up the value of a global time.Duration flag, returns 0
|
|
||||||
// if no time.Duration flag exists
|
|
||||||
func (c *Context) GlobalDuration(name string) time.Duration {
|
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupDuration(name, fs)
|
return lookupDuration(name, fs)
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalBool looks up the value of a global bool flag, returns false if no bool
|
// Float64 looks up the value of a local float64 flag, returns 0 if no float64
|
||||||
// flag exists
|
// flag exists
|
||||||
func (c *Context) GlobalBool(name string) bool {
|
func (c *Context) Float64(name string) float64 {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
|
return lookupFloat64(name, fs)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bool looks up the value of a local bool flag, returns false if no bool flag exists
|
||||||
|
func (c *Context) Bool(name string) bool {
|
||||||
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
return lookupBool(name, fs)
|
return lookupBool(name, fs)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalBoolT looks up the value of a global bool flag, returns true if no bool
|
// BoolT looks up the value of a local boolT flag, returns false if no bool flag exists
|
||||||
// flag exists
|
func (c *Context) BoolT(name string) bool {
|
||||||
func (c *Context) GlobalBoolT(name string) bool {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupBoolT(name, fs)
|
return lookupBoolT(name, fs)
|
||||||
}
|
}
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalString looks up the value of a global string flag, returns "" if no
|
// String looks up the value of a local string flag, returns "" if no string flag exists
|
||||||
// string flag exists
|
func (c *Context) String(name string) string {
|
||||||
func (c *Context) GlobalString(name string) string {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
|
||||||
return lookupString(name, fs)
|
return lookupString(name, fs)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalStringSlice looks up the value of a global string slice flag, returns
|
// StringSlice looks up the value of a local string slice flag, returns nil if no
|
||||||
// nil if no string slice flag exists
|
// string slice flag exists
|
||||||
func (c *Context) GlobalStringSlice(name string) []string {
|
func (c *Context) StringSlice(name string) []string {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
return lookupStringSlice(name, fs)
|
return lookupStringSlice(name, fs)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalIntSlice looks up the value of a global int slice flag, returns nil if
|
// IntSlice looks up the value of a local int slice flag, returns nil if no int
|
||||||
// no int slice flag exists
|
// slice flag exists
|
||||||
func (c *Context) GlobalIntSlice(name string) []int {
|
func (c *Context) IntSlice(name string) []int {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
return lookupIntSlice(name, fs)
|
return lookupIntSlice(name, fs)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalGeneric looks up the value of a global generic flag, returns nil if no
|
// Generic looks up the value of a local generic flag, returns nil if no generic
|
||||||
// generic flag exists
|
// flag exists
|
||||||
func (c *Context) GlobalGeneric(name string) interface{} {
|
func (c *Context) Generic(name string) interface{} {
|
||||||
if fs := lookupGlobalFlagSet(name, c); fs != nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
return lookupGeneric(name, fs)
|
return lookupGeneric(name, fs)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -166,61 +113,37 @@ func (c *Context) Set(name, value string) error {
|
|||||||
return c.flagSet.Set(name, value)
|
return c.flagSet.Set(name, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalSet sets a context flag to a value on the global flagset
|
|
||||||
func (c *Context) GlobalSet(name, value string) error {
|
|
||||||
return globalContext(c).flagSet.Set(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSet determines if the flag was actually set
|
// IsSet determines if the flag was actually set
|
||||||
func (c *Context) IsSet(name string) bool {
|
func (c *Context) IsSet(name string) bool {
|
||||||
if c.setFlags == nil {
|
if fs := lookupFlagSet(name, c); fs != nil {
|
||||||
c.setFlags = make(map[string]bool)
|
isSet := false
|
||||||
c.flagSet.Visit(func(f *flag.Flag) {
|
c.flagSet.Visit(func(f *flag.Flag) {
|
||||||
c.setFlags[f.Name] = true
|
if f.Name == name {
|
||||||
|
isSet = true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
return isSet
|
||||||
}
|
}
|
||||||
return c.setFlags[name] == true
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GlobalIsSet determines if the global flag was actually set
|
// LocalFlagNames returns a slice of flag names used in this context.
|
||||||
func (c *Context) GlobalIsSet(name string) bool {
|
func (c *Context) LocalFlagNames() []string {
|
||||||
if c.globalSetFlags == nil {
|
names := []string{}
|
||||||
c.globalSetFlags = make(map[string]bool)
|
c.flagSet.Visit(makeFlagNameVisitor(&names))
|
||||||
ctx := c
|
return names
|
||||||
if ctx.parentContext != nil {
|
|
||||||
ctx = ctx.parentContext
|
|
||||||
}
|
|
||||||
for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext {
|
|
||||||
ctx.flagSet.Visit(func(f *flag.Flag) {
|
|
||||||
c.globalSetFlags[f.Name] = true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.globalSetFlags[name]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagNames returns a slice of flag names used in this context.
|
// FlagNames returns a slice of flag names used by the this context and all of
|
||||||
func (c *Context) FlagNames() (names []string) {
|
// its parent contexts.
|
||||||
for _, flag := range c.Command.Flags {
|
func (c *Context) FlagNames() []string {
|
||||||
name := strings.Split(flag.GetName(), ",")[0]
|
names := []string{}
|
||||||
if name == "help" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalFlagNames returns a slice of global flag names used by the app.
|
for _, ctx := range c.Lineage() {
|
||||||
func (c *Context) GlobalFlagNames() (names []string) {
|
ctx.flagSet.Visit(makeFlagNameVisitor(&names))
|
||||||
for _, flag := range c.App.Flags {
|
|
||||||
name := strings.Split(flag.GetName(), ",")[0]
|
|
||||||
if name == "help" || name == "version" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
names = append(names, name)
|
|
||||||
}
|
}
|
||||||
return
|
|
||||||
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent returns the parent context, if any
|
// Parent returns the parent context, if any
|
||||||
@ -228,6 +151,25 @@ func (c *Context) Parent() *Context {
|
|||||||
return c.parentContext
|
return c.parentContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lineage returns *this* context and all of its ancestor contexts in order from
|
||||||
|
// child to parent
|
||||||
|
func (c *Context) Lineage() []*Context {
|
||||||
|
lineage := []*Context{}
|
||||||
|
cur := c
|
||||||
|
|
||||||
|
for {
|
||||||
|
lineage = append(lineage, cur)
|
||||||
|
|
||||||
|
if cur.parentContext == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = cur.parentContext
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineage
|
||||||
|
}
|
||||||
|
|
||||||
// Args contains apps console arguments
|
// Args contains apps console arguments
|
||||||
type Args []string
|
type Args []string
|
||||||
|
|
||||||
@ -291,15 +233,13 @@ func globalContext(ctx *Context) *Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet {
|
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||||
if ctx.parentContext != nil {
|
for _, c := range ctx.Lineage() {
|
||||||
ctx = ctx.parentContext
|
if f := c.flagSet.Lookup(name); f != nil {
|
||||||
}
|
return c.flagSet
|
||||||
for ; ctx != nil; ctx = ctx.parentContext {
|
|
||||||
if f := ctx.flagSet.Lookup(name); f != nil {
|
|
||||||
return ctx.flagSet
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,7 +341,7 @@ func lookupBoolT(name string, set *flag.FlagSet) bool {
|
|||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
|
||||||
@ -445,3 +385,12 @@ func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeFlagNameVisitor(names *[]string) func(*flag.Flag) {
|
||||||
|
return func(f *flag.Flag) {
|
||||||
|
name := strings.Split(f.Name, ",")[0]
|
||||||
|
if name != "help" && name != "version" {
|
||||||
|
(*names) = append(*names, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
163
context_test.go
163
context_test.go
@ -2,6 +2,7 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -19,8 +20,6 @@ func TestNewContext(t *testing.T) {
|
|||||||
c.Command = command
|
c.Command = command
|
||||||
expect(t, c.Int("myflag"), 12)
|
expect(t, c.Int("myflag"), 12)
|
||||||
expect(t, c.Float64("myflag64"), float64(17))
|
expect(t, c.Float64("myflag64"), float64(17))
|
||||||
expect(t, c.GlobalInt("myflag"), 42)
|
|
||||||
expect(t, c.GlobalFloat64("myflag64"), float64(47))
|
|
||||||
expect(t, c.Command.Name, "mycommand")
|
expect(t, c.Command.Name, "mycommand")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,14 +30,6 @@ func TestContext_Int(t *testing.T) {
|
|||||||
expect(t, c.Int("myflag"), 12)
|
expect(t, c.Int("myflag"), 12)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalInt(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
set.Int("myflag", 12, "doc")
|
|
||||||
c := NewContext(nil, set, nil)
|
|
||||||
expect(t, c.GlobalInt("myflag"), 12)
|
|
||||||
expect(t, c.GlobalInt("nope"), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_Float64(t *testing.T) {
|
func TestContext_Float64(t *testing.T) {
|
||||||
set := flag.NewFlagSet("test", 0)
|
set := flag.NewFlagSet("test", 0)
|
||||||
set.Float64("myflag", float64(17), "doc")
|
set.Float64("myflag", float64(17), "doc")
|
||||||
@ -46,14 +37,6 @@ func TestContext_Float64(t *testing.T) {
|
|||||||
expect(t, c.Float64("myflag"), float64(17))
|
expect(t, c.Float64("myflag"), float64(17))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalFloat64(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
set.Float64("myflag", float64(17), "doc")
|
|
||||||
c := NewContext(nil, set, nil)
|
|
||||||
expect(t, c.GlobalFloat64("myflag"), float64(17))
|
|
||||||
expect(t, c.GlobalFloat64("nope"), float64(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_Duration(t *testing.T) {
|
func TestContext_Duration(t *testing.T) {
|
||||||
set := flag.NewFlagSet("test", 0)
|
set := flag.NewFlagSet("test", 0)
|
||||||
set.Duration("myflag", time.Duration(12*time.Second), "doc")
|
set.Duration("myflag", time.Duration(12*time.Second), "doc")
|
||||||
@ -82,30 +65,6 @@ func TestContext_BoolT(t *testing.T) {
|
|||||||
expect(t, c.BoolT("myflag"), true)
|
expect(t, c.BoolT("myflag"), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalBool(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
|
|
||||||
globalSet := flag.NewFlagSet("test-global", 0)
|
|
||||||
globalSet.Bool("myflag", false, "doc")
|
|
||||||
globalCtx := NewContext(nil, globalSet, nil)
|
|
||||||
|
|
||||||
c := NewContext(nil, set, globalCtx)
|
|
||||||
expect(t, c.GlobalBool("myflag"), false)
|
|
||||||
expect(t, c.GlobalBool("nope"), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_GlobalBoolT(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
|
|
||||||
globalSet := flag.NewFlagSet("test-global", 0)
|
|
||||||
globalSet.Bool("myflag", true, "doc")
|
|
||||||
globalCtx := NewContext(nil, globalSet, nil)
|
|
||||||
|
|
||||||
c := NewContext(nil, set, globalCtx)
|
|
||||||
expect(t, c.GlobalBoolT("myflag"), true)
|
|
||||||
expect(t, c.GlobalBoolT("nope"), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_Args(t *testing.T) {
|
func TestContext_Args(t *testing.T) {
|
||||||
set := flag.NewFlagSet("test", 0)
|
set := flag.NewFlagSet("test", 0)
|
||||||
set.Bool("myflag", false, "doc")
|
set.Bool("myflag", false, "doc")
|
||||||
@ -139,25 +98,6 @@ func TestContext_IsSet(t *testing.T) {
|
|||||||
expect(t, c.IsSet("myflagGlobal"), false)
|
expect(t, c.IsSet("myflagGlobal"), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalIsSet(t *testing.T) {
|
|
||||||
set := flag.NewFlagSet("test", 0)
|
|
||||||
set.Bool("myflag", false, "doc")
|
|
||||||
set.String("otherflag", "hello world", "doc")
|
|
||||||
globalSet := flag.NewFlagSet("test", 0)
|
|
||||||
globalSet.Bool("myflagGlobal", true, "doc")
|
|
||||||
globalSet.Bool("myflagGlobalUnset", true, "doc")
|
|
||||||
globalCtx := NewContext(nil, globalSet, nil)
|
|
||||||
c := NewContext(nil, set, globalCtx)
|
|
||||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
|
||||||
globalSet.Parse([]string{"--myflagGlobal", "bat", "baz"})
|
|
||||||
expect(t, c.GlobalIsSet("myflag"), false)
|
|
||||||
expect(t, c.GlobalIsSet("otherflag"), false)
|
|
||||||
expect(t, c.GlobalIsSet("bogusflag"), false)
|
|
||||||
expect(t, c.GlobalIsSet("myflagGlobal"), true)
|
|
||||||
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
|
|
||||||
expect(t, c.GlobalIsSet("bogusGlobal"), 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")
|
||||||
@ -171,62 +111,6 @@ func TestContext_NumFlags(t *testing.T) {
|
|||||||
expect(t, c.NumFlags(), 2)
|
expect(t, c.NumFlags(), 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalFlag(t *testing.T) {
|
|
||||||
var globalFlag string
|
|
||||||
var globalFlagSet bool
|
|
||||||
app := NewApp()
|
|
||||||
app.Flags = []Flag{
|
|
||||||
StringFlag{Name: "global, g", Usage: "global"},
|
|
||||||
}
|
|
||||||
app.Action = func(c *Context) error {
|
|
||||||
globalFlag = c.GlobalString("global")
|
|
||||||
globalFlagSet = c.GlobalIsSet("global")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
app.Run([]string{"command", "-g", "foo"})
|
|
||||||
expect(t, globalFlag, "foo")
|
|
||||||
expect(t, globalFlagSet, true)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_GlobalFlagsInSubcommands(t *testing.T) {
|
|
||||||
subcommandRun := false
|
|
||||||
parentFlag := false
|
|
||||||
app := NewApp()
|
|
||||||
|
|
||||||
app.Flags = []Flag{
|
|
||||||
BoolFlag{Name: "debug, d", Usage: "Enable debugging"},
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Commands = []Command{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Flags: []Flag{
|
|
||||||
BoolFlag{Name: "parent, p", Usage: "Parent flag"},
|
|
||||||
},
|
|
||||||
Subcommands: []Command{
|
|
||||||
{
|
|
||||||
Name: "bar",
|
|
||||||
Action: func(c *Context) error {
|
|
||||||
if c.GlobalBool("debug") {
|
|
||||||
subcommandRun = true
|
|
||||||
}
|
|
||||||
if c.GlobalBool("parent") {
|
|
||||||
parentFlag = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Run([]string{"command", "-d", "foo", "-p", "bar"})
|
|
||||||
|
|
||||||
expect(t, subcommandRun, true)
|
|
||||||
expect(t, parentFlag, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext_Set(t *testing.T) {
|
func TestContext_Set(t *testing.T) {
|
||||||
set := flag.NewFlagSet("test", 0)
|
set := flag.NewFlagSet("test", 0)
|
||||||
set.Int("int", 5, "an int")
|
set.Int("int", 5, "an int")
|
||||||
@ -236,21 +120,36 @@ func TestContext_Set(t *testing.T) {
|
|||||||
expect(t, c.Int("int"), 1)
|
expect(t, c.Int("int"), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContext_GlobalSet(t *testing.T) {
|
func TestContext_LocalFlagNames(t *testing.T) {
|
||||||
gSet := flag.NewFlagSet("test", 0)
|
set := flag.NewFlagSet("test", 0)
|
||||||
gSet.Int("int", 5, "an int")
|
set.Bool("one-flag", false, "doc")
|
||||||
|
set.String("two-flag", "hello world", "doc")
|
||||||
|
globalSet := flag.NewFlagSet("test", 0)
|
||||||
|
globalSet.Bool("top-flag", true, "doc")
|
||||||
|
globalCtx := NewContext(nil, globalSet, nil)
|
||||||
|
c := NewContext(nil, set, globalCtx)
|
||||||
|
set.Parse([]string{"--one-flag", "--two-flag=foo"})
|
||||||
|
globalSet.Parse([]string{"--top-flag"})
|
||||||
|
|
||||||
set := flag.NewFlagSet("sub", 0)
|
actualFlags := c.LocalFlagNames()
|
||||||
set.Int("int", 3, "an int")
|
sort.Strings(actualFlags)
|
||||||
|
|
||||||
pc := NewContext(nil, gSet, nil)
|
expect(t, actualFlags, []string{"one-flag", "two-flag"})
|
||||||
c := NewContext(nil, set, pc)
|
}
|
||||||
|
|
||||||
c.Set("int", "1")
|
func TestContext_FlagNames(t *testing.T) {
|
||||||
expect(t, c.Int("int"), 1)
|
set := flag.NewFlagSet("test", 0)
|
||||||
expect(t, c.GlobalInt("int"), 5)
|
set.Bool("one-flag", false, "doc")
|
||||||
|
set.String("two-flag", "hello world", "doc")
|
||||||
c.GlobalSet("int", "1")
|
globalSet := flag.NewFlagSet("test", 0)
|
||||||
expect(t, c.Int("int"), 1)
|
globalSet.Bool("top-flag", true, "doc")
|
||||||
expect(t, c.GlobalInt("int"), 1)
|
globalCtx := NewContext(nil, globalSet, nil)
|
||||||
|
c := NewContext(nil, set, globalCtx)
|
||||||
|
set.Parse([]string{"--one-flag", "--two-flag=foo"})
|
||||||
|
globalSet.Parse([]string{"--top-flag"})
|
||||||
|
|
||||||
|
actualFlags := c.FlagNames()
|
||||||
|
sort.Strings(actualFlags)
|
||||||
|
|
||||||
|
expect(t, actualFlags, []string{"one-flag", "top-flag", "two-flag"})
|
||||||
}
|
}
|
||||||
|
21
flag_test.go
21
flag_test.go
@ -391,7 +391,7 @@ func TestParseMultiStringSliceWithDefaults(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
expected := []string{"10", "20"}
|
expected := []string{"10", "20"}
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
|
if !reflect.DeepEqual(ctx.StringSlice("serve"), expected) {
|
||||||
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
|
t.Errorf("main name not set: %v != %v", expected, ctx.StringSlice("serve"))
|
||||||
@ -399,6 +399,7 @@ func TestParseMultiStringSliceWithDefaults(t *testing.T) {
|
|||||||
if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
|
if !reflect.DeepEqual(ctx.StringSlice("s"), expected) {
|
||||||
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
|
t.Errorf("short name not set: %v != %v", expected, ctx.StringSlice("s"))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||||
}
|
}
|
||||||
@ -408,13 +409,14 @@ func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
|
||||||
t.Errorf("main name not set: %v", ctx.StringSlice("serve"))
|
t.Errorf("main name not set: %v", ctx.StringSlice("serve"))
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"9", "2"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"9", "2"}) {
|
||||||
t.Errorf("short name not set: %v", ctx.StringSlice("s"))
|
t.Errorf("short name not set: %v", ctx.StringSlice("s"))
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run"})
|
}).Run([]string{"run"})
|
||||||
}
|
}
|
||||||
@ -427,13 +429,14 @@ func TestParseMultiStringSliceFromEnv(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "APP_INTERVALS"},
|
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "APP_INTERVALS"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
t.Errorf("main name not set from env")
|
t.Errorf("main name not set from env")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||||
t.Errorf("short name not set from env")
|
t.Errorf("short name not set from env")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run"})
|
}).Run([]string{"run"})
|
||||||
}
|
}
|
||||||
@ -466,13 +469,14 @@ func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
t.Errorf("main name not set from env")
|
t.Errorf("main name not set from env")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("i"), []string{"20", "30", "40"}) {
|
||||||
t.Errorf("short name not set from env")
|
t.Errorf("short name not set from env")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run"})
|
}).Run([]string{"run"})
|
||||||
}
|
}
|
||||||
@ -596,13 +600,14 @@ func TestParseMultiIntSliceWithDefaults(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
||||||
t.Errorf("main name not set")
|
t.Errorf("main name not set")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
|
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{10, 20}) {
|
||||||
t.Errorf("short name not set")
|
t.Errorf("short name not set")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
}).Run([]string{"run", "-s", "10", "-s", "20"})
|
||||||
}
|
}
|
||||||
@ -612,13 +617,14 @@ func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
|
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
|
||||||
t.Errorf("main name not set")
|
t.Errorf("main name not set")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{9, 2}) {
|
if !reflect.DeepEqual(ctx.IntSlice("s"), []int{9, 2}) {
|
||||||
t.Errorf("short name not set")
|
t.Errorf("short name not set")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run"})
|
}).Run([]string{"run"})
|
||||||
}
|
}
|
||||||
@ -631,13 +637,14 @@ func TestParseMultiIntSliceFromEnv(t *testing.T) {
|
|||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "intervals, i", Value: NewIntSlice(), EnvVar: "APP_INTERVALS"},
|
IntSliceFlag{Name: "intervals, i", Value: NewIntSlice(), EnvVar: "APP_INTERVALS"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||||
t.Errorf("main name not set from env")
|
t.Errorf("main name not set from env")
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
if !reflect.DeepEqual(ctx.IntSlice("i"), []int{20, 30, 40}) {
|
||||||
t.Errorf("short name not set from env")
|
t.Errorf("short name not set from env")
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}).Run([]string{"run"})
|
}).Run([]string{"run"})
|
||||||
}
|
}
|
||||||
|
8
help.go
8
help.go
@ -209,7 +209,7 @@ func checkVersion(c *Context) bool {
|
|||||||
found := false
|
found := false
|
||||||
if VersionFlag.Name != "" {
|
if VersionFlag.Name != "" {
|
||||||
eachName(VersionFlag.Name, func(name string) {
|
eachName(VersionFlag.Name, func(name string) {
|
||||||
if c.GlobalBool(name) || c.Bool(name) {
|
if c.Bool(name) {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -221,7 +221,7 @@ func checkHelp(c *Context) bool {
|
|||||||
found := false
|
found := false
|
||||||
if HelpFlag.Name != "" {
|
if HelpFlag.Name != "" {
|
||||||
eachName(HelpFlag.Name, func(name string) {
|
eachName(HelpFlag.Name, func(name string) {
|
||||||
if c.GlobalBool(name) || c.Bool(name) {
|
if c.Bool(name) {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -239,7 +239,7 @@ func checkCommandHelp(c *Context, name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkSubcommandHelp(c *Context) bool {
|
func checkSubcommandHelp(c *Context) bool {
|
||||||
if c.GlobalBool("h") || c.GlobalBool("help") {
|
if c.Bool("h") || c.Bool("help") {
|
||||||
ShowSubcommandHelp(c)
|
ShowSubcommandHelp(c)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -248,7 +248,7 @@ func checkSubcommandHelp(c *Context) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkCompletions(c *Context) bool {
|
func checkCompletions(c *Context) bool {
|
||||||
if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion {
|
if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion {
|
||||||
ShowCompletions(c)
|
ShowCompletions(c)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user