diff --git a/CHANGELOG.md b/CHANGELOG.md index 28d72e6..c48abcc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ below this description) is likely unreleased. ## Changed -- Moved `SetBy` into the `Value` interface - this allows `Flag` to be readonly and we need to update `SetBy` anyway +- Moved `SetBy` into the `Value` interface (`value.UpdatedBy()` - this allows `Flag` to be readonly and and makes the coupling between setting the value and updating `UpdatedBy` explicit # v0.0.25 diff --git a/app_parse.go b/app_parse.go index ffbbf27..1d7bea1 100644 --- a/app_parse.go +++ b/app_parse.go @@ -199,8 +199,7 @@ func resolveFlag( } } - if fl.SetBy == "" && len(strValues) > 0 { - + if fl.Value.UpdatedBy() == value.UpdatedByUnset && len(strValues) > 0 { _, isScalar := val.(value.ScalarValue) if isScalar && len(strValues) > 1 { return fmt.Errorf("flag error: %v: flag passed multiple times, it's value (type %v), can only be updated once", name, fl.Value.Description()) @@ -224,14 +223,13 @@ func resolveFlag( if err != nil { return fmt.Errorf("error updating flag %v from passed flag value %v: %w", name, v, err) } - fl.SetBy = "passedflag" } } } // update from config { - if canUpdate && fl.SetBy == "" && configReader != nil { + if canUpdate && fl.Value.UpdatedBy() == value.UpdatedByUnset && configReader != nil { fpr, err := configReader.Search(fl.ConfigPath) if err != nil { return err @@ -247,7 +245,6 @@ func resolveFlag( err, ) } - fl.SetBy = "config" } else { v, ok := fl.Value.(value.SliceValue) if !ok { @@ -264,7 +261,6 @@ func resolveFlag( return fmt.Errorf("could not update container type value: err: %w", err) } } - fl.SetBy = "config" fl.Value = v } } @@ -273,7 +269,7 @@ func resolveFlag( // update from envvars { - if canUpdate && fl.SetBy == "" && len(fl.EnvVars) > 0 { + if canUpdate && fl.Value.UpdatedBy() == value.UpdatedByUnset && len(fl.EnvVars) > 0 { for _, e := range fl.EnvVars { val, exists := lookupEnv(e) if exists { @@ -281,7 +277,6 @@ func resolveFlag( if err != nil { return fmt.Errorf("error updating flag %v from envvar %v: %w", name, val, err) } - fl.SetBy = "envvar" break // stop looking for envvars } @@ -291,9 +286,8 @@ func resolveFlag( // update from default { - if canUpdate && fl.SetBy == "" && fl.Value.HasDefault() { + if canUpdate && fl.Value.UpdatedBy() == value.UpdatedByUnset && fl.Value.HasDefault() { fl.Value.ReplaceFromDefault(value.UpdatedByDefault) - fl.SetBy = "appdefault" } } @@ -467,7 +461,8 @@ func (app *App) parseWithOptHolder(parseOptHolder ParseOptHolder) (*ParseResult, } if !gar.HelpPassed { - if fl.Required && fl.SetBy == "" { + // TODO: do I need all the checks + if fl.Required && fl.Value.UpdatedBy() == value.UpdatedByUnset { return nil, fmt.Errorf("flag required but not set: %s", name) } } @@ -488,7 +483,7 @@ func (app *App) parseWithOptHolder(parseOptHolder ParseOptHolder) (*ParseResult, pfs := make(command.PassedFlags) for name, fl := range ftar.AllowedFlags { - if fl.SetBy != "" { + if fl.Value.UpdatedBy() != value.UpdatedByUnset { pfs[string(name)] = fl.Value.Get() } } diff --git a/flag/flag.go b/flag/flag.go index 80fe00e..166b7a0 100644 --- a/flag/flag.go +++ b/flag/flag.go @@ -73,9 +73,6 @@ type Flag struct { // IsCommandFlag is set when parsing. Set to true if the flag was attached to a command (as opposed to being inherited from a section) IsCommandFlag bool - // SetBy might be set when parsing. Possible values: appdefault, config, passedflag - SetBy string - // Value is set when parsing. Use SetBy != "" to determine whether a value was actually passed instead of being empty Value value.Value } @@ -90,7 +87,6 @@ func New(helpShort HelpShort, empty value.EmptyConstructor, opts ...FlagOpt) Fla EnvVars: nil, Required: false, IsCommandFlag: false, - SetBy: "", UnsetSentinel: "", Value: nil, } diff --git a/help/detailed/detailed.go b/help/detailed/detailed.go index 02b913c..ebca50f 100644 --- a/help/detailed/detailed.go +++ b/help/detailed/detailed.go @@ -115,14 +115,14 @@ func detailedPrintFlag(w io.Writer, color *gocolor.Color, name flag.Name, f *fla ) } - if f.SetBy != "" { + if f.Value.UpdatedBy() != value.UpdatedByUnset { switch v := f.Value.(type) { case value.DictValue: fmt.Fprintf( w, " %s (set by %s):\n", color.Add(color.Bold, "currentvalue"), - color.Add(color.Bold, f.SetBy), + color.Add(color.Bold, string(f.Value.UpdatedBy())), ) m := v.StringMap() for _, key := range common.SortedKeys(m) { @@ -145,7 +145,7 @@ func detailedPrintFlag(w io.Writer, color *gocolor.Color, name flag.Name, f *fla fmt.Fprintf(w, " %s (set by %s) :\n", color.Add(color.Bold, "currentvalue"), - color.Add(color.Bold, f.SetBy), + color.Add(color.Bold, string(f.Value.UpdatedBy())), ) for i, e := range v.StringSlice() { @@ -166,7 +166,7 @@ func detailedPrintFlag(w io.Writer, color *gocolor.Color, name flag.Name, f *fla w, " %s (set by %s) : %s\n", color.Add(color.Bold, "currentvalue"), - color.Add(color.Bold, f.SetBy), + color.Add(color.Bold, string(f.Value.UpdatedBy())), v.String(), ) default: diff --git a/value/dict/dict.go b/value/dict/dict.go index f9f1047..fabb56e 100644 --- a/value/dict/dict.go +++ b/value/dict/dict.go @@ -143,6 +143,10 @@ func (v *dictValue[_]) Update(s string, u value.UpdatedBy) error { return nil } +func (v *dictValue[_]) UpdatedBy() value.UpdatedBy { + return v.updatedBy +} + func (v *dictValue[_]) ReplaceFromDefault(u value.UpdatedBy) { if v.hasDefault { v.vals = v.defaultVals diff --git a/value/scalar/scalar.go b/value/scalar/scalar.go index eb58bbd..efa6115 100644 --- a/value/scalar/scalar.go +++ b/value/scalar/scalar.go @@ -124,6 +124,10 @@ func (v *scalarValue[T]) Update(s string, u value.UpdatedBy) error { return nil } +func (v *scalarValue[_]) UpdatedBy() value.UpdatedBy { + return v.updatedBy +} + func (v *scalarValue[_]) ReplaceFromDefault(u value.UpdatedBy) { if v.defaultVal != nil { v.updatedBy = u diff --git a/value/slice/slice.go b/value/slice/slice.go index 77dcb16..7547299 100644 --- a/value/slice/slice.go +++ b/value/slice/slice.go @@ -140,6 +140,10 @@ func (v *sliceValue[_]) Update(s string, u value.UpdatedBy) error { return nil } +func (v *sliceValue[_]) UpdatedBy() value.UpdatedBy { + return v.updatedBy +} + func (v *sliceValue[_]) ReplaceFromDefault(u value.UpdatedBy) { if v.hasDefault { v.vals = v.defaultVals diff --git a/value/value.go b/value/value.go index 20ab83e..f7104be 100644 --- a/value/value.go +++ b/value/value.go @@ -8,9 +8,9 @@ type UpdatedBy string const ( UpdatedByUnset UpdatedBy = "" - UpdatedByDefault UpdatedBy = "default" + UpdatedByDefault UpdatedBy = "appdefault" UpdatedByEnvVar UpdatedBy = "envvar" - UpdatedByFlag UpdatedBy = "flag" + UpdatedByFlag UpdatedBy = "passedflag" UpdatedByConfig UpdatedBy = "config" ) @@ -41,6 +41,9 @@ type Value interface { // and replaces scalar Values Update(string, UpdatedBy) error + // UpdatedBy returns the source of the last update + UpdatedBy() UpdatedBy + // ReplaceFromDefault updates the Value from a pre-set default, if one exists. use HasDefault to check whether a default exists ReplaceFromDefault(u UpdatedBy) }