Skip to content

Commit

Permalink
cli: add --relative-path option
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
AliceInHunterland committed Nov 20, 2023
1 parent b5cf3f5 commit 92719a4
Show file tree
Hide file tree
Showing 21 changed files with 73 additions and 39 deletions.
12 changes: 10 additions & 2 deletions cli/options/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 config files",
}

// Debug is a flag for commands that allow node in debug mode usage.
var Debug = cli.BoolFlag{
Name: "debug, d",
Expand Down Expand Up @@ -160,14 +167,15 @@ func GetRPCWithInvoker(gctx context.Context, ctx *cli.Context, signers []transac
// returns an appropriate config.
func GetConfigFromContext(ctx *cli.Context) (config.Config, error) {
var configFile = ctx.String("config-file")
var 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 (
Expand Down
4 changes: 2 additions & 2 deletions cli/server/cli_dump_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestDBRestoreDump(t *testing.T) {

loadConfig := func(t *testing.T) config.Config {
chainPath := filepath.Join(tmpDir, "neogotestchain")
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"), "")
require.NoError(t, err, "could not load config")
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
Expand Down Expand Up @@ -119,7 +119,7 @@ func TestDBDumpRestoreIncremental(t *testing.T) {
nonincDump := filepath.Join(tmpDir, "nonincDump.acc")
incDump := filepath.Join(tmpDir, "incDump.acc")

cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
cfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"), "")
require.NoError(t, err, "could not load config")
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions.DataDirectoryPath = chainPath
Expand Down
2 changes: 1 addition & 1 deletion cli/server/cli_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

func TestServerStart(t *testing.T) {
tmpDir := t.TempDir()
goodCfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"))
goodCfg, err := config.LoadFile(filepath.Join("..", "..", "config", "protocol.unit_testnet.yml"), "")
require.NoError(t, err, "could not load config")
ptr := &goodCfg
saveCfg := func(t *testing.T, f func(cfg *config.Config)) string {
Expand Down
2 changes: 1 addition & 1 deletion cli/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 12 additions & 2 deletions cli/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ 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)
})
}

func TestHandleLoggingParams(t *testing.T) {
Expand Down Expand Up @@ -233,7 +243,7 @@ func TestRestoreDB(t *testing.T) {
badCfgDir := t.TempDir()
logfile := filepath.Join(badCfgDir, "logdir")
require.NoError(t, os.WriteFile(logfile, []byte{1, 2, 3}, os.ModePerm))
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"))
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"), "")
require.NoError(t, err, "could not load config")
cfg.ApplicationConfiguration.LogPath = filepath.Join(logfile, "file.log")
out, err := yaml.Marshal(cfg)
Expand All @@ -249,7 +259,7 @@ func TestRestoreDB(t *testing.T) {
})
t.Run("invalid bc config", func(t *testing.T) {
badCfgDir := t.TempDir()
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"))
cfg, err := config.LoadFile(filepath.Join(goodCfg, "protocol.privnet.yml"), "")
require.NoError(t, err, "could not load config")
cfg.ApplicationConfiguration.DBConfiguration.Type = ""
out, err := yaml.Marshal(cfg)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ type LedgerWitnessRule struct {
// Unnamed is a contract-specific unnamed type used by its methods.
type Unnamed struct {
I *big.Int
B bool
}

// ComplicatedNameEvent represents "! complicated name %$#" event emitted by the contract.
Expand Down Expand Up @@ -822,7 +821,7 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
if !ok {
return errors.New("not an array")
}
if len(arr) != 2 {
if len(arr) != 1 {
return errors.New("wrong number of structure elements")
}

Expand All @@ -836,12 +835,6 @@ func (res *Unnamed) FromStackItem(item stackitem.Item) error {
return fmt.Errorf("field I: %w", err)
}

index++
res.B, err = arr[index].TryBool()
if err != nil {
return fmt.Errorf("field B: %w", err)
}

return nil
}

Expand Down
5 changes: 3 additions & 2 deletions cli/vm/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ 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)
c.ApplicationConfiguration.DBConfiguration.Type = dbconfig.InMemoryDB
} else {
c = *cfg
Expand Down Expand Up @@ -140,7 +141,7 @@ func newTestVMClIWithState(t *testing.T) *executor {

// After that create CLI backed by created chain.
configPath := "../../config/protocol.unit_testnet.yml"
cfg, err := config.LoadFile(configPath)
cfg, err := config.LoadFile(configPath, "")
require.NoError(t, err)
cfg.ApplicationConfiguration.DBConfiguration.Type = dbconfig.LevelDB
cfg.ApplicationConfiguration.DBConfiguration.LevelDBOptions = opts
Expand Down
2 changes: 1 addition & 1 deletion cli/vm/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion internal/testcli/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (w *ConcurrentBuffer) Reset() {

func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockchain, *rpcsrv.Server, *network.Server) {
configPath := "../../config/protocol.unit_testnet.single.yml"
cfg, err := config.LoadFile(configPath)
cfg, err := config.LoadFile(configPath, "")
require.NoError(t, err, "could not load config")
if f != nil {
f(&cfg)
Expand Down
4 changes: 2 additions & 2 deletions pkg/config/application_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ func TestApplicationConfigurationEquals(t *testing.T) {
require.True(t, o.EqualsButServices(a))
require.True(t, a.EqualsButServices(a))

cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"))
cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"), "")
require.NoError(t, err)
cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml"))
cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml"), "")
require.NoError(t, err)
require.False(t, cfg1.ApplicationConfiguration.EqualsButServices(&cfg2.ApplicationConfiguration))
}
Expand Down
28 changes: 25 additions & 3 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/nspcc-dev/neo-go/pkg/config/netmode"
Expand Down Expand Up @@ -57,14 +58,14 @@ 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) {
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) {
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)
}
Expand All @@ -88,10 +89,31 @@ func LoadFile(configPath string) (Config, error) {
return Config{}, fmt.Errorf("failed to unmarshal config YAML: %w", err)
}

if relativePath != "" {
updateRelativePaths(relativePath, &config)
}

err = config.ProtocolConfiguration.Validate()
if err != nil {
return Config{}, err
}

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)
}
2 changes: 1 addition & 1 deletion pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (
const testConfigPath = "./testdata/protocol.test.yml"

func TestUnexpectedNativeUpdateHistoryContract(t *testing.T) {
_, err := LoadFile(testConfigPath)
_, err := LoadFile(testConfigPath, "")
require.Error(t, err)
}
6 changes: 3 additions & 3 deletions pkg/config/protocol_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ func TestProtocolConfigurationEquals(t *testing.T) {
require.True(t, o.Equals(p))
require.True(t, p.Equals(p))

cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"))
cfg1, err := LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"), "")
require.NoError(t, err)
cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml"))
cfg2, err := LoadFile(filepath.Join("..", "..", "config", "protocol.testnet.yml"), "")
require.NoError(t, err)
require.False(t, cfg1.ProtocolConfiguration.Equals(&cfg2.ProtocolConfiguration))

cfg2, err = LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"))
cfg2, err = LoadFile(filepath.Join("..", "..", "config", "protocol.mainnet.yml"), "")
require.NoError(t, err)
p = &cfg1.ProtocolConfiguration
o = &cfg2.ProtocolConfiguration
Expand Down
4 changes: 2 additions & 2 deletions pkg/consensus/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ func getTestValidator(i int) (*privateKey, *publicKey) {

func newSingleTestChain(t *testing.T) *core.Blockchain {
configPath := "../../config/protocol.unit_testnet.single.yml"
cfg, err := config.LoadFile(configPath)
cfg, err := config.LoadFile(configPath, "")
require.NoError(t, err, "could not load config")

chain, err := core.NewBlockchain(storage.NewMemoryStore(), cfg.Blockchain(), zaptest.NewLogger(t))
Expand All @@ -553,7 +553,7 @@ func newSingleTestChain(t *testing.T) *core.Blockchain {
}

func newTestChain(t *testing.T, stateRootInHeader bool) *core.Blockchain {
unitTestNetCfg, err := config.Load("../../config", netmode.UnitTestNet)
unitTestNetCfg, err := config.Load("../../config", netmode.UnitTestNet, "")
require.NoError(t, err)
unitTestNetCfg.ProtocolConfiguration.StateRootInHeader = stateRootInHeader

Expand Down
2 changes: 1 addition & 1 deletion pkg/core/blockchain_core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ func TestBlockchain_InitWithIncompleteStateJump(t *testing.T) {
require.NoError(t, err)

checkNewBlockchainErr := func(t *testing.T, cfg func(c *config.Config), store storage.Store, errText string) {
unitTestNetCfg, err := config.Load("../../config", testchain.Network())
unitTestNetCfg, err := config.Load("../../config", testchain.Network(), "")
require.NoError(t, err)
cfg(&unitTestNetCfg)
log := zaptest.NewLogger(t)
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/blockchain_neotest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ func TestConfigNativeUpdateHistory(t *testing.T) {
var prefixPath = filepath.Join("..", "..", "config")
check := func(t *testing.T, cfgFileSuffix any) {
cfgPath := filepath.Join(prefixPath, fmt.Sprintf("protocol.%s.yml", cfgFileSuffix))
cfg, err := config.LoadFile(cfgPath)
cfg, err := config.LoadFile(cfgPath, "")
require.NoError(t, err, fmt.Errorf("failed to load %s", cfgPath))
natives := native.NewContracts(cfg.ProtocolConfiguration)
assert.Equal(t, len(natives.Contracts),
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func initTestChain(t testing.TB, st storage.Store, f func(*config.Config)) *Bloc
}

func initTestChainNoCheck(t testing.TB, st storage.Store, f func(*config.Config)) (*Blockchain, error) {
unitTestNetCfg, err := config.Load("../../config", testchain.Network())
unitTestNetCfg, err := config.Load("../../config", testchain.Network(), "")
require.NoError(t, err)
if f != nil {
f(&unitTestNetCfg)
Expand Down
2 changes: 1 addition & 1 deletion pkg/core/interop/runtime/ext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func getSharpTestTx(sender util.Uint160) *transaction.Transaction {
func getSharpTestGenesis(t *testing.T) *block.Block {
const configPath = "../../../../config"

cfg, err := config.Load(configPath, netmode.MainNet)
cfg, err := config.Load(configPath, netmode.MainNet, "")
require.NoError(t, err)
b, err := core.CreateGenesisBlock(cfg.ProtocolConfiguration)
require.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/core/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func TestGenesisBlockMainNet(t *testing.T) {
cfg, err := config.Load("../../config", netmode.MainNet)
cfg, err := config.Load("../../config", netmode.MainNet, "")
require.NoError(t, err)

block, err := CreateGenesisBlock(cfg.ProtocolConfiguration)
Expand All @@ -27,7 +27,7 @@ func TestGetConsensusAddressMainNet(t *testing.T) {
consensusScript = "6b123dd8bec718648852bbc78595e3536a058f9f"
)

cfg, err := config.Load("../../config", netmode.MainNet)
cfg, err := config.Load("../../config", netmode.MainNet, "")
require.NoError(t, err)

validators, _, err := validatorsFromConfig(cfg.ProtocolConfiguration)
Expand Down
2 changes: 1 addition & 1 deletion pkg/services/rpcsrv/server_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func getUnitTestChain(t testing.TB, enableOracle bool, enableNotary bool, disabl
func getUnitTestChainWithCustomConfig(t testing.TB, enableOracle bool, enableNotary bool, customCfg func(configuration *config.Config)) (*core.Blockchain, OracleHandler, config.Config, *zap.Logger) {
net := netmode.UnitTestNet
configPath := "../../../config"
cfg, err := config.Load(configPath, net)
cfg, err := config.Load(configPath, net, "")
require.NoError(t, err, "could not load config")
if customCfg != nil {
customCfg(&cfg)
Expand Down
2 changes: 1 addition & 1 deletion scripts/gendump/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func handleError(msg string, err error) {
}

func newChain() (*core.Blockchain, error) {
unitTestNetCfg, err := config.Load("./config", netmode.UnitTestNet)
unitTestNetCfg, err := config.Load("./config", netmode.UnitTestNet, "")
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 92719a4

Please sign in to comment.