From 95f45c1e60e67a27f7095088e67196eb323628fd Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Mon, 19 Aug 2019 12:06:19 -0400 Subject: [PATCH 01/58] add RequiredFlagsErr interface --- flag.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/flag.go b/flag.go index be55a33..abee563 100644 --- a/flag.go +++ b/flag.go @@ -83,6 +83,14 @@ type RequiredFlag interface { IsRequired() bool } +// RequiredFlagsErr is an interface that allows users to redefine errors on required flags +// it allows flags with user-defined errors to be backwards compatible with the Flag interface +type RequiredFlagsErr interface { + Flag + + IsRequired() bool +} + // DocGenerationFlag is an interface that allows documentation generation for the flag type DocGenerationFlag interface { Flag From a064d9082cc67b74d823c4e75e2a5fe6ccd73ae0 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 08:56:35 -0400 Subject: [PATCH 02/58] manually add FlagsErrRequired field and function to generated flags --- flag.go | 2 +- flag_generated.go | 301 +++++++++++++++++++++++++++++----------------- 2 files changed, 190 insertions(+), 113 deletions(-) diff --git a/flag.go b/flag.go index abee563..868680f 100644 --- a/flag.go +++ b/flag.go @@ -88,7 +88,7 @@ type RequiredFlag interface { type RequiredFlagsErr interface { Flag - IsRequired() bool + FlagsErrRequired() bool } // DocGenerationFlag is an interface that allows documentation generation for the flag diff --git a/flag_generated.go b/flag_generated.go index bae7d12..4d9ed7e 100644 --- a/flag_generated.go +++ b/flag_generated.go @@ -11,14 +11,15 @@ import ( // BoolFlag is a flag with type bool type BoolFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Destination *bool + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Destination *bool } // String returns a readable representation of this value @@ -37,6 +38,11 @@ func (f BoolFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f BoolFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f BoolFlag) TakesValue() bool { return false @@ -82,14 +88,15 @@ func lookupBool(name string, set *flag.FlagSet) bool { // BoolTFlag is a flag with type bool that is true by default type BoolTFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Destination *bool + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Destination *bool } // String returns a readable representation of this value @@ -108,6 +115,11 @@ func (f BoolTFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f BoolTFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f BoolTFlag) TakesValue() bool { return false @@ -153,15 +165,16 @@ func lookupBoolT(name string, set *flag.FlagSet) bool { // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) type DurationFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value time.Duration - Destination *time.Duration + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value time.Duration + Destination *time.Duration } // String returns a readable representation of this value @@ -180,6 +193,11 @@ func (f DurationFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f DurationFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f DurationFlag) TakesValue() bool { return true @@ -225,15 +243,16 @@ func lookupDuration(name string, set *flag.FlagSet) time.Duration { // Float64Flag is a flag with type float64 type Float64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value float64 - Destination *float64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value float64 + Destination *float64 } // String returns a readable representation of this value @@ -252,6 +271,11 @@ func (f Float64Flag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f Float64Flag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f Float64Flag) TakesValue() bool { return true @@ -297,14 +321,15 @@ func lookupFloat64(name string, set *flag.FlagSet) float64 { // GenericFlag is a flag with type Generic type GenericFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value Generic + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value Generic } // String returns a readable representation of this value @@ -323,6 +348,11 @@ func (f GenericFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f GenericFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f GenericFlag) TakesValue() bool { return true @@ -371,15 +401,16 @@ func lookupGeneric(name string, set *flag.FlagSet) interface{} { // Int64Flag is a flag with type int64 type Int64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value int64 - Destination *int64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value int64 + Destination *int64 } // String returns a readable representation of this value @@ -398,6 +429,11 @@ func (f Int64Flag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f Int64Flag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f Int64Flag) TakesValue() bool { return true @@ -443,15 +479,16 @@ func lookupInt64(name string, set *flag.FlagSet) int64 { // IntFlag is a flag with type int type IntFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value int - Destination *int + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value int + Destination *int } // String returns a readable representation of this value @@ -470,6 +507,11 @@ func (f IntFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f IntFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f IntFlag) TakesValue() bool { return true @@ -515,14 +557,15 @@ func lookupInt(name string, set *flag.FlagSet) int { // IntSliceFlag is a flag with type *IntSlice type IntSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value *IntSlice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value *IntSlice } // String returns a readable representation of this value @@ -541,6 +584,11 @@ func (f IntSliceFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f IntSliceFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f IntSliceFlag) TakesValue() bool { return true @@ -589,14 +637,15 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int { // Int64SliceFlag is a flag with type *Int64Slice type Int64SliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value *Int64Slice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value *Int64Slice } // String returns a readable representation of this value @@ -615,6 +664,11 @@ func (f Int64SliceFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f Int64SliceFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f Int64SliceFlag) TakesValue() bool { return true @@ -663,15 +717,16 @@ func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { // StringFlag is a flag with type string type StringFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value string - Destination *string + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value string + Destination *string } // String returns a readable representation of this value @@ -690,6 +745,11 @@ func (f StringFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f StringFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f StringFlag) TakesValue() bool { return true @@ -735,14 +795,15 @@ func lookupString(name string, set *flag.FlagSet) string { // StringSliceFlag is a flag with type *StringSlice type StringSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value *StringSlice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value *StringSlice } // String returns a readable representation of this value @@ -761,6 +822,11 @@ func (f StringSliceFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f StringSliceFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f StringSliceFlag) TakesValue() bool { return true @@ -809,15 +875,16 @@ func lookupStringSlice(name string, set *flag.FlagSet) []string { // Uint64Flag is a flag with type uint64 type Uint64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value uint64 - Destination *uint64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value uint64 + Destination *uint64 } // String returns a readable representation of this value @@ -836,6 +903,11 @@ func (f Uint64Flag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f Uint64Flag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f Uint64Flag) TakesValue() bool { return true @@ -881,15 +953,16 @@ func lookupUint64(name string, set *flag.FlagSet) uint64 { // UintFlag is a flag with type uint type UintFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - Hidden bool - TakesFile bool - Value uint - Destination *uint + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagsErr bool + Hidden bool + TakesFile bool + Value uint + Destination *uint } // String returns a readable representation of this value @@ -908,6 +981,11 @@ func (f UintFlag) IsRequired() bool { return f.Required } +// FlagsErrRequired returns whether or not the flag is required +func (f UintFlag) FlagsErrRequired() bool { + return f.RequiredFlagsErr +} + // TakesValue returns true of the flag takes a value, otherwise false func (f UintFlag) TakesValue() bool { return true @@ -950,4 +1028,3 @@ func lookupUint(name string, set *flag.FlagSet) uint { } return 0 } - From addd467e5b30964f47a54ceac0dfcb689b0b1928 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 10:03:29 -0400 Subject: [PATCH 03/58] update checkRequiredFlags function to check RequiredFlagsErr field and return map of missing flag names with matching bool for RequiredFlagsErr value --- context.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index db7cd69..85ba419 100644 --- a/context.go +++ b/context.go @@ -310,12 +310,16 @@ func (e *errRequiredFlags) getMissingFlags() []string { } func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr { - var missingFlags []string + missingFlags := make(map[string]bool) for _, f := range flags { if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() { key := strings.Split(f.GetName(), ",")[0] if !context.IsSet(key) { - missingFlags = append(missingFlags, key) + if re, ok := f.(RequiredFlagsErr); ok && re.FlagsErrRequired() { + missingFlags[key] = true + } else { + missingFlags[key] = false + } } } } From ed4ac1876d5eaa4b961c480a51b941676efd03d4 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 10:39:55 -0400 Subject: [PATCH 04/58] update requiredFlagsErr interface, errRequiredFlags struct and associated functions to handle map --- context.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/context.go b/context.go index 85ba419..4273389 100644 --- a/context.go +++ b/context.go @@ -289,23 +289,34 @@ func normalizeFlags(flags []Flag, set *flag.FlagSet) error { type requiredFlagsErr interface { error - getMissingFlags() []string + getMissingFlags() map[string]bool } type errRequiredFlags struct { - missingFlags []string + missingFlags map[string]bool } func (e *errRequiredFlags) Error() string { - numberOfMissingFlags := len(e.missingFlags) + var missingFlagNames []string + var missingFlagNamesReqErr []string + + for k, v := range e.missingFlags { + if v == false { + missingFlagNames = append(missingFlagNames, k) + } else { + missingFlagNamesReqErr = append(missingFlagNamesReqErr, k) + } + } + + numberOfMissingFlags := len(missingFlagNames) if numberOfMissingFlags == 1 { - return fmt.Sprintf("Required flag %q not set", e.missingFlags[0]) + return fmt.Sprintf("Required flag %q not set", missingFlagNames[0]) } - joinedMissingFlags := strings.Join(e.missingFlags, ", ") + joinedMissingFlags := strings.Join(missingFlagNames, ", ") return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) } -func (e *errRequiredFlags) getMissingFlags() []string { +func (e *errRequiredFlags) getMissingFlags() map[string]bool { return e.missingFlags } From fffdd82c00a338f427815ef8844cf5135e49e1f4 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 11:09:53 -0400 Subject: [PATCH 05/58] add ability to combine multiple error strings to Error() function --- context.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/context.go b/context.go index 4273389..11bb4f1 100644 --- a/context.go +++ b/context.go @@ -308,12 +308,18 @@ func (e *errRequiredFlags) Error() string { } } + var allErrors []string numberOfMissingFlags := len(missingFlagNames) if numberOfMissingFlags == 1 { - return fmt.Sprintf("Required flag %q not set", missingFlagNames[0]) + allErrors = append(allErrors, fmt.Sprintf("Required flag %q not set", missingFlagNames[0])) + } else { + joinedMissingFlags := strings.Join(missingFlagNames, ", ") + allErrors = append(allErrors, fmt.Sprintf("Required flags %q not set", joinedMissingFlags)) } - joinedMissingFlags := strings.Join(missingFlagNames, ", ") - return fmt.Sprintf("Required flags %q not set", joinedMissingFlags) + + // handle user defined errors and append + + return strings.Join(allErrors, "\n") } func (e *errRequiredFlags) getMissingFlags() map[string]bool { From eb1734ba59120625817e9c3e3d4ff497090fbe71 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 14:50:57 -0400 Subject: [PATCH 06/58] change RequiredFlagsErr to RequiredFlagErr, update to struct for custom message --- context.go | 20 ++- flag.go | 6 +- flag_generated.go | 395 ++++++++++++++++++++++++++++------------------ 3 files changed, 256 insertions(+), 165 deletions(-) diff --git a/context.go b/context.go index 11bb4f1..0fc1532 100644 --- a/context.go +++ b/context.go @@ -310,14 +310,22 @@ func (e *errRequiredFlags) Error() string { var allErrors []string numberOfMissingFlags := len(missingFlagNames) - if numberOfMissingFlags == 1 { - allErrors = append(allErrors, fmt.Sprintf("Required flag %q not set", missingFlagNames[0])) - } else { - joinedMissingFlags := strings.Join(missingFlagNames, ", ") - allErrors = append(allErrors, fmt.Sprintf("Required flags %q not set", joinedMissingFlags)) + numberOfMissingReqErrFlags := len(missingFlagNamesReqErr) + + if numberOfMissingFlags > 0 { + if numberOfMissingFlags == 1 { + allErrors = append(allErrors, fmt.Sprintf("Required flag %q not set", missingFlagNames[0])) + } else { + joinedMissingFlags := strings.Join(missingFlagNames, ", ") + allErrors = append(allErrors, fmt.Sprintf("Required flags %q not set", joinedMissingFlags)) + } } - // handle user defined errors and append + if numberOfMissingReqErrFlags > 0 { + + // handle user defined errors and append + + } return strings.Join(allErrors, "\n") } diff --git a/flag.go b/flag.go index 868680f..1f77c3e 100644 --- a/flag.go +++ b/flag.go @@ -85,10 +85,12 @@ type RequiredFlag interface { // RequiredFlagsErr is an interface that allows users to redefine errors on required flags // it allows flags with user-defined errors to be backwards compatible with the Flag interface -type RequiredFlagsErr interface { +type RequiredFlagErr interface { Flag - FlagsErrRequired() bool + IsCustom() bool + GetMessage() string + HasInterpolation() bool } // DocGenerationFlag is an interface that allows documentation generation for the flag diff --git a/flag_generated.go b/flag_generated.go index 4d9ed7e..8cc022d 100644 --- a/flag_generated.go +++ b/flag_generated.go @@ -9,17 +9,23 @@ import ( "time" ) +type FlagErr struct { + Custom bool + Message string + Interpolate bool +} + // BoolFlag is a flag with type bool type BoolFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Destination *bool + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Destination *bool } // String returns a readable representation of this value @@ -38,9 +44,14 @@ func (f BoolFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f BoolFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f BoolFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f BoolFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -88,15 +99,15 @@ func lookupBool(name string, set *flag.FlagSet) bool { // BoolTFlag is a flag with type bool that is true by default type BoolTFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Destination *bool + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Destination *bool } // String returns a readable representation of this value @@ -115,6 +126,16 @@ func (f BoolTFlag) IsRequired() bool { return f.Required } +// IsCustom returns whether or not the required flag has a custom errorj +func (f BoolTFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f BoolTFlag) GetMessage() string { + return f.RequiredFlagErr.Message +} + // FlagsErrRequired returns whether or not the flag is required func (f BoolTFlag) FlagsErrRequired() bool { return f.RequiredFlagsErr @@ -165,16 +186,16 @@ func lookupBoolT(name string, set *flag.FlagSet) bool { // DurationFlag is a flag with type time.Duration (see https://golang.org/pkg/time/#ParseDuration) type DurationFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value time.Duration - Destination *time.Duration + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value time.Duration + Destination *time.Duration } // String returns a readable representation of this value @@ -193,6 +214,16 @@ func (f DurationFlag) IsRequired() bool { return f.Required } +// IsCustom returns whether or not the required flag has a custom errorj +func (f DurationFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f DurationFlag) GetMessage() string { + return f.RequiredFlagErr.Message +} + // FlagsErrRequired returns whether or not the flag is required func (f DurationFlag) FlagsErrRequired() bool { return f.RequiredFlagsErr @@ -243,16 +274,16 @@ func lookupDuration(name string, set *flag.FlagSet) time.Duration { // Float64Flag is a flag with type float64 type Float64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value float64 - Destination *float64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value float64 + Destination *float64 } // String returns a readable representation of this value @@ -271,9 +302,14 @@ func (f Float64Flag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f Float64Flag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f Float64Flag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f Float64Flag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -321,15 +357,15 @@ func lookupFloat64(name string, set *flag.FlagSet) float64 { // GenericFlag is a flag with type Generic type GenericFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value Generic + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value Generic } // String returns a readable representation of this value @@ -348,9 +384,14 @@ func (f GenericFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f GenericFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f GenericFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f GenericFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -401,16 +442,16 @@ func lookupGeneric(name string, set *flag.FlagSet) interface{} { // Int64Flag is a flag with type int64 type Int64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value int64 - Destination *int64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value int64 + Destination *int64 } // String returns a readable representation of this value @@ -429,9 +470,14 @@ func (f Int64Flag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f Int64Flag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f Int64Flag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f Int64Flag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -479,16 +525,16 @@ func lookupInt64(name string, set *flag.FlagSet) int64 { // IntFlag is a flag with type int type IntFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value int - Destination *int + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value int + Destination *int } // String returns a readable representation of this value @@ -507,9 +553,14 @@ func (f IntFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f IntFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f IntFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f IntFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -557,15 +608,15 @@ func lookupInt(name string, set *flag.FlagSet) int { // IntSliceFlag is a flag with type *IntSlice type IntSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value *IntSlice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value *IntSlice } // String returns a readable representation of this value @@ -584,9 +635,14 @@ func (f IntSliceFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f IntSliceFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f IntSliceFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f IntSliceFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -637,15 +693,15 @@ func lookupIntSlice(name string, set *flag.FlagSet) []int { // Int64SliceFlag is a flag with type *Int64Slice type Int64SliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value *Int64Slice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value *Int64Slice } // String returns a readable representation of this value @@ -664,9 +720,14 @@ func (f Int64SliceFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f Int64SliceFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f Int64SliceFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f Int64SliceFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -717,16 +778,16 @@ func lookupInt64Slice(name string, set *flag.FlagSet) []int64 { // StringFlag is a flag with type string type StringFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value string - Destination *string + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value string + Destination *string } // String returns a readable representation of this value @@ -745,9 +806,14 @@ func (f StringFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f StringFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f StringFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f StringFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -795,15 +861,15 @@ func lookupString(name string, set *flag.FlagSet) string { // StringSliceFlag is a flag with type *StringSlice type StringSliceFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value *StringSlice + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value *StringSlice } // String returns a readable representation of this value @@ -822,9 +888,14 @@ func (f StringSliceFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f StringSliceFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f StringSliceFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f StringSliceFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -875,16 +946,16 @@ func lookupStringSlice(name string, set *flag.FlagSet) []string { // Uint64Flag is a flag with type uint64 type Uint64Flag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value uint64 - Destination *uint64 + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value uint64 + Destination *uint64 } // String returns a readable representation of this value @@ -903,9 +974,14 @@ func (f Uint64Flag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f Uint64Flag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f Uint64Flag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f Uint64Flag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false @@ -953,16 +1029,16 @@ func lookupUint64(name string, set *flag.FlagSet) uint64 { // UintFlag is a flag with type uint type UintFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagsErr bool - Hidden bool - TakesFile bool - Value uint - Destination *uint + Name string + Usage string + EnvVar string + FilePath string + Required bool + RequiredFlagErr FlagErr + Hidden bool + TakesFile bool + Value uint + Destination *uint } // String returns a readable representation of this value @@ -981,9 +1057,14 @@ func (f UintFlag) IsRequired() bool { return f.Required } -// FlagsErrRequired returns whether or not the flag is required -func (f UintFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr +// IsCustom returns whether or not the required flag has a custom errorj +func (f UintFlag) IsCustom() bool { + return f.RequiredFlagErr.Custom +} + +// GetMessage returns the custom error message +func (f UintFlag) GetMessage() string { + return f.RequiredFlagErr.Message } // TakesValue returns true of the flag takes a value, otherwise false From 52a016034a3efb885cd7f1a269d6be4581a9ccf1 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 20 Aug 2019 15:39:18 -0400 Subject: [PATCH 07/58] adjust custom-error related interface, struct and methods to reflect change in RequiredFlag interface --- context.go | 55 +++++++++++++++++++++++------------------------ flag.go | 3 +-- flag_generated.go | 15 ++----------- 3 files changed, 30 insertions(+), 43 deletions(-) diff --git a/context.go b/context.go index 0fc1532..2daa2e7 100644 --- a/context.go +++ b/context.go @@ -289,68 +289,67 @@ func normalizeFlags(flags []Flag, set *flag.FlagSet) error { type requiredFlagsErr interface { error - getMissingFlags() map[string]bool + getMissingDefaultFlags() []string + getMissingCustomFlags() []string } type errRequiredFlags struct { - missingFlags map[string]bool + missingDefaultFlags []string + missingCustomFlags []string } func (e *errRequiredFlags) Error() string { - var missingFlagNames []string - var missingFlagNamesReqErr []string - - for k, v := range e.missingFlags { - if v == false { - missingFlagNames = append(missingFlagNames, k) - } else { - missingFlagNamesReqErr = append(missingFlagNamesReqErr, k) - } - } - var allErrors []string - numberOfMissingFlags := len(missingFlagNames) - numberOfMissingReqErrFlags := len(missingFlagNamesReqErr) + numberOfMissingFlags := len(e.missingDefaultFlags) + numberOfMissingReqErrFlags := len(e.missingCustomFlags) if numberOfMissingFlags > 0 { if numberOfMissingFlags == 1 { - allErrors = append(allErrors, fmt.Sprintf("Required flag %q not set", missingFlagNames[0])) + allErrors = append(allErrors, fmt.Sprintf("Required flag %q not set", e.missingDefaultFlags[0])) } else { - joinedMissingFlags := strings.Join(missingFlagNames, ", ") + joinedMissingFlags := strings.Join(e.missingDefaultFlags, ", ") allErrors = append(allErrors, fmt.Sprintf("Required flags %q not set", joinedMissingFlags)) } } if numberOfMissingReqErrFlags > 0 { - - // handle user defined errors and append - + for i := range e.missingCustomFlags { + allErrors = append(allErrors, e.missingCustomFlags[i]) + } } return strings.Join(allErrors, "\n") } -func (e *errRequiredFlags) getMissingFlags() map[string]bool { - return e.missingFlags +func (e *errRequiredFlags) getMissingDefaultFlags() []string { + return e.missingDefaultFlags +} + +func (e *errRequiredFlags) getMissingCustomFlags() []string { + return e.missingCustomFlags } func checkRequiredFlags(flags []Flag, context *Context) requiredFlagsErr { - missingFlags := make(map[string]bool) + var missingDefaultFlags []string + var missingCustomFlags []string for _, f := range flags { if rf, ok := f.(RequiredFlag); ok && rf.IsRequired() { key := strings.Split(f.GetName(), ",")[0] if !context.IsSet(key) { - if re, ok := f.(RequiredFlagsErr); ok && re.FlagsErrRequired() { - missingFlags[key] = true + if re, ok := f.(RequiredFlagErr); ok && re.IsCustom() { + missingCustomFlags = append(missingCustomFlags, re.GetMessage()) } else { - missingFlags[key] = false + missingDefaultFlags = append(missingDefaultFlags, key) } } } } - if len(missingFlags) != 0 { - return &errRequiredFlags{missingFlags: missingFlags} + if len(missingDefaultFlags) != 0 || len(missingCustomFlags) != 0 { + return &errRequiredFlags{ + missingDefaultFlags: missingDefaultFlags, + missingCustomFlags: missingCustomFlags, + } } return nil diff --git a/flag.go b/flag.go index 1f77c3e..be6b184 100644 --- a/flag.go +++ b/flag.go @@ -83,14 +83,13 @@ type RequiredFlag interface { IsRequired() bool } -// RequiredFlagsErr is an interface that allows users to redefine errors on required flags +// RequiredFlagErr is an interface that allows users to redefine errors on required flags // it allows flags with user-defined errors to be backwards compatible with the Flag interface type RequiredFlagErr interface { Flag IsCustom() bool GetMessage() string - HasInterpolation() bool } // DocGenerationFlag is an interface that allows documentation generation for the flag diff --git a/flag_generated.go b/flag_generated.go index 8cc022d..c4d1591 100644 --- a/flag_generated.go +++ b/flag_generated.go @@ -10,9 +10,8 @@ import ( ) type FlagErr struct { - Custom bool - Message string - Interpolate bool + Custom bool + Message string } // BoolFlag is a flag with type bool @@ -136,11 +135,6 @@ func (f BoolTFlag) GetMessage() string { return f.RequiredFlagErr.Message } -// FlagsErrRequired returns whether or not the flag is required -func (f BoolTFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr -} - // TakesValue returns true of the flag takes a value, otherwise false func (f BoolTFlag) TakesValue() bool { return false @@ -224,11 +218,6 @@ func (f DurationFlag) GetMessage() string { return f.RequiredFlagErr.Message } -// FlagsErrRequired returns whether or not the flag is required -func (f DurationFlag) FlagsErrRequired() bool { - return f.RequiredFlagsErr -} - // TakesValue returns true of the flag takes a value, otherwise false func (f DurationFlag) TakesValue() bool { return true From f8eb02c99d101961632763a4a2e24ede8886c365 Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Fri, 30 Aug 2019 13:02:26 -0400 Subject: [PATCH 08/58] add required flag and custom required flag error message example to README --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/README.md b/README.md index 29ed171..60ac106 100644 --- a/README.md +++ b/README.md @@ -560,6 +560,85 @@ Will result in help output like: --lang value, -l value Language for the greeting (default: "english") ``` +#### Required Flags + +You can make a flag required by setting the `Required` field to `true`. If an end-user +fails to provide a required flag, they will be shown a default error message, or a +custom message if one is defined. To define a custom error message for a required flag, +set the `RequiredFlagErr` field equal to a `cli.FlagErr` struct with a `Custom` field of `true` +and a `Message` field containing the custom error message. Default and custom error messages +can be mixed with default messages displayed before custom messages. + +For example this: + +```go +package main + +import ( + "log" + "os" + "strings" + + "../cli" +) + +func main() { + app := cli.NewApp() + + app.Flags = []cli.Flag { + cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + Required: true, + RequiredFlagErr: cli.FlagErr{ + Custom: true, + Message: `There's a problem: "lang" is a required flag` , + }, + }, + cli.StringFlag{ + Name: "mood", + Value: "normal", + Usage: "emphasis for the greeting", + Required: true, + }, + } + + app.Action = func(c *cli.Context) error { + name := "Nefertiti" + if c.NArg() > 0 { + name = c.Args().Get(0) + } + var output string + if c.String("lang") == "spanish" { + output = "Hola " + name + } else { + output = "Hello " + name + } + + if c.String("mood") == "excited" { + output = strings.ToUpper(output) + } + + return nil + } + + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } +} +``` + +Creates an app that requires both `lang` and `mood` flags. If an attempt +to run the app is made without either, the end-user will see the following +prompts: + +``` +Required flag "mood" not set +There's a problem: "lang" is a required flag +``` + #### Values from the Environment You can also have the default value set from the environment via `EnvVar`. e.g. From 4d4a5d3b38680b63d09456c40e233e6a4b0f009b Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Mon, 9 Sep 2019 17:01:24 -0400 Subject: [PATCH 09/58] add tests for custom error messages --- app_test.go | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/app_test.go b/app_test.go index bccede4..cbb6d1e 100644 --- a/app_test.go +++ b/app_test.go @@ -1084,6 +1084,33 @@ func TestRequiredFlagAppRunBehavior(t *testing.T) { }}, expectedAnError: true, }, + { + testCase: "error_case_empty_input_with_required_flag_and_custom_error_message_on_app", + appRunInput: []string{"myCLI"}, + appFlags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + expectedAnError: true, + }, + { + testCase: "error_case_empty_input_with_required_flag_and_custom_error_message_on_command", + appRunInput: []string{"myCLI", "myCommand"}, + appCommands: []Command{{ + Name: "myCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + }}, + expectedAnError: true, + }, + { + testCase: "error_case_empty_input_with_required_flag_and_custom_error_message_on_subcommand", + appRunInput: []string{"myCLI", "myCommand", "mySubCommand"}, + appCommands: []Command{{ + Name: "myCommand", + Subcommands: []Command{{ + Name: "mySubCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + }}, + }}, + expectedAnError: true, + }, // assertion: inputing --help, when a required flag is present, does not error { testCase: "valid_case_help_input_with_required_flag_on_app", @@ -1109,6 +1136,30 @@ func TestRequiredFlagAppRunBehavior(t *testing.T) { }}, }}, }, + { + testCase: "valid_case_help_input_with_required_flag_and_custom_error_message_on_app", + appRunInput: []string{"myCLI", "--help"}, + appFlags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + }, + { + testCase: "valid_case_help_input_with_required_flag_and_custom_error_message_on_command", + appRunInput: []string{"myCLI", "myCommand", "--help"}, + appCommands: []Command{{ + Name: "myCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + }}, + }, + { + testCase: "valid_case_help_input_with_required_flag_and_custom_error_message_on_subcommand", + appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--help"}, + appCommands: []Command{{ + Name: "myCommand", + Subcommands: []Command{{ + Name: "mySubCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}}, + }}, + }}, + }, // assertion: giving optional input, when a required flag is present, errors { testCase: "error_case_optional_input_with_required_flag_on_app", @@ -1137,6 +1188,33 @@ func TestRequiredFlagAppRunBehavior(t *testing.T) { }}, expectedAnError: true, }, + { + testCase: "error_case_optional_input_with_required_flag_and_custom_error_message_on_app", + appRunInput: []string{"myCLI", "--optional", "cats"}, + appFlags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + expectedAnError: true, + }, + { + testCase: "error_case_optional_input_with_required_flag_and_custom_error_message_on_command", + appRunInput: []string{"myCLI", "myCommand", "--optional", "cats"}, + appCommands: []Command{{ + Name: "myCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + }}, + expectedAnError: true, + }, + { + testCase: "error_case_optional_input_with_required_flag_and_custom_error_message_on_subcommand", + appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--optional", "cats"}, + appCommands: []Command{{ + Name: "myCommand", + Subcommands: []Command{{ + Name: "mySubCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + }}, + }}, + expectedAnError: true, + }, // assertion: when a required flag is present, inputting that required flag does not error { testCase: "valid_case_required_flag_input_on_app", @@ -1162,6 +1240,30 @@ func TestRequiredFlagAppRunBehavior(t *testing.T) { }}, }}, }, + { + testCase: "valid_case_required_flag_input_on_app_with_custom_error_message", + appRunInput: []string{"myCLI", "--requiredFlag", "cats"}, + appFlags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + }, + { + testCase: "valid_case_required_flag_input_on_command_with_custom_error_message", + appRunInput: []string{"myCLI", "myCommand", "--requiredFlag", "cats"}, + appCommands: []Command{{ + Name: "myCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + }}, + }, + { + testCase: "valid_case_required_flag_input_on_subcommand_with_custom_error_message", + appRunInput: []string{"myCLI", "myCommand", "mySubCommand", "--requiredFlag", "cats"}, + appCommands: []Command{{ + Name: "myCommand", + Subcommands: []Command{{ + Name: "mySubCommand", + Flags: []Flag{StringFlag{Name: "requiredFlag", Required: true, RequiredFlagErr: FlagErr{Custom: true, Message:`custom error`}}, StringFlag{Name: "optional"}}, + }}, + }}, + }, } for _, test := range tdata { t.Run(test.testCase, func(t *testing.T) { From b837236bd53796d1c738282d3ada0f9ca45df3ef Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 10 Sep 2019 08:50:07 -0400 Subject: [PATCH 10/58] fix import url in README and add flag_generated.go to list of ingored files --- .gitignore | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 7a7e2d9..a9c49ca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.coverprofile node_modules/ -vendor \ No newline at end of file +vendor +flag_generated.go \ No newline at end of file diff --git a/README.md b/README.md index 60ac106..0cd124f 100644 --- a/README.md +++ b/README.md @@ -579,7 +579,7 @@ import ( "os" "strings" - "../cli" + "github.com/urfave/cli" ) func main() { From ee2dd885a6d791f11fbb256e41464eea5df6e15b Mon Sep 17 00:00:00 2001 From: Aaron Berns Date: Tue, 10 Sep 2019 08:53:36 -0400 Subject: [PATCH 11/58] remove flag_generated.go from added files --- altsrc/flag_generated.go | 346 ------------ flag_generated.go | 1100 -------------------------------------- 2 files changed, 1446 deletions(-) delete mode 100644 altsrc/flag_generated.go delete mode 100644 flag_generated.go diff --git a/altsrc/flag_generated.go b/altsrc/flag_generated.go deleted file mode 100644 index e568872..0000000 --- a/altsrc/flag_generated.go +++ /dev/null @@ -1,346 +0,0 @@ -// Code generated by fg; DO NOT EDIT. - -package altsrc - -import ( - "flag" - "github.com/urfave/cli" -) - -// 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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped BoolFlag.ApplyWithError -func (f *BoolFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.BoolFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped BoolTFlag.ApplyWithError -func (f *BoolTFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.BoolTFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped DurationFlag.ApplyWithError -func (f *DurationFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.DurationFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped Float64Flag.ApplyWithError -func (f *Float64Flag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.Float64Flag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped GenericFlag.ApplyWithError -func (f *GenericFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.GenericFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped Int64Flag.ApplyWithError -func (f *Int64Flag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.Int64Flag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped IntFlag.ApplyWithError -func (f *IntFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.IntFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped IntSliceFlag.ApplyWithError -func (f *IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.IntSliceFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped Int64SliceFlag.ApplyWithError -func (f *Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.Int64SliceFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped StringFlag.ApplyWithError -func (f *StringFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.StringFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped StringSliceFlag.ApplyWithError -func (f *StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.StringSliceFlag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped Uint64Flag.ApplyWithError -func (f *Uint64Flag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.Uint64Flag.ApplyWithError(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) -} - -// ApplyWithError saves the flagSet for later usage calls, then calls -// the wrapped UintFlag.ApplyWithError -func (f *UintFlag) ApplyWithError(set *flag.FlagSet) error { - f.set = set - return f.UintFlag.ApplyWithError(set) -} diff --git a/flag_generated.go b/flag_generated.go deleted file mode 100644 index c4d1591..0000000 --- a/flag_generated.go +++ /dev/null @@ -1,1100 +0,0 @@ -// Code generated by fg; DO NOT EDIT. - -package cli - -import ( - "flag" - "fmt" - "strconv" - "time" -) - -type FlagErr struct { - Custom bool - Message string -} - -// BoolFlag is a flag with type bool -type BoolFlag struct { - Name string - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f BoolFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f BoolFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f BoolFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f BoolFlag) TakesValue() bool { - return false -} - -// GetUsage returns the usage string for the flag -func (f BoolFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f BoolFlag) GetValue() string { - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f BoolTFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f BoolTFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f BoolTFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f BoolTFlag) TakesValue() bool { - return false -} - -// GetUsage returns the usage string for the flag -func (f BoolTFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f BoolTFlag) GetValue() string { - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f DurationFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f DurationFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f DurationFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f DurationFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f DurationFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f DurationFlag) GetValue() string { - return f.Value.String() -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f Float64Flag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f Float64Flag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f Float64Flag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f Float64Flag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f Float64Flag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f Float64Flag) GetValue() string { - return fmt.Sprintf("%f", f.Value) -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f GenericFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f GenericFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f GenericFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f GenericFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f GenericFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f GenericFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f Int64Flag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f Int64Flag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f Int64Flag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f Int64Flag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f Int64Flag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f Int64Flag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f IntFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f IntFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f IntFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f IntFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f IntFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f IntFlag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f IntSliceFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f IntSliceFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f IntSliceFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f IntSliceFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f IntSliceFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f IntSliceFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f Int64SliceFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f Int64SliceFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f Int64SliceFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f Int64SliceFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f Int64SliceFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f Int64SliceFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f StringFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f StringFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f StringFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f StringFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f StringFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f StringFlag) GetValue() string { - return f.Value -} - -// 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 "" -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f StringSliceFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f StringSliceFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f StringSliceFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f StringSliceFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f StringSliceFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f StringSliceFlag) GetValue() string { - if f.Value != nil { - return f.Value.String() - } - return "" -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f Uint64Flag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f Uint64Flag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f Uint64Flag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f Uint64Flag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f Uint64Flag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f Uint64Flag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// 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 -} - -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 - Usage string - EnvVar string - FilePath string - Required bool - RequiredFlagErr FlagErr - Hidden bool - TakesFile 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 -} - -// IsRequired returns whether or not the flag is required -func (f UintFlag) IsRequired() bool { - return f.Required -} - -// IsCustom returns whether or not the required flag has a custom errorj -func (f UintFlag) IsCustom() bool { - return f.RequiredFlagErr.Custom -} - -// GetMessage returns the custom error message -func (f UintFlag) GetMessage() string { - return f.RequiredFlagErr.Message -} - -// TakesValue returns true of the flag takes a value, otherwise false -func (f UintFlag) TakesValue() bool { - return true -} - -// GetUsage returns the usage string for the flag -func (f UintFlag) GetUsage() string { - return f.Usage -} - -// GetValue returns the flags value as string representation and an empty -// string if the flag takes no value at all. -func (f UintFlag) GetValue() string { - return fmt.Sprintf("%d", f.Value) -} - -// 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 -} - -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 -} From 322fc3bed1809802649dac769f655bdd830103ce Mon Sep 17 00:00:00 2001 From: Marwan Sulaiman Date: Wed, 4 Dec 2019 15:35:53 -0500 Subject: [PATCH 12/58] add RunWithContext + remove signal cancellation --- app.go | 10 +++++++++- context.go | 12 +----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/app.go b/app.go index a62aa23..87443ef 100644 --- a/app.go +++ b/app.go @@ -1,6 +1,7 @@ package cli import ( + "context" "flag" "fmt" "io" @@ -207,6 +208,13 @@ func (a *App) useShortOptionHandling() bool { // Run is the entry point to the cli app. Parses the arguments slice and routes // to the proper flag/args combination func (a *App) Run(arguments []string) (err error) { + return a.RunWithContext(context.Background(), arguments) +} + +// RunWithContext is like Run except it takes a Context that will be +// passed to its commands and sub-commands. Through this, you can +// propagate timeouts and cancellation requests +func (a *App) RunWithContext(ctx context.Context, arguments []string) (err error) { a.Setup() // handle the completion flag separately from the flagset since @@ -224,7 +232,7 @@ func (a *App) Run(arguments []string) (err error) { err = parseIter(set, a, arguments[1:], shellComplete) nerr := normalizeFlags(a.Flags, set) - context := NewContext(a, set, nil) + context := NewContext(a, set, &Context{Context: ctx}) if nerr != nil { _, _ = fmt.Fprintln(a.Writer, nerr) _ = ShowAppHelp(context) diff --git a/context.go b/context.go index 13fb523..5b59e75 100644 --- a/context.go +++ b/context.go @@ -5,10 +5,7 @@ import ( "errors" "flag" "fmt" - "os" - "os/signal" "strings" - "syscall" ) // Context is a type that is passed through to @@ -36,14 +33,7 @@ func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { c.Command = &Command{} if c.Context == nil { - ctx, cancel := context.WithCancel(context.Background()) - go func() { - defer cancel() - sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) - <-sigs - }() - c.Context = ctx + c.Context = context.Background() } return c From 7daa2d133e094ef5978e786e9af833a4cd65745e Mon Sep 17 00:00:00 2001 From: Marwan Sulaiman Date: Fri, 6 Dec 2019 01:20:48 -0500 Subject: [PATCH 13/58] RunWithContext -> RunContext --- app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app.go b/app.go index 87443ef..09b13be 100644 --- a/app.go +++ b/app.go @@ -208,13 +208,13 @@ func (a *App) useShortOptionHandling() bool { // Run is the entry point to the cli app. Parses the arguments slice and routes // to the proper flag/args combination func (a *App) Run(arguments []string) (err error) { - return a.RunWithContext(context.Background(), arguments) + return a.RunContext(context.Background(), arguments) } -// RunWithContext is like Run except it takes a Context that will be +// RunContext is like Run except it takes a Context that will be // passed to its commands and sub-commands. Through this, you can // propagate timeouts and cancellation requests -func (a *App) RunWithContext(ctx context.Context, arguments []string) (err error) { +func (a *App) RunContext(ctx context.Context, arguments []string) (err error) { a.Setup() // handle the completion flag separately from the flagset since From 969535eec606fc699db382e4e28221ff11c653d5 Mon Sep 17 00:00:00 2001 From: Ajitem Sahasrabuddhe Date: Sat, 7 Dec 2019 12:15:17 +0530 Subject: [PATCH 14/58] replace log.Print with t.Log --- app_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/app_test.go b/app_test.go index 7a02d65..53e78b7 100644 --- a/app_test.go +++ b/app_test.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "io/ioutil" - "log" "os" "reflect" "strings" @@ -1423,7 +1422,7 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) { } for _, flagSet := range subcommandHelpTopics { - log.Printf("==> checking with flags %v", flagSet) + t.Logf("==> checking with flags %v", flagSet) app := &App{} buf := new(bytes.Buffer) @@ -1613,7 +1612,7 @@ func TestApp_Run_Help(t *testing.T) { for _, args := range helpArguments { buf := new(bytes.Buffer) - log.Printf("==> checking with arguments %v", args) + t.Logf("==> checking with arguments %v", args) app := &App{ Name: "boom", @@ -1631,7 +1630,7 @@ func TestApp_Run_Help(t *testing.T) { } output := buf.String() - log.Printf("output: %q\n", buf.Bytes()) + t.Logf("output: %q\n", buf.Bytes()) if !strings.Contains(output, "boom - make an explosive entrance") { t.Errorf("want help to contain %q, did not: \n%q", "boom - make an explosive entrance", output) @@ -1645,7 +1644,7 @@ func TestApp_Run_Version(t *testing.T) { for _, args := range versionArguments { buf := new(bytes.Buffer) - log.Printf("==> checking with arguments %v", args) + t.Logf("==> checking with arguments %v", args) app := &App{ Name: "boom", @@ -1664,7 +1663,7 @@ func TestApp_Run_Version(t *testing.T) { } output := buf.String() - log.Printf("output: %q\n", buf.Bytes()) + t.Logf("output: %q\n", buf.Bytes()) if !strings.Contains(output, "0.1.0") { t.Errorf("want version to contain %q, did not: \n%q", "0.1.0", output) @@ -2121,7 +2120,7 @@ func TestWhenExitSubCommandWithCodeThenAppQuitUnexpectedly(t *testing.T) { var exitCodeFromExitErrHandler int app.ExitErrHandler = func(c *Context, err error) { if exitErr, ok := err.(ExitCoder); ok { - log.Print(exitErr) + t.Log(exitErr) exitCodeFromExitErrHandler = exitErr.ExitCode() } } From 0dcb2597ce9a53fda9059140328bb178029841a5 Mon Sep 17 00:00:00 2001 From: Ajitem Sahasrabuddhe Date: Sat, 7 Dec 2019 12:17:22 +0530 Subject: [PATCH 15/58] pin gfmrun to version --- .github/workflows/cli.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index f0ce60e..4c1bec5 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -26,8 +26,8 @@ jobs: - name: Set GOPATH and PATH run: | - echo "##[set-env name=GOPATH;]$(dirname $GITHUB_WORKSPACE)" - echo "##[add-path]$(dirname $GITHUB_WORKSPACE)/bin" + echo "::set-env name=GOPATH::$(dirname $GITHUB_WORKSPACE)" + echo "::add-path::$(dirname $GITHUB_WORKSPACE)/bin" shell: bash - name: Checkout Code @@ -38,7 +38,8 @@ jobs: - name: Install Dependencies run: | mkdir -p $GOPATH/bin - curl -s https://api.github.com/repos/urfave/gfmrun/releases/latest | grep gfmrun-linux-amd64 | grep download | cut -d '"' -f 4 | wget -O $GOPATH/bin/gfmrun -i - + curl -L -o $GOPATH/bin/gfmrun "https://github.com/urfave/gfmrun/releases/download/v1.2.14/gfmrun-$(go env GOOS)-amd64-v1.2.14" + chmod +x $GOPATH/bin/gfmrun npm install markdown-toc - name: Run Tests (v1) From 4af0b06f682bf252950b8f90583e3ea55f02f50e Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Sat, 7 Dec 2019 15:21:14 -0800 Subject: [PATCH 16/58] Create .codecov.yml --- .github/.codecov.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/.codecov.yml diff --git a/.github/.codecov.yml b/.github/.codecov.yml new file mode 100644 index 0000000..69cb760 --- /dev/null +++ b/.github/.codecov.yml @@ -0,0 +1 @@ +comment: false From 31c19a8ef300f6be92ef9115a50b68990b14f310 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Mon, 9 Dec 2019 11:50:47 +0100 Subject: [PATCH 17/58] timestamp flag --- flag_timestamp.go | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 flag_timestamp.go diff --git a/flag_timestamp.go b/flag_timestamp.go new file mode 100644 index 0000000..0b2cb23 --- /dev/null +++ b/flag_timestamp.go @@ -0,0 +1,130 @@ +package cli + +import ( + "flag" + "fmt" + "time" +) + + +// timestamp wrap to satisfy golang's flag interface. +type timestampWrap struct { + timestamp *time.Time + hasBeenSet bool + layout string +} + +// Set the timestamp value directly +func (t *timestampWrap) SetTimestamp(value time.Time) { + if !t.hasBeenSet { + t.timestamp = &value + t.hasBeenSet = true + } +} +// Set the timestamp string layout for future parsing +func (t *timestampWrap) SetLayout(layout string) { + t.layout = layout +} + +// Parses the string value to timestamp +func (t *timestampWrap) Set(value string) error { + timestamp, err := time.Parse(t.layout, value) + if err != nil { + return err + } + + t.timestamp = ×tamp + return nil +} + +// String returns a readable representation of this value (for usage defaults) +func (t *timestampWrap) String() string { + return fmt.Sprintf("%#v", t.timestamp) +} + +// Value returns the timestamp value stored in the flag +func (t *timestampWrap) Value() *time.Time { + return t.timestamp +} + +// Get returns the flag structure +func (t *timestampWrap) Get() interface{} { + return *t +} + +// TimestampFlag is a flag with type protobuf.timestamp +type TimestampFlag struct { + Name string + Aliases []string + Usage string + EnvVars []string + FilePath string + Required bool + Hidden bool + Layout string + Value timestampWrap + DefaultText string + HasBeenSet bool +} + +// IsSet returns whether or not the flag has been set through env or file +func (f *TimestampFlag) IsSet() bool { + return f.HasBeenSet +} + +// String returns a readable representation of this value +// (for usage defaults) +func (f *TimestampFlag) String() string { + return FlagStringer(f) +} + +// Names returns the names of the flag +func (f *TimestampFlag) Names() []string { + return flagNames(f) +} + +// IsRequired returns whether or not the flag is required +func (f *TimestampFlag) IsRequired() bool { + return f.Required +} + +// TakesValue returns true of the flag takes a value, otherwise false +func (f *TimestampFlag) TakesValue() bool { + return true +} + +// GetUsage returns the usage string for the flag +func (f *TimestampFlag) GetUsage() string { + return f.Usage +} + +// GetValue returns the flag value +func (f *TimestampFlag) GetValue() *time.Time { + return f.Value.timestamp +} + +// Apply populates the flag given the flag set and environment +func (f *TimestampFlag) Apply(set *flag.FlagSet) error { + for _, name := range f.Names() { + f.Value.SetLayout(f.Layout) + set.Var(&f.Value, name, f.Usage) + } + return nil +} + +// Timestamp gets the timestamp from a flag name +func (c *Context) Timestamp(name string) *time.Time { + if fs := lookupFlagSet(name, c); fs != nil { + return lookupTimestamp(name, fs) + } + return nil +} + +// Fetches the timestamp value from the local timestampWrap +func lookupTimestamp(name string, set *flag.FlagSet) *time.Time { + f := set.Lookup(name) + if f != nil { + return (f.Value.(*timestampWrap)).Value() + } + return nil +} From 39ba647fbb11ad594e2c1375f65cd8f0356f5b08 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Sun, 8 Dec 2019 13:32:18 +0100 Subject: [PATCH 18/58] Fix codecov reports in GitHub actions Signed-off-by: Sascha Grunert --- .github/workflows/cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 5601b19..1de31e1 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -59,7 +59,7 @@ jobs: go run build.go toc docs/v2/manual.md - name: Send Coverage Report - if: success() + if: success() && matrix.go == 1.13 && matrix.os == 'ubuntu-latest' env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: bash <(curl -s https://codecov.io/bash) From 06eb576eaac0fbe45231cb0a99e06a4c463d04d6 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Thu, 12 Dec 2019 17:31:20 +0100 Subject: [PATCH 19/58] Review fixes --- flag_test.go | 30 ++++++++++++++++++++++++-- flag_timestamp.go | 55 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/flag_test.go b/flag_test.go index 769f7bf..9151089 100644 --- a/flag_test.go +++ b/flag_test.go @@ -121,8 +121,8 @@ func TestFlagsFromEnv(t *testing.T) { a := App{ Flags: []Flag{test.flag}, Action: func(ctx *Context) error { - if !reflect.DeepEqual(ctx.Value(test.flag.Names()[0]), test.output) { - t.Errorf("ex:%01d expected %q to be parsed as %#v, instead was %#v", i, test.input, test.output, ctx.Value(test.flag.Names()[0])) + if !reflect.DeepEqual(ctx.value(test.flag.Names()[0]), test.output) { + t.Errorf("ex:%01d expected %q to be parsed as %#v, instead was %#v", i, test.input, test.output, ctx.value(test.flag.Names()[0])) } return nil }, @@ -1678,3 +1678,29 @@ func TestInt64Slice_Serialized_Set(t *testing.T) { t.Fatalf("pre and post serialization do not match: %v != %v", sl0, sl1) } } + +func TestTimestamp_set(t *testing.T) { + ts := Timestamp{ + timestamp: nil, + hasBeenSet: false, + layout: "Jan 2, 2006 at 3:04pm (MST)", + } + + time1 := "Feb 3, 2013 at 7:54pm (PST)" + if err := ts.Set(time1); err != nil { + t.Fatalf("Failed to parse time %s with layout %s", time1, ts.layout) + } + if ts.hasBeenSet == false { + t.Fatalf("hasBeenSet is not true after setting a time") + } + + ts.hasBeenSet = false + ts.SetLayout(time.RFC3339) + time2 := "2006-01-02T15:04:05Z" + if err := ts.Set(time2); err != nil { + t.Fatalf("Failed to parse time %s with layout %s", time2, ts.layout) + } + if ts.hasBeenSet == false { + t.Fatalf("hasBeenSet is not true after setting a time") + } +} diff --git a/flag_timestamp.go b/flag_timestamp.go index 0b2cb23..91b4e87 100644 --- a/flag_timestamp.go +++ b/flag_timestamp.go @@ -6,53 +6,58 @@ import ( "time" ) - -// timestamp wrap to satisfy golang's flag interface. -type timestampWrap struct { +// Timestamp wrap to satisfy golang's flag interface. +type Timestamp struct { timestamp *time.Time hasBeenSet bool layout string } +// Timestamp constructor +func NewTimestamp(timestamp time.Time) *Timestamp { + return &Timestamp{timestamp: ×tamp} +} + // Set the timestamp value directly -func (t *timestampWrap) SetTimestamp(value time.Time) { +func (t *Timestamp) SetTimestamp(value time.Time) { if !t.hasBeenSet { t.timestamp = &value t.hasBeenSet = true } } // Set the timestamp string layout for future parsing -func (t *timestampWrap) SetLayout(layout string) { +func (t *Timestamp) SetLayout(layout string) { t.layout = layout } // Parses the string value to timestamp -func (t *timestampWrap) Set(value string) error { +func (t *Timestamp) Set(value string) error { timestamp, err := time.Parse(t.layout, value) if err != nil { return err } t.timestamp = ×tamp + t.hasBeenSet = true return nil } // String returns a readable representation of this value (for usage defaults) -func (t *timestampWrap) String() string { +func (t *Timestamp) String() string { return fmt.Sprintf("%#v", t.timestamp) } // Value returns the timestamp value stored in the flag -func (t *timestampWrap) Value() *time.Time { +func (t *Timestamp) Value() *time.Time { return t.timestamp } // Get returns the flag structure -func (t *timestampWrap) Get() interface{} { +func (t *Timestamp) Get() interface{} { return *t } -// TimestampFlag is a flag with type protobuf.timestamp +// TimestampFlag is a flag with type time type TimestampFlag struct { Name string Aliases []string @@ -62,7 +67,7 @@ type TimestampFlag struct { Required bool Hidden bool Layout string - Value timestampWrap + Value *Timestamp DefaultText string HasBeenSet bool } @@ -98,16 +103,32 @@ func (f *TimestampFlag) GetUsage() string { return f.Usage } -// GetValue returns the flag value -func (f *TimestampFlag) GetValue() *time.Time { - return f.Value.timestamp +// GetValue returns the flags value as string representation and an empty +// string if the flag takes no value at all. +func (f *TimestampFlag) GetValue() string { + if f.Value != nil { + return f.Value.timestamp.String() + } + return "" } // Apply populates the flag given the flag set and environment func (f *TimestampFlag) Apply(set *flag.FlagSet) error { + if f.Layout == "" { + return fmt.Errorf("timestamp Layout is required") + } + f.Value = &Timestamp{} + f.Value.SetLayout(f.Layout) + + if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok { + if err := f.Value.Set(val); err != nil { + return fmt.Errorf("could not parse %q as timestamp value for flag %s: %s", val, f.Name, err) + } + f.HasBeenSet = true + } + for _, name := range f.Names() { - f.Value.SetLayout(f.Layout) - set.Var(&f.Value, name, f.Usage) + set.Var(f.Value, name, f.Usage) } return nil } @@ -124,7 +145,7 @@ func (c *Context) Timestamp(name string) *time.Time { func lookupTimestamp(name string, set *flag.FlagSet) *time.Time { f := set.Lookup(name) if f != nil { - return (f.Value.(*timestampWrap)).Value() + return (f.Value.(*Timestamp)).Value() } return nil } From c62d7736ea411dab88efaf9bb7175454038a380f Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Thu, 12 Dec 2019 17:31:41 +0100 Subject: [PATCH 20/58] fmt --- flag_float64.go | 4 ++-- flag_timestamp.go | 7 ++++--- help.go | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/flag_float64.go b/flag_float64.go index 2285547..31f06f3 100644 --- a/flag_float64.go +++ b/flag_float64.go @@ -18,11 +18,11 @@ type Float64Flag struct { Value float64 DefaultText string Destination *float64 - HasBeenSet bool + HasBeenSet bool } // IsSet returns whether or not the flag has been set through env or file -func (f *Float64Flag)IsSet() bool { +func (f *Float64Flag) IsSet() bool { return f.HasBeenSet } diff --git a/flag_timestamp.go b/flag_timestamp.go index 91b4e87..d24edcd 100644 --- a/flag_timestamp.go +++ b/flag_timestamp.go @@ -8,9 +8,9 @@ import ( // Timestamp wrap to satisfy golang's flag interface. type Timestamp struct { - timestamp *time.Time + timestamp *time.Time hasBeenSet bool - layout string + layout string } // Timestamp constructor @@ -25,6 +25,7 @@ func (t *Timestamp) SetTimestamp(value time.Time) { t.hasBeenSet = true } } + // Set the timestamp string layout for future parsing func (t *Timestamp) SetLayout(layout string) { t.layout = layout @@ -66,7 +67,7 @@ type TimestampFlag struct { FilePath string Required bool Hidden bool - Layout string + Layout string Value *Timestamp DefaultText string HasBeenSet bool diff --git a/help.go b/help.go index aa5947d..c1e974a 100644 --- a/help.go +++ b/help.go @@ -138,7 +138,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden { continue } - for _, name := range flag.Names(){ + for _, name := range flag.Names() { name = strings.TrimSpace(name) // this will get total count utf8 letters in flag name count := utf8.RuneCountInString(name) From 76ebb62d0216a11c92b2b4a5158aaabec8508c70 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Thu, 12 Dec 2019 17:40:18 +0100 Subject: [PATCH 21/58] fix flagTests loop --- flag_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flag_test.go b/flag_test.go index 9151089..0801cfb 100644 --- a/flag_test.go +++ b/flag_test.go @@ -121,8 +121,8 @@ func TestFlagsFromEnv(t *testing.T) { a := App{ Flags: []Flag{test.flag}, Action: func(ctx *Context) error { - if !reflect.DeepEqual(ctx.value(test.flag.Names()[0]), test.output) { - t.Errorf("ex:%01d expected %q to be parsed as %#v, instead was %#v", i, test.input, test.output, ctx.value(test.flag.Names()[0])) + if !reflect.DeepEqual(ctx.Value(test.flag.Names()[0]), test.output) { + t.Errorf("ex:%01d expected %q to be parsed as %#v, instead was %#v", i, test.input, test.output, ctx.Value(test.flag.Names()[0])) } return nil }, From d2b7f68cf3114a2791169d79d9077d279cdd0a44 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Thu, 12 Dec 2019 18:14:08 +0100 Subject: [PATCH 22/58] Add more tests --- flag_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/flag_test.go b/flag_test.go index 0801cfb..aaf3a6a 100644 --- a/flag_test.go +++ b/flag_test.go @@ -1704,3 +1704,32 @@ func TestTimestamp_set(t *testing.T) { t.Fatalf("hasBeenSet is not true after setting a time") } } + +func TestTimestampFlagApply(t *testing.T) { + expectedResult, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") + fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: time.RFC3339} + set := flag.NewFlagSet("test", 0) + _ = fl.Apply(set) + + err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"}) + expect(t, err, nil) + expect(t, *fl.Value.timestamp, expectedResult) +} + +func TestTimestampFlagApply_Fail_Parse_Wrong_Layout(t *testing.T) { + fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: "randomlayout"} + set := flag.NewFlagSet("test", 0) + _ = fl.Apply(set) + + err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"}) + expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"randomlayout\": cannot parse \"2006-01-02T15:04:05Z\" as \"randomlayout\"")) +} + +func TestTimestampFlagApply_Fail_Parse_Wrong_Time(t *testing.T) { + fl := TimestampFlag{Name: "time", Aliases: []string{"t"}, Layout: "Jan 2, 2006 at 3:04pm (MST)"} + set := flag.NewFlagSet("test", 0) + _ = fl.Apply(set) + + err := set.Parse([]string{"--time", "2006-01-02T15:04:05Z"}) + expect(t, err, fmt.Errorf("invalid value \"2006-01-02T15:04:05Z\" for flag -time: parsing time \"2006-01-02T15:04:05Z\" as \"Jan 2, 2006 at 3:04pm (MST)\": cannot parse \"2006-01-02T15:04:05Z\" as \"Jan\"")) +} From f29ad2ad48349c92f5f43846c50d455dfbbd23e8 Mon Sep 17 00:00:00 2001 From: Liam Hampton Date: Thu, 12 Dec 2019 21:24:43 +0000 Subject: [PATCH 23/58] fix some golint errors show in go report card Signed-off-by: Liam Hampton --- category.go | 1 + errors.go | 1 + flag_path.go | 2 +- help.go | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/category.go b/category.go index d9e73a0..abd9dce 100644 --- a/category.go +++ b/category.go @@ -1,5 +1,6 @@ package cli +// CommandCategories allows for category manipulation type CommandCategories interface { // AddCommand adds a command to a category, creating a new category if necessary. AddCommand(category string, command *Command) diff --git a/errors.go b/errors.go index be58903..f9cb4e0 100644 --- a/errors.go +++ b/errors.go @@ -48,6 +48,7 @@ func (m *multiError) Errors() []error { return errs } +// ErrorFormatter is the interface that will format the error output type ErrorFormatter interface { Format(s fmt.State, verb rune) } diff --git a/flag_path.go b/flag_path.go index d6b23c3..a322857 100644 --- a/flag_path.go +++ b/flag_path.go @@ -72,7 +72,7 @@ func (f *PathFlag) Apply(set *flag.FlagSet) error { return nil } -// String looks up the value of a local PathFlag, returns +// Path looks up the value of a local PathFlag, returns // "" if not found func (c *Context) Path(name string) string { if fs := lookupFlagSet(name, c); fs != nil { diff --git a/help.go b/help.go index aa5947d..c1e974a 100644 --- a/help.go +++ b/help.go @@ -138,7 +138,7 @@ func printFlagSuggestions(lastArg string, flags []Flag, writer io.Writer) { if bflag, ok := flag.(*BoolFlag); ok && bflag.Hidden { continue } - for _, name := range flag.Names(){ + for _, name := range flag.Names() { name = strings.TrimSpace(name) // this will get total count utf8 letters in flag name count := utf8.RuneCountInString(name) From 0f11fc8f30ad9ed9405ba70341d20f275d75f713 Mon Sep 17 00:00:00 2001 From: Liam Hampton Date: Thu, 12 Dec 2019 21:29:09 +0000 Subject: [PATCH 24/58] amend comments Signed-off-by: Liam Hampton --- category.go | 2 +- errors.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/category.go b/category.go index abd9dce..867e390 100644 --- a/category.go +++ b/category.go @@ -1,6 +1,6 @@ package cli -// CommandCategories allows for category manipulation +// CommandCategories interface allows for category manipulation type CommandCategories interface { // AddCommand adds a command to a category, creating a new category if necessary. AddCommand(category string, command *Command) diff --git a/errors.go b/errors.go index f9cb4e0..344b436 100644 --- a/errors.go +++ b/errors.go @@ -48,7 +48,7 @@ func (m *multiError) Errors() []error { return errs } -// ErrorFormatter is the interface that will format the error output +// ErrorFormatter is the interface that will suitably format the error output type ErrorFormatter interface { Format(s fmt.State, verb rune) } From 2eb5b301511593cd2abfdba94df3e22c9cdbfa8f Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Thu, 12 Dec 2019 23:03:40 -0800 Subject: [PATCH 25/58] add codecov token --- .github/workflows/cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 1de31e1..90f8867 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -61,5 +61,5 @@ jobs: - name: Send Coverage Report if: success() && matrix.go == 1.13 && matrix.os == 'ubuntu-latest' env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_TOKEN: fa7ff1caed3c43c68ae994495a6469d8 run: bash <(curl -s https://codecov.io/bash) From a8fbae22aeb8c6811d8ca1ebf9c5ad37c4f0d9dd Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Fri, 13 Dec 2019 08:58:11 +0100 Subject: [PATCH 26/58] Add codecov action Signed-off-by: Sascha Grunert --- .github/workflows/cli.yml | 9 +++++---- appveyor.yml | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 90f8867..eb6da39 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -58,8 +58,9 @@ jobs: go run build.go gfmrun docs/v2/manual.md go run build.go toc docs/v2/manual.md - - name: Send Coverage Report + - name: Upload coverage to Codecov if: success() && matrix.go == 1.13 && matrix.os == 'ubuntu-latest' - env: - CODECOV_TOKEN: fa7ff1caed3c43c68ae994495a6469d8 - run: bash <(curl -s https://codecov.io/bash) + uses: codecov/codecov-action@v1 + with: + token: 0a8cc73b-bb7c-480b-8626-38a461643761 + fail_ci_if_error: true diff --git a/appveyor.yml b/appveyor.yml index 6ae54b2..f1cae90 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,10 +20,9 @@ install: - go version - go env - go get github.com/urfave/gfmrun/cmd/gfmrun - - go get golang.org/x/tools/cmd/goimports - go mod tidy build_script: - go run build.go vet - go run build.go test - - go run build.go gfmrun docs/v1/manual.md \ No newline at end of file + - go run build.go gfmrun docs/v1/manual.md From 106103ee7b3ebbde16f13fbb1540332c2cc9ebdb Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Fri, 13 Dec 2019 19:54:14 -0800 Subject: [PATCH 27/58] Update app.go --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 09b13be..c04e9af 100644 --- a/app.go +++ b/app.go @@ -13,7 +13,7 @@ import ( ) var ( - changeLogURL = "https://github.com/urfave/cli/blob/master/CHANGELOG.md" + changeLogURL = "https://github.com/urfave/cli/blob/master/docs/CHANGELOG.md" appActionDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL) contactSysadmin = "This is an error in the application. Please contact the distributor of this application if this is not you." errInvalidActionType = NewExitError("ERROR invalid Action type. "+ From d4715a44b9f1f3c71ead0ac405cac1caea8adce9 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Mon, 16 Dec 2019 12:06:39 +0100 Subject: [PATCH 28/58] timestampflag examples --- docs/v2/manual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 5e04d4e..0be9007 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1364,6 +1364,8 @@ func main() { &cli.StringFlag{Name: "dance-move", Aliases: []string{"d"}}, &cli.StringSliceFlag{Name: "names", Aliases: []string{"N"}}, &cli.UintFlag{Name: "age"}, + &cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"}, + &cli.TimestampFlag{Name: "birthday", Layout: "2006-01-02"}, &cli.Uint64Flag{Name: "bigage"}, }, EnableBashCompletion: true, From 07a35024e7624cd89d075b3dba61f0602cf13d53 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Mon, 16 Dec 2019 15:12:42 +0100 Subject: [PATCH 29/58] put the manual in its own doc block --- docs/v2/manual.md | 37 +++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 12 ++++++++++++ 3 files changed, 50 insertions(+) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 0be9007..8f66092 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1150,6 +1150,43 @@ The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which is checked by the cli internals in order to print the `App.Version` via `cli.VersionPrinter` and break execution. +### Timestamp Flag + +Using the timestamp flag is simple, You can look at time.Parse to get layout examples : https://golang.org/pkg/time/#example_Parse + + +``` go +package main + +import ( + "fmt" + "log" + "os" + + "github.com/urfave/cli/v2" +) + +func main() { + app := &cli.App{ + Flags: []cli.Flag { + &cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"}, + }, + Action: func(c *cli.Context) error { + fmt.Printf("%#v",c.Timestamp("meeting").String()) + return nil + }, + } + + err := app.Run(os.Args) + if err != nil { + log.Fatal(err) + } +} +``` + #### Customization The default flag may be customized to something other than `-v/--version` by diff --git a/go.mod b/go.mod index c38d41c..5c001de 100644 --- a/go.mod +++ b/go.mod @@ -5,5 +5,6 @@ go 1.11 require ( github.com/BurntSushi/toml v0.3.1 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d + github.com/urfave/gfmrun v1.2.14 // indirect gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index ef121ff..f88b936 100644 --- a/go.sum +++ b/go.sum @@ -2,12 +2,24 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/gfmrun v1.2.14 h1:z8u4ikt3fWAAdMeeKjx/wX4AyFkNNLYcjaRQOUZ2FJk= +github.com/urfave/gfmrun v1.2.14/go.mod h1:ojqta1nGJf8QmY7bNdi2Q+9FjcvDosUokI6eiWrkDWg= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= From 539d14a1e124f42e1cabda93095c6e89907661e8 Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Mon, 16 Dec 2019 15:16:41 +0100 Subject: [PATCH 30/58] fix tests --- docs/v2/manual.md | 2 -- go.mod | 1 - go.sum | 12 ------------ 3 files changed, 15 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 8f66092..5e54d64 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1401,8 +1401,6 @@ func main() { &cli.StringFlag{Name: "dance-move", Aliases: []string{"d"}}, &cli.StringSliceFlag{Name: "names", Aliases: []string{"N"}}, &cli.UintFlag{Name: "age"}, - &cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"}, - &cli.TimestampFlag{Name: "birthday", Layout: "2006-01-02"}, &cli.Uint64Flag{Name: "bigage"}, }, EnableBashCompletion: true, diff --git a/go.mod b/go.mod index 5c001de..c38d41c 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,5 @@ go 1.11 require ( github.com/BurntSushi/toml v0.3.1 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d - github.com/urfave/gfmrun v1.2.14 // indirect gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index f88b936..ef121ff 100644 --- a/go.sum +++ b/go.sum @@ -2,24 +2,12 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/gfmrun v1.2.14 h1:z8u4ikt3fWAAdMeeKjx/wX4AyFkNNLYcjaRQOUZ2FJk= -github.com/urfave/gfmrun v1.2.14/go.mod h1:ojqta1nGJf8QmY7bNdi2Q+9FjcvDosUokI6eiWrkDWg= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= From 00d9600bb05565e5d1886972c05c13a59ec5748b Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Wed, 18 Dec 2019 00:40:37 -0800 Subject: [PATCH 31/58] Update cli.yml --- .github/workflows/cli.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index eb6da39..826762c 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -1,6 +1,9 @@ name: Run Tests on: + push: + branches: + - master pull_request: branches: - master From dcbd0094dd1e0f8416d6169b0a137d0ab3b0fa9c Mon Sep 17 00:00:00 2001 From: Martin Lees Date: Wed, 18 Dec 2019 17:30:16 +0100 Subject: [PATCH 32/58] removal of timestamp flag doc --- docs/v2/manual.md | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 5e54d64..5e04d4e 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1150,43 +1150,6 @@ The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which is checked by the cli internals in order to print the `App.Version` via `cli.VersionPrinter` and break execution. -### Timestamp Flag - -Using the timestamp flag is simple, You can look at time.Parse to get layout examples : https://golang.org/pkg/time/#example_Parse - - -``` go -package main - -import ( - "fmt" - "log" - "os" - - "github.com/urfave/cli/v2" -) - -func main() { - app := &cli.App{ - Flags: []cli.Flag { - &cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"}, - }, - Action: func(c *cli.Context) error { - fmt.Printf("%#v",c.Timestamp("meeting").String()) - return nil - }, - } - - err := app.Run(os.Args) - if err != nil { - log.Fatal(err) - } -} -``` - #### Customization The default flag may be customized to something other than `-v/--version` by From 3eee4a466e388ce08db9f36702d16ebcd7d1eb26 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Wed, 18 Dec 2019 18:09:40 -0800 Subject: [PATCH 33/58] Update cli.yml --- .github/workflows/cli.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 826762c..90a8115 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -45,19 +45,20 @@ jobs: chmod +x $GOPATH/bin/gfmrun npm install markdown-toc - - name: Run Tests (v1) - if: contains(github.base_ref, 'v1') + - name: Run Tests run: | go run build.go vet go run build.go test + + - name: Run Tests (v1) + if: contains(github.base_ref, 'v1') + run: | go run build.go gfmrun docs/v1/manual.md go run build.go toc docs/v1/manual.md - name: Run Tests (v2) if: contains(github.base_ref, 'master') run: | - go run build.go vet - go run build.go test go run build.go gfmrun docs/v2/manual.md go run build.go toc docs/v2/manual.md From 8313645760c76196c2263c2e9e291511b9e8ade4 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Wed, 18 Dec 2019 18:11:43 -0800 Subject: [PATCH 34/58] Update cli.yml --- .github/workflows/cli.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cli.yml b/.github/workflows/cli.yml index 826762c..169d3f1 100644 --- a/.github/workflows/cli.yml +++ b/.github/workflows/cli.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - v1 pull_request: branches: - master From 7ca7126677f5280f461325ca8164e58b6295e212 Mon Sep 17 00:00:00 2001 From: Nick Olinger Date: Thu, 19 Dec 2019 22:22:26 +0900 Subject: [PATCH 35/58] Update readme build info --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a8657bf..4762323 100644 --- a/README.md +++ b/README.md @@ -64,5 +64,5 @@ export PATH=$PATH:$GOPATH/bin ### Supported platforms cli is tested against multiple versions of Go on Linux, and against the latest -released version of Go on OS X and Windows. For full details, see -[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml). +released version of Go on OS X and Windows. This project uses Github Actions for +builds. For more build info, please look at the [./.github/workflows/cli.yml](https://github.com/urfave/cli/blob/master/.github/workflows/cli.yml). From 777b332bb7072b4d998798be0940dce165416beb Mon Sep 17 00:00:00 2001 From: Link Dupont Date: Wed, 18 Dec 2019 14:46:13 -0500 Subject: [PATCH 36/58] Use VisibleFlags during doc generation Hidden commands are excluded during doc generation but hidden flags are not. Using VisibleFlags() instead of the Flags slice fixes that. Signed-off-by: Link Dupont --- docs.go | 4 ++-- docs_test.go | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs.go b/docs.go index a8f5de9..dc16fc8 100644 --- a/docs.go +++ b/docs.go @@ -48,8 +48,8 @@ func (a *App) writeDocTemplate(w io.Writer) error { return t.ExecuteTemplate(w, name, &cliTemplate{ App: a, Commands: prepareCommands(a.Commands, 0), - GlobalArgs: prepareArgsWithValues(a.Flags), - SynopsisArgs: prepareArgsSynopsis(a.Flags), + GlobalArgs: prepareArgsWithValues(a.VisibleFlags()), + SynopsisArgs: prepareArgsSynopsis(a.VisibleFlags()), }) } diff --git a/docs_test.go b/docs_test.go index e52cf8b..e49dfba 100644 --- a/docs_test.go +++ b/docs_test.go @@ -22,6 +22,10 @@ func testApp() *App { Aliases: []string{"b"}, Usage: "another usage text", }, + &BoolFlag{ + Name: "hidden-flag", + Hidden: true, + }, } app.Commands = []*Command{{ Aliases: []string{"c"}, From e6e7a02882ebcd8800dd3893145fea38a6e8aa15 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Sat, 21 Dec 2019 13:57:36 -0800 Subject: [PATCH 37/58] Update manual.md --- docs/v2/manual.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 5e04d4e..38aff71 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -13,6 +13,7 @@ cli v2 manual + [Values from the Environment](#values-from-the-environment) + [Values from files](#values-from-files) + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) + + [Required flags](#required) + [Default Values for help output](#default-values-for-help-output) + [Precedence](#precedence) * [Subcommands](#subcommands) From 90a349938e87484449c1b4a93632df5b2a70b231 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Sat, 21 Dec 2019 14:31:20 -0800 Subject: [PATCH 38/58] temp remove --- docs/v2/manual.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 38aff71..5e04d4e 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -13,7 +13,6 @@ cli v2 manual + [Values from the Environment](#values-from-the-environment) + [Values from files](#values-from-files) + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) - + [Required flags](#required) + [Default Values for help output](#default-values-for-help-output) + [Precedence](#precedence) * [Subcommands](#subcommands) From e373baeb40c44b34fddb5a8d39ee259e7823bd79 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Sat, 21 Dec 2019 14:40:04 -0800 Subject: [PATCH 39/58] toc --- docs/v2/manual.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index d470a2e..35a6691 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -13,6 +13,7 @@ cli v2 manual + [Values from the Environment](#values-from-the-environment) + [Values from files](#values-from-files) + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others) + + [Required Flags](#required-flags) + [Default Values for help output](#default-values-for-help-output) + [Precedence](#precedence) * [Subcommands](#subcommands) From daa24f660ae41afbbbc9477a92495d08f871bc67 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Sat, 21 Dec 2019 14:47:18 -0800 Subject: [PATCH 40/58] copy cleanup, remove feature not present in pr --- docs/v2/manual.md | 41 +++++++++-------------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 35a6691..0ec940f 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -644,14 +644,10 @@ func main() { #### Required Flags -You can make a flag required by setting the `Required` field to `true`. If an end-user -fails to provide a required flag, they will be shown a default error message, or a -custom message if one is defined. To define a custom error message for a required flag, -set the `RequiredFlagErr` field equal to a `cli.FlagErr` struct with a `Custom` field of `true` -and a `Message` field containing the custom error message. Default and custom error messages -can be mixed with default messages displayed before custom messages. +You can make a flag required by setting the `Required` field to `true`. If a user +does not provide a required flag, they will be shown an error message. -For example this: +Take for example this app that reqiures the `lang` flag: ```go package main @@ -673,34 +669,18 @@ func main() { Value: "english", Usage: "language for the greeting", Required: true, - RequiredFlagErr: cli.FlagErr{ - Custom: true, - Message: `There's a problem: "lang" is a required flag` , - }, - }, - cli.StringFlag{ - Name: "mood", - Value: "normal", - Usage: "emphasis for the greeting", - Required: true, }, } app.Action = func(c *cli.Context) error { - name := "Nefertiti" - if c.NArg() > 0 { - name = c.Args().Get(0) - } + var output string if c.String("lang") == "spanish" { - output = "Hola " + name + output = "Hola" } else { - output = "Hello " + name - } - - if c.String("mood") == "excited" { - output = strings.ToUpper(output) + output = "Hello" } + fmt.Println(output) return nil } @@ -712,13 +692,10 @@ func main() { } ``` -Creates an app that requires both `lang` and `mood` flags. If an attempt -to run the app is made without either, the end-user will see the following -prompts: +If the app is run without the `lang` flag, the user will see the following message ``` -Required flag "mood" not set -There's a problem: "lang" is a required flag +Required flag "lang" not set ``` #### Default Values for help output From 9ab51c32d94c02c6a82d4ea398ec38de513e4d30 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Sat, 21 Dec 2019 15:48:07 -0800 Subject: [PATCH 41/58] appease gfmrun --- docs/v2/manual.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 0ec940f..d1cb132 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -649,6 +649,9 @@ does not provide a required flag, they will be shown an error message. Take for example this app that reqiures the `lang` flag: + ```go package main @@ -673,7 +676,6 @@ func main() { } app.Action = func(c *cli.Context) error { - var output string if c.String("lang") == "spanish" { output = "Hola" @@ -681,7 +683,6 @@ func main() { output = "Hello" } fmt.Println(output) - return nil } From dd803d3ea33f6dc789257182e57890a0aca15eee Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Tue, 24 Dec 2019 01:22:07 -0800 Subject: [PATCH 42/58] Update README.md --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4762323..5d24156 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ Usage documentation exists for each major version. Don't know what version you'r - `v2` - [./docs/v2/manual.md](./docs/v2/manual.md) - `v1` - [./docs/v1/manual.md](./docs/v1/manual.md) +## Installation + +Make sure you have a working Go environment. Go version 1.11+ is supported. [See the install instructions for Go](http://golang.org/doc/install.html). + +Go Modules are strongly recommended when using this package. [See the go blog guide on using Go Modules](https://blog.golang.org/using-go-modules). + ### Using `v2` releases ``` @@ -37,7 +43,7 @@ import ( ### Using `v1` releases ``` -$ go get github.com/urfave/cli +$ GO111MODULE=on go get github.com/urfave/cli ``` ```go @@ -48,11 +54,6 @@ import ( ... ``` -## Installation - -Make sure you have a working Go environment. Go version 1.10+ is supported. [See -the install instructions for Go](http://golang.org/doc/install.html). - ### GOPATH Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can From 8bb9d2149a8f75b0fda974c1dea233d7aae072fb Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Tue, 24 Dec 2019 02:07:27 -0800 Subject: [PATCH 43/58] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 4762323..cb45948 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ cli === -[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli) [![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli) From 93fe02a2720224b3c70b262b25f4755c10d7de23 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Tue, 24 Dec 2019 03:59:10 -0800 Subject: [PATCH 44/58] Update CHANGELOG.md --- docs/CHANGELOG.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9aee16f..d46619a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,25 @@ View [unreleased 2.X] series changes. +## [2.1.0] - 2019-12-24 + +### Fixed + +* Fixed some golint errors in [urfave/cli/pull/988](https://github.com/urfave/cli/pull/988) via [@liamchampton](https://github.com/liamchampton) +* Fixed a panic with flag completion [urfave/cli/pull/946](https://github.com/urfave/cli/pull/946) via [@unRob](https://github.com/unRob) + +### Changed + +* Changed docs generation to use visible flags in [urfave/cli/pull/999](https://github.com/urfave/cli/pull/999) via [@subpop](https://github.com/subpop) +* Changed `App.Run` to use an optional context for timeouts and cancellation in [urfave/cli/pull/975](https://github.com/urfave/cli/pull/975) via [@marwan-at-work](https://github.com/marwan-at-work) +* Changed version info to be hidden if the user has not defined a version in [urfave/cli/pull/955](https://github.com/urfave/cli/pull/955) via [@asahasrabuddhe](https://github.com/asahasrabuddhe) +* Changed docs generation to take into account multiple authors in [urfave/cli/pull/900](https://github.com/urfave/cli/pull/900) via [@saschagrunert](https://github.com/saschagrunert) +* Changed context to expose a `Value` accessor in [urfave/cli/pull/741](https://github.com/urfave/cli/pull/741) via [@corruptmemory](https://github.com/corruptmemory) + +### Added + +* Added timestamp flag in [urfave/cli/pull/987](https://github.com/urfave/cli/pull/987) via [@drov0](https://github.com/drov0) + ## [2.0.0] - 2019-11-17 The V2 changes were all shipped in [urfave/cli/pull/892](https://github.com/urfave/cli/pull/892), which was created with the effort of over a dozen participants! They are: @@ -520,7 +539,8 @@ signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. ### Added - Initial implementation. -[unreleased 2.X]: https://github.com/urfave/cli/compare/v2.0.0...HEAD +[unreleased 2.X]: https://github.com/urfave/cli/compare/v2.1.0...HEAD +[2.1.0]: https://github.com/urfave/cli/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/urfave/cli/compare/v1.22.2...v2.0.0 [unreleased 1.22.X]: https://github.com/urfave/cli/compare/v1.22.2...v1 From eed2043467b2444cd9a949a3207fbff5eb54ff82 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Tue, 24 Dec 2019 04:01:27 -0800 Subject: [PATCH 45/58] Update CHANGELOG.md --- docs/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index d46619a..ceb381f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,6 +8,8 @@ View [unreleased 2.X] series changes. ## [2.1.0] - 2019-12-24 +These release notes were written for the git hash [ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8](https://github.com/urfave/cli/tree/ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8) + ### Fixed * Fixed some golint errors in [urfave/cli/pull/988](https://github.com/urfave/cli/pull/988) via [@liamchampton](https://github.com/liamchampton) From 49db826a05b1fc34d466cd4d8d6b893fe833c802 Mon Sep 17 00:00:00 2001 From: "lynn [they]" Date: Tue, 24 Dec 2019 06:13:41 -0800 Subject: [PATCH 46/58] Update manual.md --- docs/v2/manual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 5e04d4e..512ad57 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1,6 +1,8 @@ cli v2 manual === +todo + - [Getting Started](#getting-started) From b44b656820e88ee033a64813725d07bf301c25dc Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 07:22:30 -0800 Subject: [PATCH 47/58] failing test --- context_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/context_test.go b/context_test.go index 3cefcca..7bb30e1 100644 --- a/context_test.go +++ b/context_test.go @@ -293,6 +293,13 @@ func TestContext_Lineage(t *testing.T) { expect(t, lineage[1], parentCtx) } +func TestContext_BackgroundContextAttributeAccessing(t *testing.T) { + parentContext := context.Background() + ctx := NewContext(nil, nil, &Context{Context: parentContext}) + value := ctx.Bool("some-bool") + expect(t, value, false) +} + func TestContext_lookupFlagSet(t *testing.T) { set := flag.NewFlagSet("test", 0) set.Bool("local-flag", false, "doc") From 5e433e09e68e05ec9efb8e4c845134f734a71106 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 07:23:17 -0800 Subject: [PATCH 48/58] Revert "Update manual.md" This reverts commit 49db826a05b1fc34d466cd4d8d6b893fe833c802. --- docs/v2/manual.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 512ad57..5e04d4e 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1,8 +1,6 @@ cli v2 manual === -todo - - [Getting Started](#getting-started) From 7b57234c15257477d4539f2447173bc65d7b1e11 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 07:23:36 -0800 Subject: [PATCH 49/58] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b013e4a..5c9c00a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules/ vendor .idea +coverage.txt From b62c6419cbe25e1b792ef9fa298c8e8c70d87251 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 07:49:37 -0800 Subject: [PATCH 50/58] new tests --- context.go | 7 +++++- context_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/context.go b/context.go index 5b59e75..e1cf3da 100644 --- a/context.go +++ b/context.go @@ -24,7 +24,12 @@ type Context struct { // NewContext creates a new context. For use in when invoking an App or Command action. func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - c := &Context{App: app, flagSet: set, parentContext: parentCtx} + c := &Context{ + App: app, + flagSet: set, + parentContext: parentCtx, + } + if parentCtx != nil { c.Context = parentCtx.Context c.shellComplete = parentCtx.shellComplete diff --git a/context_test.go b/context_test.go index 7bb30e1..818cb5a 100644 --- a/context_test.go +++ b/context_test.go @@ -293,13 +293,6 @@ func TestContext_Lineage(t *testing.T) { expect(t, lineage[1], parentCtx) } -func TestContext_BackgroundContextAttributeAccessing(t *testing.T) { - parentContext := context.Background() - ctx := NewContext(nil, nil, &Context{Context: parentContext}) - value := ctx.Bool("some-bool") - expect(t, value, false) -} - func TestContext_lookupFlagSet(t *testing.T) { set := flag.NewFlagSet("test", 0) set.Bool("local-flag", false, "doc") @@ -351,6 +344,57 @@ func TestContextPropagation(t *testing.T) { } } +func TestContextAttributeAccessing(t *testing.T) { + tdata := []struct { + testCase string + setBoolInput string + ctxBoolInput string + newContextInput *Context + }{ + { + testCase: "empty", + setBoolInput: "", + ctxBoolInput: "", + newContextInput: nil, + }, + { + testCase: "empty_with_background_context", + setBoolInput: "", + ctxBoolInput: "", + newContextInput: &Context{Context: context.Background()}, + }, + { + testCase: "empty_set_bool_and_present_ctx_bool", + setBoolInput: "", + ctxBoolInput: "ctx-bool", + newContextInput: nil, + }, + { + testCase: "empty_set_bool_and_present_ctx_bool_with_background_context", + setBoolInput: "", + ctxBoolInput: "ctx-bool", + newContextInput: &Context{Context: context.Background()}, + }, + } + + for _, test := range tdata { + t.Run(test.testCase, func(t *testing.T) { + // setup + set := flag.NewFlagSet("test", 0) + set.Bool(test.setBoolInput, false, "doc") + ctx := NewContext(nil, set, test.newContextInput) + + // logic under test + value := ctx.Bool(test.ctxBoolInput) + + // assertions + if value != false { + t.Errorf("expected test.value to be false, but it was not") + } + }) + } +} + func TestCheckRequiredFlags(t *testing.T) { tdata := []struct { testCase string From 1651eec7b89a7e727630b8b2591d91d7346dc40a Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 08:53:59 -0800 Subject: [PATCH 51/58] add a fix --- context.go | 4 ++++ context_test.go | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/context.go b/context.go index e1cf3da..4d8c023 100644 --- a/context.go +++ b/context.go @@ -33,6 +33,10 @@ func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { if parentCtx != nil { c.Context = parentCtx.Context c.shellComplete = parentCtx.shellComplete + + if parentCtx.flagSet == nil { + parentCtx.flagSet = &flag.FlagSet{} + } } c.Command = &Command{} diff --git a/context_test.go b/context_test.go index 818cb5a..8f255eb 100644 --- a/context_test.go +++ b/context_test.go @@ -380,8 +380,8 @@ func TestContextAttributeAccessing(t *testing.T) { for _, test := range tdata { t.Run(test.testCase, func(t *testing.T) { // setup - set := flag.NewFlagSet("test", 0) - set.Bool(test.setBoolInput, false, "doc") + set := flag.NewFlagSet("some-flag-set-name", 0) + set.Bool(test.setBoolInput, false, "usage documentation") ctx := NewContext(nil, set, test.newContextInput) // logic under test @@ -389,7 +389,7 @@ func TestContextAttributeAccessing(t *testing.T) { // assertions if value != false { - t.Errorf("expected test.value to be false, but it was not") + t.Errorf("expected \"value\" to be false, but it was not") } }) } From 9eb7426ac304058926bc6ee3eb0b3bf99530d4f6 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 08:55:31 -0800 Subject: [PATCH 52/58] add a fix --- context_test.go | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/context_test.go b/context_test.go index 8f255eb..ccf8846 100644 --- a/context_test.go +++ b/context_test.go @@ -370,11 +370,35 @@ func TestContextAttributeAccessing(t *testing.T) { newContextInput: nil, }, { - testCase: "empty_set_bool_and_present_ctx_bool_with_background_context", + testCase: "present_set_bool_and_present_ctx_bool_with_background_context", setBoolInput: "", ctxBoolInput: "ctx-bool", newContextInput: &Context{Context: context.Background()}, }, + { + testCase: "present_set_bool_and_present_ctx_bool", + setBoolInput: "ctx-bool", + ctxBoolInput: "ctx-bool", + newContextInput: nil, + }, + { + testCase: "present_set_bool_and_present_ctx_bool_with_background_context", + setBoolInput: "ctx-bool", + ctxBoolInput: "ctx-bool", + newContextInput: &Context{Context: context.Background()}, + }, + { + testCase: "present_set_bool_and_different_ctx_bool", + setBoolInput: "ctx-bool", + ctxBoolInput: "not-ctx-bool", + newContextInput: nil, + }, + { + testCase: "present_set_bool_and_different_ctx_bool_with_background_context", + setBoolInput: "ctx-bool", + ctxBoolInput: "not-ctx-bool", + newContextInput: &Context{Context: context.Background()}, + }, } for _, test := range tdata { From 5d74b7723ac465d1cce7f13408a3abfba592ed58 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 08:56:36 -0800 Subject: [PATCH 53/58] reduce diff --- context.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/context.go b/context.go index 4d8c023..4fe9568 100644 --- a/context.go +++ b/context.go @@ -24,11 +24,7 @@ type Context struct { // NewContext creates a new context. For use in when invoking an App or Command action. func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { - c := &Context{ - App: app, - flagSet: set, - parentContext: parentCtx, - } + c := &Context{App: app, flagSet: set, parentContext: parentCtx} if parentCtx != nil { c.Context = parentCtx.Context From 11777de30c8e2529666650b871dd37f00e2423ba Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 08:58:27 -0800 Subject: [PATCH 54/58] reduce diff --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5c9c00a..b013e4a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ node_modules/ vendor .idea -coverage.txt From 35510ee0f9f9b436136d2e954ef2b9be585483e6 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 08:58:40 -0800 Subject: [PATCH 55/58] reduce diff --- context.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/context.go b/context.go index 4fe9568..c0c526f 100644 --- a/context.go +++ b/context.go @@ -25,11 +25,9 @@ type Context struct { // NewContext creates a new context. For use in when invoking an App or Command action. func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { c := &Context{App: app, flagSet: set, parentContext: parentCtx} - if parentCtx != nil { c.Context = parentCtx.Context c.shellComplete = parentCtx.shellComplete - if parentCtx.flagSet == nil { parentCtx.flagSet = &flag.FlagSet{} } From c806e29aa5f04b9da78a952293b2269518f66132 Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 09:34:31 -0800 Subject: [PATCH 56/58] fix doc tests --- docs/v2/manual.md | 93 ++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 5e04d4e..739a0e9 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1401,51 +1401,54 @@ func main() { cli.ShowSubcommandHelp(c) cli.ShowVersion(c) - fmt.Printf("%#v\n", c.App.Command("doo")) - if c.Bool("infinite") { - c.App.Run([]string{"app", "doo", "wop"}) - } - - if c.Bool("forevar") { - c.App.RunAsSubcommand(c) - } - c.App.Setup() - fmt.Printf("%#v\n", c.App.VisibleCategories()) - fmt.Printf("%#v\n", c.App.VisibleCommands()) - fmt.Printf("%#v\n", c.App.VisibleFlags()) - - fmt.Printf("%#v\n", c.Args().First()) - if c.Args().Len() > 0 { - fmt.Printf("%#v\n", c.Args().Get(1)) - } - fmt.Printf("%#v\n", c.Args().Present()) - fmt.Printf("%#v\n", c.Args().Tail()) - - set := flag.NewFlagSet("contrive", 0) - nc := cli.NewContext(c.App, set, c) - - fmt.Printf("%#v\n", nc.Args()) - fmt.Printf("%#v\n", nc.Bool("nope")) - fmt.Printf("%#v\n", !nc.Bool("nerp")) - fmt.Printf("%#v\n", nc.Duration("howlong")) - fmt.Printf("%#v\n", nc.Float64("hay")) - fmt.Printf("%#v\n", nc.Generic("bloop")) - fmt.Printf("%#v\n", nc.Int64("bonk")) - fmt.Printf("%#v\n", nc.Int64Slice("burnks")) - fmt.Printf("%#v\n", nc.Int("bips")) - fmt.Printf("%#v\n", nc.IntSlice("blups")) - fmt.Printf("%#v\n", nc.String("snurt")) - fmt.Printf("%#v\n", nc.StringSlice("snurkles")) - fmt.Printf("%#v\n", nc.Uint("flub")) - fmt.Printf("%#v\n", nc.Uint64("florb")) - - fmt.Printf("%#v\n", nc.FlagNames()) - fmt.Printf("%#v\n", nc.IsSet("wat")) - fmt.Printf("%#v\n", nc.Set("wat", "nope")) - fmt.Printf("%#v\n", nc.NArg()) - fmt.Printf("%#v\n", nc.NumFlags()) - fmt.Printf("%#v\n", nc.Lineage()[1]) - + fmt.Printf("%#v\n", c.App.Command("doo")) + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // if c.Bool("infinite") { + // c.App.Run([]string{"app", "doo", "wop"}) + // } + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // if c.Bool("forevar") { + // c.App.RunAsSubcommand(c) + // } + c.App.Setup() + fmt.Printf("%#v\n", c.App.VisibleCategories()) + fmt.Printf("%#v\n", c.App.VisibleCommands()) + fmt.Printf("%#v\n", c.App.VisibleFlags()) + + fmt.Printf("%#v\n", c.Args().First()) + if c.Args().Len() > 0 { + fmt.Printf("%#v\n", c.Args().Get(1)) + } + fmt.Printf("%#v\n", c.Args().Present()) + fmt.Printf("%#v\n", c.Args().Tail()) + + set := flag.NewFlagSet("contrive", 0) + nc := cli.NewContext(c.App, set, c) + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // fmt.Printf("%#v\n", nc.Args()) + // fmt.Printf("%#v\n", nc.Bool("nope")) + // fmt.Printf("%#v\n", !nc.Bool("nerp")) + // fmt.Printf("%#v\n", nc.Duration("howlong")) + // fmt.Printf("%#v\n", nc.Float64("hay")) + // fmt.Printf("%#v\n", nc.Generic("bloop")) + // fmt.Printf("%#v\n", nc.Int64("bonk")) + // fmt.Printf("%#v\n", nc.Int64Slice("burnks")) + // fmt.Printf("%#v\n", nc.Int("bips")) + // fmt.Printf("%#v\n", nc.IntSlice("blups")) + // fmt.Printf("%#v\n", nc.String("snurt")) + // fmt.Printf("%#v\n", nc.StringSlice("snurkles")) + // fmt.Printf("%#v\n", nc.Uint("flub")) + // fmt.Printf("%#v\n", nc.Uint64("florb")) + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // fmt.Printf("%#v\n", nc.FlagNames()) + // fmt.Printf("%#v\n", nc.IsSet("wat")) + // fmt.Printf("%#v\n", nc.Set("wat", "nope")) + // fmt.Printf("%#v\n", nc.NArg()) + // fmt.Printf("%#v\n", nc.NumFlags()) + // fmt.Printf("%#v\n", nc.Lineage()[1]) nc.Set("wat", "also-nope") ec := cli.Exit("ohwell", 86) From b429f0381cc4ef88f7560a34103730ca33f1dc0b Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 09:35:38 -0800 Subject: [PATCH 57/58] fix identation diff --- docs/v2/manual.md | 96 +++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/docs/v2/manual.md b/docs/v2/manual.md index 739a0e9..b04ae02 100644 --- a/docs/v2/manual.md +++ b/docs/v2/manual.md @@ -1401,54 +1401,54 @@ func main() { cli.ShowSubcommandHelp(c) cli.ShowVersion(c) - fmt.Printf("%#v\n", c.App.Command("doo")) - // // uncomment when https://github.com/urfave/cli/pull/1014 is released - // if c.Bool("infinite") { - // c.App.Run([]string{"app", "doo", "wop"}) - // } - - // // uncomment when https://github.com/urfave/cli/pull/1014 is released - // if c.Bool("forevar") { - // c.App.RunAsSubcommand(c) - // } - c.App.Setup() - fmt.Printf("%#v\n", c.App.VisibleCategories()) - fmt.Printf("%#v\n", c.App.VisibleCommands()) - fmt.Printf("%#v\n", c.App.VisibleFlags()) - - fmt.Printf("%#v\n", c.Args().First()) - if c.Args().Len() > 0 { - fmt.Printf("%#v\n", c.Args().Get(1)) - } - fmt.Printf("%#v\n", c.Args().Present()) - fmt.Printf("%#v\n", c.Args().Tail()) - - set := flag.NewFlagSet("contrive", 0) - nc := cli.NewContext(c.App, set, c) - - // // uncomment when https://github.com/urfave/cli/pull/1014 is released - // fmt.Printf("%#v\n", nc.Args()) - // fmt.Printf("%#v\n", nc.Bool("nope")) - // fmt.Printf("%#v\n", !nc.Bool("nerp")) - // fmt.Printf("%#v\n", nc.Duration("howlong")) - // fmt.Printf("%#v\n", nc.Float64("hay")) - // fmt.Printf("%#v\n", nc.Generic("bloop")) - // fmt.Printf("%#v\n", nc.Int64("bonk")) - // fmt.Printf("%#v\n", nc.Int64Slice("burnks")) - // fmt.Printf("%#v\n", nc.Int("bips")) - // fmt.Printf("%#v\n", nc.IntSlice("blups")) - // fmt.Printf("%#v\n", nc.String("snurt")) - // fmt.Printf("%#v\n", nc.StringSlice("snurkles")) - // fmt.Printf("%#v\n", nc.Uint("flub")) - // fmt.Printf("%#v\n", nc.Uint64("florb")) - - // // uncomment when https://github.com/urfave/cli/pull/1014 is released - // fmt.Printf("%#v\n", nc.FlagNames()) - // fmt.Printf("%#v\n", nc.IsSet("wat")) - // fmt.Printf("%#v\n", nc.Set("wat", "nope")) - // fmt.Printf("%#v\n", nc.NArg()) - // fmt.Printf("%#v\n", nc.NumFlags()) - // fmt.Printf("%#v\n", nc.Lineage()[1]) + fmt.Printf("%#v\n", c.App.Command("doo")) + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // if c.Bool("infinite") { + // c.App.Run([]string{"app", "doo", "wop"}) + // } + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // if c.Bool("forevar") { + // c.App.RunAsSubcommand(c) + // } + c.App.Setup() + fmt.Printf("%#v\n", c.App.VisibleCategories()) + fmt.Printf("%#v\n", c.App.VisibleCommands()) + fmt.Printf("%#v\n", c.App.VisibleFlags()) + + fmt.Printf("%#v\n", c.Args().First()) + if c.Args().Len() > 0 { + fmt.Printf("%#v\n", c.Args().Get(1)) + } + fmt.Printf("%#v\n", c.Args().Present()) + fmt.Printf("%#v\n", c.Args().Tail()) + + set := flag.NewFlagSet("contrive", 0) + nc := cli.NewContext(c.App, set, c) + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // fmt.Printf("%#v\n", nc.Args()) + // fmt.Printf("%#v\n", nc.Bool("nope")) + // fmt.Printf("%#v\n", !nc.Bool("nerp")) + // fmt.Printf("%#v\n", nc.Duration("howlong")) + // fmt.Printf("%#v\n", nc.Float64("hay")) + // fmt.Printf("%#v\n", nc.Generic("bloop")) + // fmt.Printf("%#v\n", nc.Int64("bonk")) + // fmt.Printf("%#v\n", nc.Int64Slice("burnks")) + // fmt.Printf("%#v\n", nc.Int("bips")) + // fmt.Printf("%#v\n", nc.IntSlice("blups")) + // fmt.Printf("%#v\n", nc.String("snurt")) + // fmt.Printf("%#v\n", nc.StringSlice("snurkles")) + // fmt.Printf("%#v\n", nc.Uint("flub")) + // fmt.Printf("%#v\n", nc.Uint64("florb")) + + // // uncomment when https://github.com/urfave/cli/pull/1014 is released + // fmt.Printf("%#v\n", nc.FlagNames()) + // fmt.Printf("%#v\n", nc.IsSet("wat")) + // fmt.Printf("%#v\n", nc.Set("wat", "nope")) + // fmt.Printf("%#v\n", nc.NArg()) + // fmt.Printf("%#v\n", nc.NumFlags()) + // fmt.Printf("%#v\n", nc.Lineage()[1]) nc.Set("wat", "also-nope") ec := cli.Exit("ohwell", 86) From 5b57b2bf679aa4a26e93c8b1f29e56147ca1b3fe Mon Sep 17 00:00:00 2001 From: Lynn Cyrin Date: Tue, 24 Dec 2019 09:46:31 -0800 Subject: [PATCH 58/58] add changelog --- docs/CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ceb381f..383507d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -6,6 +6,12 @@ View [unreleased 2.X] series changes. +## [2.1.1] - 2019-12-24 + +### Fixed + +* Fixed a `Context` regression introduced in `v2.1.0` in [urfave/cli/pull/1014](https://github.com/urfave/cli/pull/1014) via [@lynncyrin](https://github.com/lynncyrin) + ## [2.1.0] - 2019-12-24 These release notes were written for the git hash [ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8](https://github.com/urfave/cli/tree/ae84df4cef4a2a6f1a0cb1d41ea0f3af8755e5a8) @@ -541,7 +547,8 @@ signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`. ### Added - Initial implementation. -[unreleased 2.X]: https://github.com/urfave/cli/compare/v2.1.0...HEAD +[unreleased 2.X]: https://github.com/urfave/cli/compare/v2.1.1...HEAD +[2.1.1]: https://github.com/urfave/cli/compare/v2.1.0...v2.1.1 [2.1.0]: https://github.com/urfave/cli/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/urfave/cli/compare/v1.22.2...v2.0.0