golang: how to support cli params, env vars and config file with viper but no cobra?

huangapple go评论159阅读模式
英文:

golang: how to support cli params, env vars and config file with viper but no cobra?

问题

我正在尝试编写一个只有一个命令的应用程序,因此,我在考虑是否可以跳过使用Cobra。

该应用程序应该能够支持所有类型的配置:

  • 命令行参数
  • 环境变量
  • 配置文件

我正在使用viper,但无法读取我的命令行参数。

  v := viper.New()
  viper.SetConfigName("config") 
  viper.AddConfigPath(".")      
  v.SetDefault(pathKey, defaultPath)

  fs := pflag.NewFlagSet("app", pflag.ExitOnError)
  fs.String(pathKey, defaultPath, "Default path")
  fs.StringSlice(wordsKey, []string{""}, "Words")
  fs.String(loglevelKey, "info", "Log level")

  if err := v.BindPFlags(fs); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  if err := fs.Parse(os.Args[1:]); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }

  v.AutomaticEnv()

  if err := v.ReadInConfig(); err != nil {
    fmt.Println("no conf file") //忽略,可以是命令行参数或配置文件
  }

  var c conf
  if err := v.Unmarshal(&c); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }

但是我从未将命令行参数传递给conf结构体。在Unmarshal之前打印v不显示我提供的任何命令行参数。

我漏掉了什么?我需要使用Cobra吗?
还是我需要手动将每个flagset标志(例如fs.String(pathKey, defaultPath, "Default path"))分配给配置结构体?

英文:

I am trying to write an app which only has one command, hence, I was thinking I might skip Cobra.

The app should be able to support all types of config:

  • command line params
  • env vars
  • config file

I am using viper but I can't get it to read my cli params.

  v := viper.New()
  viper.SetConfigName("config") 
  viper.AddConfigPath(".")      
  v.SetDefault(pathKey, defaultPath)

  fs := pflag.NewFlagSet("app", pflag.ExitOnError)
  fs.String(pathKey, defaultPath, "Default path")
  fs.StringSlice(wordsKey, []string{""}, "Words")
  fs.String(loglevelKey, "info", "Log level")

  if err := v.BindPFlags(fs); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }
  if err := fs.Parse(os.Args[1:]); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }

  v.AutomaticEnv()

  if err := v.ReadInConfig(); err != nil {
    fmt.Println("no conf file") //ignore, it can be either cli params, or conf file
  }

  var c conf
  if err := v.Unmarshal(&c); err != nil {
    fmt.Println(err)
    os.Exit(1)
  }

But I never get the cli params into the conf struct. Printing v before the Unmarshal doesn't show any of the cli params I provide.

What am I missing? Do I need to use cobra for this?
Or do I have to assign each flagset flag, e.g. fs.String(pathKey, defaultPath, "Default path"), manually to the config struct?

答案1

得分: 1

为了后世,我认为我找到了问题所在:

我的conf结构体的键名与标志不对应。例如,设置json:"logLevel",而字段名为DisplayLogLevel是不够的,必须是:

const (
  pathKey = "path"
  wordsKey = "words"
  logLevelKey = "logLevel"
)

type conf struct {
   Path string `json:"path"`
   Words []string `json:"words"`
   LogLevel string `json:"logLevel"`
}
英文:

For posterity, I think I found the issue:

My conf struct didn't have the correspondent key names as the flags do. Setting the json:"logLevel" for example while the field is called DisplayLogLevel is not enough, it must be:

const (
  pathKey = "path"
  wordsKey = "words"
  logLevelKey = "logLevel"
)

type conf struct {
   Path string `json:"path"`
   Words []string `json:"words"`
   LogLevel string `json:"logLevel"`
}

答案2

得分: 0

也许你需要设置配置类型。从https://github.com/spf13/viper中获取:

viper.SetConfigType("yaml") // 如果配置文件的名称中没有扩展名,则需要设置此项

英文:

maybe you have to set config type. From https://github.com/spf13/viper:

viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name

huangapple
  • 本文由 发表于 2022年1月12日 04:13:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/70672896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定