dongzhi6927 2019-01-26 15:23
浏览 7

如何仅提取在cli中显式设置的标志集?

I am new to cobra and viper.

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:

  1. Have an array of the command flags. Initialize an empty map[string]interface{}
  2. Iterate through the array, and check if the flag is set/changed via flags.Changed("flag"). If flag is changed, then add it to map
  3. Convert map to json
  4. Unmarshal 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.

  • 写回答

1条回答 默认 最新

  • dqce48404 2019-01-26 18:11
    关注

    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
        ...
    }
    
    1. Set the defaults in cobra to nil for both those fields.
      This way you'd know that the default of Cobra is to not set the value. Whenever the value is set, it'll be a non nil value. Hope that helps!
    评论

报告相同问题?

悬赏问题

  • ¥15 远程桌面文档内容复制粘贴,格式会变化
  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题