From 99f7fe736a1b21af8d8768ebb8f58d2b89bc2651 Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Tue, 14 Mar 2017 15:35:10 +0000 Subject: [PATCH] onedrive: implement Move #197 --- docs/content/overview.md | 2 +- fs/operations.go | 2 +- onedrive/api/types.go | 11 +++++++ onedrive/onedrive.go | 63 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/docs/content/overview.md b/docs/content/overview.md index 47624f3ce..1b801c815 100644 --- a/docs/content/overview.md +++ b/docs/content/overview.md @@ -111,7 +111,7 @@ operations more efficient. | Dropbox | Yes | Yes | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | | Google Cloud Storage | Yes | Yes | No | No | No | | Amazon Drive | Yes | No | Yes | Yes | No [#575](https://github.com/ncw/rclone/issues/575) | -| Microsoft One Drive | Yes | Yes | No [#197](https://github.com/ncw/rclone/issues/197) | No [#197](https://github.com/ncw/rclone/issues/197) | No [#575](https://github.com/ncw/rclone/issues/575) | +| Microsoft One Drive | Yes | Yes | Yes | No [#197](https://github.com/ncw/rclone/issues/197) | No [#575](https://github.com/ncw/rclone/issues/575) | | Hubic | Yes † | Yes | No | No | No | | Backblaze B2 | No | No | No | No | Yes | | Yandex Disk | Yes | No | No | No | No [#575](https://github.com/ncw/rclone/issues/575) | diff --git a/fs/operations.go b/fs/operations.go index 5a8ab8799..9adcff4bf 100644 --- a/fs/operations.go +++ b/fs/operations.go @@ -395,7 +395,7 @@ func Move(fdst Fs, dst Object, remote string, src Object) (err error) { Debugf(src, "Can't move, switching to copy") default: Stats.Error() - Errorf(dst, "Couldn't move: %v", err) + Errorf(src, "Couldn't move: %v", err) return err } } diff --git a/onedrive/api/types.go b/onedrive/api/types.go index 062b50da2..eb9569209 100644 --- a/onedrive/api/types.go +++ b/onedrive/api/types.go @@ -200,6 +200,17 @@ type CopyItemRequest struct { Name *string `json:"name"` // Optional The new name for the copy. If this isn't provided, the same name will be used as the original. } +// MoveItemRequest is the request to copy an item object +// +// Note: The parentReference should include either an id or path but +// not both. If both are included, they need to reference the same +// item or an error will occur. +type MoveItemRequest struct { + ParentReference *ItemReference `json:"parentReference,omitempty"` // Reference to the destination parent directory + Name string `json:"name,omitempty"` // Optional The new name for the file. If this isn't provided, the same name will be used as the original. + FileSystemInfo *FileSystemInfoFacet `json:"fileSystemInfo,omitempty"` // File system information on client. Read-write. +} + // AsyncOperationStatus provides information on the status of a asynchronous job progress. // // The following API calls return AsyncOperationStatus resources: diff --git a/onedrive/onedrive.go b/onedrive/onedrive.go index 9b1dd1770..fb810fddf 100644 --- a/onedrive/onedrive.go +++ b/onedrive/onedrive.go @@ -667,6 +667,67 @@ func (f *Fs) Purge() error { return f.purgeCheck("", false) } +// Move src to this remote using server side move operations. +// +// This is stored with the remote path given +// +// It returns the destination Object and a possible error +// +// Will only be called if src.Fs().Name() == f.Name() +// +// If it isn't possible then return fs.ErrorCantMove +func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) { + srcObj, ok := src.(*Object) + if !ok { + fs.Debugf(src, "Can't move - not same remote type") + return nil, fs.ErrorCantMove + } + + // create the destination directory if necessary + err := f.dirCache.FindRoot(true) + if err != nil { + return nil, err + } + + // Create temporary object + dstObj, leaf, directoryID, err := f.createObject(remote, srcObj.modTime, srcObj.size) + if err != nil { + return nil, err + } + + // Move the object + opts := rest.Opts{ + Method: "PATCH", + Path: "/drive/items/" + srcObj.id, + } + move := api.MoveItemRequest{ + Name: replaceReservedChars(leaf), + ParentReference: &api.ItemReference{ + ID: directoryID, + }, + // We set the mod time too as it gets reset otherwise + FileSystemInfo: &api.FileSystemInfoFacet{ + CreatedDateTime: api.Timestamp(srcObj.modTime), + LastModifiedDateTime: api.Timestamp(srcObj.modTime), + }, + } + var resp *http.Response + var info api.Item + err = f.pacer.Call(func() (bool, error) { + resp, err = f.srv.CallJSON(&opts, &move, &info) + return shouldRetry(resp, err) + }) + if err != nil { + return nil, err + } + + err = dstObj.setMetaData(&info) + if err != nil { + return nil, err + } + return dstObj, nil +} + // DirCacheFlush resets the directory cache - used in testing as an // optional interface func (f *Fs) DirCacheFlush() { @@ -1000,7 +1061,7 @@ var ( _ fs.Fs = (*Fs)(nil) _ fs.Purger = (*Fs)(nil) _ fs.Copier = (*Fs)(nil) - // _ fs.Mover = (*Fs)(nil) + _ fs.Mover = (*Fs)(nil) // _ fs.DirMover = (*Fs)(nil) _ fs.DirCacheFlusher = (*Fs)(nil) _ fs.Object = (*Object)(nil)