|
|
- package cli
-
- import (
- "os"
- "path/filepath"
- "strings"
-
- "github.com/spf13/cobra"
- "github.com/spf13/viper"
- )
-
- const (
- HomeFlag = "home"
- TraceFlag = "trace"
- OutputFlag = "output" // used in the cli
- )
-
- // PrepareBaseCmd is meant for tendermint and other servers
- func PrepareBaseCmd(cmd *cobra.Command, envPrefix, defaultHome string) *cobra.Command {
- // the primary caller of this command is in the SDK and
- // returning the cobra.Command object avoids breaking that
- // code. In the long term, the SDK could avoid this entirely.
- cobra.OnInitialize(func() { InitEnv(envPrefix) })
- cmd.PersistentFlags().StringP(HomeFlag, "", defaultHome, "directory for config and data")
- cmd.PersistentFlags().Bool(TraceFlag, false, "print out full stack trace on errors")
- cmd.PersistentPreRunE = concatCobraCmdFuncs(BindFlagsLoadViper, cmd.PersistentPreRunE)
- return cmd
- }
-
- // InitEnv sets to use ENV variables if set.
- func InitEnv(prefix string) {
- // This copies all variables like TMROOT to TM_ROOT,
- // so we can support both formats for the user
- prefix = strings.ToUpper(prefix)
- ps := prefix + "_"
- for _, e := range os.Environ() {
- kv := strings.SplitN(e, "=", 2)
- if len(kv) == 2 {
- k, v := kv[0], kv[1]
- if strings.HasPrefix(k, prefix) && !strings.HasPrefix(k, ps) {
- k2 := strings.Replace(k, prefix, ps, 1)
- os.Setenv(k2, v)
- }
- }
- }
-
- // env variables with TM prefix (eg. TM_ROOT)
- viper.SetEnvPrefix(prefix)
- viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
- viper.AutomaticEnv()
- }
-
- type cobraCmdFunc func(cmd *cobra.Command, args []string) error
-
- // Returns a single function that calls each argument function in sequence
- // RunE, PreRunE, PersistentPreRunE, etc. all have this same signature
- func concatCobraCmdFuncs(fs ...cobraCmdFunc) cobraCmdFunc {
- return func(cmd *cobra.Command, args []string) error {
- for _, f := range fs {
- if f != nil {
- if err := f(cmd, args); err != nil {
- return err
- }
- }
- }
- return nil
- }
- }
-
- // Bind all flags and read the config into viper
- func BindFlagsLoadViper(cmd *cobra.Command, args []string) error {
- // cmd.Flags() includes flags from this command and all persistent flags from the parent
- if err := viper.BindPFlags(cmd.Flags()); err != nil {
- return err
- }
-
- homeDir := viper.GetString(HomeFlag)
- viper.Set(HomeFlag, homeDir)
- viper.SetConfigName("config") // name of config file (without extension)
- viper.AddConfigPath(homeDir) // search root directory
- viper.AddConfigPath(filepath.Join(homeDir, "config")) // search root directory /config
-
- // If a config file is found, read it in.
- if err := viper.ReadInConfig(); err == nil {
- // stderr, so if we redirect output to json file, this doesn't appear
- // fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
- } else if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
- // ignore not found error, return other errors
- return err
- }
- return nil
- }
|