Merge PR #2972: Fix gaiacli config and make it non-interactive only
* Fix gaiacli config and make it non-interactive only Closes: #2734 * Update cli tests * Remove --list, by default and with no args print config * Small improvements * Warn user when file doesn't exist * Fix integration tests
This commit is contained in:
committed by
Christopher Goes
parent
d8fbae677f
commit
d32e4a9fe0
+119
-93
@@ -1,131 +1,157 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/pelletier/go-toml"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type cliConfig struct {
|
||||
Home string `toml:"home"`
|
||||
ChainID string `toml:"chain_id"`
|
||||
TrustNode bool `toml:"trust_node"`
|
||||
Output string `toml:"output"`
|
||||
Node string `toml:"node"`
|
||||
Trace bool `toml:"trace"`
|
||||
const (
|
||||
flagGet = "get"
|
||||
)
|
||||
|
||||
var configDefaults map[string]string
|
||||
|
||||
func init() {
|
||||
configDefaults = map[string]string{
|
||||
"chain_id": "",
|
||||
"output": "text",
|
||||
"node": "tcp://localhost:26657",
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigCmd returns a CLI command to interactively create a
|
||||
// Gaia CLI config file.
|
||||
func ConfigCmd() *cobra.Command {
|
||||
cfg := &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Interactively creates a Gaia CLI config file",
|
||||
cmd := &cobra.Command{
|
||||
Use: "config <key> [value]",
|
||||
Short: "Create or query a Gaia CLI configuration file",
|
||||
RunE: runConfigCmd,
|
||||
Args: cobra.RangeArgs(0, 2),
|
||||
}
|
||||
|
||||
return cfg
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultCLIHome,
|
||||
"set client's home directory for configuration")
|
||||
cmd.Flags().Bool(flagGet, false,
|
||||
"print configuration value or its default if unset")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func runConfigCmd(cmd *cobra.Command, args []string) error {
|
||||
home, err := homedir.Dir()
|
||||
cfgFile, err := ensureConfFile(viper.GetString(cli.HomeFlag))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdin := BufferStdin()
|
||||
getAction := viper.GetBool(flagGet)
|
||||
if getAction && len(args) != 1 {
|
||||
return fmt.Errorf("wrong number of arguments")
|
||||
}
|
||||
|
||||
gaiaCLIHome, err := handleGaiaCLIHome(home, stdin)
|
||||
// Load configuration
|
||||
tree, err := loadConfigFile(cfgFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
node, err := handleNode(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trustNode, err := handleTrustNode(stdin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chainID, err := types.DefaultChainID()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("Couldn't populate ChainID, so using an empty one.")
|
||||
}
|
||||
|
||||
cfg := &cliConfig{
|
||||
Home: gaiaCLIHome,
|
||||
ChainID: chainID,
|
||||
TrustNode: trustNode,
|
||||
Output: "text",
|
||||
Node: node,
|
||||
Trace: false,
|
||||
}
|
||||
|
||||
return createGaiaCLIConfig(cfg)
|
||||
}
|
||||
|
||||
func handleGaiaCLIHome(dir string, stdin *bufio.Reader) (string, error) {
|
||||
dirName := ".gaiacli"
|
||||
home, err := GetString(fmt.Sprintf("Where is your gaiacli home directory? (Default: ~/%s)", dirName), stdin)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if home == "" {
|
||||
home = path.Join(dir, dirName)
|
||||
}
|
||||
|
||||
return home, nil
|
||||
}
|
||||
|
||||
func handleNode(stdin *bufio.Reader) (string, error) {
|
||||
defaultNode := "tcp://localhost:26657"
|
||||
node, err := GetString(fmt.Sprintf("Where is your validator node running? (Default: %s)", defaultNode), stdin)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if node == "" {
|
||||
node = defaultNode
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
func handleTrustNode(stdin *bufio.Reader) (bool, error) {
|
||||
return GetConfirmation("Do you trust this node?", stdin)
|
||||
}
|
||||
|
||||
func createGaiaCLIConfig(cfg *cliConfig) error {
|
||||
cfgPath := path.Join(cfg.Home, "config")
|
||||
err := os.MkdirAll(cfgPath, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := toml.Marshal(*cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cfgFile := path.Join(cfgPath, "config.toml")
|
||||
if info, err := os.Stat(cfgFile); err == nil && !info.IsDir() {
|
||||
err = os.Rename(cfgFile, path.Join(cfgPath, "config.toml-old"))
|
||||
// Print the config and exit
|
||||
if len(args) == 0 {
|
||||
s, err := tree.ToTomlString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Print(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(cfgFile, data, os.ModePerm)
|
||||
key := args[0]
|
||||
// Get value action
|
||||
if getAction {
|
||||
switch key {
|
||||
case "trace", "trust_node":
|
||||
fmt.Println(tree.GetDefault(key, false).(bool))
|
||||
default:
|
||||
if defaultValue, ok := configDefaults[key]; ok {
|
||||
fmt.Println(tree.GetDefault(key, defaultValue).(string))
|
||||
return nil
|
||||
}
|
||||
return errUnknownConfigKey(key)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set value action
|
||||
value := args[1]
|
||||
switch key {
|
||||
case "chain_id", "output", "node":
|
||||
tree.Set(key, value)
|
||||
case "trace", "trust_node":
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tree.Set(key, boolVal)
|
||||
default:
|
||||
return errUnknownConfigKey(key)
|
||||
}
|
||||
|
||||
// Save configuration to disk
|
||||
if err := saveConfigFile(cfgFile, tree); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "configuration saved to %s\n", cfgFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureConfFile(rootDir string) (string, error) {
|
||||
cfgPath := path.Join(rootDir, "config")
|
||||
if err := os.MkdirAll(cfgPath, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return path.Join(cfgPath, "config.toml"), 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 *toml.Tree) error {
|
||||
fp, err := os.OpenFile(cfgFile, os.O_WRONLY|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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user