Skip to content

Add missing compatibility for flag.boolFlag.IsBoolFlag() #281

Description

@squ94wk

In the standard flag package the flag.boolValue interface with its special IsBoolFlag() bool method is honored by the parser and allows creating flag.Value types that don't require an argument.

In pflag creating such a flag is only possible by overwriting the pflag.Flag's NoOptDefVal field with "true" or an equivalent (see strconv.ParseBool). The behavior of custom Value types that also implement IsBoolFlag() bool (hence are flag.boolValue or pflag.boolValue) is not compatible to the flag package, since passing no argument for the flag results in an error.

This snippet demonstrates it:

package main

import (
	"flag"
	"log"
	"strconv"

	"github.com/spf13/pflag"
)

/* straight from bool.go */
// -- bool Value
type boolValue bool

func newBoolValue(val bool, p *bool) *boolValue {
	*p = val
	return (*boolValue)(p)
}

func (b *boolValue) Set(s string) error {
	v, err := strconv.ParseBool(s)
	*b = boolValue(v)
	return err
}

func (b *boolValue) Type() string {
	return "bool"
}

func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }

func (b *boolValue) IsBoolFlag() bool { return true }


func main() {
	var flagValue, pflagValue, pflagValue2 bool
	flagSet := flag.NewFlagSet("flag", flag.ContinueOnError)
	flagSet.Var(newBoolValue(false, &flagValue), "bool", "may omit argument")

	pflagSet := pflag.NewFlagSet("pflag", pflag.ContinueOnError)
	pflagSet.Var(newBoolValue(false, &pflagValue), "bool", "can't omit argument")
	boolFlag := pflagSet.VarPF(newBoolValue(false, &pflagValue2), "bool2", "", "has default argument if none exists")
	boolFlag.NoOptDefVal = "true"

	fErr := flagSet.Parse([]string{"--bool"})
	pfErr := pflagSet.Parse([]string{"--bool2", "--bool"})

	if (fErr == nil) != (pfErr == nil) {
		log.Println("flag and pflag handle boolValue differently")
	}

	if !pflagValue && pflagValue2 {
		log.Println("have to modify pflag.Flag value to get same behavior as with flag")
	}
}

Is this an aspect that is supposed to be compatible to flag?
I can understand that it makes sense to place the possibility to omit an argument to the Flag type and not the Value type.
But I also think it's good if I can specify that my Value type can be set without a value.

If this should be "fixed", I'd be happy to help.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions