Add srcRemote and dstRemote parameters to DirMove #954

This commit is contained in:
Nick Craig-Wood 2017-02-05 21:20:56 +00:00
parent e4835f535d
commit f3c5745468
9 changed files with 172 additions and 92 deletions

View File

@ -660,55 +660,90 @@ func (f *Fs) DirCacheFlush() {
f.dirCache.ResetRoot()
}
// DirMove moves src directory to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) (err error) {
// go test -v -run '^Test(Setup|Init|FsMkdir|FsPutFile1|FsPutFile2|FsUpdateFile1|FsDirMove)$
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) (err error) {
srcFs, ok := src.(*Fs)
if !ok {
fs.Debugf(src, "DirMove error: not same remote type")
return fs.ErrorCantDirMove
}
// Check if destination exists
if f.dirCache.FoundRoot() {
fs.Debugf(src, "DirMove error: destination exists")
return fs.ErrorDirExists
}
srcPath := path.Join(srcFs.root, srcRemote)
dstPath := path.Join(f.root, dstRemote)
// Refuse to move to or from the root
if f.root == "" || srcFs.root == "" {
if srcPath == "" || dstPath == "" {
fs.Debugf(src, "DirMove error: Can't move root")
return errors.New("can't move root directory")
}
// Find ID of parent
dstLeaf, dstDirectoryID, err := f.dirCache.FindPath(f.root, true)
if err != nil {
return err
}
// Find the ID of the source and make a node from it
// find the root src directory
err = srcFs.dirCache.FindRoot(false)
if err != nil {
fs.Debugf(src, "DirMove error: error finding src root: %v", err)
return err
}
srcDirectoryID, err := srcFs.dirCache.RootParentID()
// find the root dst directory
if dstRemote != "" {
err = f.dirCache.FindRoot(true)
if err != nil {
return err
}
} else {
if f.dirCache.FoundRoot() {
return fs.ErrorDirExists
}
}
// Find ID of dst parent, creating subdirs if necessary
findPath := dstRemote
if dstRemote == "" {
findPath = f.root
}
dstLeaf, dstDirectoryID, err := f.dirCache.FindPath(findPath, true)
if err != nil {
return err
}
// Check destination does not exist
if dstRemote != "" {
_, err = f.dirCache.FindDir(dstRemote, false)
if err == fs.ErrorDirNotFound {
// OK
} else if err != nil {
return err
} else {
return fs.ErrorDirExists
}
}
// Find ID of src parent
findPath = srcRemote
var srcDirectoryID string
if srcRemote == "" {
srcDirectoryID, err = srcFs.dirCache.RootParentID()
} else {
_, srcDirectoryID, err = srcFs.dirCache.FindPath(findPath, false)
}
if err != nil {
return err
}
srcLeaf, _ := dircache.SplitPath(srcPath)
// Find ID of src
srcID, err := srcFs.dirCache.FindDir(srcRemote, false)
if err != nil {
fs.Debugf(src, "DirMove error: error finding src RootParentID: %v", err)
return err
}
srcLeaf, _ := dircache.SplitPath(srcFs.root)
// FIXME make a proper node.UpdateMetadata command
srcInfo := acd.NodeFromId(srcFs.dirCache.RootID(), f.c.Nodes)
srcInfo := acd.NodeFromId(srcID, f.c.Nodes)
var jsonStr string
err = srcFs.pacer.Call(func() (bool, error) {
jsonStr, err = srcInfo.GetMetadata()
@ -724,10 +759,13 @@ func (f *Fs) DirMove(src fs.Fs) (err error) {
return err
}
err = f.moveNode(srcFs.root, dstLeaf, dstDirectoryID, srcInfo, srcLeaf, srcDirectoryID, true)
err = f.moveNode(srcPath, dstLeaf, dstDirectoryID, srcInfo, srcLeaf, srcDirectoryID, true)
if err != nil {
return err
}
srcFs.dirCache.ResetRoot()
return err
srcFs.dirCache.FlushDir(srcRemote)
return nil
}
// purgeCheck remotes the root directory, if check is set then it

View File

@ -254,15 +254,15 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
return f.newObject(oResult), nil
}
// DirMove moves src to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) error {
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) error {
do := f.Fs.Features().DirMove
if do == nil {
return fs.ErrorCantDirMove
@ -272,7 +272,7 @@ func (f *Fs) DirMove(src fs.Fs) error {
fs.Debugf(srcFs, "Can't move directory - not same remote type")
return fs.ErrorCantDirMove
}
return do(srcFs.Fs)
return do(srcFs.Fs, f.cipher.EncryptDirName(srcRemote), f.cipher.EncryptDirName(dstRemote))
}
// PutUnchecked uploads the object

View File

@ -791,34 +791,72 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// DirMove moves src directory to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) error {
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) error {
srcFs, ok := src.(*Fs)
if !ok {
fs.Debugf(srcFs, "Can't move directory - not same remote type")
return fs.ErrorCantDirMove
}
// Check if destination exists
if f.dirCache.FoundRoot() {
return fs.ErrorDirExists
}
srcPath := path.Join(srcFs.root, srcRemote)
dstPath := path.Join(f.root, dstRemote)
// Refuse to move to or from the root
if f.root == "" || srcFs.root == "" {
if srcPath == "" || dstPath == "" {
fs.Debugf(src, "DirMove error: Can't move root")
return errors.New("can't move root directory")
}
// Find ID of parent
leaf, directoryID, err := f.dirCache.FindPath(f.root, true)
// find the root src directory
err := srcFs.dirCache.FindRoot(false)
if err != nil {
return err
}
// find the root dst directory
if dstRemote != "" {
err = f.dirCache.FindRoot(true)
if err != nil {
return err
}
} else {
if f.dirCache.FoundRoot() {
return fs.ErrorDirExists
}
}
// Find ID of dst parent, creating subdirs if necessary
var leaf, directoryID string
findPath := dstRemote
if dstRemote == "" {
findPath = f.root
}
leaf, directoryID, err = f.dirCache.FindPath(findPath, true)
if err != nil {
return err
}
// Check destination does not exist
if dstRemote != "" {
_, err = f.dirCache.FindDir(dstRemote, false)
if err == fs.ErrorDirNotFound {
// OK
} else if err != nil {
return err
} else {
return fs.ErrorDirExists
}
}
// Find ID of src
srcID, err := srcFs.dirCache.FindDir(srcRemote, false)
if err != nil {
return err
}
@ -829,13 +867,13 @@ func (f *Fs) DirMove(src fs.Fs) error {
Parents: []*drive.ParentReference{{Id: directoryID}},
}
err = f.pacer.Call(func() (bool, error) {
_, err = f.svc.Files.Patch(srcFs.dirCache.RootID(), &patch).Do()
_, err = f.svc.Files.Patch(srcID, &patch).Do()
return shouldRetry(err)
})
if err != nil {
return err
}
srcFs.dirCache.ResetRoot()
srcFs.dirCache.FlushDir(srcRemote)
return nil
}

View File

@ -563,19 +563,22 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// DirMove moves src to this remote using server side move operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) error {
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) error {
srcFs, ok := src.(*Fs)
if !ok {
fs.Debugf(srcFs, "Can't move directory - not same remote type")
return fs.ErrorCantDirMove
}
srcPath := path.Join(srcFs.slashRoot, srcRemote)
dstPath := path.Join(f.slashRoot, dstRemote)
// Check if destination exists
entry, err := f.db.Metadata(f.slashRoot, false, false, "", "", metadataLimit)
@ -583,8 +586,11 @@ func (f *Fs) DirMove(src fs.Fs) error {
return fs.ErrorDirExists
}
// Make sure the parent directory exists
// ...apparently not necessary
// Do the move
_, err = f.db.Move(srcFs.slashRoot, f.slashRoot)
_, err = f.db.Move(srcPath, dstPath)
if err != nil {
return errors.Wrap(err, "MoveDir failed")
}

View File

@ -256,15 +256,15 @@ type Features struct {
// If it isn't possible then return fs.ErrorCantMove
Move func(src Object, remote string) (Object, error)
// DirMove moves src to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
DirMove func(src Fs) error
DirMove func(src Fs, srcRemote, dstRemote string) error
// UnWrap returns the Fs that this Fs is wrapping
UnWrap func() Fs
@ -412,15 +412,15 @@ type Mover interface {
// DirMover is an optional interface for Fs
type DirMover interface {
// DirMove moves src to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
DirMove(src Fs) error
DirMove(src Fs, srcRemote, dstRemote string) error
}
// UnWrapper is an optional interfaces for Fs

View File

@ -1107,7 +1107,7 @@ func MoveDir(fdst, fsrc Fs) error {
return nil
}
Debugf(fdst, "Using server side directory move")
err := fdstDirMove(fsrc)
err := fdstDirMove(fsrc, "", "")
switch err {
case ErrorCantDirMove, ErrorDirExists:
Infof(fdst, "Server side directory move failed - fallback to file moves: %v", err)

View File

@ -481,6 +481,8 @@ func TestFsMove(t *testing.T) {
// If destination exists then return fs.ErrorDirExists
// TestFsDirMove tests DirMove
//
// go test -v -run '^Test(Setup|Init|FsMkdir|FsPutFile1|FsPutFile2|FsUpdateFile1|FsDirMove)$
func TestFsDirMove(t *testing.T) {
skipIfNotOk(t)
@ -491,7 +493,7 @@ func TestFsDirMove(t *testing.T) {
}
// Check it can't move onto itself
err := doDirMove(remote)
err := doDirMove(remote, "", "")
require.Equal(t, fs.ErrorDirExists, err)
// new remote
@ -499,17 +501,23 @@ func TestFsDirMove(t *testing.T) {
require.NoError(t, err)
defer removeNewRemote()
const newName = "new_name/sub_new_name"
// try the move
err = newRemote.Features().DirMove(remote)
err = newRemote.Features().DirMove(remote, "", newName)
require.NoError(t, err)
// check remotes
// FIXME: Prints errors.
fstest.CheckListing(t, remote, []fstest.Item{})
fstest.CheckListing(t, newRemote, []fstest.Item{file2, file1})
file1Copy := file1
file1Copy.Path = path.Join(newName, file1.Path)
file2Copy := file2
file2Copy.Path = path.Join(newName, file2.Path)
file2Copy.WinPath = path.Join(newName, file2.WinPath)
fstest.CheckListing(t, newRemote, []fstest.Item{file2Copy, file1Copy})
// move it back
err = doDirMove(newRemote)
err = doDirMove(newRemote, newName, "")
require.NoError(t, err)
// check remotes

View File

@ -485,38 +485,38 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// DirMove moves src directory to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) error {
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) error {
srcFs, ok := src.(*Fs)
if !ok {
fs.Debugf(srcFs, "Can't move directory - not same remote type")
return fs.ErrorCantDirMove
}
// Check if source exists
sstat, err := os.Lstat(srcFs.root)
if err != nil {
return err
}
// And is a directory
if !sstat.IsDir() {
return fs.ErrorCantDirMove
}
srcPath := f.cleanPath(filepath.Join(srcFs.root, srcRemote))
dstPath := f.cleanPath(filepath.Join(f.root, dstRemote))
// Check if destination exists
_, err = os.Lstat(f.root)
_, err := os.Lstat(dstPath)
if !os.IsNotExist(err) {
return fs.ErrorDirExists
}
// Create parent of destination
dstParentPath, _ := getDirFile(dstPath)
err = os.MkdirAll(dstParentPath, 0777)
if err != nil {
return err
}
// Do the move
return os.Rename(srcFs.root, f.root)
return os.Rename(srcPath, dstPath)
}
// Hashes returns the supported hash sets.

View File

@ -384,23 +384,25 @@ func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
return dstObj, nil
}
// DirMove moves src directory to this remote using server side move
// operations.
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
//
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
func (f *Fs) DirMove(src fs.Fs) error {
func (f *Fs) DirMove(src fs.Fs, srcRemote, dstRemote string) error {
srcFs, ok := src.(*Fs)
if !ok {
fs.Debugf(srcFs, "Can't move directory - not same remote type")
return fs.ErrorCantDirMove
}
srcPath := path.Join(srcFs.root, srcRemote)
dstPath := path.Join(f.root, dstRemote)
// Check if destination exists
ok, err := f.dirExists(f.root)
ok, err := f.dirExists(dstPath)
if err != nil {
return errors.Wrap(err, "DirMove dirExists dst failed")
}
@ -408,31 +410,19 @@ func (f *Fs) DirMove(src fs.Fs) error {
return fs.ErrorDirExists
}
// Refuse to move to or from the root
if f.root == "" || srcFs.root == "" {
fs.Debugf(src, "DirMove error: Can't move root")
return errors.New("can't move root directory")
}
// Make sure the parent directory exists
// err = f.mkParentDir(f.root)
// if err != nil {
// return errors.Wrap(err, "DirMove mkParentDir dst failed")
// }
// Make sure the source directory exists
err = srcFs.mkdir(srcFs.root)
err = f.mkdir(path.Dir(dstPath))
if err != nil {
return errors.Wrap(err, "DirMove mkdir src failed")
return errors.Wrap(err, "DirMove mkParentDir dst failed")
}
// Do the move
err = f.sftpClient.Rename(
srcFs.root,
f.root,
srcPath,
dstPath,
)
if err != nil {
return errors.Wrapf(err, "DirMove Rename(%q,%q) failed", srcFs.root, f.root)
return errors.Wrapf(err, "DirMove Rename(%q,%q) failed", srcPath, dstPath)
}
return nil
}