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

[SG-1060] Add custom vars to CLI config #928

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ vue/dist
release/
mytestnet/
github.com/

.vscode/
231 changes: 231 additions & 0 deletions cmd/starsd/cmd/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package cmd

import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"text/template"

"github.com/spf13/cobra"
viper "github.com/spf13/viper"

tmcli "github.com/cometbft/cometbft/libs/cli"

"github.com/cosmos/cosmos-sdk/client"
scconfig "github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/flags"
)

type StargazeCustomClient struct {
scconfig.ClientConfig
Gas string `mapstructure:"gas" json:"gas"`
GasPrices string `mapstructure:"gas-prices" json:"gas-prices"`
GasAdjustment string `mapstructure:"gas-adjustment" json:"gas-adjustment"`

Fees string `mapstructure:"fees" json:"fees"`
FeeGranter string `mapstructure:"fee-granter" json:"fee-granter"`
FeePayer string `mapstructure:"fee-payer" json:"fee-payer"`

Note string `mapstructure:"note" json:"note"`
}

// ConfigCmd returns a CLI command to interactively create an application CLI
// config file.
func ConfigCmd() *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")

conf, err := getClientConfig(configPath, clientCtx.Viper)
if err != nil {
return fmt.Errorf("couldn't get client config: %v", err)
}

scc := StargazeCustomClient{
*conf,
os.Getenv("STARSD_GAS"),
os.Getenv("STARSD_GAS_PRICES"),
os.Getenv("STARSD_GAS_ADJUSTMENT"),

os.Getenv("STARSD_FEES"),
os.Getenv("STARSD_FEE_GRANTER"),
os.Getenv("STARSD_FEE_PAYER"),

os.Getenv("STARSD_NOTE"),
}

switch len(args) {
case 0:
s, err := json.MarshalIndent(scc, "", "\t")
if err != nil {
return err
}

cmd.Println(string(s))

case 1:
// it's a get
key := args[0]

switch key {
case flags.FlagChainID:
cmd.Println(conf.ChainID)
case flags.FlagKeyringBackend:
cmd.Println(conf.KeyringBackend)
case tmcli.OutputFlag:
cmd.Println(conf.Output)
case flags.FlagNode:
cmd.Println(conf.Node)
case flags.FlagBroadcastMode:
cmd.Println(conf.BroadcastMode)

// Custom flags
case flags.FlagGas:
cmd.Println(scc.Gas)
case flags.FlagGasPrices:
cmd.Println(scc.GasPrices)
case flags.FlagGasAdjustment:
cmd.Println(scc.GasAdjustment)
case flags.FlagFees:
cmd.Println(scc.Fees)
case flags.FlagFeeGranter:
cmd.Println(scc.FeeGranter)
case flags.FlagFeePayer:
cmd.Println(scc.FeePayer)
case flags.FlagNote:
cmd.Println(scc.Note)
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:
scc.ChainID = value
case flags.FlagKeyringBackend:
scc.KeyringBackend = value
case tmcli.OutputFlag:
scc.Output = value
case flags.FlagNode:
scc.Node = value
case flags.FlagBroadcastMode:
scc.BroadcastMode = value
case flags.FlagGas:
scc.Gas = value
case flags.FlagGasPrices:
scc.GasPrices = value
scc.Fees = "" // resets since we can only use 1 at a time
case flags.FlagGasAdjustment:
scc.GasAdjustment = value
case flags.FlagFees:
scc.Fees = value
scc.GasPrices = "" // resets since we can only use 1 at a time
case flags.FlagFeeGranter:
scc.FeeGranter = value
case flags.FlagFeePayer:
scc.FeePayer = value
case flags.FlagNote:
scc.Note = value
default:
return errUnknownConfigKey(key)
}

confFile := filepath.Join(configPath, "client.toml")
if err := writeConfigToFile(confFile, &scc); err != nil {
return fmt.Errorf("could not write client config to the file: %v", err)
}

default:
panic("cound not execute config command")
}

return nil
}

const defaultConfigTemplate = `# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml

###############################################################################
### Client Configuration ###
###############################################################################

# The network chain ID
chain-id = "{{ .ChainID }}"
# The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory)
keyring-backend = "{{ .KeyringBackend }}"
# CLI output format (text|json)
output = "{{ .Output }}"
# <host>:<port> to Tendermint RPC interface for this chain
node = "{{ .Node }}"
# Transaction broadcasting mode (sync|async|block)
broadcast-mode = "{{ .BroadcastMode }}"

# Amount of gas per transaction
gas = "{{ .Gas }}"
# Price per unit of gas (ex: 0.005ujuno)
gas-prices = "{{ .GasPrices }}"
gas-adjustment = "{{ .GasAdjustment }}"

# Fees to use instead of set gas prices
fees = "{{ .Fees }}"
fee-granter = "{{ .FeeGranter }}"
fee-payer = "{{ .FeePayer }}"

# Memo to include in your Transactions
note = "{{ .Note }}"
`

// writeConfigToFile parses defaultConfigTemplate, renders config using the template and writes it to
// configFilePath.
func writeConfigToFile(configFilePath string, config *StargazeCustomClient) error {
var buffer bytes.Buffer

tmpl := template.New("clientConfigFileTemplate")
configTemplate, err := tmpl.Parse(defaultConfigTemplate)
if err != nil {
return err
}

if err := configTemplate.Execute(&buffer, config); err != nil {
return err
}

return os.WriteFile(configFilePath, buffer.Bytes(), 0o600)
}

// getClientConfig reads values from client.toml file and unmarshalls them into ClientConfig
func getClientConfig(configPath string, v *viper.Viper) (*scconfig.ClientConfig, error) {
v.AddConfigPath(configPath)
v.SetConfigName("client")
v.SetConfigType("toml")

if err := v.ReadInConfig(); err != nil {
return nil, err
}

conf := new(scconfig.ClientConfig)
if err := v.Unmarshal(conf); err != nil {
return nil, err
}

return conf, nil
}

func errUnknownConfigKey(key string) error {
return fmt.Errorf("unknown configuration key: %q", key)
}
46 changes: 45 additions & 1 deletion cmd/starsd/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
WithHomeDir(app.DefaultNodeHome).
WithViper(EnvironmentPrefix)

// Enables extra params in client.toml like gas, gas-price, gas-adjustment, fees, note, etc.
SetCustomEnvVariablesFromClientToml(initClientCtx)

rootCmd := &cobra.Command{
Use: version.AppName,
Short: "Stargaze App",
Expand Down Expand Up @@ -100,12 +103,53 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
return rootCmd, encodingConfig
}

// Reads the custom extra values in the config.toml file if set.
// If they are, then use them.
func SetCustomEnvVariablesFromClientToml(ctx client.Context) {
configFilePath := filepath.Join(ctx.HomeDir, "config", "client.toml")

if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
return
}

viper := ctx.Viper
viper.SetConfigFile(configFilePath)

if err := viper.ReadInConfig(); err != nil {
panic(err)
}

setEnvFromConfig := func(key string, envVar string) {
// if the user sets the env key manually, then we don't want to override it
if os.Getenv(envVar) != "" {
return
}

// reads from the config file
val := viper.GetString(key)
if val != "" {
// Sets the env for this instance of the app only.
os.Setenv(envVar, val)
}
}

// gas
setEnvFromConfig("gas", "STARSD_GAS")
setEnvFromConfig("gas-prices", "STARSD_GAS_PRICES")
setEnvFromConfig("gas-adjustment", "STARSD_GAS_ADJUSTMENT")
// fees
setEnvFromConfig("fees", "STARSD_FEES")
setEnvFromConfig("fee-account", "STARSD_FEE_ACCOUNT")
// memo
setEnvFromConfig("note", "STARSD_NOTE")
}

func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
rootCmd.AddCommand(
genutilcli.InitCmd(app.ModuleBasics, app.DefaultNodeHome),
tmcli.NewCompletionCmd(rootCmd, true),
debug.Cmd(),
config.Cmd(),
ConfigCmd(),
Bech32Cmd(),
pruning.PruningCmd(newApp),
)
Expand Down
Loading