Skip to content

Commit

Permalink
Config: fix don't create empty dir when resolving path (thrasher-corp…
Browse files Browse the repository at this point in the history
…#575)

* Config: fix don't create empty dir when resolving path

* refactor migration of default config file

* gracefully handle src == target on Move
* create target directory on Move, if necessary

* unify resolution of default config location

* refactor the use of flagSet to be explicit
* remove package variable
* use empty config file path setting if not set in flags
* resolve default file location the same way when showing the target and
when loading default config file

* don't migrate if target file is the same as source

* rename configfile to configFile

* add migrateConfig tests
  • Loading branch information
Rots authored Oct 15, 2020
1 parent f11c904 commit 8c86aac
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 125 deletions.
18 changes: 18 additions & 0 deletions common/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,29 @@ func Write(file string, data []byte) error {
// This must be used across the codebase for compatibility with Docker volumes
// and Golang (fixes Invalid cross-device link when using os.Rename)
func Move(sourcePath, destPath string) error {
sourceAbs, err := filepath.Abs(sourcePath)
if err != nil {
return err
}
destAbs, err := filepath.Abs(destPath)
if err != nil {
return err
}
if sourceAbs == destAbs {
return nil
}
inputFile, err := os.Open(sourcePath)
if err != nil {
return err
}

destDir := filepath.Dir(destPath)
if !Exists(destDir) {
err = os.MkdirAll(destDir, 0770)
if err != nil {
return err
}
}
outputFile, err := os.Create(destPath)
if err != nil {
inputFile.Close()
Expand Down
13 changes: 11 additions & 2 deletions common/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,25 @@ func TestMove(t *testing.T) {
{InFile: "*", OutFile: "gct.txt", Write: true, ErrExpected: true},
{InFile: "*", OutFile: "gct.txt", Write: false, ErrExpected: true},
{InFile: "in.txt", OutFile: "*", Write: true, ErrExpected: true},
{InFile: "in.txt", OutFile: "gct.txt", Write: true, ErrExpected: false},
}
default:
tests = []testTable{
{InFile: "", OutFile: "gct.txt", Write: true, ErrExpected: true},
{InFile: "", OutFile: "gct.txt", Write: false, ErrExpected: true},
{InFile: "in.txt", OutFile: "", Write: true, ErrExpected: true},
{InFile: "in.txt", OutFile: "gct.txt", Write: true, ErrExpected: false},
}
}
tests = append(tests, []testTable{
{InFile: "in.txt", OutFile: "gct.txt", Write: true, ErrExpected: false},
{InFile: "in.txt", OutFile: "non-existing/gct.txt", Write: true, ErrExpected: false},
{InFile: "in.txt", OutFile: "in.txt", Write: true, ErrExpected: false},
}...)

if Exists("non-existing") {
t.Error("target 'non-existing' should not exist")
}
defer os.RemoveAll("non-existing")
defer os.Remove("in.txt")

for x := range tests {
err := tester(tests[x].InFile, tests[x].OutFile, tests[x].Write)
Expand Down
158 changes: 64 additions & 94 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -1457,129 +1457,99 @@ func (c *Config) CheckConnectionMonitorConfig() {
// Windows: %APPDATA%\GoCryptoTrader\config.json or config.dat
// Helpful for printing application usage
func DefaultFilePath() string {
f := filepath.Join(common.GetDefaultDataDir(runtime.GOOS), File)
if !file.Exists(f) {
encFile := filepath.Join(common.GetDefaultDataDir(runtime.GOOS), EncryptedFile)
if file.Exists(encFile) {
return encFile
}
foundConfig, _, err := GetFilePath("")
if err != nil {
// If there was no config file, show default location for .json
return filepath.Join(common.GetDefaultDataDir(runtime.GOOS), File)
}
return f
return foundConfig
}

// GetAndMigrateDefaultPath returns the target config file
// migrating it from the old default location to new one,
// if it was implicitly loaded from a default location and
// wasn't already in the correct 'new' default location
func GetAndMigrateDefaultPath(configFile string) (string, error) {
filePath, wasDefault, err := GetFilePath(configFile)
if err != nil {
return "", err
}
if wasDefault {
return migrateConfig(filePath, common.GetDefaultDataDir(runtime.GOOS))
}
return filePath, nil
}

// GetFilePath returns the desired config file or the default config file name
// based on if the application is being run under test or normal mode. It will
// also move/rename the config file under the following conditions:
// 1) If a config file is found in the executable path directory and no explicit
// config path is set, plus no config is found in the GCT data dir, it will
// move it to the GCT data dir. If a config already exists in the GCT data
// dir, it will warn the user and load the config found in the GCT data dir
// 2) If a config file in the GCT data dir has the file extension .dat but
// contains json data, it will rename to the file to config.json
// 3) If a config file in the GCT data dir has the file extension .json but
// contains encrypted data, it will rename the file to config.dat
func GetFilePath(configfile string) (string, error) {
// and whether it was loaded from a default location (rather than explicitly specified)
func GetFilePath(configfile string) (configPath string, isImplicitDefaultPath bool, err error) {
if configfile != "" {
return configfile, nil
return configfile, false, nil
}

exePath, err := common.GetExecutablePath()
if err != nil {
return "", err
return "", false, err
}

oldDirs := []string{
newDir := common.GetDefaultDataDir(runtime.GOOS)
defaultPaths := []string{
filepath.Join(exePath, File),
filepath.Join(exePath, EncryptedFile),
}

newDir := common.GetDefaultDataDir(runtime.GOOS)
err = common.CreateDir(newDir)
if err != nil {
return "", err
}
newDirs := []string{
filepath.Join(newDir, File),
filepath.Join(newDir, EncryptedFile),
}

// First upgrade the old dir config file if it exists to the corresponding
// new one
for x := range oldDirs {
if !file.Exists(oldDirs[x]) {
continue
}
if file.Exists(newDirs[x]) {
log.Warnf(log.ConfigMgr,
"config.json file found in root dir and gct dir; cannot overwrite, defaulting to gct dir config.json at %s",
newDirs[x])
return newDirs[x], nil
}
if filepath.Ext(oldDirs[x]) == ".json" {
err = file.Move(oldDirs[x], newDirs[0])
if err != nil {
return "", err
}
log.Debugf(log.ConfigMgr,
"Renamed old config file %s to %s\n",
oldDirs[x],
newDirs[0])
} else {
err = file.Move(oldDirs[x], newDirs[1])
if err != nil {
return "", err
}
log.Debugf(log.ConfigMgr,
"Renamed old config file %s to %s\n",
oldDirs[x],
newDirs[1])
for _, p := range defaultPaths {
if file.Exists(p) {
configfile = p
break
}
}
if configfile == "" {
return "", false, fmt.Errorf("config.json file not found in %s, please follow README.md in root dir for config generation",
newDir)
}

// Secondly check to see if the new config file extension is correct or not
for x := range newDirs {
if !file.Exists(newDirs[x]) {
continue
}

data, err := ioutil.ReadFile(newDirs[x])
if err != nil {
return "", err
}

if ConfirmECS(data) {
if filepath.Ext(newDirs[x]) == ".dat" {
return newDirs[x], nil
}

err = file.Move(newDirs[x], newDirs[1])
if err != nil {
return "", err
}
return newDirs[1], nil
}
return configfile, true, nil
}

if filepath.Ext(newDirs[x]) == ".json" {
return newDirs[x], nil
}
// migrateConfig will move the config file to the target
// config directory as `File` or `EncryptedFile` depending on whether the config
// is encrypted
func migrateConfig(configFile, targetDir string) (string, error) {
data, err := ioutil.ReadFile(configFile)
if err != nil {
return "", err
}

err = file.Move(newDirs[x], newDirs[0])
if err != nil {
return "", err
}
var target string
if ConfirmECS(data) {
target = EncryptedFile
} else {
target = File
}
target = filepath.Join(targetDir, target)
if configFile == target {
return configFile, nil
}
if file.Exists(target) {
log.Warnf(log.ConfigMgr, "config file already found in '%s'; not overwriting, defaulting to %s", target, configFile)
return configFile, nil
}

return newDirs[0], nil
err = file.Move(configFile, target)
if err != nil {
return "", err
}

return "", fmt.Errorf("config.json file not found in %s, please follow README.md in root dir for config generation",
newDir)
return target, nil
}

// ReadConfig verifies and checks for encryption and verifies the unencrypted
// file contains JSON.
// Prompts for decryption key, if target file is encrypted
func (c *Config) ReadConfig(configPath string, dryrun bool) error {
defaultPath, err := GetFilePath(configPath)
defaultPath, _, err := GetFilePath(configPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -1658,7 +1628,7 @@ func (c *Config) SaveConfig(configPath string, dryrun bool) error {
return nil
}

defaultPath, err := GetFilePath(configPath)
defaultPath, _, err := GetFilePath(configPath)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 8c86aac

Please sign in to comment.