-
Notifications
You must be signed in to change notification settings - Fork 23
Open
Description
Hi there
Long story short, I started from cobra-cli boilerplate, and taking snippets of this repository I got a root command working.
But my issue now is that subcommands don't take env / config file in account, just flags. After trials & errors, seems I would need to add ViperCfg.ReadInConfig()
in all the subcommands' init. Not really elegant, I guess I'm missing something as PersistentPreRun should propagate the viper config reading. But well, beginner's struggles.
So wondering what I'm missing here / how would you deal with subcommands in your setup ?
Here's my root.go
package cmd
import (
"fmt"
"os"
"strings"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)
var logLevel string
var rootCmd = &cobra.Command{
Use: "tool",
Short: "tool is a tool.",
Long: `tool allow you to .`,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if strings.ToLower(logFormat) == "text" {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339}).
With().
Timestamp().
Caller().
Logger()
}
switch strings.ToLower(logLevel) {
case "trace":
zerolog.SetGlobalLevel(zerolog.TraceLevel)
}
},
}
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initializeConfig)
rootCmd.PersistentFlags().StringVarP(&configFile, "config", "c", "", "Configuration file (default /etc/tool/config.yaml > $HOME/.tool/config.yaml > ./.config.yaml)")
rootCmd.PersistentFlags().StringVarP(&logLevel, "loglevel", "l", "INFO", "Log level. From the less verbose to the most, panic, fatal, error, warn, info, debug, trace")
}
var viperCfg viper.Viper
func initializeConfig() {
viperCfg = *viper.New()
if configFile != "" {
viperCfg.SetConfigFile(configFile)
} else {
viperCfg.SetConfigName("config")
home, _ := os.UserHomeDir()
viperCfg.AddConfigPath(".")
viperCfg.AddConfigPath(home + ".config/tool")
viperCfg.AddConfigPath("/etc/tool")
}
if err := viperCfg.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
log.Fatal().Msgf("Couldn't parse configuration file %s", viperCfg.ConfigFileUsed())
}
}
viperCfg.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viperCfg.AutomaticEnv()
bindFlags()
}
func bindFlags() {
rootCmd.Flags().VisitAll(func(f *pflag.Flag) {
configName := f.Name
if !f.Changed && viperCfg.IsSet(configName) {
val := viperCfg.Get(configName)
rootCmd.Flags().Set(f.Name, fmt.Sprintf("%v", val))
}
})
}
And the shortened generate.go
package cmd
import (
"os"
"strings"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
var valuesFile string
var generateCmd = &cobra.Command{
Use: "generate",
Short: "Generate",
Long: `Create the
`,
Run: generate,
}
func init() {
rootCmd.AddCommand(generateCmd)
generateCmd.Flags().StringVarP(&valuesFile, "values", "f", "./values.yaml", "Path of the")
// insert ViperCfg.ReadInConfig() to get the config file settings taken in account
}
func generate(cmd *cobra.Command, args []string) {
_, errVal := os.Stat(valuesFiles)
if os.IsNotExist(errVal) {
log.Fatal().Msgf("Values file '%s' doesn't exist", valuesFiles)
}
// ...
}
Metadata
Metadata
Assignees
Labels
No labels