Skip to content

Commit

Permalink
Add move file functionality to the filesys package (#39)
Browse files Browse the repository at this point in the history
* Add move file functionality to the filesys package
  • Loading branch information
Brian Hendriks committed Aug 17, 2019
1 parent 09f9dbc commit e53f027
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 64 deletions.
3 changes: 3 additions & 0 deletions go/libraries/utils/filesys/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ type WritableFS interface {
// Delete will delete an empty directory, or a file. If trying delete a directory that is not empty you can set force to
// true in order to delete the dir and all of it's contents
Delete(path string, force bool) error

// MoveFile will move a file from the srcPath in the filesystem to the destPath
MoveFile(srcPath, destPath string) error
}

// FSIterCB specifies the signature of the function that will be called for every item found while iterating.
Expand Down
126 changes: 63 additions & 63 deletions go/libraries/utils/filesys/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@
package filesys

import (
"bytes"
"path/filepath"
"reflect"
"sort"
"testing"

"github.com/stretchr/testify/require"

"github.com/liquidata-inc/dolt/go/libraries/utils/osutil"
"github.com/liquidata-inc/dolt/go/libraries/utils/test"
)

const (
testFilename = "testfile.txt"
movedFilename = "movedfile.txt"
testString = "this is a test"
testStringLen = int64(len(testString))
)
Expand All @@ -39,70 +41,68 @@ var filesysetmsToTest = map[string]Filesys{
func TestFilesystems(t *testing.T) {
dir := test.TestDir("filesys_test")
fp := filepath.Join(dir, testFilename)
movedFilePath := filepath.Join(dir, movedFilename)

for fsName, fs := range filesysetmsToTest {
if exists, _ := fs.Exists(dir); exists {
t.Error("fs:", fsName, "Directory existed before it was created:", dir)
continue
}

err := fs.MkDirs(dir)

if err != nil {
t.Error("fs:", fsName, "failed to make dir", dir, err)
continue
}

if exists, isDir := fs.Exists(dir); !exists || !isDir {
t.Error("fs:", fsName, "Directory not found after creating:", dir)
continue
}

_, err = fs.OpenForRead(dir)

if err == nil {
t.Error("fs:", fsName, "shouldn't be able to open a directory for reading")
continue
}

_, err = fs.OpenForWrite(dir)

if err == nil {
t.Error("fs:", fsName, "shouldn't be able to open a directory for writing")
continue
}

if exists, _ := fs.Exists(fp); exists {
t.Error("fs:", fsName, "file existed before creating:", fp)
continue
}

_, err = fs.OpenForRead(fp)

if err == nil {
t.Error("fs:", fsName, "Shouldn't be able to read a file that isn't there")
continue
}

data := test.RandomData(256 * 1024)
err = fs.WriteFile(fp, data)

if err != nil {
t.Error("fs:", fsName, "failed to write file", fp, err)
continue
}

dataRead, err := fs.ReadFile(fp)

if err != nil {
t.Error("fs:", fsName, "failed to read the data that was written", fp, err)
continue
}

if !bytes.Equal(dataRead, data) {
t.Error("fs:", fsName, "data read does not match what was written", fp)
continue
}
t.Run(fsName, func(t *testing.T) {
// Test file doesn't exist before creation
exists, _ := fs.Exists(dir)
require.False(t, exists)

// Test creating a directory
err := fs.MkDirs(dir)
require.NoError(t, err)

// Test directory exists, and is in fact a directory
exists, isDir := fs.Exists(dir)
require.True(t, exists)
require.True(t, isDir)

// Test failure to open a directory for read
_, err = fs.OpenForRead(dir)
require.Error(t, err)

// Test failure to open a directory for write
_, err = fs.OpenForWrite(dir)
require.Error(t, err)

// Test file doesn't exist before creation
exists, _ = fs.Exists(fp)
require.False(t, exists)

// Test can't open a file that doesn't exist for read
_, err = fs.OpenForRead(fp)
require.Error(t, err)

data := test.RandomData(256 * 1024)

// Test writing file with random data
err = fs.WriteFile(fp, data)
require.NoError(t, err)

// Test that the data can be read back and hasn't changed
dataRead, err := fs.ReadFile(fp)
require.NoError(t, err)
require.Equal(t, dataRead, data)

// Test moving the file
err = fs.MoveFile(fp, movedFilePath)
require.NoError(t, err)

// Test that there is no longer a file at the initial path
exists, _ = fs.Exists(fp)
require.False(t, exists)

// Test that a file exists at the new location
exists, isDir = fs.Exists(movedFilePath)
require.True(t, exists)
require.False(t, isDir)

// Test that the data can be read back and hasn't changed since being moved
dataRead, err = fs.ReadFile(movedFilePath)
require.NoError(t, err)
require.Equal(t, dataRead, data)
})
}
}

Expand Down
45 changes: 44 additions & 1 deletion go/libraries/utils/filesys/inmemfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ func (fs *InMemFS) Delete(path string, force bool) error {

isEmpty := true
toDelete := map[string]bool{path: true}
fs.Iter(path, true, func(path string, size int64, isDir bool) (stop bool) {
err := fs.Iter(path, true, func(path string, size int64, isDir bool) (stop bool) {
isEmpty = false
if !force {
return true
Expand All @@ -355,6 +355,10 @@ func (fs *InMemFS) Delete(path string, force bool) error {
return false
})

if err != nil {
return err
}

if !force && !isEmpty {
return errors.New(path + " is a directory which is not empty. Delete the contents first, or set force to true")
}
Expand All @@ -372,6 +376,45 @@ func (fs *InMemFS) Delete(path string, force bool) error {
return nil
}

// MoveFile will move a file from the srcPath in the filesystem to the destPath
func (fs *InMemFS) MoveFile(srcPath, destPath string) error {
srcPath = fs.getAbsPath(srcPath)
destPath = fs.getAbsPath(destPath)

if exists, destIsDir := fs.Exists(destPath); exists && destIsDir {
return ErrIsDir
}

if obj, ok := fs.objs[srcPath]; ok {
if obj.isDir() {
return ErrIsDir
}

destDir := filepath.Dir(destPath)
destParentDir, err := fs.mkDirs(destDir)

if err != nil {
return err
}

destObj := &memFile{destPath, obj.(*memFile).data, destParentDir}

fs.objs[destPath] = destObj
delete(fs.objs, srcPath)

parentDir := obj.parent()
if parentDir != nil {
delete(parentDir.objs, srcPath)
}

destParentDir.objs[destPath] = destObj

return nil
}

return os.ErrNotExist
}

// converts a path to an absolute path. If it's already an absolute path the input path will be returned unaltered
func (fs *InMemFS) Abs(path string) (string, error) {
path = fs.pathToNative(path)
Expand Down
18 changes: 18 additions & 0 deletions go/libraries/utils/filesys/localfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@ func (fs *localFS) Delete(path string, force bool) error {
}
}

// MoveFile will move a file from the srcPath in the filesystem to the destPath
func (fs *localFS) MoveFile(srcPath, destPath string) error {
var err error
srcPath, err = fs.Abs(srcPath)

if err != nil {
return err
}

destPath, err = fs.Abs(destPath)

if err != nil {
return err
}

return os.Rename(srcPath, destPath)
}

// converts a path to an absolute path. If it's already an absolute path the input path will be returned unaltered
func (fs *localFS) Abs(path string) (string, error) {
return filepath.Abs(path)
Expand Down

0 comments on commit e53f027

Please sign in to comment.