mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 08:23:47 +01:00
Add srcRemote and dstRemote parameters to DirMove #954
This commit is contained in:
parent
e4835f535d
commit
f3c5745468
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
}
|
||||
|
12
fs/fs.go
12
fs/fs.go
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
32
sftp/sftp.go
32
sftp/sftp.go
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user