I wanted to know if there's a way to exclude flag values that aren't set by the user from cli. So my problem is, I have some optional flags in my cobra cmd
that have default values. I wonder if there's a way to exclude these optional flags if they aren't set by the user from being processed? Or in another perspective, is there a way to extract flags that are changed by the user explicitly from cli from a cmd
flagset?
Here's an example to better illustrate my case:
var cmd = &cobra.Command{
Use: "command [operations]",
Short: "Perform some commands",
Run: func(cmd *cobra.Command, args []string) {
var user User
err := viper.Unmarshal(&user)
fmt.Println(err)
fmt.Println(user)
},
}
cmd.PersistentFlags().String("name", "", "Your Name (Required)")
cmd.PersistentFlags().String("description", "", "Description")
cmd.PersistentFlags().String("address", "", "Address")
cmd.PersistentFlags().Int("age", -1, "Age")
cmd.MarkPersistentFlagRequired("name")
viper.BindPFlags(cmd.PersistentFlags())
So suppose for age and address, I want them to be optional and not propagated when they're passed to struct. So this means, in the cli, the user is not required to submit the age
and address
flags and the default values for these optional flags are nil. However, Int & String flags are strongly typed, so they require default values (eg: ""
and -1
). As a result, when I bind the command pflags to viper and user don't input age & address values in the cli, viper will receive ""
for address and -1
for age. Using the above method, the default values will get propagated to the User struct.
What I want is, to exclude flag values that aren't set by the user. Is there a way for me to exclude User struct from receiving flag values that aren't explicitly set by the user?
My current solution to exclude the unset flags from being processed in the User struct is currently like this:
map[string]interface{}
flags.Changed("flag")
. If flag is changed, then add it to mapUnmarshal json object to struct
// inside the Run function of a cobra command
aMap := make(map[string]interface{})
flags := cmd.Flags()
for _, flag := range cmdFlags {
if flags.Changed(flag) {
aMap[flag] = viper.Get(flag)
}
}
jsonStr, _ := json.Marshal(aMap)
var user User
json.Unmarshal(jsonStr, &user)
fmt.Println(user)
But I was wondering if there is a better alternative than my solution above. Preferably, I don't want to change anything in the User
struct as it is imported from an external package.
Thank you. Your help is greatly appreciated.
Suppose your User
struct looks like this:
type User struct {
...
age int
address string
...
}
Then by default initialization of the User
struct will set age => 0, address => 0
. So even if viper doesn't set defaults. Go internally will.
What I suggest is:
1. Change how user struct is created
type User struct {
...
age *int
address *string
...
}
nil
for both those fields.nil
value. Hope that helps!