pflag icon indicating copy to clipboard operation
pflag copied to clipboard

Value's that implement IsBoolFlag() always show a default value

Open twelvelabs opened this issue 2 years ago • 0 comments

I've implemented a custom Value type for managing generic data. Everything works as it should, but the flags always show a default in their usage string regardless of whether they have a zero value:

type Value struct {
    data     interface{}
    dataType string
}

func (v *Value) String() string {
    return cast.ToString(v.Get())
}

func (v *Value) Get() interface{} {
    return v.data
}

func (v *Value) Set(data string) error {
    // validates, casts, and sets v.data using v.Type()
}

func (v *Value) Type() string {
    return v.dataType
}

func (v *Value) IsBoolFlag() bool {
    return v.Type() == "bool"
}


func main() {
    value := &Value{
        data: "",
        dataType: "string",
    }
    pflag.Var(value, "project-name", "Some usage text")
    pflag.Parse()
    // Prints:
    // --project-name string   Some usage text (default "")
    pflag.Usage()


    flag := pflag.Lookup("project-name")
    // Prints:
    // default: '', isZero: false
    fmt.Printf("default: %q, isZero: %v", flag.DefValue, flag.defaultIsZeroValue())
}

The issue seems to be caused here - by checking for whether the value implements the boolFlag interface (rather than the return value of IsBoolFlag()):

https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/flag.go#L536-L541

Seems like the fix would be to move the boolFlag check prior to the switch statement and have it actually call IsBoolFlag(), like so:

    if bf, ok := f.Value.(boolFlag); ok && bf.IsBoolFlag() {
        return f.DefValue == "false"
    }
    switch f.Value.(type) { ... }

Then custom values would make it through to the default case in the switch statement.

twelvelabs avatar Sep 22 '22 21:09 twelvelabs