cosmos-sdk/tools/confix/cmd/mutate.go
2024-07-29 06:16:21 +00:00

127 lines
3.8 KiB
Go

package cmd
import (
"context"
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/creachadair/tomledit"
"github.com/creachadair/tomledit/parser"
"github.com/creachadair/tomledit/transform"
"github.com/spf13/cobra"
"cosmossdk.io/tools/confix"
"github.com/cosmos/cosmos-sdk/client"
)
// SetCommand returns a CLI command to interactively update an application config value.
func SetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "set [config] [key] [value]",
Short: "Set an application config value",
Long: "Set an application config value. The [config] argument must be the path of the file when using the `confix` tool standalone, otherwise it must be the name of the config file without the .toml extension.",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
filename, inputValue := args[0], args[2]
// parse key e.g mempool.size -> [mempool, size]
key := strings.Split(args[1], ".")
clientCtx := client.GetClientContextFromCmd(cmd)
if clientCtx.HomeDir != "" {
filename = filepath.Join(clientCtx.HomeDir, "config", filename+tomlSuffix)
}
plan := transform.Plan{
{
Desc: fmt.Sprintf("update %q=%q in %s", key, inputValue, filename),
T: transform.Func(func(_ context.Context, doc *tomledit.Document) error {
results := doc.Find(key...)
if len(results) == 0 {
return fmt.Errorf("key %q not found", key)
} else if len(results) > 1 {
return fmt.Errorf("key %q is ambiguous", key)
}
value, err := parser.ParseValue(inputValue)
if err != nil {
value = parser.MustValue(`"` + inputValue + `"`)
}
if ok := transform.InsertMapping(results[0].Section, &parser.KeyValue{
Block: results[0].Block,
Name: results[0].Name,
Value: value,
}, true); !ok {
return errors.New("failed to set value")
}
return nil
}),
},
}
outputPath := filename
if FlagStdOut {
outputPath = ""
}
ctx := cmd.Context()
if FlagVerbose {
ctx = confix.WithLogWriter(ctx, cmd.ErrOrStderr())
}
doc, err := confix.LoadConfig(filename)
if err != nil {
return err
}
return confix.Upgrade(ctx, plan, doc, filename, outputPath, FlagSkipValidate)
},
}
cmd.Flags().BoolVar(&FlagStdOut, "stdout", false, "print the updated config to stdout")
cmd.Flags().BoolVarP(&FlagVerbose, "verbose", "v", false, "log changes to stderr")
cmd.Flags().BoolVarP(&FlagSkipValidate, "skip-validate", "s", false, "skip configuration validation (allows to mutate unknown configurations)")
return cmd
}
// GetCommand returns a CLI command to interactively get an application config value.
func GetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "get [config] [key]",
Short: "Get an application config value",
Long: "Get an application config value. The [config] argument must be the path of the file when using the `confix` tool standalone, otherwise it must be the name of the config file without the .toml extension.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
filename, key := args[0], args[1]
// parse key e.g mempool.size -> [mempool, size]
keys := strings.Split(key, ".")
clientCtx := client.GetClientContextFromCmd(cmd)
if clientCtx.HomeDir != "" {
filename = filepath.Join(clientCtx.HomeDir, "config", filename+tomlSuffix)
}
doc, err := confix.LoadConfig(filename)
if err != nil {
return fmt.Errorf("failed to load config: %w", err)
}
results := doc.Find(keys...)
if len(results) == 0 {
return fmt.Errorf("key %q not found", key)
} else if len(results) > 1 {
return fmt.Errorf("key %q is ambiguous", key)
}
return clientCtx.PrintString(fmt.Sprintf("%s\n", results[0].Value.String()))
},
}
return cmd
}