Skip to content

Flag default assignments should be lazily applied #257

@briandealwis

Description

@briandealwis

Re: GoogleContainerTools/skaffold#4129, spf13/cobra#1047

In Skaffold we use cobra and pflags to define our CLI. We have the flags toggle values directly in an options object. We have two commands that take the same flags but with different defaults. The following snippet demonstrates the issue:

var blowup bool

cmd1 := cobra.Command{}
cmd1.Flags().BoolVar(&blowup, "blowup", false, "When set to false, blowup")

cmd2 := cobra.Command{}
cmd2.Flags().BoolVar(&blowup, "blowup", true, "When set to false, blowup")

cmd1.ParseFlags(os.Args[1:])
fmt.Printf("blowup = %v\n", blowup)

So even though we have two FlagSets, because they reference the same value, the default value for the last flag defined "wins" unless the option is explicitly defined on the command-line.

The issue here is that pflags applies the default value immediately. BoolVar() just delegates BoolVarP(), and BoolVarP() uses newBoolValue():

pflag/bool.go

Lines 47 to 57 in 81378bb

// BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
func (f *FlagSet) BoolVar(p *bool, name string, value bool, usage string) {
f.BoolVarP(p, name, "", value, usage)
}
// BoolVarP is like BoolVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
flag := f.VarPF(newBoolValue(value, p), name, shorthand, usage)
flag.NoOptDefVal = "true"
}

newBoolValue() allocates a container to map the provider pointer to the default value, but it immediately assigns the value:

pflag/bool.go

Lines 15 to 18 in 81378bb

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

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