Add context propagation to rclone

- Change rclone/fs interfaces to accept context.Context
- Update interface implementations to use context.Context
- Change top level usage to propagate context to lover level functions

Context propagation is needed for stopping transfers and passing other
request-scoped values.
This commit is contained in:
Aleksandar Jankovic
2019-06-17 10:34:30 +02:00
committed by Nick Craig-Wood
parent a2c317b46e
commit f78cd1e043
156 changed files with 2570 additions and 2380 deletions

View File

@@ -2,6 +2,7 @@
package fs
import (
"context"
"encoding/json"
"fmt"
"io"
@@ -245,11 +246,11 @@ type Fs interface {
//
// This should return ErrDirNotFound if the directory isn't
// found.
List(dir string) (entries DirEntries, err error)
List(ctx context.Context, dir string) (entries DirEntries, err error)
// NewObject finds the Object at remote. If it can't be found
// it returns the error ErrorObjectNotFound.
NewObject(remote string) (Object, error)
NewObject(ctx context.Context, remote string) (Object, error)
// Put in to the remote path with the modTime given of the given size
//
@@ -260,17 +261,17 @@ type Fs interface {
// May create the object even if it returns an error - if so
// will return the object and the error, otherwise will return
// nil and the error
Put(in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
Put(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
// Mkdir makes the directory (container, bucket)
//
// Shouldn't return an error if it already exists
Mkdir(dir string) error
Mkdir(ctx context.Context, dir string) error
// Rmdir removes the directory (container, bucket) if empty
//
// Return an error if it doesn't exist or isn't empty
Rmdir(dir string) error
Rmdir(ctx context.Context, dir string) error
}
// Info provides a read only interface to information about a filesystem.
@@ -299,20 +300,20 @@ type Object interface {
ObjectInfo
// SetModTime sets the metadata on the object to set the modification date
SetModTime(time.Time) error
SetModTime(ctx context.Context, t time.Time) error
// Open opens the file for read. Call Close() on the returned io.ReadCloser
Open(options ...OpenOption) (io.ReadCloser, error)
Open(ctx context.Context, options ...OpenOption) (io.ReadCloser, error)
// Update in to the object with the modTime given of the given size
//
// When called from outside a Fs by rclone, src.Size() will always be >= 0.
// But for unknown-sized objects (indicated by src.Size() == -1), Upload should either
// return an error or update the object properly (rather than e.g. calling panic).
Update(in io.Reader, src ObjectInfo, options ...OpenOption) error
Update(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) error
// Removes this object
Remove() error
Remove(ctx context.Context) error
}
// ObjectInfo provides read only information about an object.
@@ -324,7 +325,7 @@ type ObjectInfo interface {
// Hash returns the selected checksum of the file
// If no checksum is available it returns ""
Hash(hash.Type) (string, error)
Hash(ctx context.Context, ty hash.Type) (string, error)
// Storable says whether this object can be stored
Storable() bool
@@ -342,7 +343,7 @@ type DirEntry interface {
// ModTime returns the modification date of the file
// It should return a best guess if one isn't available
ModTime() time.Time
ModTime(context.Context) time.Time
// Size returns the size of the file
Size() int64
@@ -365,7 +366,7 @@ type Directory interface {
type MimeTyper interface {
// MimeType returns the content type of the Object if
// known, or "" if not
MimeType() string
MimeType(ctx context.Context) string
}
// IDer is an optional interface for Object
@@ -430,7 +431,7 @@ func ObjectOptionalInterfaces(o Object) (supported, unsupported []string) {
type ListRCallback func(entries DirEntries) error
// ListRFn is defines the call used to recursively list a directory
type ListRFn func(dir string, callback ListRCallback) error
type ListRFn func(ctx context.Context, dir string, callback ListRCallback) error
// NewUsageValue makes a valid value
func NewUsageValue(value int64) *int64 {
@@ -476,7 +477,7 @@ type Features struct {
// quicker than just running Remove() on the result of List()
//
// Return an error if it doesn't exist
Purge func() error
Purge func(ctx context.Context) error
// Copy src to this remote using server side copy operations.
//
@@ -487,7 +488,7 @@ type Features struct {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantCopy
Copy func(src Object, remote string) (Object, error)
Copy func(ctx context.Context, src Object, remote string) (Object, error)
// Move src to this remote using server side move operations.
//
@@ -498,7 +499,7 @@ type Features struct {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
Move func(src Object, remote string) (Object, error)
Move func(ctx context.Context, src Object, remote string) (Object, error)
// DirMove moves src, srcRemote to this remote at dstRemote
// using server side move operations.
@@ -508,12 +509,12 @@ type Features struct {
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
DirMove func(src Fs, srcRemote, dstRemote string) error
DirMove func(ctx context.Context, src Fs, srcRemote, dstRemote string) error
// ChangeNotify calls the passed function with a path
// that has had changes. If the implementation
// uses polling, it should adhere to the given interval.
ChangeNotify func(func(string, EntryType), <-chan time.Duration)
ChangeNotify func(context.Context, func(string, EntryType), <-chan time.Duration)
// UnWrap returns the Fs that this Fs is wrapping
UnWrap func() Fs
@@ -529,7 +530,7 @@ type Features struct {
DirCacheFlush func()
// PublicLink generates a public link to the remote path (usually readable by anyone)
PublicLink func(remote string) (string, error)
PublicLink func(ctx context.Context, remote string) (string, error)
// Put in to the remote path with the modTime given of the given size
//
@@ -539,24 +540,24 @@ type Features struct {
//
// May create duplicates or return errors if src already
// exists.
PutUnchecked func(in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
PutUnchecked func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
// PutStream uploads to the remote path with the modTime given of indeterminate size
//
// May create the object even if it returns an error - if so
// will return the object and the error, otherwise will return
// nil and the error
PutStream func(in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
PutStream func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
// MergeDirs merges the contents of all the directories passed
// in into the first one and rmdirs the other directories.
MergeDirs func([]Directory) error
MergeDirs func(ctx context.Context, dirs []Directory) error
// CleanUp the trash in the Fs
//
// Implement this if you have a way of emptying the trash or
// otherwise cleaning up old versions of files.
CleanUp func() error
CleanUp func(ctx context.Context) error
// ListR lists the objects and directories of the Fs starting
// from dir recursively into out.
@@ -577,14 +578,14 @@ type Features struct {
ListR ListRFn
// About gets quota information from the Fs
About func() (*Usage, error)
About func(ctx context.Context) (*Usage, error)
// OpenWriterAt opens with a handle for random access writes
//
// Pass in the remote desired and the size if known.
//
// It truncates any existing object
OpenWriterAt func(remote string, size int64) (WriterAtCloser, error)
OpenWriterAt func(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
}
// Disable nil's out the named feature. If it isn't found then it
@@ -803,7 +804,7 @@ type Purger interface {
// quicker than just running Remove() on the result of List()
//
// Return an error if it doesn't exist
Purge() error
Purge(ctx context.Context) error
}
// Copier is an optional interface for Fs
@@ -817,7 +818,7 @@ type Copier interface {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantCopy
Copy(src Object, remote string) (Object, error)
Copy(ctx context.Context, src Object, remote string) (Object, error)
}
// Mover is an optional interface for Fs
@@ -831,7 +832,7 @@ type Mover interface {
// Will only be called if src.Fs().Name() == f.Name()
//
// If it isn't possible then return fs.ErrorCantMove
Move(src Object, remote string) (Object, error)
Move(ctx context.Context, src Object, remote string) (Object, error)
}
// DirMover is an optional interface for Fs
@@ -844,7 +845,7 @@ type DirMover interface {
// If it isn't possible then return fs.ErrorCantDirMove
//
// If destination exists then return fs.ErrorDirExists
DirMove(src Fs, srcRemote, dstRemote string) error
DirMove(ctx context.Context, src Fs, srcRemote, dstRemote string) error
}
// ChangeNotifier is an optional interface for Fs
@@ -858,7 +859,7 @@ type ChangeNotifier interface {
// The ChangeNotify implementation must empty the channel
// regularly. When the channel gets closed, the implementation
// should stop polling and release resources.
ChangeNotify(func(string, EntryType), <-chan time.Duration)
ChangeNotify(context.Context, func(string, EntryType), <-chan time.Duration)
}
// UnWrapper is an optional interfaces for Fs
@@ -892,7 +893,7 @@ type PutUncheckeder interface {
//
// May create duplicates or return errors if src already
// exists.
PutUnchecked(in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
PutUnchecked(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
}
// PutStreamer is an optional interface for Fs
@@ -902,20 +903,20 @@ type PutStreamer interface {
// May create the object even if it returns an error - if so
// will return the object and the error, otherwise will return
// nil and the error
PutStream(in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
PutStream(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
}
// PublicLinker is an optional interface for Fs
type PublicLinker interface {
// PublicLink generates a public link to the remote path (usually readable by anyone)
PublicLink(remote string) (string, error)
PublicLink(ctx context.Context, remote string) (string, error)
}
// MergeDirser is an option interface for Fs
type MergeDirser interface {
// MergeDirs merges the contents of all the directories passed
// in into the first one and rmdirs the other directories.
MergeDirs([]Directory) error
MergeDirs(ctx context.Context, dirs []Directory) error
}
// CleanUpper is an optional interfaces for Fs
@@ -924,7 +925,7 @@ type CleanUpper interface {
//
// Implement this if you have a way of emptying the trash or
// otherwise cleaning up old versions of files.
CleanUp() error
CleanUp(ctx context.Context) error
}
// ListRer is an optional interfaces for Fs
@@ -945,7 +946,7 @@ type ListRer interface {
//
// Don't implement this unless you have a more efficient way
// of listing recursively that doing a directory traversal.
ListR(dir string, callback ListRCallback) error
ListR(ctx context.Context, dir string, callback ListRCallback) error
}
// RangeSeeker is the interface that wraps the RangeSeek method.
@@ -958,13 +959,13 @@ type RangeSeeker interface {
// limiting the total length to limit.
//
// RangeSeek with a limit of < 0 is equivalent to a regular Seek.
RangeSeek(offset int64, whence int, length int64) (int64, error)
RangeSeek(ctx context.Context, offset int64, whence int, length int64) (int64, error)
}
// Abouter is an optional interface for Fs
type Abouter interface {
// About gets quota information from the Fs
About() (*Usage, error)
About(ctx context.Context) (*Usage, error)
}
// OpenWriterAter is an optional interface for Fs
@@ -974,7 +975,7 @@ type OpenWriterAter interface {
// Pass in the remote desired and the size if known.
//
// It truncates any existing object
OpenWriterAt(remote string, size int64) (WriterAtCloser, error)
OpenWriterAt(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
}
// ObjectsChan is a channel of Objects
@@ -1195,8 +1196,8 @@ func CheckClose(c io.Closer, err *error) {
// FileExists returns true if a file remote exists.
// If remote is a directory, FileExists returns false.
func FileExists(fs Fs, remote string) (bool, error) {
_, err := fs.NewObject(remote)
func FileExists(ctx context.Context, fs Fs, remote string) (bool, error) {
_, err := fs.NewObject(ctx, remote)
if err != nil {
if err == ErrorObjectNotFound || err == ErrorNotAFile || err == ErrorPermissionDenied {
return false, nil