@ -3,11 +3,11 @@ package cli
import (
import (
"flag"
"flag"
"fmt"
"fmt"
"os"
"reflect"
"reflect"
"runtime"
"runtime"
"strconv"
"strconv"
"strings"
"strings"
"syscall"
"time"
"time"
)
)
@ -62,13 +62,29 @@ type Flag interface {
GetName ( ) string
GetName ( ) string
}
}
func flagSet ( name string , flags [ ] Flag ) * flag . FlagSet {
// errorableFlag is an interface that allows us to return errors during apply
// it allows flags defined in this library to return errors in a fashion backwards compatible
// TODO remove in v2 and modify the existing Flag interface to return errors
type errorableFlag interface {
Flag
applyWithError ( * flag . FlagSet ) error
}
func flagSet ( name string , flags [ ] Flag ) ( * flag . FlagSet , error ) {
set := flag . NewFlagSet ( name , flag . ContinueOnError )
set := flag . NewFlagSet ( name , flag . ContinueOnError )
for _ , f := range flags {
for _ , f := range flags {
//TODO remove in v2 when errorableFlag is removed
if f , ok := f . ( errorableFlag ) ; ok {
if err := f . applyWithError ( set ) ; err != nil {
return nil , err
}
} else {
f . Apply ( set )
f . Apply ( set )
}
}
return set
}
return set , nil
}
}
func eachName ( longName string , fn func ( string ) ) {
func eachName ( longName string , fn func ( string ) ) {
@ -87,13 +103,22 @@ type Generic interface {
// Apply takes the flagset and calls Set on the generic flag with the value
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
// provided by the user for parsing by the flag
// Ignores parsing errors
func ( f GenericFlag ) Apply ( set * flag . FlagSet ) {
func ( f GenericFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError 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 ) applyWithError ( set * flag . FlagSet ) error {
val := f . Value
val := f . Value
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
val . Set ( envVal )
if err := val . Set ( envVal ) ; err != nil {
return fmt . Errorf ( "could not parse %s as value for flag %s: %s" , envVal , f . Name , err )
}
break
break
}
}
}
}
@ -102,9 +127,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
set . Var ( f . Value , name , f . Usage )
set . Var ( f . Value , name , f . Usage )
} )
} )
return nil
}
}
// StringSlice is an opaque type for []string to satisfy flag.Value
// StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter
type StringSlice [ ] string
type StringSlice [ ] string
// Set appends the string value to the list of values
// Set appends the string value to the list of values
@ -123,16 +150,29 @@ func (f *StringSlice) Value() []string {
return * f
return * f
}
}
// Get returns the slice of strings set by this flag
func ( f * StringSlice ) Get ( ) interface { } {
return * f
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f StringSliceFlag ) Apply ( set * flag . FlagSet ) {
func ( f StringSliceFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f StringSliceFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
newVal := & StringSlice { }
newVal := & StringSlice { }
for _ , s := range strings . Split ( envVal , "," ) {
for _ , s := range strings . Split ( envVal , "," ) {
s = strings . TrimSpace ( s )
s = strings . TrimSpace ( s )
newVal . Set ( s )
if err := newVal . Set ( s ) ; err != nil {
return fmt . Errorf ( "could not parse %s as string value for flag %s: %s" , envVal , f . Name , err )
}
}
}
f . Value = newVal
f . Value = newVal
break
break
@ -146,9 +186,11 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
}
}
set . Var ( f . Value , name , f . Usage )
set . Var ( f . Value , name , f . Usage )
} )
} )
return nil
}
}
// IntSlice is an opaque type for []int to satisfy flag.Value
// IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter
type IntSlice [ ] int
type IntSlice [ ] int
// Set parses the value into an integer and appends it to the list of values
// Set parses the value into an integer and appends it to the list of values
@ -171,18 +213,28 @@ func (f *IntSlice) Value() []int {
return * f
return * f
}
}
// Get returns the slice of ints set by this flag
func ( f * IntSlice ) Get ( ) interface { } {
return * f
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f IntSliceFlag ) Apply ( set * flag . FlagSet ) {
func ( f IntSliceFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f IntSliceFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
newVal := & IntSlice { }
newVal := & IntSlice { }
for _ , s := range strings . Split ( envVal , "," ) {
for _ , s := range strings . Split ( envVal , "," ) {
s = strings . TrimSpace ( s )
s = strings . TrimSpace ( s )
err := newVal . Set ( s )
if err := newVal . Set ( s ) ; err != nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as int slice value for flag %s: %s" , envVal , f . Name , err )
fmt . Fprintf ( ErrWriter , err . Error ( ) )
}
}
}
}
f . Value = newVal
f . Value = newVal
@ -197,9 +249,11 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
}
}
set . Var ( f . Value , name , f . Usage )
set . Var ( f . Value , name , f . Usage )
} )
} )
return nil
}
}
// Int64Slice is an opaque type for []int to satisfy flag.Value
// Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter
type Int64Slice [ ] int64
type Int64Slice [ ] int64
// Set parses the value into an integer and appends it to the list of values
// Set parses the value into an integer and appends it to the list of values
@ -222,18 +276,28 @@ func (f *Int64Slice) Value() []int64 {
return * f
return * f
}
}
// Get returns the slice of ints set by this flag
func ( f * Int64Slice ) Get ( ) interface { } {
return * f
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f Int64SliceFlag ) Apply ( set * flag . FlagSet ) {
func ( f Int64SliceFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f Int64SliceFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
newVal := & Int64Slice { }
newVal := & Int64Slice { }
for _ , s := range strings . Split ( envVal , "," ) {
for _ , s := range strings . Split ( envVal , "," ) {
s = strings . TrimSpace ( s )
s = strings . TrimSpace ( s )
err := newVal . Set ( s )
if err := newVal . Set ( s ) ; err != nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as int64 slice value for flag %s: %s" , envVal , f . Name , err )
fmt . Fprintf ( ErrWriter , err . Error ( ) )
}
}
}
}
f . Value = newVal
f . Value = newVal
@ -248,19 +312,33 @@ func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
}
}
set . Var ( f . Value , name , f . Usage )
set . Var ( f . Value , name , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f BoolFlag ) Apply ( set * flag . FlagSet ) {
func ( f BoolFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f BoolFlag ) applyWithError ( set * flag . FlagSet ) error {
val := false
val := false
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
if envVal == "" {
val = false
break
}
envValBool , err := strconv . ParseBool ( envVal )
envValBool , err := strconv . ParseBool ( envVal )
if err == nil {
if err ! = nil {
val = envValBool
return fmt . Errorf ( "could not parse %s as bool value for flag %s: %s" , envVal , f . Name , err )
}
}
val = envValBool
break
break
}
}
}
}
@ -273,23 +351,38 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
}
}
set . Bool ( name , val , f . Usage )
set . Bool ( name , val , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f BoolTFlag ) Apply ( set * flag . FlagSet ) {
func ( f BoolTFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f BoolTFlag ) applyWithError ( set * flag . FlagSet ) error {
val := true
val := true
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
if envVal == "" {
val = false
break
}
envValBool , err := strconv . ParseBool ( envVal )
envValBool , err := strconv . ParseBool ( envVal )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as bool value for flag %s: %s" , envVal , f . Name , err )
}
val = envValBool
val = envValBool
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -298,14 +391,22 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) {
}
}
set . Bool ( name , val , f . Usage )
set . Bool ( name , val , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f StringFlag ) Apply ( set * flag . FlagSet ) {
func ( f StringFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f StringFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
f . Value = envVal
f . Value = envVal
break
break
}
}
@ -319,22 +420,31 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
}
}
set . String ( name , f . Value , f . Usage )
set . String ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f IntFlag ) Apply ( set * flag . FlagSet ) {
func ( f IntFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f IntFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValInt , err := strconv . ParseInt ( envVal , 0 , 64 )
envValInt , err := strconv . ParseInt ( envVal , 0 , 64 )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as int value for flag %s: %s" , envVal , f . Name , err )
}
f . Value = int ( envValInt )
f . Value = int ( envValInt )
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -343,22 +453,32 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
}
}
set . Int ( name , f . Value , f . Usage )
set . Int ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f Int64Flag ) Apply ( set * flag . FlagSet ) {
func ( f Int64Flag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f Int64Flag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValInt , err := strconv . ParseInt ( envVal , 0 , 64 )
envValInt , err := strconv . ParseInt ( envVal , 0 , 64 )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as int value for flag %s: %s" , envVal , f . Name , err )
}
f . Value = envValInt
f . Value = envValInt
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -367,22 +487,32 @@ func (f Int64Flag) Apply(set *flag.FlagSet) {
}
}
set . Int64 ( name , f . Value , f . Usage )
set . Int64 ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f UintFlag ) Apply ( set * flag . FlagSet ) {
func ( f UintFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f UintFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValInt , err := strconv . ParseUint ( envVal , 0 , 64 )
envValInt , err := strconv . ParseUint ( envVal , 0 , 64 )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as uint value for flag %s: %s" , envVal , f . Name , err )
}
f . Value = uint ( envValInt )
f . Value = uint ( envValInt )
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -391,22 +521,32 @@ func (f UintFlag) Apply(set *flag.FlagSet) {
}
}
set . Uint ( name , f . Value , f . Usage )
set . Uint ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f Uint64Flag ) Apply ( set * flag . FlagSet ) {
func ( f Uint64Flag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f Uint64Flag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValInt , err := strconv . ParseUint ( envVal , 0 , 64 )
envValInt , err := strconv . ParseUint ( envVal , 0 , 64 )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as uint64 value for flag %s: %s" , envVal , f . Name , err )
}
f . Value = uint64 ( envValInt )
f . Value = uint64 ( envValInt )
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -415,22 +555,32 @@ func (f Uint64Flag) Apply(set *flag.FlagSet) {
}
}
set . Uint64 ( name , f . Value , f . Usage )
set . Uint64 ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f DurationFlag ) Apply ( set * flag . FlagSet ) {
func ( f DurationFlag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f DurationFlag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValDuration , err := time . ParseDuration ( envVal )
envValDuration , err := time . ParseDuration ( envVal )
if err == nil {
if err != nil {
return fmt . Errorf ( "could not parse %s as duration for flag %s: %s" , envVal , f . Name , err )
}
f . Value = envValDuration
f . Value = envValDuration
break
break
}
}
}
}
}
}
}
eachName ( f . Name , func ( name string ) {
eachName ( f . Name , func ( name string ) {
if f . Destination != nil {
if f . Destination != nil {
@ -439,18 +589,29 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
}
}
set . Duration ( name , f . Value , f . Usage )
set . Duration ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
// Apply populates the flag given the flag set and environment
// Apply populates the flag given the flag set and environment
// Ignores errors
func ( f Float64Flag ) Apply ( set * flag . FlagSet ) {
func ( f Float64Flag ) Apply ( set * flag . FlagSet ) {
f . applyWithError ( set )
}
// applyWithError populates the flag given the flag set and environment
func ( f Float64Flag ) applyWithError ( set * flag . FlagSet ) error {
if f . EnvVar != "" {
if f . EnvVar != "" {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
for _ , envVar := range strings . Split ( f . EnvVar , "," ) {
envVar = strings . TrimSpace ( envVar )
envVar = strings . TrimSpace ( envVar )
if envVal := os . Getenv ( envVar ) ; envVal != "" {
if envVal , ok := syscall . Getenv ( envVar ) ; ok {
envValFloat , err := strconv . ParseFloat ( envVal , 10 )
envValFloat , err := strconv . ParseFloat ( envVal , 10 )
if err = = nil {
if err ! = nil {
f . Value = float64 ( envValFloat )
return fmt . Errorf ( "could not parse %s as float64 value for flag %s: %s" , envVal , f . Name , err )
}
}
f . Value = float64 ( envValFloat )
break
}
}
}
}
}
}
@ -462,6 +623,8 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
}
}
set . Float64 ( name , f . Value , f . Usage )
set . Float64 ( name , f . Value , f . Usage )
} )
} )
return nil
}
}
func visibleFlags ( fl [ ] Flag ) [ ] Flag {
func visibleFlags ( fl [ ] Flag ) [ ] Flag {