Skip to content
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

R4R: Fix gaiacli config and make it non-interactive only #2972

Merged
merged 6 commits into from
Dec 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@
name = "github.com/rakyll/statik"
version = "=v0.1.4"

[[constraint]]
name = "github.com/mitchellh/go-homedir"
version = "1.0.0"

## transitive deps, without releases:

[[override]]
Expand Down
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ BREAKING CHANGES
* Gaia CLI (`gaiacli`)
* [cli] [\#2595](https://github.com/cosmos/cosmos-sdk/issues/2595) Remove `keys new` in favor of `keys add` incorporating existing functionality with addition of key recovery functionality.
* [cli] [\#2971](https://github.com/cosmos/cosmos-sdk/pull/2971) Additional verification when running `gaiad gentx`
* [cli] [\#2734](https://github.com/cosmos/cosmos-sdk/issues/2734) Rewrite `gaiacli config`. It is now a non-interactive config utility.

* Gaia
- [#128](https://github.com/tendermint/devops/issues/128) Updated CircleCI job to trigger website build on every push to master/develop.
Expand Down
168 changes: 97 additions & 71 deletions client/config.go
Original file line number Diff line number Diff line change
@@ -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"
)

const (
flagGet = "get"
)

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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI flag and this should just use a constant variable, no? Just to be safe.

}
}

// 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()

gaiaCLIHome, err := handleGaiaCLIHome(home, stdin)
if err != nil {
return err
getAction := viper.GetBool(flagGet)
if getAction && len(args) != 1 {
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
// Print the config and exit
if len(args) == 0 {
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 "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
}

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":
cwgoes marked this conversation as resolved.
Show resolved Hide resolved
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 %s\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) {
fmt.Fprintf(os.Stderr, "%s does not exist\n", cfgFile)
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)
}
Loading