go-ethereum/internal/cli/command.go
Pratik Patil 71980bf5b1
internal/cli: use config file for flags in new-cli, builder/files: update defaults (#457)
* updated simple.json and simple.hcl

* added annotations for developer and grpc block

* added toml tags and simple.toml file

* added support for toml config files

* updated simple files toml, hcl, json

* added config.toml in builder/files and updated bor.service

* add dumpconfig command in cli for exporting configs

* update docs

* updated .goreleaser.yml (POS-651)

* changed --config to -config

* added test config for tests and fixed lint errors

* made fields of type big.int and time.Duration private, removed merge from dumpconfig, setting up default values to the Raw fields in dumpconfig, and fixed one lint error

* fixed lint errors (strange)

* lint fix

* private no-more, using '-' in name tags to ignore

* updated name tags, made c.configFile as a stringFlag (only one config file supported) and updated the merge logic in command.go -> Run()

* fix: set method for big.Int flags, added a TODO

* handeled bigInt and timeDuration type, bug fix in config_legacy, lint fix

* updated flags, consistent across flags.go and config.go

* fixed config test and updated test hcl, json config files

* updated config legacy test

* added test to check values of cmd flags, restructured Run in command.go, linter fix

* fix linters

* lint again

* changed 2 flags and assert -> require

* changed the 2 flags back

* updated correct congig.toml path and made mainnet default

* updated config.toml with new flags

* added sample config (toml) file

* removed sample-config.toml and added it in docs/config.md

Co-authored-by: Manav Darji <manavdarji.india@gmail.com>
2022-07-27 12:28:26 +05:30

288 lines
6 KiB
Go

package cli
import (
"fmt"
"os"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/internal/cli/flagset"
"github.com/ethereum/go-ethereum/internal/cli/server"
"github.com/ethereum/go-ethereum/internal/cli/server/proto"
"github.com/ethereum/go-ethereum/node"
"github.com/mitchellh/cli"
"github.com/ryanuber/columnize"
"google.golang.org/grpc"
)
const (
emptyPlaceHolder = "<none>"
)
type MarkDownCommand interface {
MarkDown
cli.Command
}
type MarkDownCommandFactory func() (MarkDownCommand, error)
func Run(args []string) int {
commands := Commands()
mappedCommands := make(map[string]cli.CommandFactory)
for k, v := range commands {
// Declare a new v to limit the scope of v to inside the block, so the anonymous function below
// can get the "current" value of v, instead of the value of last v in the loop.
// See this post: https://stackoverflow.com/questions/10116507/go-transfer-var-into-anonymous-function for more explanation
v := v
mappedCommands[k] = func() (cli.Command, error) {
cmd, err := v()
return cmd.(cli.Command), err
}
}
cli := &cli.CLI{
Name: "bor",
Args: args,
Commands: mappedCommands,
}
exitCode, err := cli.Run()
if err != nil {
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
return 1
}
return exitCode
}
func Commands() map[string]MarkDownCommandFactory {
ui := &cli.BasicUi{
Reader: os.Stdin,
Writer: os.Stdout,
ErrorWriter: os.Stderr,
}
meta2 := &Meta2{
UI: ui,
}
meta := &Meta{
UI: ui,
}
return map[string]MarkDownCommandFactory{
"server": func() (MarkDownCommand, error) {
return &server.Command{
UI: ui,
}, nil
},
"version": func() (MarkDownCommand, error) {
return &VersionCommand{
UI: ui,
}, nil
},
"dumpconfig": func() (MarkDownCommand, error) {
return &DumpconfigCommand{
Meta2: meta2,
}, nil
},
"debug": func() (MarkDownCommand, error) {
return &DebugCommand{
UI: ui,
}, nil
},
"debug pprof": func() (MarkDownCommand, error) {
return &DebugPprofCommand{
Meta2: meta2,
}, nil
},
"debug block": func() (MarkDownCommand, error) {
return &DebugBlockCommand{
Meta2: meta2,
}, nil
},
"chain": func() (MarkDownCommand, error) {
return &ChainCommand{
UI: ui,
}, nil
},
"chain watch": func() (MarkDownCommand, error) {
return &ChainWatchCommand{
Meta2: meta2,
}, nil
},
"chain sethead": func() (MarkDownCommand, error) {
return &ChainSetHeadCommand{
Meta2: meta2,
}, nil
},
"account": func() (MarkDownCommand, error) {
return &Account{
UI: ui,
}, nil
},
"account new": func() (MarkDownCommand, error) {
return &AccountNewCommand{
Meta: meta,
}, nil
},
"account import": func() (MarkDownCommand, error) {
return &AccountImportCommand{
Meta: meta,
}, nil
},
"account list": func() (MarkDownCommand, error) {
return &AccountListCommand{
Meta: meta,
}, nil
},
"peers": func() (MarkDownCommand, error) {
return &PeersCommand{
UI: ui,
}, nil
},
"peers add": func() (MarkDownCommand, error) {
return &PeersAddCommand{
Meta2: meta2,
}, nil
},
"peers remove": func() (MarkDownCommand, error) {
return &PeersRemoveCommand{
Meta2: meta2,
}, nil
},
"peers list": func() (MarkDownCommand, error) {
return &PeersListCommand{
Meta2: meta2,
}, nil
},
"peers status": func() (MarkDownCommand, error) {
return &PeersStatusCommand{
Meta2: meta2,
}, nil
},
"status": func() (MarkDownCommand, error) {
return &StatusCommand{
Meta2: meta2,
}, nil
},
"fingerprint": func() (MarkDownCommand, error) {
return &FingerprintCommand{
UI: ui,
}, nil
},
"attach": func() (MarkDownCommand, error) {
return &AttachCommand{
UI: ui,
Meta: meta,
Meta2: meta2,
}, nil
},
"bootnode": func() (MarkDownCommand, error) {
return &BootnodeCommand{
UI: ui,
}, nil
},
}
}
type Meta2 struct {
UI cli.Ui
addr string
}
func (m *Meta2) NewFlagSet(n string) *flagset.Flagset {
f := flagset.NewFlagSet(n)
f.StringFlag(&flagset.StringFlag{
Name: "address",
Value: &m.addr,
Usage: "Address of the grpc endpoint",
Default: "127.0.0.1:3131",
})
return f
}
func (m *Meta2) Conn() (*grpc.ClientConn, error) {
conn, err := grpc.Dial(m.addr, grpc.WithInsecure())
if err != nil {
return nil, fmt.Errorf("failed to connect to server: %v", err)
}
return conn, nil
}
func (m *Meta2) BorConn() (proto.BorClient, error) {
conn, err := m.Conn()
if err != nil {
return nil, err
}
return proto.NewBorClient(conn), nil
}
// Meta is a helper utility for the commands
type Meta struct {
UI cli.Ui
dataDir string
keyStoreDir string
}
func (m *Meta) NewFlagSet(n string) *flagset.Flagset {
f := flagset.NewFlagSet(n)
f.StringFlag(&flagset.StringFlag{
Name: "datadir",
Value: &m.dataDir,
Usage: "Path of the data directory to store information",
})
f.StringFlag(&flagset.StringFlag{
Name: "keystore",
Value: &m.keyStoreDir,
Usage: "Path of the data directory to store information",
})
return f
}
func (m *Meta) AskPassword() (string, error) {
return m.UI.AskSecret("Your new account is locked with a password. Please give a password. Do not forget this password")
}
func (m *Meta) GetKeystore() (*keystore.KeyStore, error) {
cfg := node.DefaultConfig
cfg.DataDir = m.dataDir
cfg.KeyStoreDir = m.keyStoreDir
stack, err := node.New(&cfg)
if err != nil {
return nil, err
}
keydir := stack.KeyStoreDir()
scryptN := keystore.StandardScryptN
scryptP := keystore.StandardScryptP
keys := keystore.NewKeyStore(keydir, scryptN, scryptP)
return keys, nil
}
func formatList(in []string) string {
columnConf := columnize.DefaultConfig()
columnConf.Empty = emptyPlaceHolder
return columnize.Format(in, columnConf)
}
func formatKV(in []string) string {
columnConf := columnize.DefaultConfig()
columnConf.Empty = emptyPlaceHolder
columnConf.Glue = " = "
return columnize.Format(in, columnConf)
}