cobraとviperで設定ファイルの値をフラグの値で上書きする
Go言語でコマンドを作ろうとしたときに、オプションの指定に設定ファイルの読み込みと、オプションで読み込んだ値を上書きをしたかったのでcobraとviperでの実現の仕方を確認する。
ロングオプションを利用する
を参考に。
記事にあるように、 viper.BindPFlag() を呼び出さないと値がフラグの値で更新されない。
また、PersistentFlags().String()でデフォルト値を設定しても、configFileの指定と違い意味が無いので行わない。
package main import ( "github.com/spf13/cobra" "fmt" "github.com/spf13/viper" "os" ) // 設定項目 type Config struct { ApplicationName string Debug bool } // 設定ファイル名 var configFile string var config Config func main() { rootCmd := &cobra.Command{ Use: "app", Run: func(c *cobra.Command, args []string) { // セットされた値の取得 fmt.Printf("configFile: %s\nconfig: %#v\n", configFile, config) }, } // デフォルト値を設定する rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "default_config.toml", "config file name") rootCmd.PersistentFlags().String("name", "", "application name") viper.BindPFlag("ApplicationName", rootCmd.PersistentFlags().Lookup("name")) cobra.OnInitialize(func() { viper.SetConfigFile(configFile) viper.AutomaticEnv() if err := viper.ReadInConfig(); err != nil { fmt.Println("config file read error") fmt.Println(err) os.Exit(1) } if err := viper.Unmarshal(&config); err != nil { fmt.Println("config file Unmarshal error") fmt.Println(err) os.Exit(1) } }) if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } println(config.ApplicationName) }
ショートオプションも追加
ヘルプオプションの実行結果
$ go run main.go --help Usage: app [flags] Flags: -c, --config string config file name (default "default_config.toml") -h, --help help for app -n, --name string application name
ショートオプションを使うには PersistentFlags().StringVarP() を利用する。
pflag/flag.go at master · spf13/pflag · GitHubにあるようにショートオプションには1文字のみ利用可能で、それ以上の文字を指定するとエラーになる。
package main import ( "github.com/spf13/cobra" "fmt" "github.com/spf13/viper" "os" ) // 設定項目 type Config struct { ApplicationName string Debug bool } // 設定ファイル名 var configFile string var config Config func main() { rootCmd := &cobra.Command{ Use: "app", Run: func(c *cobra.Command, args []string) { // セットされた値の取得 fmt.Printf("configFile: %s\nconfig: %#v\n", configFile, config) }, } // デフォルト値を設定する rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "default_config.toml", "config file name") rootCmd.PersistentFlags().StringVarP(&config.ApplicationName, "name", "n", "", "application name") viper.BindPFlag("ApplicationName", rootCmd.PersistentFlags().Lookup("name")) cobra.OnInitialize(func() { viper.SetConfigFile(configFile) viper.AutomaticEnv() if err := viper.ReadInConfig(); err != nil { fmt.Println("config file read error") fmt.Println(err) os.Exit(1) } if err := viper.Unmarshal(&config); err != nil { fmt.Println("config file Unmarshal error") fmt.Println(err) os.Exit(1) } }) if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) } println(config.ApplicationName)
実行結果を見るとやりたかったことが実現出来ていることがわかる。
$ cat default_config.toml ApplicationName = "DEFAULT_APP_TOML" Debug = true $ go run main.go configFile: default_config.toml config: main.Config{ApplicationName:"DEFAULT_APP_TOML", Debug:true} DEFAULT_APP_TOML $ go run main.go -n abc configFile: default_config.toml config: main.Config{ApplicationName:"abc", Debug:true} abc