-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix gaiacli config and make it non-interactive only
Closes: #2734
- Loading branch information
Alessio Treglia
committed
Dec 4, 2018
1 parent
d8fbae6
commit 7b94da2
Showing
5 changed files
with
111 additions
and
106 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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 |
---|---|---|
@@ -1,131 +1,164 @@ | ||
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" | ||
) | ||
|
||
const ( | ||
flagGet = "get" | ||
flagList = "list" | ||
) | ||
|
||
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"` | ||
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.MaximumNArgs(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") | ||
cmd.Flags().BoolP(flagList, "l", false, | ||
"list all variables set in the config file, along with their values") | ||
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, listAction := viper.GetBool(flagGet), viper.GetBool(flagList) | ||
// Args validation | ||
if listAction && getAction { | ||
return fmt.Errorf("only one action at a time") | ||
} | ||
|
||
gaiaCLIHome, err := handleGaiaCLIHome(home, stdin) | ||
if err != nil { | ||
return err | ||
if (listAction && len(args) != 0) || | ||
(getAction && len(args) != 1) || len(args) != 2 { | ||
return fmt.Errorf("wrong number of arguments") | ||
} | ||
|
||
node, err := handleNode(stdin) | ||
// Load configuration | ||
tree, err := loadConfigFile(cfgFile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
trustNode, err := handleTrustNode(stdin) | ||
if err != nil { | ||
return err | ||
// List action | ||
if listAction { | ||
s, err := tree.ToTomlString() | ||
if err != nil { | ||
return err | ||
} | ||
fmt.Print(s) | ||
return nil | ||
} | ||
|
||
chainID, err := types.DefaultChainID() | ||
key := args[0] | ||
// Get value action | ||
if getAction { | ||
switch key { | ||
case "chain_id", "output", "node": | ||
defaultValue := configDefaults[key] | ||
fmt.Println(tree.GetDefault(key, defaultValue).(string)) | ||
case "trace", "trust_node": | ||
fmt.Println(tree.GetDefault(key, false).(bool)) | ||
default: | ||
return errUnknownConfigKey(key) | ||
} | ||
return nil | ||
} | ||
|
||
if err != nil { | ||
fmt.Println("Couldn't populate ChainID, so using an empty one.") | ||
// 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) | ||
} | ||
|
||
cfg := &cliConfig{ | ||
Home: gaiaCLIHome, | ||
ChainID: chainID, | ||
TrustNode: trustNode, | ||
Output: "text", | ||
Node: node, | ||
Trace: false, | ||
// Save configuration to disk | ||
if err := saveConfigFile(cfgFile, tree); err != nil { | ||
return err | ||
} | ||
fmt.Fprintf(os.Stderr, "configuration saved to %q\n", cfgFile) | ||
|
||
return createGaiaCLIConfig(cfg) | ||
return nil | ||
} | ||
|
||
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 { | ||
func ensureConfFile(rootDir string) (string, error) { | ||
cfgPath := path.Join(rootDir, "config") | ||
if err := os.MkdirAll(cfgPath, os.ModePerm); err != nil { | ||
return "", err | ||
} | ||
|
||
if home == "" { | ||
home = path.Join(dir, dirName) | ||
} | ||
|
||
return home, nil | ||
return path.Join(cfgPath, "config.toml"), 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 | ||
func loadConfigFile(cfgFile string) (*toml.Tree, error) { | ||
if _, err := os.Stat(cfgFile); os.IsNotExist(err) { | ||
return toml.Load(``) | ||
} | ||
|
||
if node == "" { | ||
node = defaultNode | ||
bz, err := ioutil.ReadFile(cfgFile) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
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) | ||
tree, err := toml.LoadBytes(bz) | ||
if err != nil { | ||
return err | ||
return nil, err | ||
} | ||
|
||
data, err := toml.Marshal(*cfg) | ||
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() | ||
|
||
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")) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
_, err = tree.WriteTo(fp) | ||
return err | ||
} | ||
|
||
return ioutil.WriteFile(cfgFile, data, os.ModePerm) | ||
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