mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 15:09:42 +00:00
Fix Docker os.Rename invalid cross-device link issue (#386)
* Adds new file.Move func to address a bug with Golang/Docker volumes when using os.Rename Also uses TempDir for tests instead of live directories and increases test coverage for file.Write * Goimport the imports * Make usage of file package name consistent so it no longer clashes with vars * Remove outputFile if io.Copy fails
This commit is contained in:
@@ -279,7 +279,7 @@ func ExtractPort(host string) int {
|
||||
func OutputCSV(filePath string, data [][]string) error {
|
||||
_, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
errTwo := WriteFile(filePath, nil)
|
||||
errTwo := ioutil.WriteFile(filePath, nil, 0770)
|
||||
if errTwo != nil {
|
||||
return errTwo
|
||||
}
|
||||
@@ -295,11 +295,6 @@ func OutputCSV(filePath string, data [][]string) error {
|
||||
return writer.WriteAll(data)
|
||||
}
|
||||
|
||||
// WriteFile writes selected data to a file and returns an error
|
||||
func WriteFile(file string, data []byte) error {
|
||||
return ioutil.WriteFile(file, data, 0644)
|
||||
}
|
||||
|
||||
// GetURIPath returns the path of a URL given a URI
|
||||
func GetURIPath(uri string) string {
|
||||
urip, err := url.Parse(uri)
|
||||
@@ -353,8 +348,8 @@ func CreateDir(dir string) error {
|
||||
return os.MkdirAll(dir, 0770)
|
||||
}
|
||||
|
||||
// ChangePerm lists all the directories and files in an array
|
||||
func ChangePerm(directory string) error {
|
||||
// ChangePermission lists all the directories and files in an array
|
||||
func ChangePermission(directory string) error {
|
||||
return filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -504,11 +504,11 @@ func TestCreateDir(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangePerm(t *testing.T) {
|
||||
testDir := filepath.Join(GetDefaultDataDir(runtime.GOOS), "TestFileASDFGHJ")
|
||||
func TestChangePermission(t *testing.T) {
|
||||
testDir := filepath.Join(os.TempDir(), "TestFileASDFGHJ")
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
err := ChangePerm("*")
|
||||
err := ChangePermission("*")
|
||||
if err == nil {
|
||||
t.Fatal("expected an error on non-existent path")
|
||||
}
|
||||
@@ -516,7 +516,7 @@ func TestChangePerm(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Mkdir failed. Err: %v", err)
|
||||
}
|
||||
err = ChangePerm(GetDefaultDataDir(runtime.GOOS))
|
||||
err = ChangePermission(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("ChangePerm was unsuccessful. Err: %v", err)
|
||||
}
|
||||
@@ -529,7 +529,7 @@ func TestChangePerm(t *testing.T) {
|
||||
t.Fatalf("os.Remove failed. Err: %v", err)
|
||||
}
|
||||
default:
|
||||
err := ChangePerm("")
|
||||
err := ChangePermission("")
|
||||
if err == nil {
|
||||
t.Fatal("expected an error on non-existent path")
|
||||
}
|
||||
@@ -537,7 +537,7 @@ func TestChangePerm(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Mkdir failed. Err: %v", err)
|
||||
}
|
||||
err = ChangePerm(GetDefaultDataDir(runtime.GOOS))
|
||||
err = ChangePermission(testDir)
|
||||
if err != nil {
|
||||
t.Fatalf("ChangePerm was unsuccessful. Err: %v", err)
|
||||
}
|
||||
|
||||
47
common/file/file.go
Normal file
47
common/file/file.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Write writes selected data to a file or returns an error if it fails. This
|
||||
// func also ensures that all files are set to this permission (only rw access
|
||||
// for the running user and the group the user is a member of)
|
||||
func Write(file string, data []byte) error {
|
||||
return ioutil.WriteFile(file, data, 0770)
|
||||
}
|
||||
|
||||
// Move moves a file from a source path to a destination path
|
||||
// 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 {
|
||||
inputFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outputFile, err := os.Create(destPath)
|
||||
if err != nil {
|
||||
inputFile.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(outputFile, inputFile)
|
||||
inputFile.Close()
|
||||
outputFile.Close()
|
||||
if err != nil {
|
||||
if errRem := os.Remove(destPath); errRem != nil {
|
||||
return fmt.Errorf(
|
||||
"unable to os.Remove error: %s after io.Copy error: %s",
|
||||
errRem,
|
||||
err,
|
||||
)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return os.Remove(sourcePath)
|
||||
}
|
||||
106
common/file/file_test.go
Normal file
106
common/file/file_test.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
tester := func(in string) error {
|
||||
err := Write(in, []byte("GoCryptoTrader"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Remove(in)
|
||||
}
|
||||
|
||||
type testTable struct {
|
||||
InFile string
|
||||
ErrExpected bool
|
||||
Cleanup bool
|
||||
}
|
||||
|
||||
var tests []testTable
|
||||
testFile := filepath.Join(os.TempDir(), "gcttest.txt")
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
tests = []testTable{
|
||||
{InFile: "*", ErrExpected: true},
|
||||
{InFile: testFile, ErrExpected: false},
|
||||
}
|
||||
default:
|
||||
tests = []testTable{
|
||||
{InFile: "", ErrExpected: true},
|
||||
{InFile: testFile, ErrExpected: false},
|
||||
}
|
||||
}
|
||||
|
||||
for x := range tests {
|
||||
err := tester(tests[x].InFile)
|
||||
if err != nil && !tests[x].ErrExpected {
|
||||
t.Errorf("Test %d failed, unexpected err %s\n", x, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMove(t *testing.T) {
|
||||
tester := func(in, out string, write bool) error {
|
||||
if write {
|
||||
if err := ioutil.WriteFile(in, []byte("GoCryptoTrader"), 0770); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := Move(in, out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.Contains(string(contents), "GoCryptoTrader") {
|
||||
return fmt.Errorf("unable to find previously written data")
|
||||
}
|
||||
|
||||
return os.Remove(out)
|
||||
}
|
||||
|
||||
type testTable struct {
|
||||
InFile string
|
||||
OutFile string
|
||||
Write bool
|
||||
ErrExpected bool
|
||||
}
|
||||
|
||||
var tests []testTable
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
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},
|
||||
}
|
||||
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},
|
||||
}
|
||||
}
|
||||
|
||||
for x := range tests {
|
||||
err := tester(tests[x].InFile, tests[x].OutFile, tests[x].Write)
|
||||
if err != nil && !tests[x].ErrExpected {
|
||||
t.Errorf("Test %d failed, unexpected err %s\n", x, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user