cli: add --relative-path option

To be able running the node from any working directory by simply
pointing the relative-path as prefix for relative parameters set in
config.

Closes #3179.

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
Ekaterina Pavlova 2023-11-23 21:41:50 +04:00
parent 195bb742ca
commit f457d50773
6 changed files with 58 additions and 11 deletions

View file

@ -73,6 +73,13 @@ var ConfigFile = cli.StringFlag{
Usage: "path to the node configuration file (overrides --config-path option)",
}
// RelativePath is a flag for commands that use node configuration and provide
// a prefix to all relative paths in config files.
var RelativePath = cli.StringFlag{
Name: "relative-path",
Usage: "a prefix to all relative paths in the node configuration file",
}
// Debug is a flag for commands that allow node in debug mode usage.
var Debug = cli.BoolFlag{
Name: "debug, d",
@ -159,15 +166,18 @@ func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transac
// GetConfigFromContext looks at the path and the mode flags in the given config and
// returns an appropriate config.
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
var configFile = ctx.String("config-file")
var (
configFile = ctx.String("config-file")
relativePath = ctx.String("relative-path")
)
if len(configFile) != 0 {
return config.LoadFile(configFile)
return config.LoadFile(configFile, relativePath)
}
var configPath = "./config"
if argCp := ctx.String("config-path"); argCp != "" {
configPath = argCp
}
return config.Load(configPath, GetNetwork(ctx))
return config.Load(configPath, GetNetwork(ctx), relativePath)
}
var (

View file

@ -34,7 +34,7 @@ import (
// NewCommands returns 'node' command.
func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags = append(cfgFlags, options.Network...)
var cfgWithCountFlags = make([]cli.Flag, len(cfgFlags))
copy(cfgWithCountFlags, cfgFlags)

View file

@ -49,6 +49,18 @@ func TestGetConfigFromContext(t *testing.T) {
require.NoError(t, err)
require.Equal(t, netmode.TestNet, cfg.ProtocolConfiguration.Magic)
})
t.Run("relative-path", func(t *testing.T) {
set := flag.NewFlagSet("flagSet", flag.ExitOnError)
set.String("relative-path", "../../config", "")
set.Bool("testnet", true, "")
set.String("config-file", "../../config/protocol.testnet.yml", "")
ctx := cli.NewContext(cli.NewApp(), set, nil)
cfg, err := options.GetConfigFromContext(ctx)
require.NoError(t, err)
require.Equal(t, "../../config/chains/testnet", cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
require.Equal(t, "/cn_wallet.json", cfg.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "/notary_wallet.json", cfg.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
})
}
func TestHandleLoggingParams(t *testing.T) {

View file

@ -95,8 +95,10 @@ func newTestVMCLIWithLogoAndCustomConfig(t *testing.T, printLogo bool, cfg *conf
if cfg == nil {
configPath := "../../config/protocol.unit_testnet.single.yml"
var err error
c, err = config.LoadFile(configPath)
c, err = config.LoadFile(configPath, "../../config")
require.NoError(t, err, "could not load chain config")
require.Equal(t, "../../testdata/wallet1_solo.json", c.ApplicationConfiguration.Consensus.UnlockWallet.Path)
require.Equal(t, "/notary_wallet.json", c.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
} else {
c = *cfg

View file

@ -13,7 +13,7 @@ import (
// NewCommands returns 'vm' command.
func NewCommands() []cli.Command {
cfgFlags := []cli.Flag{options.Config, options.ConfigFile}
cfgFlags := []cli.Flag{options.Config, options.ConfigFile, options.RelativePath}
cfgFlags = append(cfgFlags, options.Network...)
return []cli.Command{{
Name: "vm",

View file

@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"os"
"path/filepath"
"time"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
@ -57,15 +58,17 @@ func (c Config) Blockchain() Blockchain {
}
// Load attempts to load the config from the given
// path for the given netMode.
func Load(path string, netMode netmode.Magic) (Config, error) {
// path for the given netMode. If relativePath is not empty, relative paths in the
// config will be updated based on the provided relative path.
func Load(path string, netMode netmode.Magic, relativePath ...string) (Config, error) {
configPath := fmt.Sprintf("%s/protocol.%s.yml", path, netMode)
return LoadFile(configPath)
return LoadFile(configPath, relativePath...)
}
// LoadFile loads config from the provided path. It also applies backwards compatibility
// fixups if necessary.
func LoadFile(configPath string) (Config, error) {
// fixups if necessary. If relativePath is not empty, relative paths in the config will
// be updated based on the provided relative path.
func LoadFile(configPath string, relativePath ...string) (Config, error) {
if _, err := os.Stat(configPath); os.IsNotExist(err) {
return Config{}, fmt.Errorf("config '%s' doesn't exist", configPath)
}
@ -89,6 +92,9 @@ func LoadFile(configPath string) (Config, error) {
if err != nil {
return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
}
if len(relativePath) == 1 && relativePath[0] != "" {
updateRelativePaths(relativePath[0], &config)
}
err = config.ProtocolConfiguration.Validate()
if err != nil {
@ -97,3 +103,20 @@ func LoadFile(configPath string) (Config, error) {
return config, nil
}
// updateRelativePaths updates relative paths in the config structure based on the provided relative path.
func updateRelativePaths(relativePath string, config *Config) {
updatePath := func(path *string) {
if *path != "" && !filepath.IsAbs(*path) {
*path = filepath.Join(relativePath, *path)
}
}
updatePath(&config.ApplicationConfiguration.LogPath)
updatePath(&config.ApplicationConfiguration.DBConfiguration.BoltDBOptions.FilePath)
updatePath(&config.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath)
updatePath(&config.ApplicationConfiguration.Consensus.UnlockWallet.Path)
updatePath(&config.ApplicationConfiguration.P2PNotary.UnlockWallet.Path)
updatePath(&config.ApplicationConfiguration.Oracle.UnlockWallet.Path)
updatePath(&config.ApplicationConfiguration.StateRoot.UnlockWallet.Path)
}