1

I am using github.com/spf13/cobra to parse command-line flags and just about everything I'm doing is working well, but I'm having trouble figuring out how to get a specifically typed value out of a *cobra.Command at runtime.

My command definition looks like this in cmd/generate.go:

var (
    generateCommand = &cobra.Command{
        // ...
    }

    generateTokenCommand = &cobra.Command{
        // ...
        Run: func(cmd *cobra.Command, args []string) {
           // command body here
        }
    }

)

func init() {
    generateCommand.AddCommand(generateTokenCommand)

    // setup generate token flags
    flags := generateTokenCommand.Flags()
    flags.Uint64P("user-id", "i", 1, "User ID")
    flags.BoolP("is-admin", "a", "Is admin.")
    // other flags.StringP, but those are easy
}

NOTE: I know that there are APIs for binding these to static variables, I'm trying to avoid doing that if at all possible to keep things contained within Cobra.

Inside generateTokenCommand.Run, e.g. my entry point, I'm having trouble getting non-string values out of cobra.Command.

When I need to get a string value, I can simply:

var email string = cmd.Flag("email").Value.String()

pflags.Flag has a field named Value, which is of type pflags.Value, which looks like this:

// Value is the interface to the dynamic value stored in a flag.
// (The default value is represented as a string.)
type Value interface {
    String() string
    Set(string) error
    Type() string
}

If I drop into a debugger and grab the value like so:

userIdValue := cmd.Flag("user-id").Value

I see that the runtime type of this is *github.com/spf13/pflag.uint64Value, but since this is a private type, I don't seem to be able to cast the value:

// does not compile
cmd.Flag("user-id").Value.(uint64)

How can I cast or use another method to resolve this Value as a uint64?

Naftuli Kay
  • 87,710
  • 93
  • 269
  • 411

1 Answers1

1

I may have found the answer after diving deeper, there is a method on pflags.FlagSet called GetUint64:

// GetUint64 return the uint64 value of a flag with the given name
func (f *FlagSet) GetUint64(name string) (uint64, error) {
    val, err := f.getFlagType(name, "uint64", uint64Conv)
    if err != nil {
        return 0, err
    }
    return val.(uint64), nil
}

I think my issue has been getting used to the documentation and the way that Golang source code is organized, but this does work:

uid, err := cmd.Flags().GetUint64("user-id")
Naftuli Kay
  • 87,710
  • 93
  • 269
  • 411