-
Notifications
You must be signed in to change notification settings - Fork 3.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add client config #8820
Closed
cyberbono3
wants to merge
14
commits into
cosmos:master
from
cyberbono3:cyberbono3/8529-add-client-config
Closed
Add client config #8820
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
aecceec
add client config draft
cyberbono3 536ec0d
my current state
cyberbono3 8dbc688
refactored code,feedback required
cyberbono3 b7c9376
use json to print out all fields of ClientConfig struct
cyberbono3 d0a3197
introduce default constant values for ClientConfig
cyberbono3 db07ea2
removed panic from WriteConfigFile and InitConfigTemplate
cyberbono3 7a1f9a8
implemented setters for ClientConfig
cyberbono3 20f5f98
modified root.go to add clicfg.Cmd to rootCmd and util.go in intercep…
cyberbono3 f4f6dde
able to write config to client.toml
cyberbono3 560a740
refactored, config subcommand works
cyberbono3 a807879
UpdateClientContextFromClientConfig
cyberbono3 8125d5e
ReadFromClientConfig
cyberbono3 ec04cac
homeflag bug fixed
cyberbono3 d2250f6
current state
cyberbono3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package config | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"path/filepath" | ||
|
||
tmcli "github.com/tendermint/tendermint/libs/cli" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/client/flags" | ||
) | ||
|
||
// Cmd returns a CLI command to interactively create an application CLI | ||
// config file. | ||
func Cmd() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "config <key> [value]", | ||
Short: "Create or query an application CLI configuration file", | ||
RunE: runConfigCmd, | ||
Args: cobra.RangeArgs(0, 2), | ||
} | ||
return cmd | ||
} | ||
|
||
func runConfigCmd(cmd *cobra.Command, args []string) error { | ||
|
||
clientCtx := client.GetClientContextFromCmd(cmd) | ||
configPath := filepath.Join(clientCtx.HomeDir, "config") | ||
|
||
/* | ||
if err := ensureConfigPath(configPath); err != nil { | ||
return fmt.Errorf("couldn't make client config: %v", err) | ||
} | ||
*/ | ||
|
||
cliConfig, err := getClientConfig(configPath, clientCtx.Viper) | ||
if err != nil { | ||
return fmt.Errorf("couldn't get client config: %v", err) | ||
} | ||
|
||
switch len(args) { | ||
case 0: | ||
// print all client config fields to sdt out | ||
s, _ := json.MarshalIndent(cliConfig, "", "\t") | ||
cmd.Println(string(s)) | ||
|
||
case 1: | ||
// it's a get | ||
// TODO implement method for get | ||
// should i implement getters here? | ||
key := args[0] | ||
switch key { | ||
case flags.FlagChainID: | ||
cmd.Println(cliConfig.ChainID) | ||
case flags.FlagKeyringBackend: | ||
cmd.Println(cliConfig.KeyringBackend) | ||
case tmcli.OutputFlag: | ||
cmd.Println(cliConfig.Output) | ||
case flags.FlagNode: | ||
cmd.Println(cliConfig.Node) | ||
case flags.FlagBroadcastMode: | ||
cmd.Println(cliConfig.BroadcastMode) | ||
default: | ||
err := errUnknownConfigKey(key) | ||
return fmt.Errorf("couldn't get the value for the key: %v, error: %v", key, err) | ||
} | ||
|
||
case 2: | ||
// it's set | ||
|
||
key, value := args[0], args[1] | ||
|
||
switch key { | ||
case flags.FlagChainID: | ||
cliConfig.SetChainID(value) | ||
case flags.FlagKeyringBackend: | ||
cliConfig.SetKeyringBackend(value) | ||
case tmcli.OutputFlag: | ||
cliConfig.SetOutput(value) | ||
case flags.FlagNode: | ||
cliConfig.SetNode(value) | ||
case flags.FlagBroadcastMode: | ||
cliConfig.SetBroadcastMode(value) | ||
default: | ||
return errUnknownConfigKey(key) | ||
} | ||
|
||
configTemplate, err := initConfigTemplate() | ||
if err != nil { | ||
return fmt.Errorf("could not initiate config template: %v", err) | ||
} | ||
|
||
cliConfigFile := filepath.Join(configPath, "client.toml") | ||
if err := writeConfigFile(cliConfigFile, cliConfig, configTemplate); err != nil { | ||
return fmt.Errorf("could not write client config to the file: %v", err) | ||
} | ||
|
||
default: | ||
// print error | ||
return errors.New("cound not execute config command") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func errUnknownConfigKey(key string) error { | ||
return fmt.Errorf("unknown configuration key: %q", key) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
) | ||
|
||
// Default constants | ||
const ( | ||
chainID = "" | ||
keyringBackend = "os" | ||
output = "text" | ||
node = "tcp://localhost:26657" | ||
broadcastMode = "sync" | ||
) | ||
|
||
type ClientConfig struct { | ||
ChainID string `mapstructure:"chain-id" json:"chain-id"` | ||
KeyringBackend string `mapstructure:"keyring-backend" json:"keyring-backend"` | ||
Output string `mapstructure:"output" json:"output"` | ||
Node string `mapstructure:"node" json:"node"` | ||
BroadcastMode string `mapstructure:"broadcast-mode" json:"broadcast-mode"` | ||
} | ||
|
||
func DefaultClientConfig() *ClientConfig { | ||
return &ClientConfig{chainID, keyringBackend, output, node, broadcastMode} | ||
} | ||
|
||
func (c *ClientConfig) SetChainID(chainID string) { | ||
c.ChainID = chainID | ||
} | ||
|
||
func (c *ClientConfig) SetKeyringBackend(keyringBackend string) { | ||
c.KeyringBackend = keyringBackend | ||
} | ||
|
||
func (c *ClientConfig) SetOutput(output string) { | ||
c.Output = output | ||
} | ||
|
||
func (c *ClientConfig) SetNode(node string) { | ||
c.Node = node | ||
} | ||
|
||
func (c *ClientConfig) SetBroadcastMode(broadcastMode string) { | ||
c.BroadcastMode = broadcastMode | ||
} | ||
|
||
// ReadFromClientConfig reads values from client.toml file and updates them in client Context | ||
func ReadFromClientConfig(ctx client.Context) (client.Context, error) { | ||
|
||
configPath := filepath.Join(ctx.HomeDir, "config") | ||
configFilePath := filepath.Join(configPath, "client.toml") | ||
|
||
conf := DefaultClientConfig() | ||
|
||
switch _, err := os.Stat(configFilePath); { | ||
// config file does not exist | ||
case os.IsNotExist(err): | ||
// we create ~/.simapp/config/client.toml with default values | ||
|
||
// create a directority configPath | ||
if err := ensureConfigPath(configPath); err != nil { | ||
amaury1093 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return ctx, fmt.Errorf("couldn't make client config: %v", err) | ||
} | ||
|
||
configTemplate, err := initConfigTemplate() | ||
if err != nil { | ||
return ctx, fmt.Errorf("could not initiate config template: %v", err) | ||
} | ||
|
||
if err := writeConfigFile(configFilePath, conf, configTemplate); err != nil { | ||
return ctx, fmt.Errorf("could not write client config to the file: %v", err) | ||
} | ||
// config file exists and we read config values from client.toml file | ||
default: | ||
conf, err = getClientConfig(configPath, ctx.Viper) | ||
if err != nil { | ||
return ctx, fmt.Errorf("couldn't get client config: %v", err) | ||
} | ||
} | ||
|
||
keyring, err := client.NewKeyringFromFlags(ctx, conf.KeyringBackend) | ||
if err != nil { | ||
return ctx, fmt.Errorf("couldn't get key ring: %v", err) | ||
} | ||
|
||
ctx = ctx.WithChainID(conf.ChainID). | ||
WithKeyring(keyring). | ||
WithOutputFormat(conf.Output). | ||
WithNodeURI(conf.Node). | ||
WithBroadcastMode(conf.BroadcastMode) | ||
|
||
return ctx, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package config | ||
|
||
import ( | ||
"errors" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var ErrWrongNumberOfArgs = errors.New("wrong number of arguments") | ||
|
||
// For https://github.com/cosmos/cosmos-sdk/issues/3899 | ||
func Test_runConfigCmdTwiceWithShorterNodeValue(t *testing.T) { | ||
// Prepare environment | ||
t.Parallel() | ||
cleanup := tmpDir(t) | ||
defer cleanup() | ||
_ = os.RemoveAll(filepath.Join("config")) | ||
|
||
// Init command config | ||
cmd := Cmd() | ||
assert.NotNil(t, cmd) | ||
|
||
err := cmd.RunE(cmd, []string{"node", "tcp://localhost:26657"}) | ||
assert.Nil(t, err) | ||
|
||
err = cmd.RunE(cmd, []string{"node", "--get"}) | ||
assert.Nil(t, err) | ||
|
||
err = cmd.RunE(cmd, []string{"node", "tcp://local:26657"}) | ||
assert.Nil(t, err) | ||
|
||
err = cmd.RunE(cmd, []string{"node", "--get"}) | ||
assert.Nil(t, err) | ||
|
||
err = cmd.RunE(cmd, nil) | ||
assert.Nil(t, err) | ||
|
||
err = cmd.RunE(cmd, []string{"invalidKey", "--get"}) | ||
require.Equal(t, err, errUnknownConfigKey("invalidKey")) | ||
|
||
err = cmd.RunE(cmd, []string{"invalidArg1"}) | ||
require.Equal(t, err, ErrWrongNumberOfArgs) | ||
|
||
err = cmd.RunE(cmd, []string{"invalidKey", "invalidValue"}) | ||
require.Equal(t, err, errUnknownConfigKey("invalidKey")) | ||
|
||
// TODO add testing of pririty environmental variable, flag and file | ||
// for now manual testign is ok | ||
|
||
} | ||
|
||
func tmpDir(t *testing.T) func() { | ||
dir, err := ioutil.TempDir("", t.Name()+"_") | ||
require.NoError(t, err) | ||
return func() { _ = os.RemoveAll(dir) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package config | ||
|
||
import ( | ||
"bytes" | ||
"os" | ||
"text/template" | ||
|
||
"github.com/spf13/viper" | ||
tmos "github.com/tendermint/tendermint/libs/os" | ||
) | ||
|
||
const defaultConfigTemplate = `# This is a TOML config file. | ||
# For more information, see https://github.com/toml-lang/toml | ||
|
||
############################################################################### | ||
### Client Configuration ### | ||
############################################################################### | ||
|
||
|
||
chain-id = "{{ .ChainID }}" | ||
keyring-backend = "{{ .KeyringBackend }}" | ||
output = "{{ .Output }}" | ||
node = "{{ .Node }}" | ||
broadcast-mode = "{{ .BroadcastMode }}" | ||
` | ||
|
||
// InitConfigTemplate initiates config template that will be used in | ||
// WriteConfigFile | ||
func initConfigTemplate() (*template.Template, error) { | ||
tmpl := template.New("clientConfigFileTemplate") | ||
configTemplate, err := tmpl.Parse(defaultConfigTemplate) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return configTemplate, nil | ||
} | ||
|
||
// writeConfigFile renders config using the template and writes it to | ||
// configFilePath. | ||
func writeConfigFile(cfgFile string, config *ClientConfig, configTemplate *template.Template) error { | ||
var buffer bytes.Buffer | ||
|
||
if err := configTemplate.Execute(&buffer, config); err != nil { | ||
return err | ||
} | ||
|
||
tmos.MustWriteFile(cfgFile, buffer.Bytes(), 0644) | ||
return nil | ||
|
||
} | ||
|
||
func ensureConfigPath(configPath string) error { | ||
if err := os.MkdirAll(configPath, os.ModePerm); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func getClientConfig(configPath string, v *viper.Viper) (*ClientConfig, error) { | ||
|
||
v.AddConfigPath(configPath) | ||
v.SetConfigName("client") | ||
v.SetConfigType("toml") | ||
|
||
if err := v.ReadInConfig(); err != nil { | ||
return nil, err | ||
} | ||
|
||
conf := new(ClientConfig) | ||
if err := v.Unmarshal(conf); err != nil { | ||
return nil, err | ||
} | ||
|
||
return conf, nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we dont need ensureConfigPath anymore, cause ~/.simapp/config directory will exist in any way due to ReadFromClientConfig logic