diff --git a/client/config/config.go b/client/config/config.go index cb66efa2bf94..39cbac3aa5d5 100644 --- a/client/config/config.go +++ b/client/config/config.go @@ -1,85 +1,41 @@ package config import ( + "errors" "fmt" - "io" "os" + "path" "strconv" - "errors" - - toml "github.com/pelletier/go-toml" "github.com/spf13/cobra" "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client/flags" + tmcli "github.com/tendermint/tendermint/libs/cli" ) -const ( - flagGet = "get" -) - -/* - -Plan: - -0. When the user uses the gaiacli config node command to set the node value, - the new value is written successfully to the ~/.gaiacli/config/config.toml - -1.Create $NODE_DIR/config/client.toml to hold all client-side configuration -(e.g. keyring-backend, node, chain-id etc...)+ - - -2. Enable get functionality of client-side configuration - -get examples - -config keyring-backend --get //keyring-backend returns value from config file -config with no args --get //prints default config and exits -config invalidArg --get // returns error unknown conf key -config keyring-backend output --get // returns error too many arguments - -config without arguments // just print config from config file - - -3.Enable set functionality of client side configuration - -config keyring-backend test // sets keyring-backend = test - expected behavior - -config keyring-backend with no arguments // outputs default -config invalidKey invalidValue - - -*/ - var ErrWrongNumberOfArgs = fmt.Errorf("wrong number of arguments") - -type ClientConfig struct{ - - ChainID string `mapstructure:"chain-id"` +type ClientConfig struct { + ChainID string `mapstructure:"chain-id"` KeyringBackend string `mapstructure:"keyring-backend"` - Output string `mapstructure:"output"` - Node string `mapstructure:"node"` - BroadcastMode string `mapstructure:"broadcast-mode"` - Trace bool `mapstructure:"trace"` + Output string `mapstructure:"output"` + Node string `mapstructure:"node"` + BroadcastMode string `mapstructure:"broadcast-mode"` + Trace bool `mapstructure:"trace"` } func DefaultClientConfig() *ClientConfig { return &ClientConfig{ - ChainID : "", - KeyringBackend :"os", - Output : "text", - Node: "tcp://localhost:26657", - BroadcastMode : "sync", - Trace : false, + ChainID: "", + KeyringBackend: "os", + Output: "text", + Node: "tcp://localhost:26657", + BroadcastMode: "sync", + Trace: false, } } - - // Cmd returns a CLI command to interactively create an application CLI // config file. func Cmd(defaultCLIHome string) *cobra.Command { @@ -92,220 +48,104 @@ func Cmd(defaultCLIHome string) *cobra.Command { cmd.Flags().String(flags.FlagHome, defaultCLIHome, "set client's home directory for configuration") - cmd.Flags().Bool(flagGet, false, - "print configuration value or its default if unset") + // cmd.Flags().Bool(flagGet, false, + // "print configuration value or its default if unset") return cmd } func runConfigCmd(cmd *cobra.Command, args []string) error { - - InitConfigTemplate() + v := viper.New() - cfgPath, err := ensureConfFile(viper.GetString(flags.FlagHome)) + cfgPath, err := ensureCfgPath(v.GetString(flags.FlagHome)) if err != nil { + fmt.Fprintf(os.Stderr, "Unable to make config path: %v\n", err) return err } - getAction := viper.GetBool(flagGet) - if getAction && len(args) != 1 { - return ErrWrongNumberOfArgs - } - - cliConfig, err := getClientConfig(cfgPath) + cliConfig, err := getClientConfig(cfgPath, v) if err != nil { - return fmt.Errorf("Unable to get client config %v", err) + fmt.Fprintf(os.Stderr, "Unable to get client config: %v\n", err) + return err } - switch len(args) { case 0: // print all client config fields to sdt out - // TODO implement method to print out all client config fiels + // TODO implement method to print out all client config fields fmt.Println(cliConfig.ChainID) fmt.Println(cliConfig.KeyringBackend) fmt.Println(cliConfig.Output) fmt.Println(cliConfig.Node) fmt.Println(cliConfig.BroadcastMode) fmt.Println(cliConfig.Trace) - + case 1: - // it's a get + // it's a get // TODO implement method for get + // should i implement getters here? key := args[0] switch key { - case "chain-id": fmt.Println(cliConfig.ChainID) - case "keyring-backend": fmt.Println(cliConfig.KeyringBackend) - case "output": fmt.Println(cliConfig.Output) - case "node": fmt.Println(cliConfig.Node) - case "broadcast-mode": fmt.Println(cliConfig.BroadcastMode) - case "trace": fmt.Println(cliConfig.Trace) - default : - return errUnknownConfigKey(key) + case flags.FlagChainID: + fmt.Println(cliConfig.ChainID) + case flags.FlagKeyringBackend: + fmt.Println(cliConfig.KeyringBackend) + case tmcli.OutputFlag: + fmt.Println(cliConfig.Output) + case flags.FlagNode: + fmt.Println(cliConfig.Node) + case flags.FlagBroadcastMode: + fmt.Println(cliConfig.BroadcastMode) + case "trace": + fmt.Println(cliConfig.Trace) + default: + err := errUnknownConfigKey(key) + fmt.Fprintf(os.Stderr, "Unable to get the value for the key: %v, error: %v\n", key, err) + return err } case 2: // it's set // TODO impement method for set // TODO implement setters - key, value := args[0], args[1] - switch key { - case "chain-id": cliConfig.ChainID = value - case "keyring-backend": cliConfig.KeyringBackend = value - case "output": cliConfig.Output = value - case "node": cliConfig.Node = value - case "broadcast-mode": cliConfig.BroadcastMode = value - case "trace": - boolVal, err := strconv.ParseBool(value) - if err != nil { - return err - } - cliConfig.Trace = boolVal - default : - return errUnknownConfigKey(key) - } - - default: - // print error - return errors.New("Unknown configuration error") - } - - - WriteConfigFile() - - - - return nil - - - - - - - - -} + key, value := args[0], args[1] - -/* -func runConfigCmd(cmd *cobra.Command, args []string) error { - cfgFile, err := ensureConfFile(viper.GetString(flags.FlagHome)) - if err != nil { - return err - } - - getAction := viper.GetBool(flagGet) - if getAction && len(args) != 1 { - return fmt.Errorf("wrong number of arguments") - } - - // load configuration - tree, err := loadConfigFile(cfgFile) - if err != nil { - return err - } - - // print the default config and exit - if len(args) == 0 { - s, err := tree.ToTomlString() - if err != nil { - return err - } - fmt.Print(s) - return nil - } - - key := args[0] - - // get config value for a given key - if getAction { switch key { - case "chain-id", "keyring-backend", "output", "node", "broadcast-mode": - fmt.Println(tree.Get(key).(string)) - + case flags.FlagChainID: + cliConfig.ChainID = value + case flags.FlagKeyringBackend: + cliConfig.KeyringBackend = value + case tmcli.OutputFlag: + cliConfig.Output = value + case flags.FlagNode: + cliConfig.Node = value + case flags.FlagBroadcastMode: + cliConfig.BroadcastMode = value case "trace": - fmt.Println(tree.Get(key).(bool)) - - default: - // do we need to print out default value here in case key is invalid? - if defaultValue, ok := configDefaults[key]; ok { - fmt.Println(tree.GetDefault(key, defaultValue).(string)) - return nil + boolVal, err := strconv.ParseBool(value) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse value to bool, err: %v\n", err) + return err } - + cliConfig.Trace = boolVal + default: return errUnknownConfigKey(key) } - return nil - } - - // if we set value in configuration, the number of arguments must be 2 - if len(args) != 2 { - return ErrWrongNumberOfArgs - } - - value := args[1] - - // set config value for a given key - switch key { - case "chain-id", "keyring-backend", "output", "node", "broadcast-mode": - tree.Set(key, value) - - case "trace": - boolVal, err := strconv.ParseBool(value) - if err != nil { - return err - } - - tree.Set(key, boolVal) + configTemplate := InitConfigTemplate() + cfgFile := path.Join(cfgPath, "config.toml") + WriteConfigFile(cfgFile, cliConfig, configTemplate) default: - return errUnknownConfigKey(key) - } - - // save configuration to disk - if err := saveConfigFile(cfgFile, tree); err != nil { + // print error + err := errors.New("unable to execute config command") + fmt.Fprintf(os.Stderr, "%v\n", err) return err } - fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile) return nil } -*/ - - -/* -func loadConfigFile(cfgFile string) (*toml.Tree, error) { - if _, err := os.Stat(cfgFile); os.IsNotExist(err) { - fmt.Fprintf(os.Stderr, "%s does not exist\n", cfgFile) - return toml.Load(``) - } - - bz, err := ioutil.ReadFile(cfgFile) - if err != nil { - return nil, err - } - - tree, err := toml.LoadBytes(bz) - if err != nil { - return nil, err - } - - return tree, nil -} -*/ - -func saveConfigFile(cfgFile string, tree io.WriterTo) error { - fp, err := os.OpenFile(cfgFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644) - if err != nil { - return err - } - defer fp.Close() - - _, err = tree.WriteTo(fp) - return err -} func errUnknownConfigKey(key string) error { return fmt.Errorf("unknown configuration key: %q", key) diff --git a/client/config/toml.go b/client/config/toml.go index 7332a81becac..0b2c38494624 100644 --- a/client/config/toml.go +++ b/client/config/toml.go @@ -2,10 +2,9 @@ package config import ( "bytes" - "text/template" "os" "path" - + "text/template" "github.com/spf13/viper" tmos "github.com/tendermint/tendermint/libs/os" @@ -27,41 +26,42 @@ broadcast-mode = "{{ .ClientConfig.BroadcastMode }}" trace = "{{ .ClientConfig.Trace }}" ` -var configTemplate *template.Template - -func InitConfigTemplate() { - var err error - +// InitConfigTemplate initiates config template that will be used in +// WriteConfigFile +func InitConfigTemplate() *template.Template { tmpl := template.New("clientConfigFileTemplate") - - if configTemplate, err = tmpl.Parse(defaultConfigTemplate); err != nil { + configTemplate, err := tmpl.Parse(defaultConfigTemplate) + if err != nil { panic(err) } + return configTemplate } // ParseConfig retrieves the default environment configuration for the // application. -func ParseConfig() *ClientConfig { +func ParseConfig(v *viper.Viper) (*ClientConfig, error) { conf := DefaultClientConfig() - _ = viper.Unmarshal(conf) + if err := v.Unmarshal(conf); err != nil { + return nil, err + } - return conf + return conf, nil } // WriteConfigFile renders config using the template and writes it to // configFilePath. -func WriteConfigFile(configFilePath string, config *ClientConfig) { +func WriteConfigFile(cfgFile string, config *ClientConfig, configTemplate *template.Template) { var buffer bytes.Buffer if err := configTemplate.Execute(&buffer, config); err != nil { panic(err) } - tmos.MustWriteFile(configFilePath, buffer.Bytes(), 0644) + tmos.MustWriteFile(cfgFile, buffer.Bytes(), 0644) } -func ensureConfFile(rootDir string) (string, error) { +func ensureCfgPath(rootDir string) (string, error) { cfgPath := path.Join(rootDir, "config") if err := os.MkdirAll(cfgPath, os.ModePerm); err != nil { // config directory return "", err @@ -70,18 +70,19 @@ func ensureConfFile(rootDir string) (string, error) { return cfgPath, nil } -func getClientConfig(cfgPath string) (*ClientConfig, error) { - viper.AddConfigPath(cfgPath) - viper.SetConfigName("client") - viper.SetConfigType("toml") - if err := viper.ReadInConfig(); err != nil { +func getClientConfig(cfgPath string, v *viper.Viper) (*ClientConfig, error) { + v.AddConfigPath(cfgPath) + v.SetConfigName("client") + v.SetConfigType("toml") + v.AutomaticEnv() + if err := v.ReadInConfig(); err != nil { return nil, err } conf := new(ClientConfig) - if err := viper.Unmarshal(conf); err != nil { + if err := v.Unmarshal(conf); err != nil { return nil, err } - return conf,nil + return conf, nil } diff --git a/server/util.go b/server/util.go index 68f1c4828166..86c9f0fd7d75 100644 --- a/server/util.go +++ b/server/util.go @@ -14,6 +14,7 @@ import ( "syscall" "time" + clicfg "github.com/cosmos/cosmos-sdk/client/config" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" @@ -242,6 +243,18 @@ func interceptConfigs(rootViper *viper.Viper) (*tmcfg.Config, error) { return nil, fmt.Errorf("failed to merge configuration: %w", err) } + // Adding default ClientConfig and writing it into "client.toml" + cliCfgFilePath := filepath.Join(configPath, "client.toml") + if _, err := os.Stat(cliCfgFilePath); os.IsNotExist(err) { + cliConfig, err := clicfg.ParseConfig(rootViper) + if err != nil { + return nil, fmt.Errorf("failed to parse %s: %w", cliCfgFilePath, err) + } + + configTemplate := clicfg.InitConfigTemplate() + clicfg.WriteConfigFile(cliCfgFilePath, cliConfig, configTemplate) + } + return conf, nil } diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 676427248971..0c7f7725bc29 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -94,7 +94,7 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { // add rosetta rootCmd.AddCommand(server.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler)) - // add cli config + // add client config rootCmd.AddCommand(clicfg.Cmd(flags.FlagHome)) }