From 6185b8d8fd27da0a3d35457ccb4dfdab261a1295 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 00:56:44 -0400 Subject: [PATCH 01/17] Generate code for flag types and context accessors --- .travis.yml | 2 + appveyor.yml | 3 + cli.go | 2 + context.go | 184 ----------------- flag-types.json | 79 ++++++++ flag.go | 261 ------------------------- flag_generated.go | 467 ++++++++++++++++++++++++++++++++++++++++++++ generate-flag-types | 116 +++++++++++ runtests | 18 +- 9 files changed, 682 insertions(+), 450 deletions(-) create mode 100644 flag-types.json create mode 100644 flag_generated.go create mode 100755 generate-flag-types diff --git a/.travis.yml b/.travis.yml index 273d017..905a9cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,11 +29,13 @@ matrix: before_script: - go get github.com/urfave/gfmxr/... +- go get golang.org/x/tools/cmd/goimports - if [ ! -f node_modules/.bin/markdown-toc ] ; then npm install markdown-toc ; fi script: +- ./runtests gen - ./runtests vet - ./runtests test - ./runtests gfmxr diff --git a/appveyor.yml b/appveyor.yml index 173086e..ae91ae8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,9 +17,12 @@ install: - go version - go env - go get github.com/urfave/gfmxr/... +- go get golang.org/x/tools/cmd/goimports - go get -v -t ./... build_script: +- python runtests gen - python runtests vet - python runtests test - python runtests gfmxr +- python runtests toc diff --git a/cli.go b/cli.go index f0440c5..1e53dbf 100644 --- a/cli.go +++ b/cli.go @@ -17,3 +17,5 @@ // app.Run(os.Args) // } package cli + +//go:generate python ./generate-flag-types flag_generated.go flag-types.json diff --git a/context.go b/context.go index 879bae5..762d389 100644 --- a/context.go +++ b/context.go @@ -26,190 +26,6 @@ func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { return &Context{App: app, flagSet: set, parentContext: parentCtx} } -// Int looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int(name string) int { - return lookupInt(name, c.flagSet) -} - -// Int64 looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Int64(name string) int64 { - return lookupInt64(name, c.flagSet) -} - -// Uint looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Uint(name string) uint { - return lookupUint(name, c.flagSet) -} - -// Uint64 looks up the value of a local int flag, returns 0 if no int flag exists -func (c *Context) Uint64(name string) uint64 { - return lookupUint64(name, c.flagSet) -} - -// 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) -} - -// Int64Slice looks up the value of a local int slice flag, returns nil if no int -// slice flag exists -func (c *Context) Int64Slice(name string) []int64 { - return lookupInt64Slice(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 0 -} - -// GlobalInt64 looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalInt64(name string) int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64(name, fs) - } - return 0 -} - -// GlobalUint looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalUint(name string) uint { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint(name, fs) - } - return 0 -} - -// GlobalUint64 looks up the value of a global int flag, returns 0 if no int flag exists -func (c *Context) GlobalUint64(name string) uint64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupUint64(name, fs) - } - return 0 -} - -// GlobalFloat64 looks up the value of a global float64 flag, returns float64(0) -// if no float64 flag exists -func (c *Context) GlobalFloat64(name string) float64 { - if fs := lookupGlobalFlagSet(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 0 -} - -// GlobalBool looks up the value of a global bool flag, returns false if no bool -// flag exists -func (c *Context) GlobalBool(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBool(name, fs) - } - return false -} - -// GlobalBoolT looks up the value of a global bool flag, returns true if no bool -// flag exists -func (c *Context) GlobalBoolT(name string) bool { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupBoolT(name, fs) - } - return false -} - -// GlobalString looks up the value of a global string flag, returns "" if no -// string flag exists -func (c *Context) GlobalString(name string) string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupString(name, fs) - } - return "" -} - -// GlobalStringSlice looks up the value of a global string slice flag, returns -// nil if no string slice flag exists -func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupStringSlice(name, fs) - } - return nil -} - -// GlobalIntSlice looks up the value of a global int slice flag, returns nil if -// no int slice flag exists -func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupIntSlice(name, fs) - } - return nil -} - -// GlobalInt64Slice looks up the value of a global int slice flag, returns nil if -// no int slice flag exists -func (c *Context) GlobalInt64Slice(name string) []int64 { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupInt64Slice(name, fs) - } - return nil -} - -// GlobalGeneric looks up the value of a global generic flag, returns nil if no -// generic flag exists -func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupGlobalFlagSet(name, c); fs != nil { - return lookupGeneric(name, fs) - } - return nil -} - // NumFlags returns the number of flags set func (c *Context) NumFlags() int { return c.flagSet.NFlag() diff --git a/flag-types.json b/flag-types.json new file mode 100644 index 0000000..2085350 --- /dev/null +++ b/flag-types.json @@ -0,0 +1,79 @@ +[ + { + "name": "Bool", + "type": "bool", + "value": false, + "context_default": "false" + }, + { + "name": "BoolT", + "type": "bool", + "value": false, + "doctail": " that is true by default", + "context_default": "false" + }, + { + "name": "Duration", + "type": "time.Duration", + "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", + "context_default": "0" + }, + { + "name": "Float64", + "type": "float64", + "context_default": "0" + }, + { + "name": "Generic", + "type": "Generic", + "dest": false, + "context_default": "nil", + "context_type": "interface{}" + }, + { + "name": "Int64", + "type": "int64", + "context_default": "0" + }, + { + "name": "Int", + "type": "int", + "context_default": "0" + }, + { + "name": "IntSlice", + "type": "*IntSlice", + "dest": false, + "context_default": "nil", + "context_type": "[]int" + }, + { + "name": "Int64Slice", + "type": "*Int64Slice", + "dest": false, + "context_default": "nil", + "context_type": "[]int64" + }, + { + "name": "String", + "type": "string", + "context_default": "\"\"" + }, + { + "name": "StringSlice", + "type": "*StringSlice", + "dest": false, + "context_default": "nil", + "context_type": "[]string" + }, + { + "name": "Uint64", + "type": "uint64", + "context_default": "0" + }, + { + "name": "Uint", + "type": "uint", + "context_default": "0" + } +] diff --git a/flag.go b/flag.go index f8a28d1..e748c02 100644 --- a/flag.go +++ b/flag.go @@ -70,22 +70,6 @@ type Generic interface { String() string } -// GenericFlag is the flag type for types implementing Generic -type GenericFlag struct { - Name string - Value Generic - Usage string - EnvVar string - Hidden bool -} - -// String returns the string representation of the generic flag to display the -// help text to the user (uses the String() method of the generic flag to show -// the value) -func (f GenericFlag) String() string { - return FlagStringer(f) -} - // Apply takes the flagset and calls Set on the generic flag with the value // provided by the user for parsing by the flag func (f GenericFlag) Apply(set *flag.FlagSet) { @@ -105,11 +89,6 @@ func (f GenericFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of a flag. -func (f GenericFlag) GetName() string { - return f.Name -} - // StringSlice is an opaque type for []string to satisfy flag.Value type StringSlice []string @@ -129,21 +108,6 @@ func (f *StringSlice) Value() []string { return *f } -// StringSliceFlag is a string flag that can be specified multiple times on the -// command-line -type StringSliceFlag struct { - Name string - Value *StringSlice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f StringSliceFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f StringSliceFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -169,11 +133,6 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of a flag. -func (f StringSliceFlag) GetName() string { - return f.Name -} - // IntSlice is an opaque type for []int to satisfy flag.Value type IntSlice []int @@ -197,21 +156,6 @@ func (f *IntSlice) Value() []int { return *f } -// IntSliceFlag is an int flag that can be specified multiple times on the -// command-line -type IntSliceFlag struct { - Name string - Value *IntSlice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f IntSliceFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f IntSliceFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -240,11 +184,6 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f IntSliceFlag) GetName() string { - return f.Name -} - // Int64Slice is an opaque type for []int to satisfy flag.Value type Int64Slice []int64 @@ -268,21 +207,6 @@ func (f *Int64Slice) Value() []int64 { return *f } -// Int64SliceFlag is an int flag that can be specified multiple times on the -// command-line -type Int64SliceFlag struct { - Name string - Value *Int64Slice - Usage string - EnvVar string - Hidden bool -} - -// String returns the usage -func (f Int64SliceFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f Int64SliceFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -311,25 +235,6 @@ func (f Int64SliceFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f Int64SliceFlag) GetName() string { - return f.Name -} - -// BoolFlag is a switch that defaults to false -type BoolFlag struct { - Name string - Usage string - EnvVar string - Destination *bool - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f BoolFlag) Apply(set *flag.FlagSet) { val := false @@ -355,26 +260,6 @@ func (f BoolFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f BoolFlag) GetName() string { - return f.Name -} - -// BoolTFlag this represents a boolean flag that is true by default, but can -// still be set to false by --some-flag=false -type BoolTFlag struct { - Name string - Usage string - EnvVar string - Destination *bool - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f BoolTFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f BoolTFlag) Apply(set *flag.FlagSet) { val := true @@ -400,26 +285,6 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f BoolTFlag) GetName() string { - return f.Name -} - -// StringFlag represents a flag that takes as string value -type StringFlag struct { - Name string - Value string - Usage string - EnvVar string - Destination *string - Hidden bool -} - -// String returns the usage -func (f StringFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f StringFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -441,26 +306,6 @@ func (f StringFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f StringFlag) GetName() string { - return f.Name -} - -// IntFlag is a flag that takes an integer -type IntFlag struct { - Name string - Value int - Usage string - EnvVar string - Destination *int - Hidden bool -} - -// String returns the usage -func (f IntFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f IntFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -485,26 +330,6 @@ func (f IntFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f IntFlag) GetName() string { - return f.Name -} - -// Int64Flag is a flag that takes a 64-bit integer -type Int64Flag struct { - Name string - Value int64 - Usage string - EnvVar string - Destination *int64 - Hidden bool -} - -// String returns the usage -func (f Int64Flag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f Int64Flag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -529,26 +354,6 @@ func (f Int64Flag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f Int64Flag) GetName() string { - return f.Name -} - -// UintFlag is a flag that takes an unsigned integer -type UintFlag struct { - Name string - Value uint - Usage string - EnvVar string - Destination *uint - Hidden bool -} - -// String returns the usage -func (f UintFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f UintFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -573,26 +378,6 @@ func (f UintFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f UintFlag) GetName() string { - return f.Name -} - -// Uint64Flag is a flag that takes an unsigned 64-bit integer -type Uint64Flag struct { - Name string - Value uint64 - Usage string - EnvVar string - Destination *uint64 - Hidden bool -} - -// String returns the usage -func (f Uint64Flag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f Uint64Flag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -617,27 +402,6 @@ func (f Uint64Flag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f Uint64Flag) GetName() string { - return f.Name -} - -// DurationFlag is a flag that takes a duration specified in Go's duration -// format: https://golang.org/pkg/time/#ParseDuration -type DurationFlag struct { - Name string - Value time.Duration - Usage string - EnvVar string - Destination *time.Duration - Hidden bool -} - -// String returns a readable representation of this value (for usage defaults) -func (f DurationFlag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f DurationFlag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -662,26 +426,6 @@ func (f DurationFlag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f DurationFlag) GetName() string { - return f.Name -} - -// Float64Flag is a flag that takes an float value -type Float64Flag struct { - Name string - Value float64 - Usage string - EnvVar string - Destination *float64 - Hidden bool -} - -// String returns the usage -func (f Float64Flag) String() string { - return FlagStringer(f) -} - // Apply populates the flag given the flag set and environment func (f Float64Flag) Apply(set *flag.FlagSet) { if f.EnvVar != "" { @@ -705,11 +449,6 @@ func (f Float64Flag) Apply(set *flag.FlagSet) { }) } -// GetName returns the name of the flag. -func (f Float64Flag) GetName() string { - return f.Name -} - func visibleFlags(fl []Flag) []Flag { visible := []Flag{} for _, flag := range fl { diff --git a/flag_generated.go b/flag_generated.go new file mode 100644 index 0000000..5cbdb83 --- /dev/null +++ b/flag_generated.go @@ -0,0 +1,467 @@ +package cli + +import "time" + +// WARNING: This file is generated! + +// BoolFlag is a flag with type bool +type BoolFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolFlag) GetName() string { + return f.Name +} + +// Bool looks up the value of a local BoolFlag, returns +// false if not found +func (c *Context) Bool(name string) bool { + return lookupBool(name, c.flagSet) +} + +// 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 +} + +// BoolTFlag is a flag with type bool that is true by default +type BoolTFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Destination *bool +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f BoolTFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f BoolTFlag) GetName() string { + return f.Name +} + +// BoolT looks up the value of a local BoolTFlag, returns +// false if not found +func (c *Context) BoolT(name string) bool { + return lookupBoolT(name, c.flagSet) +} + +// GlobalBoolT looks up the value of a global BoolTFlag, returns +// false if not found +func (c *Context) GlobalBoolT(name string) bool { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupBoolT(name, fs) + } + return false +} + +// DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) +type DurationFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value time.Duration + Destination *time.Duration +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f DurationFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f DurationFlag) GetName() string { + return f.Name +} + +// Duration looks up the value of a local DurationFlag, returns +// 0 if not found +func (c *Context) Duration(name string) time.Duration { + return lookupDuration(name, c.flagSet) +} + +// 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 +} + +// Float64Flag is a flag with type float64 +type Float64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value float64 + Destination *float64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Float64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Float64Flag) GetName() string { + return f.Name +} + +// Float64 looks up the value of a local Float64Flag, returns +// 0 if not found +func (c *Context) Float64(name string) float64 { + return lookupFloat64(name, c.flagSet) +} + +// 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 +} + +// GenericFlag is a flag with type Generic +type GenericFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value Generic +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f GenericFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f GenericFlag) GetName() string { + return f.Name +} + +// Generic looks up the value of a local GenericFlag, returns +// nil if not found +func (c *Context) Generic(name string) interface{} { + return lookupGeneric(name, c.flagSet) +} + +// 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 +} + +// Int64Flag is a flag with type int64 +type Int64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int64 + Destination *int64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64Flag) GetName() string { + return f.Name +} + +// Int64 looks up the value of a local Int64Flag, returns +// 0 if not found +func (c *Context) Int64(name string) int64 { + return lookupInt64(name, c.flagSet) +} + +// 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 +} + +// IntFlag is a flag with type int +type IntFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value int + Destination *int +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntFlag) GetName() string { + return f.Name +} + +// Int looks up the value of a local IntFlag, returns +// 0 if not found +func (c *Context) Int(name string) int { + return lookupInt(name, c.flagSet) +} + +// 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 +} + +// IntSliceFlag is a flag with type *IntSlice +type IntSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *IntSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f IntSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f IntSliceFlag) GetName() string { + return f.Name +} + +// IntSlice looks up the value of a local IntSliceFlag, returns +// nil if not found +func (c *Context) IntSlice(name string) []int { + return lookupIntSlice(name, c.flagSet) +} + +// 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 +} + +// Int64SliceFlag is a flag with type *Int64Slice +type Int64SliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *Int64Slice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Int64SliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Int64SliceFlag) GetName() string { + return f.Name +} + +// Int64Slice looks up the value of a local Int64SliceFlag, returns +// nil if not found +func (c *Context) Int64Slice(name string) []int64 { + return lookupInt64Slice(name, c.flagSet) +} + +// GlobalInt64Slice looks up the value of a global Int64SliceFlag, returns +// nil if not found +func (c *Context) GlobalInt64Slice(name string) []int64 { + if fs := lookupGlobalFlagSet(name, c); fs != nil { + return lookupInt64Slice(name, fs) + } + return nil +} + +// StringFlag is a flag with type string +type StringFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value string + Destination *string +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringFlag) GetName() string { + return f.Name +} + +// String looks up the value of a local StringFlag, returns +// "" if not found +func (c *Context) String(name string) string { + return lookupString(name, c.flagSet) +} + +// 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 lookupString(name, fs) + } + return "" +} + +// StringSliceFlag is a flag with type *StringSlice +type StringSliceFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value *StringSlice +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f StringSliceFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f StringSliceFlag) GetName() string { + return f.Name +} + +// StringSlice looks up the value of a local StringSliceFlag, returns +// nil if not found +func (c *Context) StringSlice(name string) []string { + return lookupStringSlice(name, c.flagSet) +} + +// 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 +} + +// Uint64Flag is a flag with type uint64 +type Uint64Flag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint64 + Destination *uint64 +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f Uint64Flag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f Uint64Flag) GetName() string { + return f.Name +} + +// Uint64 looks up the value of a local Uint64Flag, returns +// 0 if not found +func (c *Context) Uint64(name string) uint64 { + return lookupUint64(name, c.flagSet) +} + +// 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 +} + +// UintFlag is a flag with type uint +type UintFlag struct { + Name string + Usage string + EnvVar string + Hidden bool + Value uint + Destination *uint +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f UintFlag) String() string { + return FlagStringer(f) +} + +// GetName returns the name of the flag +func (f UintFlag) GetName() string { + return f.Name +} + +// Uint looks up the value of a local UintFlag, returns +// 0 if not found +func (c *Context) Uint(name string) uint { + return lookupUint(name, c.flagSet) +} + +// 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 +} diff --git a/generate-flag-types b/generate-flag-types new file mode 100755 index 0000000..7fea977 --- /dev/null +++ b/generate-flag-types @@ -0,0 +1,116 @@ +#!/usr/bin/env python + +from __future__ import print_function, unicode_literals + +import io +import json +import os +import subprocess +import sys +import textwrap + + +def main(sysargs=sys.argv[:]): + _generate_flag_types(sys.argv[1], sys.argv[2]) + return 0 + + +def _generate_flag_types(output_filename, types_filename): + try: + types = _load_types(types_filename) + if os.path.exists(output_filename): + os.chmod(output_filename, 0644) + + with io.open(output_filename, 'w', encoding='utf-8') as outfile: + _write_flag_types(outfile, types) + + new_content = subprocess.check_output( + ['goimports', output_filename] + ).decode('utf-8') + + with io.open(output_filename, 'w', encoding='utf-8') as outfile: + print(new_content, file=outfile, end='') + + finally: + if os.path.exists(output_filename): + os.chmod(output_filename, 0444) + + +def _load_types(types_filename): + with io.open(types_filename, encoding='utf-8') as infile: + return json.load(infile) + + +def _write_flag_types(outfile, types): + _fwrite(outfile, """\ + package cli + + // WARNING: This file is generated! + + """) + + for typedef in types: + typedef.setdefault('doctail', '') + typedef.setdefault('context_type', typedef['type']) + typedef.setdefault('struct', True) + typedef.setdefault('dest', True) + typedef.setdefault('value', True) + + if typedef['struct']: + _fwrite(outfile, """\ + // {name}Flag is a flag with type {type}{doctail} + type {name}Flag struct {{ + Name string + Usage string + EnvVar string + Hidden bool + """.format(**typedef)) + + if typedef['value']: + _fwrite(outfile, """\ + Value {type} + """.format(**typedef)) + + if typedef['dest']: + _fwrite(outfile, """\ + Destination *{type} + """.format(**typedef)) + + _fwrite(outfile, "\n}\n\n") + + _fwrite(outfile, """\ + // String returns a readable representation of this value + // (for usage defaults) + func (f {name}Flag) String() string {{ + return FlagStringer(f) + }} + + // GetName returns the name of the flag + func (f {name}Flag) GetName() string {{ + return f.Name + }} + + // {name} looks up the value of a local {name}Flag, returns + // {context_default} if not found + func (c *Context) {name}(name string) {context_type} {{ + return lookup{name}(name, c.flagSet) + }} + + // Global{name} looks up the value of a global {name}Flag, returns + // {context_default} if not found + func (c *Context) Global{name}(name string) {context_type} {{ + if fs := lookupGlobalFlagSet(name, c); fs != nil {{ + return lookup{name}(name, fs) + }} + return {context_default} + }} + + """.format(**typedef)) + + +def _fwrite(outfile, text): + print(textwrap.dedent(text), end='', file=outfile) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/runtests b/runtests index 0a7b483..4fa4e1e 100755 --- a/runtests +++ b/runtests @@ -20,6 +20,7 @@ def main(sysargs=sys.argv[:]): 'test': _test, 'gfmxr': _gfmxr, 'toc': _toc, + 'gen': _gen, } parser = argparse.ArgumentParser() @@ -34,7 +35,7 @@ def main(sysargs=sys.argv[:]): def _test(): if check_output('go version'.split()).split()[2] < 'go1.2': - _run('go test -v .'.split()) + _run('go test -v .') return coverprofiles = [] @@ -51,7 +52,7 @@ def _test(): ]) combined_name = _combine_coverprofiles(coverprofiles) - _run('go tool cover -func={}'.format(combined_name).split()) + _run('go tool cover -func={}'.format(combined_name)) os.remove(combined_name) @@ -60,15 +61,22 @@ def _gfmxr(): def _vet(): - _run('go vet ./...'.split()) + _run('go vet ./...') def _toc(): - _run(['node_modules/.bin/markdown-toc', '-i', 'README.md']) - _run(['git', 'diff', '--quiet']) + _run('node_modules/.bin/markdown-toc -i README.md') + _run('git diff --quiet') + + +def _gen(): + _run('go generate .') + _run('git diff --quiet') def _run(command): + if hasattr(command, 'split'): + command = command.split() print('runtests: {}'.format(' '.join(command)), file=sys.stderr) check_call(command) From d1081fb23f2091cbb571cd8f1ae882f2507ee468 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 01:08:19 -0400 Subject: [PATCH 02/17] Skip go generate check on older versions --- runtests | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/runtests b/runtests index 4fa4e1e..7066932 100755 --- a/runtests +++ b/runtests @@ -70,6 +70,11 @@ def _toc(): def _gen(): + go_version = check_output('go version'.split()).split()[2] + if go_version < 'go1.4': + print('runtests: skip on {}'.format(go_version), file=sys.stderr) + return + _run('go generate .') _run('git diff --quiet') From 2455dd1f29d401e80df49f8914f6eccb759b7a79 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 01:09:21 -0400 Subject: [PATCH 03/17] Skip go generate test on Windows --- appveyor.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ae91ae8..f37ab9e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,11 +17,9 @@ install: - go version - go env - go get github.com/urfave/gfmxr/... -- go get golang.org/x/tools/cmd/goimports - go get -v -t ./... build_script: -- python runtests gen - python runtests vet - python runtests test - python runtests gfmxr From 1a9f445800d5282fe41f3939d868b05bb436a4b4 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 09:42:02 -0400 Subject: [PATCH 04/17] Try to run markdown-toc on Windows again (???) --- runtests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtests b/runtests index 7066932..77a4c44 100755 --- a/runtests +++ b/runtests @@ -65,7 +65,7 @@ def _vet(): def _toc(): - _run('node_modules/.bin/markdown-toc -i README.md') + _run('bash node_modules/.bin/markdown-toc -i README.md') _run('git diff --quiet') From ee0375e901f6c9dd041ea59f152add693f0d0314 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 09:42:33 -0400 Subject: [PATCH 05/17] Nope, forget about toc on Windows --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f37ab9e..173086e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,4 +23,3 @@ build_script: - python runtests vet - python runtests test - python runtests gfmxr -- python runtests toc From 111ea8b9d305f5baf383934c0aaead5f79dfd5eb Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 23 Jun 2016 09:59:04 -0400 Subject: [PATCH 06/17] Unbreak runtests toc target --- runtests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtests b/runtests index 77a4c44..7066932 100755 --- a/runtests +++ b/runtests @@ -65,7 +65,7 @@ def _vet(): def _toc(): - _run('bash node_modules/.bin/markdown-toc -i README.md') + _run('node_modules/.bin/markdown-toc -i README.md') _run('git diff --quiet') From 2ec9cfb7f949f8cc7e438470f1ab22630e3e4a98 Mon Sep 17 00:00:00 2001 From: Jesse Szwedko Date: Mon, 27 Jun 2016 22:28:27 -0700 Subject: [PATCH 07/17] Add missing fixes to `CHANGELOG.md` --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d975be7..4744a5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ **ATTN**: This project uses [semantic versioning](http://semver.org/). ## [Unreleased] + ### Added - `./runtests` test runner with coverage tracking by default - testing on OS X @@ -16,6 +17,9 @@ ### Fixed - Printing of command aliases in help text - Printing of visible flags for both struct and struct pointer flags +- Display the `help` subcommand when using `CommandCategories` +- No longer swallows `panic`s that occur within the `Action`s themselves when + detecting the signature of the `Action` field ## [1.17.0] - 2016-05-09 ### Added From 1efa31f08b9333f1bd4882d61f9d668a70cd902e Mon Sep 17 00:00:00 2001 From: Jesse Szwedko Date: Mon, 27 Jun 2016 22:30:56 -0700 Subject: [PATCH 08/17] Release v1.18.0 --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4744a5a..d1904fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ## [Unreleased] +## [1.18.0] - 2016-06-27 ### Added - `./runtests` test runner with coverage tracking by default - testing on OS X @@ -300,7 +301,8 @@ signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. ### Added - Initial implementation. -[Unreleased]: https://github.com/urfave/cli/compare/v1.17.0...HEAD +[Unreleased]: https://github.com/urfave/cli/compare/v1.18.0...HEAD +[1.18.0]: https://github.com/urfave/cli/compare/v1.17.0...v1.18.0 [1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0 [1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0 [1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0 From 3a8ad862a66b30452bd9e10ee5c7a60d4a86fcb7 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 10 Jul 2016 12:26:09 -0400 Subject: [PATCH 09/17] Add help text/docs for generate-flag-types script --- cli.go | 2 +- generate-flag-types | 142 +++++++++++++++++++++++++++++++------------- runtests | 4 +- 3 files changed, 104 insertions(+), 44 deletions(-) diff --git a/cli.go b/cli.go index 1e53dbf..1247a84 100644 --- a/cli.go +++ b/cli.go @@ -18,4 +18,4 @@ // } package cli -//go:generate python ./generate-flag-types flag_generated.go flag-types.json +//go:generate python ./generate-flag-types -i flag-types.json -o flag_generated.go diff --git a/generate-flag-types b/generate-flag-types index 7fea977..fc25349 100755 --- a/generate-flag-types +++ b/generate-flag-types @@ -1,44 +1,106 @@ #!/usr/bin/env python +""" +The flag types that ship with the cli library have many things in common, and +so we can take advantage of the `go generate` command to create much of the +source code from a list of definitions. These definitions attempt to cover +the parts that vary between flag types, and should evolve as needed. + +An example of the minimum definition needed is: + + { + "name": "SomeType", + "type": "sometype", + "context_default": "nil" + } + +In this example, the generated code will include a type named `SomeTypeFlag` +that is expected to wrap a value of type `sometype`. Fetching values by name +via `*cli.Context` will default to a value of `nil`. + +A more complete, albeit somewhat redundant, example showing all available +definition keys is: + + { + "name": "VeryMuchType", + "type": "*VeryMuchType", + "value": true, + "dest": false, + "doctail": " which really only wraps a []float64, oh well!", + "context_type": "[]float64", + "context_default": "nil" + } + +The meaning of each field is as follows: + + name (string) - The type "name", which will be suffixed with + `Flag` when generating the type definition + type (string) - The type that the generated `Flag` type is + expected to "contain" as its `.Value` member + value (bool) - Should the generated type have a `Value` member? + dest (bool) - Should the generated type support a destination + pointer? + doctail (string) - Additional docs for the flag type comment + context_type (string) - The literal type used in the `*cli.Context` + reader func signature + context_default (string) - The literal value used as the default by the + `*cli.Context` reader funcs when no value is + present + +""" from __future__ import print_function, unicode_literals -import io +import argparse import json import os import subprocess import sys +import tempfile import textwrap -def main(sysargs=sys.argv[:]): - _generate_flag_types(sys.argv[1], sys.argv[2]) - return 0 - +class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, + argparse.RawDescriptionHelpFormatter): + pass -def _generate_flag_types(output_filename, types_filename): - try: - types = _load_types(types_filename) - if os.path.exists(output_filename): - os.chmod(output_filename, 0644) - with io.open(output_filename, 'w', encoding='utf-8') as outfile: - _write_flag_types(outfile, types) +def main(sysargs=sys.argv[:]): + parser = argparse.ArgumentParser( + description='Generate flag type code!', + formatter_class=_FancyFormatter) + parser.add_argument( + '-i', '--in-json', + type=argparse.FileType('r'), + default=sys.stdin, + help='Input JSON file which defines each type to be generated' + ) + parser.add_argument( + '-o', '--out-go', + type=argparse.FileType('w'), + default=sys.stdout, + help='Output file/stream to which generated source will be written' + ) + parser.epilog = __doc__ + + args = parser.parse_args(sysargs[1:]) + _generate_flag_types(args.out_go, args.in_json) + return 0 - new_content = subprocess.check_output( - ['goimports', output_filename] - ).decode('utf-8') - with io.open(output_filename, 'w', encoding='utf-8') as outfile: - print(new_content, file=outfile, end='') +def _generate_flag_types(output_go, input_json): + types = json.load(input_json) - finally: - if os.path.exists(output_filename): - os.chmod(output_filename, 0444) + tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) + _write_flag_types(tmp, types) + tmp.close() + new_content = subprocess.check_output( + ['goimports', tmp.name] + ).decode('utf-8') -def _load_types(types_filename): - with io.open(types_filename, encoding='utf-8') as infile: - return json.load(infile) + print(new_content, file=output_go, end='') + output_go.flush() + os.remove(tmp.name) def _write_flag_types(outfile, types): @@ -52,31 +114,29 @@ def _write_flag_types(outfile, types): for typedef in types: typedef.setdefault('doctail', '') typedef.setdefault('context_type', typedef['type']) - typedef.setdefault('struct', True) typedef.setdefault('dest', True) typedef.setdefault('value', True) - if typedef['struct']: + _fwrite(outfile, """\ + // {name}Flag is a flag with type {type}{doctail} + type {name}Flag struct {{ + Name string + Usage string + EnvVar string + Hidden bool + """.format(**typedef)) + + if typedef['value']: _fwrite(outfile, """\ - // {name}Flag is a flag with type {type}{doctail} - type {name}Flag struct {{ - Name string - Usage string - EnvVar string - Hidden bool + Value {type} """.format(**typedef)) - if typedef['value']: - _fwrite(outfile, """\ - Value {type} - """.format(**typedef)) - - if typedef['dest']: - _fwrite(outfile, """\ - Destination *{type} - """.format(**typedef)) + if typedef['dest']: + _fwrite(outfile, """\ + Destination *{type} + """.format(**typedef)) - _fwrite(outfile, "\n}\n\n") + _fwrite(outfile, "\n}\n\n") _fwrite(outfile, """\ // String returns a readable representation of this value diff --git a/runtests b/runtests index 7066932..fda1564 100755 --- a/runtests +++ b/runtests @@ -66,7 +66,7 @@ def _vet(): def _toc(): _run('node_modules/.bin/markdown-toc -i README.md') - _run('git diff --quiet') + _run('git diff --exit-code') def _gen(): @@ -76,7 +76,7 @@ def _gen(): return _run('go generate .') - _run('git diff --quiet') + _run('git diff --exit-code') def _run(command): From 77f1130e6514c23e8de3777a57755b2af063bafc Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 10 Jul 2016 12:50:57 -0400 Subject: [PATCH 10/17] Generate flag type lookup funcs --- context.go | 152 ----------------------------------------- flag-types.json | 38 +++++++---- flag_generated.go | 162 +++++++++++++++++++++++++++++++++++++++++++- generate-flag-types | 24 ++++++- 4 files changed, 209 insertions(+), 167 deletions(-) diff --git a/context.go b/context.go index 762d389..14ad3f7 100644 --- a/context.go +++ b/context.go @@ -3,9 +3,7 @@ package cli import ( "errors" "flag" - "strconv" "strings" - "time" ) // Context is a type that is passed through to @@ -173,156 +171,6 @@ func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { return nil } -func lookupInt(name string, set *flag.FlagSet) int { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return int(val) - } - - return 0 -} - -func lookupInt64(name string, set *flag.FlagSet) int64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseInt(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupUint(name string, set *flag.FlagSet) uint { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return uint(val) - } - - return 0 -} - -func lookupUint64(name string, set *flag.FlagSet) uint64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseUint(f.Value.String(), 0, 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupDuration(name string, set *flag.FlagSet) time.Duration { - f := set.Lookup(name) - if f != nil { - val, err := time.ParseDuration(f.Value.String()) - if err == nil { - return val - } - } - - return 0 -} - -func lookupFloat64(name string, set *flag.FlagSet) float64 { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseFloat(f.Value.String(), 64) - if err != nil { - return 0 - } - return val - } - - return 0 -} - -func lookupString(name string, set *flag.FlagSet) string { - f := set.Lookup(name) - if f != nil { - return f.Value.String() - } - - return "" -} - -func lookupStringSlice(name string, set *flag.FlagSet) []string { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*StringSlice)).Value() - - } - - return nil -} - -func lookupIntSlice(name string, set *flag.FlagSet) []int { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*IntSlice)).Value() - - } - - return nil -} - -func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { - f := set.Lookup(name) - if f != nil { - return (f.Value.(*Int64Slice)).Value() - - } - - return nil -} - -func lookupGeneric(name string, set *flag.FlagSet) interface{} { - f := set.Lookup(name) - if f != nil { - return f.Value - } - return nil -} - -func lookupBool(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return false - } - return val - } - - return false -} - -func lookupBoolT(name string, set *flag.FlagSet) bool { - f := set.Lookup(name) - if f != nil { - val, err := strconv.ParseBool(f.Value.String()) - if err != nil { - return true - } - return val - } - - return false -} - func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { switch ff.Value.(type) { case *StringSlice: diff --git a/flag-types.json b/flag-types.json index 2085350..1223107 100644 --- a/flag-types.json +++ b/flag-types.json @@ -3,25 +3,29 @@ "name": "Bool", "type": "bool", "value": false, - "context_default": "false" + "context_default": "false", + "parser": "strconv.ParseBool(f.Value.String())" }, { "name": "BoolT", "type": "bool", "value": false, "doctail": " that is true by default", - "context_default": "false" + "context_default": "false", + "parser": "strconv.ParseBool(f.Value.String())" }, { "name": "Duration", "type": "time.Duration", "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", - "context_default": "0" + "context_default": "0", + "parser": "time.ParseDuration(f.Value.String())" }, { "name": "Float64", "type": "float64", - "context_default": "0" + "context_default": "0", + "parser": "strconv.ParseFloat(f.Value.String(), 64)" }, { "name": "Generic", @@ -33,47 +37,57 @@ { "name": "Int64", "type": "int64", - "context_default": "0" + "context_default": "0", + "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" }, { "name": "Int", "type": "int", - "context_default": "0" + "context_default": "0", + "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", + "parser_cast": "int(parsed)" }, { "name": "IntSlice", "type": "*IntSlice", "dest": false, "context_default": "nil", - "context_type": "[]int" + "context_type": "[]int", + "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" }, { "name": "Int64Slice", "type": "*Int64Slice", "dest": false, "context_default": "nil", - "context_type": "[]int64" + "context_type": "[]int64", + "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" }, { "name": "String", "type": "string", - "context_default": "\"\"" + "context_default": "\"\"", + "parser": "f.Value.String(), error(nil)" }, { "name": "StringSlice", "type": "*StringSlice", "dest": false, "context_default": "nil", - "context_type": "[]string" + "context_type": "[]string", + "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" }, { "name": "Uint64", "type": "uint64", - "context_default": "0" + "context_default": "0", + "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" }, { "name": "Uint", "type": "uint", - "context_default": "0" + "context_default": "0", + "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", + "parser_cast": "uint(parsed)" } ] diff --git a/flag_generated.go b/flag_generated.go index 5cbdb83..491b619 100644 --- a/flag_generated.go +++ b/flag_generated.go @@ -1,6 +1,10 @@ package cli -import "time" +import ( + "flag" + "strconv" + "time" +) // WARNING: This file is generated! @@ -39,6 +43,18 @@ func (c *Context) GlobalBool(name string) bool { return false } +func lookupBool(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + // BoolTFlag is a flag with type bool that is true by default type BoolTFlag struct { Name string @@ -74,6 +90,18 @@ func (c *Context) GlobalBoolT(name string) bool { return false } +func lookupBoolT(name string, set *flag.FlagSet) bool { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseBool(f.Value.String()) + if err != nil { + return false + } + return parsed + } + return false +} + // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) type DurationFlag struct { Name string @@ -110,6 +138,18 @@ func (c *Context) GlobalDuration(name string) time.Duration { return 0 } +func lookupDuration(name string, set *flag.FlagSet) time.Duration { + f := set.Lookup(name) + if f != nil { + parsed, err := time.ParseDuration(f.Value.String()) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + // Float64Flag is a flag with type float64 type Float64Flag struct { Name string @@ -146,6 +186,18 @@ func (c *Context) GlobalFloat64(name string) float64 { return 0 } +func lookupFloat64(name string, set *flag.FlagSet) float64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseFloat(f.Value.String(), 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + // GenericFlag is a flag with type Generic type GenericFlag struct { Name string @@ -181,6 +233,18 @@ func (c *Context) GlobalGeneric(name string) interface{} { return nil } +func lookupGeneric(name string, set *flag.FlagSet) interface{} { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value, error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + // Int64Flag is a flag with type int64 type Int64Flag struct { Name string @@ -217,6 +281,18 @@ func (c *Context) GlobalInt64(name string) int64 { return 0 } +func lookupInt64(name string, set *flag.FlagSet) int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + // IntFlag is a flag with type int type IntFlag struct { Name string @@ -253,6 +329,18 @@ func (c *Context) GlobalInt(name string) int { return 0 } +func lookupInt(name string, set *flag.FlagSet) int { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseInt(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return int(parsed) + } + return 0 +} + // IntSliceFlag is a flag with type *IntSlice type IntSliceFlag struct { Name string @@ -288,6 +376,18 @@ func (c *Context) GlobalIntSlice(name string) []int { return nil } +func lookupIntSlice(name string, set *flag.FlagSet) []int { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*IntSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + // Int64SliceFlag is a flag with type *Int64Slice type Int64SliceFlag struct { Name string @@ -323,6 +423,18 @@ func (c *Context) GlobalInt64Slice(name string) []int64 { return nil } +func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*Int64Slice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + // StringFlag is a flag with type string type StringFlag struct { Name string @@ -359,6 +471,18 @@ func (c *Context) GlobalString(name string) string { return "" } +func lookupString(name string, set *flag.FlagSet) string { + f := set.Lookup(name) + if f != nil { + parsed, err := f.Value.String(), error(nil) + if err != nil { + return "" + } + return parsed + } + return "" +} + // StringSliceFlag is a flag with type *StringSlice type StringSliceFlag struct { Name string @@ -394,6 +518,18 @@ func (c *Context) GlobalStringSlice(name string) []string { return nil } +func lookupStringSlice(name string, set *flag.FlagSet) []string { + f := set.Lookup(name) + if f != nil { + parsed, err := (f.Value.(*StringSlice)).Value(), error(nil) + if err != nil { + return nil + } + return parsed + } + return nil +} + // Uint64Flag is a flag with type uint64 type Uint64Flag struct { Name string @@ -430,6 +566,18 @@ func (c *Context) GlobalUint64(name string) uint64 { return 0 } +func lookupUint64(name string, set *flag.FlagSet) uint64 { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return parsed + } + return 0 +} + // UintFlag is a flag with type uint type UintFlag struct { Name string @@ -465,3 +613,15 @@ func (c *Context) GlobalUint(name string) uint { } return 0 } + +func lookupUint(name string, set *flag.FlagSet) uint { + f := set.Lookup(name) + if f != nil { + parsed, err := strconv.ParseUint(f.Value.String(), 0, 64) + if err != nil { + return 0 + } + return uint(parsed) + } + return 0 +} diff --git a/generate-flag-types b/generate-flag-types index fc25349..9bf0998 100755 --- a/generate-flag-types +++ b/generate-flag-types @@ -27,7 +27,9 @@ definition keys is: "dest": false, "doctail": " which really only wraps a []float64, oh well!", "context_type": "[]float64", - "context_default": "nil" + "context_default": "nil", + "parser": "parseVeryMuchType(f.Value.String())", + "parser_cast": "[]float64(parsed)" } The meaning of each field is as follows: @@ -45,7 +47,11 @@ The meaning of each field is as follows: context_default (string) - The literal value used as the default by the `*cli.Context` reader funcs when no value is present - + parser (string) - Literal code used to parse the flag `f`, + expected to have a return signature of + (value, error) + parser_cast (string) - Literal code used to cast the `parsed` value + returned from the `parser` code """ from __future__ import print_function, unicode_literals @@ -116,6 +122,9 @@ def _write_flag_types(outfile, types): typedef.setdefault('context_type', typedef['type']) typedef.setdefault('dest', True) typedef.setdefault('value', True) + typedef.setdefault('parser', 'f.Value, error(nil)') + typedef.setdefault('parser_cast', 'parsed') + _fwrite(outfile, """\ // {name}Flag is a flag with type {type}{doctail} @@ -165,6 +174,17 @@ def _write_flag_types(outfile, types): return {context_default} }} + func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ + f := set.Lookup(name) + if f != nil {{ + parsed, err := {parser} + if err != nil {{ + return {context_default} + }} + return {parser_cast} + }} + return {context_default} + }} """.format(**typedef)) From fa120b0c1d65175cbcdbb897e413735d22b7e381 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sun, 10 Jul 2016 19:27:39 -0400 Subject: [PATCH 11/17] Drop testing of go1.1.2 since it's already a fairly diverged set of tests, and the fact that it passes appears to be causing issues with overall CI build status, which is probably some odd issue that surfaces because we're using `matrix.include` --- .travis.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 273d017..ab0a7f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,12 +20,6 @@ matrix: include: - go: 1.6.2 os: osx - - go: 1.1.2 - install: go get -v . - before_script: echo skipping gfmxr on $TRAVIS_GO_VERSION - script: - - ./runtests vet - - ./runtests test before_script: - go get github.com/urfave/gfmxr/... From bef215fe3ed717d51740539f305aad331d4b9f0d Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Mon, 11 Jul 2016 07:39:58 +0100 Subject: [PATCH 12/17] app: Allocate Metadata map automatically --- app.go | 4 ++++ command_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/app.go b/app.go index a046c01..0755bb6 100644 --- a/app.go +++ b/app.go @@ -160,6 +160,10 @@ func (a *App) Setup() { a.categories = a.categories.AddCommand(command.Category, command) } sort.Sort(a.categories) + + if a.Metadata == nil { + a.Metadata = make(map[string]interface{}) + } } // Run is the entry point to the cli app. Parses the arguments slice and routes diff --git a/command_test.go b/command_test.go index 6608254..1d5a711 100644 --- a/command_test.go +++ b/command_test.go @@ -73,6 +73,54 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { } } +func TestCommand_Run_BeforeSavesMetadata(t *testing.T) { + var receivedMsgFromAction string + var receivedMsgFromAfter string + + app := NewApp() + app.Commands = []Command{ + { + Name: "bar", + Before: func(c *Context) error { + c.App.Metadata["msg"] = "hello world" + return nil + }, + Action: func(c *Context) error { + msg, ok := c.App.Metadata["msg"] + if !ok { + return errors.New("msg not found") + } + receivedMsgFromAction = msg.(string) + return nil + }, + After: func(c *Context) error { + msg, ok := c.App.Metadata["msg"] + if !ok { + return errors.New("msg not found") + } + receivedMsgFromAfter = msg.(string) + return nil + }, + }, + } + + err := app.Run([]string{"foo", "bar"}) + if err != nil { + t.Fatalf("expected no error from Run, got %s", err) + } + + expectedMsg := "hello world" + + if receivedMsgFromAction != expectedMsg { + t.Fatalf("expected msg from Action to match. Given: %q\nExpected: %q", + receivedMsgFromAction, expectedMsg) + } + if receivedMsgFromAfter != expectedMsg { + t.Fatalf("expected msg from After to match. Given: %q\nExpected: %q", + receivedMsgFromAction, expectedMsg) + } +} + func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { app := NewApp() app.Commands = []Command{ From 06f64bd31d9e873d15133b0dc374bad55c1f88df Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 11 Jul 2016 05:16:14 -0400 Subject: [PATCH 13/17] Update docs and change log regarding go1.1 drop --- CHANGELOG.md | 2 ++ README.md | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d1904fe..daacd76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ **ATTN**: This project uses [semantic versioning](http://semver.org/). ## [Unreleased] +### Changed +- Raise minimum tested/supported Go version to 1.2+ ## [1.18.0] - 2016-06-27 ### Added diff --git a/README.md b/README.md index ebb1d74..0ffa92f 100644 --- a/README.md +++ b/README.md @@ -60,18 +60,16 @@ organized, and expressive! ## Installation -Make sure you have a working Go environment. Go version 1.1+ is required for -core cli, whereas use of the [`./altsrc`](./altsrc) input extensions requires Go -version 1.2+. [See the install -instructions](http://golang.org/doc/install.html). +Make sure you have a working Go environment. Go version 1.2+ is supported. [See +the install instructions for Go](http://golang.org/doc/install.html). To install cli, simply run: ``` $ go get github.com/urfave/cli ``` -Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands -can be easily used: +Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can +be easily used: ``` export PATH=$PATH:$GOPATH/bin ``` From c3b03b8437db746cd0b1bcf48dbea12b0c8f4484 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 11 Jul 2016 06:01:08 -0400 Subject: [PATCH 14/17] Adding flag type generation for altsrc and a mention of this whole thing in the change log --- CHANGELOG.md | 2 + altsrc/altsrc.go | 3 + altsrc/flag.go | 176 --------------------------- altsrc/flag_generated.go | 256 +++++++++++++++++++++++++++++++++++++++ cli.go | 2 +- generate-flag-types | 88 +++++++++++--- 6 files changed, 330 insertions(+), 197 deletions(-) create mode 100644 altsrc/altsrc.go create mode 100644 altsrc/flag_generated.go diff --git a/CHANGELOG.md b/CHANGELOG.md index d1904fe..0f74c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ **ATTN**: This project uses [semantic versioning](http://semver.org/). ## [Unreleased] +### Added +- Flag type code generation via `go generate` ## [1.18.0] - 2016-06-27 ### Added diff --git a/altsrc/altsrc.go b/altsrc/altsrc.go new file mode 100644 index 0000000..ac34bf6 --- /dev/null +++ b/altsrc/altsrc.go @@ -0,0 +1,3 @@ +package altsrc + +//go:generate python ../generate-flag-types altsrc -i ../flag-types.json -o flag_generated.go diff --git a/altsrc/flag.go b/altsrc/flag.go index 3e44d02..8add2fb 100644 --- a/altsrc/flag.go +++ b/altsrc/flag.go @@ -1,7 +1,6 @@ package altsrc import ( - "flag" "fmt" "os" "strconv" @@ -63,18 +62,6 @@ func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context } } -// GenericFlag is the flag type that wraps cli.GenericFlag to allow -// for other values to be specified -type GenericFlag struct { - cli.GenericFlag - set *flag.FlagSet -} - -// NewGenericFlag creates a new GenericFlag -func NewGenericFlag(flag cli.GenericFlag) *GenericFlag { - return &GenericFlag{GenericFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a generic value to the flagSet if required func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -94,25 +81,6 @@ func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourc return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped GenericFlag.Apply -func (f *GenericFlag) Apply(set *flag.FlagSet) { - f.set = set - f.GenericFlag.Apply(set) -} - -// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow -// for other values to be specified -type StringSliceFlag struct { - cli.StringSliceFlag - set *flag.FlagSet -} - -// NewStringSliceFlag creates a new StringSliceFlag -func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag { - return &StringSliceFlag{StringSliceFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a StringSlice value to the flagSet if required func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -135,25 +103,6 @@ func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputS return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped StringSliceFlag.Apply -func (f *StringSliceFlag) Apply(set *flag.FlagSet) { - f.set = set - f.StringSliceFlag.Apply(set) -} - -// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow -// for other values to be specified -type IntSliceFlag struct { - cli.IntSliceFlag - set *flag.FlagSet -} - -// NewIntSliceFlag creates a new IntSliceFlag -func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag { - return &IntSliceFlag{IntSliceFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a IntSlice value if required func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -176,25 +125,6 @@ func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSour return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped IntSliceFlag.Apply -func (f *IntSliceFlag) Apply(set *flag.FlagSet) { - f.set = set - f.IntSliceFlag.Apply(set) -} - -// BoolFlag is the flag type that wraps cli.BoolFlag to allow -// for other values to be specified -type BoolFlag struct { - cli.BoolFlag - set *flag.FlagSet -} - -// NewBoolFlag creates a new BoolFlag -func NewBoolFlag(flag cli.BoolFlag) *BoolFlag { - return &BoolFlag{BoolFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a Bool value to the flagSet if required func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -213,25 +143,6 @@ func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceCo return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped BoolFlag.Apply -func (f *BoolFlag) Apply(set *flag.FlagSet) { - f.set = set - f.BoolFlag.Apply(set) -} - -// BoolTFlag is the flag type that wraps cli.BoolTFlag to allow -// for other values to be specified -type BoolTFlag struct { - cli.BoolTFlag - set *flag.FlagSet -} - -// NewBoolTFlag creates a new BoolTFlag -func NewBoolTFlag(flag cli.BoolTFlag) *BoolTFlag { - return &BoolTFlag{BoolTFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a BoolT value to the flagSet if required func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -250,26 +161,6 @@ func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceC return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped BoolTFlag.Apply -func (f *BoolTFlag) Apply(set *flag.FlagSet) { - f.set = set - - f.BoolTFlag.Apply(set) -} - -// StringFlag is the flag type that wraps cli.StringFlag to allow -// for other values to be specified -type StringFlag struct { - cli.StringFlag - set *flag.FlagSet -} - -// NewStringFlag creates a new StringFlag -func NewStringFlag(flag cli.StringFlag) *StringFlag { - return &StringFlag{StringFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a String value to the flagSet if required func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -288,26 +179,6 @@ func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSource return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped StringFlag.Apply -func (f *StringFlag) Apply(set *flag.FlagSet) { - f.set = set - - f.StringFlag.Apply(set) -} - -// IntFlag is the flag type that wraps cli.IntFlag to allow -// for other values to be specified -type IntFlag struct { - cli.IntFlag - set *flag.FlagSet -} - -// NewIntFlag creates a new IntFlag -func NewIntFlag(flag cli.IntFlag) *IntFlag { - return &IntFlag{IntFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a int value to the flagSet if required func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -326,25 +197,6 @@ func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceCon return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped IntFlag.Apply -func (f *IntFlag) Apply(set *flag.FlagSet) { - f.set = set - f.IntFlag.Apply(set) -} - -// DurationFlag is the flag type that wraps cli.DurationFlag to allow -// for other values to be specified -type DurationFlag struct { - cli.DurationFlag - set *flag.FlagSet -} - -// NewDurationFlag creates a new DurationFlag -func NewDurationFlag(flag cli.DurationFlag) *DurationFlag { - return &DurationFlag{DurationFlag: flag, set: nil} -} - // ApplyInputSourceValue applies a Duration value to the flagSet if required func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -363,26 +215,6 @@ func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSour return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped DurationFlag.Apply -func (f *DurationFlag) Apply(set *flag.FlagSet) { - f.set = set - - f.DurationFlag.Apply(set) -} - -// Float64Flag is the flag type that wraps cli.Float64Flag to allow -// for other values to be specified -type Float64Flag struct { - cli.Float64Flag - set *flag.FlagSet -} - -// NewFloat64Flag creates a new Float64Flag -func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag { - return &Float64Flag{Float64Flag: flag, set: nil} -} - // ApplyInputSourceValue applies a Float64 value to the flagSet if required func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { if f.set != nil { @@ -402,14 +234,6 @@ func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourc return nil } -// Apply saves the flagSet for later usage then calls -// the wrapped Float64Flag.Apply -func (f *Float64Flag) Apply(set *flag.FlagSet) { - f.set = set - - f.Float64Flag.Apply(set) -} - func isEnvVarSet(envVars string) bool { for _, envVar := range strings.Split(envVars, ",") { envVar = strings.TrimSpace(envVar) diff --git a/altsrc/flag_generated.go b/altsrc/flag_generated.go new file mode 100644 index 0000000..fa76724 --- /dev/null +++ b/altsrc/flag_generated.go @@ -0,0 +1,256 @@ +package altsrc + +import ( + "flag" + + "github.com/urfave/cli" +) + +// WARNING: This file is generated! + +// BoolFlag is the flag type that wraps cli.BoolFlag to allow +// for other values to be specified +type BoolFlag struct { + cli.BoolFlag + set *flag.FlagSet +} + +// NewBoolFlag creates a new BoolFlag +func NewBoolFlag(fl cli.BoolFlag) *BoolFlag { + return &BoolFlag{BoolFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped BoolFlag.Apply +func (f *BoolFlag) Apply(set *flag.FlagSet) { + f.set = set + f.BoolFlag.Apply(set) +} + +// BoolTFlag is the flag type that wraps cli.BoolTFlag to allow +// for other values to be specified +type BoolTFlag struct { + cli.BoolTFlag + set *flag.FlagSet +} + +// NewBoolTFlag creates a new BoolTFlag +func NewBoolTFlag(fl cli.BoolTFlag) *BoolTFlag { + return &BoolTFlag{BoolTFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped BoolTFlag.Apply +func (f *BoolTFlag) Apply(set *flag.FlagSet) { + f.set = set + f.BoolTFlag.Apply(set) +} + +// DurationFlag is the flag type that wraps cli.DurationFlag to allow +// for other values to be specified +type DurationFlag struct { + cli.DurationFlag + set *flag.FlagSet +} + +// NewDurationFlag creates a new DurationFlag +func NewDurationFlag(fl cli.DurationFlag) *DurationFlag { + return &DurationFlag{DurationFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped DurationFlag.Apply +func (f *DurationFlag) Apply(set *flag.FlagSet) { + f.set = set + f.DurationFlag.Apply(set) +} + +// Float64Flag is the flag type that wraps cli.Float64Flag to allow +// for other values to be specified +type Float64Flag struct { + cli.Float64Flag + set *flag.FlagSet +} + +// NewFloat64Flag creates a new Float64Flag +func NewFloat64Flag(fl cli.Float64Flag) *Float64Flag { + return &Float64Flag{Float64Flag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped Float64Flag.Apply +func (f *Float64Flag) Apply(set *flag.FlagSet) { + f.set = set + f.Float64Flag.Apply(set) +} + +// GenericFlag is the flag type that wraps cli.GenericFlag to allow +// for other values to be specified +type GenericFlag struct { + cli.GenericFlag + set *flag.FlagSet +} + +// NewGenericFlag creates a new GenericFlag +func NewGenericFlag(fl cli.GenericFlag) *GenericFlag { + return &GenericFlag{GenericFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped GenericFlag.Apply +func (f *GenericFlag) Apply(set *flag.FlagSet) { + f.set = set + f.GenericFlag.Apply(set) +} + +// Int64Flag is the flag type that wraps cli.Int64Flag to allow +// for other values to be specified +type Int64Flag struct { + cli.Int64Flag + set *flag.FlagSet +} + +// NewInt64Flag creates a new Int64Flag +func NewInt64Flag(fl cli.Int64Flag) *Int64Flag { + return &Int64Flag{Int64Flag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped Int64Flag.Apply +func (f *Int64Flag) Apply(set *flag.FlagSet) { + f.set = set + f.Int64Flag.Apply(set) +} + +// IntFlag is the flag type that wraps cli.IntFlag to allow +// for other values to be specified +type IntFlag struct { + cli.IntFlag + set *flag.FlagSet +} + +// NewIntFlag creates a new IntFlag +func NewIntFlag(fl cli.IntFlag) *IntFlag { + return &IntFlag{IntFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped IntFlag.Apply +func (f *IntFlag) Apply(set *flag.FlagSet) { + f.set = set + f.IntFlag.Apply(set) +} + +// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow +// for other values to be specified +type IntSliceFlag struct { + cli.IntSliceFlag + set *flag.FlagSet +} + +// NewIntSliceFlag creates a new IntSliceFlag +func NewIntSliceFlag(fl cli.IntSliceFlag) *IntSliceFlag { + return &IntSliceFlag{IntSliceFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped IntSliceFlag.Apply +func (f *IntSliceFlag) Apply(set *flag.FlagSet) { + f.set = set + f.IntSliceFlag.Apply(set) +} + +// Int64SliceFlag is the flag type that wraps cli.Int64SliceFlag to allow +// for other values to be specified +type Int64SliceFlag struct { + cli.Int64SliceFlag + set *flag.FlagSet +} + +// NewInt64SliceFlag creates a new Int64SliceFlag +func NewInt64SliceFlag(fl cli.Int64SliceFlag) *Int64SliceFlag { + return &Int64SliceFlag{Int64SliceFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped Int64SliceFlag.Apply +func (f *Int64SliceFlag) Apply(set *flag.FlagSet) { + f.set = set + f.Int64SliceFlag.Apply(set) +} + +// StringFlag is the flag type that wraps cli.StringFlag to allow +// for other values to be specified +type StringFlag struct { + cli.StringFlag + set *flag.FlagSet +} + +// NewStringFlag creates a new StringFlag +func NewStringFlag(fl cli.StringFlag) *StringFlag { + return &StringFlag{StringFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped StringFlag.Apply +func (f *StringFlag) Apply(set *flag.FlagSet) { + f.set = set + f.StringFlag.Apply(set) +} + +// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow +// for other values to be specified +type StringSliceFlag struct { + cli.StringSliceFlag + set *flag.FlagSet +} + +// NewStringSliceFlag creates a new StringSliceFlag +func NewStringSliceFlag(fl cli.StringSliceFlag) *StringSliceFlag { + return &StringSliceFlag{StringSliceFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped StringSliceFlag.Apply +func (f *StringSliceFlag) Apply(set *flag.FlagSet) { + f.set = set + f.StringSliceFlag.Apply(set) +} + +// Uint64Flag is the flag type that wraps cli.Uint64Flag to allow +// for other values to be specified +type Uint64Flag struct { + cli.Uint64Flag + set *flag.FlagSet +} + +// NewUint64Flag creates a new Uint64Flag +func NewUint64Flag(fl cli.Uint64Flag) *Uint64Flag { + return &Uint64Flag{Uint64Flag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped Uint64Flag.Apply +func (f *Uint64Flag) Apply(set *flag.FlagSet) { + f.set = set + f.Uint64Flag.Apply(set) +} + +// UintFlag is the flag type that wraps cli.UintFlag to allow +// for other values to be specified +type UintFlag struct { + cli.UintFlag + set *flag.FlagSet +} + +// NewUintFlag creates a new UintFlag +func NewUintFlag(fl cli.UintFlag) *UintFlag { + return &UintFlag{UintFlag: fl, set: nil} +} + +// Apply saves the flagSet for later usage calls, then calls the +// wrapped UintFlag.Apply +func (f *UintFlag) Apply(set *flag.FlagSet) { + f.set = set + f.UintFlag.Apply(set) +} diff --git a/cli.go b/cli.go index 1247a84..74fd101 100644 --- a/cli.go +++ b/cli.go @@ -18,4 +18,4 @@ // } package cli -//go:generate python ./generate-flag-types -i flag-types.json -o flag_generated.go +//go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go diff --git a/generate-flag-types b/generate-flag-types index 9bf0998..e48e7fd 100755 --- a/generate-flag-types +++ b/generate-flag-types @@ -13,9 +13,9 @@ An example of the minimum definition needed is: "context_default": "nil" } -In this example, the generated code will include a type named `SomeTypeFlag` -that is expected to wrap a value of type `sometype`. Fetching values by name -via `*cli.Context` will default to a value of `nil`. +In this example, the code generated for the `cli` package will include a type +named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. +Fetching values by name via `*cli.Context` will default to a value of `nil`. A more complete, albeit somewhat redundant, example showing all available definition keys is: @@ -36,12 +36,14 @@ The meaning of each field is as follows: name (string) - The type "name", which will be suffixed with `Flag` when generating the type definition - type (string) - The type that the generated `Flag` type is - expected to "contain" as its `.Value` member - value (bool) - Should the generated type have a `Value` member? - dest (bool) - Should the generated type support a destination - pointer? - doctail (string) - Additional docs for the flag type comment + for `cli` and the wrapper type for `altsrc` + type (string) - The type that the generated `Flag` type for `cli` + is expected to "contain" as its `.Value` member + value (bool) - Should the generated `cli` type have a `Value` + member? + dest (bool) - Should the generated `cli` type support a + destination pointer? + doctail (string) - Additional docs for the `cli` flag type comment context_type (string) - The literal type used in the `*cli.Context` reader func signature context_default (string) - The literal value used as the default by the @@ -74,6 +76,11 @@ def main(sysargs=sys.argv[:]): parser = argparse.ArgumentParser( description='Generate flag type code!', formatter_class=_FancyFormatter) + parser.add_argument( + 'package', + type=str, default='cli', choices=['cli', 'altsrc'], + help='Package for which flag types will be generated' + ) parser.add_argument( '-i', '--in-json', type=argparse.FileType('r'), @@ -89,15 +96,15 @@ def main(sysargs=sys.argv[:]): parser.epilog = __doc__ args = parser.parse_args(sysargs[1:]) - _generate_flag_types(args.out_go, args.in_json) + _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) return 0 -def _generate_flag_types(output_go, input_json): +def _generate_flag_types(writefunc, output_go, input_json): types = json.load(input_json) tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) - _write_flag_types(tmp, types) + writefunc(tmp, types) tmp.close() new_content = subprocess.check_output( @@ -109,7 +116,16 @@ def _generate_flag_types(output_go, input_json): os.remove(tmp.name) -def _write_flag_types(outfile, types): +def _set_typedef_defaults(typedef): + typedef.setdefault('doctail', '') + typedef.setdefault('context_type', typedef['type']) + typedef.setdefault('dest', True) + typedef.setdefault('value', True) + typedef.setdefault('parser', 'f.Value, error(nil)') + typedef.setdefault('parser_cast', 'parsed') + + +def _write_cli_flag_types(outfile, types): _fwrite(outfile, """\ package cli @@ -118,13 +134,7 @@ def _write_flag_types(outfile, types): """) for typedef in types: - typedef.setdefault('doctail', '') - typedef.setdefault('context_type', typedef['type']) - typedef.setdefault('dest', True) - typedef.setdefault('value', True) - typedef.setdefault('parser', 'f.Value, error(nil)') - typedef.setdefault('parser_cast', 'parsed') - + _set_typedef_defaults(typedef) _fwrite(outfile, """\ // {name}Flag is a flag with type {type}{doctail} @@ -188,9 +198,47 @@ def _write_flag_types(outfile, types): """.format(**typedef)) +def _write_altsrc_flag_types(outfile, types): + _fwrite(outfile, """\ + package altsrc + + // WARNING: This file is generated! + + """) + + for typedef in types: + _set_typedef_defaults(typedef) + + _fwrite(outfile, """\ + // {name}Flag is the flag type that wraps cli.{name}Flag to allow + // for other values to be specified + type {name}Flag struct {{ + cli.{name}Flag + set *flag.FlagSet + }} + + // New{name}Flag creates a new {name}Flag + func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{ + return &{name}Flag{{{name}Flag: fl, set: nil}} + }} + + // Apply saves the flagSet for later usage calls, then calls the + // wrapped {name}Flag.Apply + func (f *{name}Flag) Apply(set *flag.FlagSet) {{ + f.set = set + f.{name}Flag.Apply(set) + }} + """.format(**typedef)) + + def _fwrite(outfile, text): print(textwrap.dedent(text), end='', file=outfile) +_WRITEFUNCS = { + 'cli': _write_cli_flag_types, + 'altsrc': _write_altsrc_flag_types +} + if __name__ == '__main__': sys.exit(main()) From 8d976fe182232580613656aab99fc64953eeba83 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Mon, 11 Jul 2016 06:02:15 -0400 Subject: [PATCH 15/17] Get package choices from source of truth --- generate-flag-types | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate-flag-types b/generate-flag-types index e48e7fd..8567f5d 100755 --- a/generate-flag-types +++ b/generate-flag-types @@ -78,7 +78,7 @@ def main(sysargs=sys.argv[:]): formatter_class=_FancyFormatter) parser.add_argument( 'package', - type=str, default='cli', choices=['cli', 'altsrc'], + type=str, default='cli', choices=_WRITEFUNCS.keys(), help='Package for which flag types will be generated' ) parser.add_argument( From 65da20beab3e0596b247efee5ffe55bec8eed4d8 Mon Sep 17 00:00:00 2001 From: Jesse Szwedko Date: Wed, 13 Jul 2016 14:44:13 -0700 Subject: [PATCH 16/17] Correctly show help message if `-h` is provided to subcommand Currently, if an action is specified on a subcommand, it ignores the `-h` and `--help` flags if passed to the subcommand, e.g.: `foo bar -h` would call the default action on `bar` rather than show the help documentation. Fixes #477 --- app_test.go | 1 + help.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app_test.go b/app_test.go index 9c6b960..b0b02e6 100644 --- a/app_test.go +++ b/app_test.go @@ -908,6 +908,7 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) { Name: "foo", Description: "descriptive wall of text about how it does foo things", Subcommands: []Command{subCmdBar, subCmdBaz}, + Action: func(c *Context) error { return nil }, } app.Commands = []Command{cmd} diff --git a/help.go b/help.go index 0f4cf14..ba34719 100644 --- a/help.go +++ b/help.go @@ -240,7 +240,7 @@ func checkCommandHelp(c *Context, name string) bool { } func checkSubcommandHelp(c *Context) bool { - if c.GlobalBool("h") || c.GlobalBool("help") { + if c.Bool("h") || c.Bool("help") { ShowSubcommandHelp(c) return true } From cbaa419c8f805af5cd7098b9ced636ad0cebcfd7 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Thu, 14 Jul 2016 16:02:57 -0400 Subject: [PATCH 17/17] Generate all code when checking for changes --- runtests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtests b/runtests index fda1564..2e47233 100755 --- a/runtests +++ b/runtests @@ -75,7 +75,7 @@ def _gen(): print('runtests: skip on {}'.format(go_version), file=sys.stderr) return - _run('go generate .') + _run('go generate ./...') _run('git diff --exit-code')