forked from TrueCloudLab/rclone
Fix error counter - fixes #3650
For few commands, RClone counts a error multiple times. This was fixed by creating a new error type which keeps a flag to remember if the error has already been counted or not. The CountError function now wraps the original error eith the above new error type and returns it.
This commit is contained in:
parent
19229b1215
commit
75a6c49f87
18 changed files with 157 additions and 77 deletions
|
@ -350,7 +350,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
||||||
err = errors.Wrapf(err, "failed to open directory %q", dir)
|
err = errors.Wrapf(err, "failed to open directory %q", dir)
|
||||||
fs.Errorf(dir, "%v", err)
|
fs.Errorf(dir, "%v", err)
|
||||||
if isPerm {
|
if isPerm {
|
||||||
accounting.Stats(ctx).Error(fserrors.NoRetryError(err))
|
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(err))
|
||||||
err = nil // ignore error but fail sync
|
err = nil // ignore error but fail sync
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -386,7 +386,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
||||||
if fierr != nil {
|
if fierr != nil {
|
||||||
err = errors.Wrapf(err, "failed to read directory %q", namepath)
|
err = errors.Wrapf(err, "failed to read directory %q", namepath)
|
||||||
fs.Errorf(dir, "%v", fierr)
|
fs.Errorf(dir, "%v", fierr)
|
||||||
accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
|
_ = accounting.Stats(ctx).Error(fserrors.NoRetryError(fierr)) // fail the sync
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fis = append(fis, fi)
|
fis = append(fis, fi)
|
||||||
|
@ -409,7 +409,7 @@ func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err e
|
||||||
// Skip bad symlinks
|
// Skip bad symlinks
|
||||||
err = fserrors.NoRetryError(errors.Wrap(err, "symlink"))
|
err = fserrors.NoRetryError(errors.Wrap(err, "symlink"))
|
||||||
fs.Errorf(newRemote, "Listing error: %v", err)
|
fs.Errorf(newRemote, "Listing error: %v", err)
|
||||||
accounting.Stats(ctx).Error(err)
|
err = accounting.Stats(ctx).Error(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
26
cmd/cmd.go
26
cmd/cmd.go
|
@ -82,7 +82,7 @@ func ShowVersion() {
|
||||||
func NewFsFile(remote string) (fs.Fs, string) {
|
func NewFsFile(remote string) (fs.Fs, string) {
|
||||||
_, _, fsPath, err := fs.ParseRemote(remote)
|
_, _, fsPath, err := fs.ParseRemote(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
||||||
}
|
}
|
||||||
f, err := cache.Get(remote)
|
f, err := cache.Get(remote)
|
||||||
|
@ -92,7 +92,7 @@ func NewFsFile(remote string) (fs.Fs, string) {
|
||||||
case nil:
|
case nil:
|
||||||
return f, ""
|
return f, ""
|
||||||
default:
|
default:
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
||||||
}
|
}
|
||||||
return nil, ""
|
return nil, ""
|
||||||
|
@ -107,13 +107,13 @@ func newFsFileAddFilter(remote string) (fs.Fs, string) {
|
||||||
if fileName != "" {
|
if fileName != "" {
|
||||||
if !filter.Active.InActive() {
|
if !filter.Active.InActive() {
|
||||||
err := errors.Errorf("Can't limit to single files when using filters: %v", remote)
|
err := errors.Errorf("Can't limit to single files when using filters: %v", remote)
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatalf(err.Error())
|
log.Fatalf(err.Error())
|
||||||
}
|
}
|
||||||
// Limit transfers to this file
|
// Limit transfers to this file
|
||||||
err := filter.Active.AddFile(fileName)
|
err := filter.Active.AddFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatalf("Failed to limit to single file %q: %v", remote, err)
|
log.Fatalf("Failed to limit to single file %q: %v", remote, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ func NewFsSrc(args []string) fs.Fs {
|
||||||
func newFsDir(remote string) fs.Fs {
|
func newFsDir(remote string) fs.Fs {
|
||||||
f, err := cache.Get(remote)
|
f, err := cache.Get(remote)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
log.Fatalf("Failed to create file system for %q: %v", remote, err)
|
||||||
}
|
}
|
||||||
return f
|
return f
|
||||||
|
@ -189,11 +189,11 @@ func NewFsSrcDstFiles(args []string) (fsrc fs.Fs, srcFileName string, fdst fs.Fs
|
||||||
fdst, err := cache.Get(dstRemote)
|
fdst, err := cache.Get(dstRemote)
|
||||||
switch err {
|
switch err {
|
||||||
case fs.ErrorIsFile:
|
case fs.ErrorIsFile:
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
log.Fatalf("Source doesn't exist or is a directory and destination is a file")
|
log.Fatalf("Source doesn't exist or is a directory and destination is a file")
|
||||||
case nil:
|
case nil:
|
||||||
default:
|
default:
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
log.Fatalf("Failed to create file system for destination %q: %v", dstRemote, err)
|
log.Fatalf("Failed to create file system for destination %q: %v", dstRemote, err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -239,7 +239,7 @@ func Run(Retry bool, showStats bool, cmd *cobra.Command, f func() error) {
|
||||||
SigInfoHandler()
|
SigInfoHandler()
|
||||||
for try := 1; try <= *retries; try++ {
|
for try := 1; try <= *retries; try++ {
|
||||||
err = f()
|
err = f()
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
lastErr := accounting.GlobalStats().GetLastError()
|
lastErr := accounting.GlobalStats().GetLastError()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = lastErr
|
err = lastErr
|
||||||
|
@ -386,12 +386,12 @@ func initConfig() {
|
||||||
fs.Infof(nil, "Creating CPU profile %q\n", *cpuProfile)
|
fs.Infof(nil, "Creating CPU profile %q\n", *cpuProfile)
|
||||||
f, err := os.Create(*cpuProfile)
|
f, err := os.Create(*cpuProfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
err = pprof.StartCPUProfile(f)
|
err = pprof.StartCPUProfile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
atexit.Register(func() {
|
atexit.Register(func() {
|
||||||
|
@ -405,17 +405,17 @@ func initConfig() {
|
||||||
fs.Infof(nil, "Saving Memory profile %q\n", *memProfile)
|
fs.Infof(nil, "Saving Memory profile %q\n", *memProfile)
|
||||||
f, err := os.Create(*memProfile)
|
f, err := os.Create(*memProfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
err = pprof.WriteHeapProfile(f)
|
err = pprof.WriteHeapProfile(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
err = f.Close()
|
err = f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -88,7 +88,7 @@ func cryptCheck(ctx context.Context, fdst, fsrc fs.Fs) error {
|
||||||
underlyingDst := cryptDst.UnWrap()
|
underlyingDst := cryptDst.UnWrap()
|
||||||
underlyingHash, err := underlyingDst.Hash(ctx, hashType)
|
underlyingHash, err := underlyingDst.Hash(ctx, hashType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dst, "Error reading hash from underlying %v: %v", underlyingDst, err)
|
fs.Errorf(dst, "Error reading hash from underlying %v: %v", underlyingDst, err)
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
@ -97,7 +97,7 @@ func cryptCheck(ctx context.Context, fdst, fsrc fs.Fs) error {
|
||||||
}
|
}
|
||||||
cryptHash, err := fcrypt.ComputeHash(ctx, cryptDst, src, hashType)
|
cryptHash, err := fcrypt.ComputeHash(ctx, cryptDst, src, hashType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dst, "Error computing hash: %v", err)
|
fs.Errorf(dst, "Error computing hash: %v", err)
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func cryptCheck(ctx context.Context, fdst, fsrc fs.Fs) error {
|
||||||
}
|
}
|
||||||
if cryptHash != underlyingHash {
|
if cryptHash != underlyingHash {
|
||||||
err = errors.Errorf("hashes differ (%s:%s) %q vs (%s:%s) %q", fdst.Name(), fdst.Root(), cryptHash, fsrc.Name(), fsrc.Root(), underlyingHash)
|
err = errors.Errorf("hashes differ (%s:%s) %q vs (%s:%s) %q", fdst.Name(), fdst.Root(), cryptHash, fsrc.Name(), fsrc.Root(), underlyingHash)
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(src, err.Error())
|
fs.Errorf(src, err.Error())
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,7 @@ func withHeader(name string, value string, next http.Handler) http.Handler {
|
||||||
|
|
||||||
// serveError returns an http.StatusInternalServerError and logs the error
|
// serveError returns an http.StatusInternalServerError and logs the error
|
||||||
func serveError(what interface{}, w http.ResponseWriter, text string, err error) {
|
func serveError(what interface{}, w http.ResponseWriter, text string, err error) {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(what, "%s: %v", text, err)
|
fs.Errorf(what, "%s: %v", text, err)
|
||||||
http.Error(w, text+".", http.StatusInternalServerError)
|
http.Error(w, text+".", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func (d *Directory) AddEntry(remote string, isDir bool) {
|
||||||
|
|
||||||
// Error logs the error and if a ResponseWriter is given it writes a http.StatusInternalServerError
|
// Error logs the error and if a ResponseWriter is given it writes a http.StatusInternalServerError
|
||||||
func Error(what interface{}, w http.ResponseWriter, text string, err error) {
|
func Error(what interface{}, w http.ResponseWriter, text string, err error) {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(what, "%s: %v", text, err)
|
fs.Errorf(what, "%s: %v", text, err)
|
||||||
if w != nil {
|
if w != nil {
|
||||||
http.Error(w, text+".", http.StatusInternalServerError)
|
http.Error(w, text+".", http.StatusInternalServerError)
|
||||||
|
|
|
@ -271,7 +271,7 @@ func (s *server) postObject(w http.ResponseWriter, r *http.Request, remote strin
|
||||||
|
|
||||||
_, err := operations.RcatSize(r.Context(), s.f, remote, r.Body, r.ContentLength, time.Now())
|
_, err := operations.RcatSize(r.Context(), s.f, remote, r.Body, r.ContentLength, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
accounting.Stats(r.Context()).Error(err)
|
err = accounting.Stats(r.Context()).Error(err)
|
||||||
fs.Errorf(remote, "Post request rcat error: %v", err)
|
fs.Errorf(remote, "Post request rcat error: %v", err)
|
||||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||||
|
|
||||||
|
|
|
@ -475,14 +475,16 @@ func (s *StatsInfo) Errored() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error adds a single error into the stats, assigns lastError and eventually sets fatalError or retryError
|
// Error adds a single error into the stats, assigns lastError and eventually sets fatalError or retryError
|
||||||
func (s *StatsInfo) Error(err error) {
|
func (s *StatsInfo) Error(err error) error {
|
||||||
if err == nil {
|
if err == nil || fserrors.IsCounted(err) {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
s.errors++
|
s.errors++
|
||||||
s.lastError = err
|
s.lastError = err
|
||||||
|
err = fserrors.FsError(err)
|
||||||
|
fserrors.Count(err)
|
||||||
switch {
|
switch {
|
||||||
case fserrors.IsFatalError(err):
|
case fserrors.IsFatalError(err):
|
||||||
s.fatalError = true
|
s.fatalError = true
|
||||||
|
@ -495,6 +497,7 @@ func (s *StatsInfo) Error(err error) {
|
||||||
case !fserrors.IsNoRetryError(err):
|
case !fserrors.IsNoRetryError(err):
|
||||||
s.retryError = true
|
s.retryError = true
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetryAfter returns the time to retry after if it is set. It will
|
// RetryAfter returns the time to retry after if it is set. It will
|
||||||
|
|
|
@ -78,7 +78,7 @@ func TestStatsError(t *testing.T) {
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
t1 := t0.Add(time.Second)
|
t1 := t0.Add(time.Second)
|
||||||
|
|
||||||
s.Error(nil)
|
_ = s.Error(nil)
|
||||||
assert.Equal(t, int64(0), s.GetErrors())
|
assert.Equal(t, int64(0), s.GetErrors())
|
||||||
assert.False(t, s.HadFatalError())
|
assert.False(t, s.HadFatalError())
|
||||||
assert.False(t, s.HadRetryError())
|
assert.False(t, s.HadRetryError())
|
||||||
|
@ -86,7 +86,7 @@ func TestStatsError(t *testing.T) {
|
||||||
assert.Equal(t, nil, s.GetLastError())
|
assert.Equal(t, nil, s.GetLastError())
|
||||||
assert.False(t, s.Errored())
|
assert.False(t, s.Errored())
|
||||||
|
|
||||||
s.Error(io.EOF)
|
_ = s.Error(io.EOF)
|
||||||
assert.Equal(t, int64(1), s.GetErrors())
|
assert.Equal(t, int64(1), s.GetErrors())
|
||||||
assert.False(t, s.HadFatalError())
|
assert.False(t, s.HadFatalError())
|
||||||
assert.True(t, s.HadRetryError())
|
assert.True(t, s.HadRetryError())
|
||||||
|
@ -95,7 +95,7 @@ func TestStatsError(t *testing.T) {
|
||||||
assert.True(t, s.Errored())
|
assert.True(t, s.Errored())
|
||||||
|
|
||||||
e := fserrors.ErrorRetryAfter(t0)
|
e := fserrors.ErrorRetryAfter(t0)
|
||||||
s.Error(e)
|
_ = s.Error(e)
|
||||||
assert.Equal(t, int64(2), s.GetErrors())
|
assert.Equal(t, int64(2), s.GetErrors())
|
||||||
assert.False(t, s.HadFatalError())
|
assert.False(t, s.HadFatalError())
|
||||||
assert.True(t, s.HadRetryError())
|
assert.True(t, s.HadRetryError())
|
||||||
|
@ -103,14 +103,14 @@ func TestStatsError(t *testing.T) {
|
||||||
assert.Equal(t, e, s.GetLastError())
|
assert.Equal(t, e, s.GetLastError())
|
||||||
|
|
||||||
err := errors.Wrap(fserrors.ErrorRetryAfter(t1), "potato")
|
err := errors.Wrap(fserrors.ErrorRetryAfter(t1), "potato")
|
||||||
s.Error(err)
|
err = s.Error(err)
|
||||||
assert.Equal(t, int64(3), s.GetErrors())
|
assert.Equal(t, int64(3), s.GetErrors())
|
||||||
assert.False(t, s.HadFatalError())
|
assert.False(t, s.HadFatalError())
|
||||||
assert.True(t, s.HadRetryError())
|
assert.True(t, s.HadRetryError())
|
||||||
assert.Equal(t, t1, s.RetryAfter())
|
assert.Equal(t, t1, s.RetryAfter())
|
||||||
assert.Equal(t, t1, fserrors.RetryAfterErrorTime(err))
|
assert.Equal(t, t1, fserrors.RetryAfterErrorTime(err))
|
||||||
|
|
||||||
s.Error(fserrors.FatalError(io.EOF))
|
_ = s.Error(fserrors.FatalError(io.EOF))
|
||||||
assert.Equal(t, int64(4), s.GetErrors())
|
assert.Equal(t, int64(4), s.GetErrors())
|
||||||
assert.True(t, s.HadFatalError())
|
assert.True(t, s.HadFatalError())
|
||||||
assert.True(t, s.HadRetryError())
|
assert.True(t, s.HadRetryError())
|
||||||
|
@ -124,7 +124,7 @@ func TestStatsError(t *testing.T) {
|
||||||
assert.Equal(t, nil, s.GetLastError())
|
assert.Equal(t, nil, s.GetLastError())
|
||||||
assert.False(t, s.Errored())
|
assert.False(t, s.Errored())
|
||||||
|
|
||||||
s.Error(fserrors.NoRetryError(io.EOF))
|
_ = s.Error(fserrors.NoRetryError(io.EOF))
|
||||||
assert.Equal(t, int64(1), s.GetErrors())
|
assert.Equal(t, int64(1), s.GetErrors())
|
||||||
assert.False(t, s.HadFatalError())
|
assert.False(t, s.HadFatalError())
|
||||||
assert.False(t, s.HadRetryError())
|
assert.False(t, s.HadRetryError())
|
||||||
|
|
|
@ -86,7 +86,7 @@ func newTransferRemoteSize(stats *StatsInfo, remote string, size int64, checking
|
||||||
// Must be called after transfer is finished to run proper cleanups.
|
// Must be called after transfer is finished to run proper cleanups.
|
||||||
func (tr *Transfer) Done(err error) {
|
func (tr *Transfer) Done(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tr.stats.Error(err)
|
err = tr.stats.Error(err)
|
||||||
|
|
||||||
tr.mu.Lock()
|
tr.mu.Lock()
|
||||||
tr.err = err
|
tr.err = err
|
||||||
|
|
|
@ -32,7 +32,7 @@ var (
|
||||||
//
|
//
|
||||||
// This is a function pointer to decouple the config
|
// This is a function pointer to decouple the config
|
||||||
// implementation from the fs
|
// implementation from the fs
|
||||||
CountError = func(err error) {}
|
CountError = func(err error) error { return nil }
|
||||||
|
|
||||||
// ConfigProvider is the config key used for provider options
|
// ConfigProvider is the config key used for provider options
|
||||||
ConfigProvider = "provider"
|
ConfigProvider = "provider"
|
||||||
|
|
|
@ -230,6 +230,64 @@ func IsRetryAfterError(err error) bool {
|
||||||
return !RetryAfterErrorTime(err).IsZero()
|
return !RetryAfterErrorTime(err).IsZero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountableError is an optional interface for error. It stores a boolean
|
||||||
|
// which signifies if the error has already been counted or not
|
||||||
|
type CountableError interface {
|
||||||
|
error
|
||||||
|
Count()
|
||||||
|
IsCounted() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrappedFatalError is an error wrapped so it will satisfy the
|
||||||
|
// Retrier interface and return true
|
||||||
|
type wrappedCountableError struct {
|
||||||
|
error
|
||||||
|
isCounted bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountableError interface
|
||||||
|
func (err *wrappedCountableError) Count() {
|
||||||
|
err.isCounted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// CountableError interface
|
||||||
|
func (err *wrappedCountableError) IsCounted() bool {
|
||||||
|
return err.isCounted
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *wrappedCountableError) Cause() error {
|
||||||
|
return err.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCounted returns true if err conforms to the CountableError interface
|
||||||
|
// and has already been counted
|
||||||
|
func IsCounted(err error) bool {
|
||||||
|
if r, ok := err.(CountableError); ok {
|
||||||
|
return r.IsCounted()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count sets the isCounted variable on the error if it conforms to the
|
||||||
|
// CountableError interface
|
||||||
|
func Count(err error) {
|
||||||
|
if r, ok := err.(CountableError); ok {
|
||||||
|
r.Count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check interface
|
||||||
|
var _ CountableError = &wrappedCountableError{error: error(nil)}
|
||||||
|
|
||||||
|
// FsError makes an error which can keep a record that it is already counted
|
||||||
|
// or not
|
||||||
|
func FsError(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
err = errors.New("countable error")
|
||||||
|
}
|
||||||
|
return &wrappedCountableError{error: err}
|
||||||
|
}
|
||||||
|
|
||||||
// Cause is a souped up errors.Cause which can unwrap some standard
|
// Cause is a souped up errors.Cause which can unwrap some standard
|
||||||
// library errors too. It returns true if any of the intermediate
|
// library errors too. It returns true if any of the intermediate
|
||||||
// errors had a Timeout() or Temporary() method which returned true.
|
// errors had a Timeout() or Temporary() method which returned true.
|
||||||
|
|
|
@ -393,14 +393,14 @@ func (m *March) processJob(job listDirJob) ([]listDirJob, error) {
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
if srcListErr != nil {
|
if srcListErr != nil {
|
||||||
fs.Errorf(job.srcRemote, "error reading source directory: %v", srcListErr)
|
fs.Errorf(job.srcRemote, "error reading source directory: %v", srcListErr)
|
||||||
fs.CountError(srcListErr)
|
srcListErr = fs.CountError(srcListErr)
|
||||||
return nil, srcListErr
|
return nil, srcListErr
|
||||||
}
|
}
|
||||||
if dstListErr == fs.ErrorDirNotFound {
|
if dstListErr == fs.ErrorDirNotFound {
|
||||||
// Copy the stuff anyway
|
// Copy the stuff anyway
|
||||||
} else if dstListErr != nil {
|
} else if dstListErr != nil {
|
||||||
fs.Errorf(job.dstRemote, "error reading destination directory: %v", dstListErr)
|
fs.Errorf(job.dstRemote, "error reading destination directory: %v", dstListErr)
|
||||||
fs.CountError(dstListErr)
|
dstListErr = fs.CountError(dstListErr)
|
||||||
return nil, dstListErr
|
return nil, dstListErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ outer:
|
||||||
_, err := f.NewObject(ctx, newName)
|
_, err := f.NewObject(ctx, newName)
|
||||||
for ; err != fs.ErrorObjectNotFound; suffix++ {
|
for ; err != fs.ErrorObjectNotFound; suffix++ {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(o, "Failed to check for existing object: %v", err)
|
fs.Errorf(o, "Failed to check for existing object: %v", err)
|
||||||
continue outer
|
continue outer
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ outer:
|
||||||
if !fs.Config.DryRun {
|
if !fs.Config.DryRun {
|
||||||
newObj, err := doMove(ctx, o, newName)
|
newObj, err := doMove(ctx, o, newName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(o, "Failed to rename: %v", err)
|
fs.Errorf(o, "Failed to rename: %v", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ func checkHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object, ht hash.
|
||||||
g.Go(func() (err error) {
|
g.Go(func() (err error) {
|
||||||
srcHash, err = src.Hash(ctx, ht)
|
srcHash, err = src.Hash(ctx, ht)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(src, "Failed to calculate src hash: %v", err)
|
fs.Errorf(src, "Failed to calculate src hash: %v", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -71,7 +71,7 @@ func checkHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object, ht hash.
|
||||||
g.Go(func() (err error) {
|
g.Go(func() (err error) {
|
||||||
dstHash, err = dst.Hash(ctx, ht)
|
dstHash, err = dst.Hash(ctx, ht)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dst, "Failed to calculate dst hash: %v", err)
|
fs.Errorf(dst, "Failed to calculate dst hash: %v", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -234,7 +234,7 @@ func equal(ctx context.Context, src fs.ObjectInfo, dst fs.Object, opt equalOpt)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dst, "Failed to set modification time: %v", err)
|
fs.Errorf(dst, "Failed to set modification time: %v", err)
|
||||||
} else {
|
} else {
|
||||||
fs.Infof(src, "Updated modification time in destination")
|
fs.Infof(src, "Updated modification time in destination")
|
||||||
|
@ -408,7 +408,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(src, "Failed to copy: %v", err)
|
fs.Errorf(src, "Failed to copy: %v", err)
|
||||||
return newDst, err
|
return newDst, err
|
||||||
}
|
}
|
||||||
|
@ -417,7 +417,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
|
||||||
if sizeDiffers(src, dst) {
|
if sizeDiffers(src, dst) {
|
||||||
err = errors.Errorf("corrupted on transfer: sizes differ %d vs %d", src.Size(), dst.Size())
|
err = errors.Errorf("corrupted on transfer: sizes differ %d vs %d", src.Size(), dst.Size())
|
||||||
fs.Errorf(dst, "%v", err)
|
fs.Errorf(dst, "%v", err)
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
removeFailedCopy(ctx, dst)
|
removeFailedCopy(ctx, dst)
|
||||||
return newDst, err
|
return newDst, err
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Obj
|
||||||
if !equal {
|
if !equal {
|
||||||
err = errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum)
|
err = errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum)
|
||||||
fs.Errorf(dst, "%v", err)
|
fs.Errorf(dst, "%v", err)
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
removeFailedCopy(ctx, dst)
|
removeFailedCopy(ctx, dst)
|
||||||
return newDst, err
|
return newDst, err
|
||||||
}
|
}
|
||||||
|
@ -492,7 +492,7 @@ func Move(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.
|
||||||
case fs.ErrorCantMove:
|
case fs.ErrorCantMove:
|
||||||
fs.Debugf(src, "Can't move, switching to copy")
|
fs.Debugf(src, "Can't move, switching to copy")
|
||||||
default:
|
default:
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(src, "Couldn't move: %v", err)
|
fs.Errorf(src, "Couldn't move: %v", err)
|
||||||
return newDst, err
|
return newDst, err
|
||||||
}
|
}
|
||||||
|
@ -558,8 +558,8 @@ func DeleteFileWithBackupDir(ctx context.Context, dst fs.Object, backupDir fs.Fs
|
||||||
err = dst.Remove(ctx)
|
err = dst.Remove(ctx)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
|
||||||
fs.Errorf(dst, "Couldn't %s: %v", action, err)
|
fs.Errorf(dst, "Couldn't %s: %v", action, err)
|
||||||
|
err = fs.CountError(err)
|
||||||
} else if !fs.Config.DryRun {
|
} else if !fs.Config.DryRun {
|
||||||
fs.Infof(dst, actioned)
|
fs.Infof(dst, actioned)
|
||||||
}
|
}
|
||||||
|
@ -685,7 +685,7 @@ func checkIdentical(ctx context.Context, dst, src fs.Object) (differ bool, noHas
|
||||||
if !same {
|
if !same {
|
||||||
err = errors.Errorf("%v differ", ht)
|
err = errors.Errorf("%v differ", ht)
|
||||||
fs.Errorf(src, "%v", err)
|
fs.Errorf(src, "%v", err)
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
return false, false
|
return false, false
|
||||||
|
@ -716,7 +716,7 @@ func (c *checkMarch) DstOnly(dst fs.DirEntry) (recurse bool) {
|
||||||
}
|
}
|
||||||
err := errors.Errorf("File not in %v", c.fsrc)
|
err := errors.Errorf("File not in %v", c.fsrc)
|
||||||
fs.Errorf(dst, "%v", err)
|
fs.Errorf(dst, "%v", err)
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
atomic.AddInt32(&c.differences, 1)
|
atomic.AddInt32(&c.differences, 1)
|
||||||
atomic.AddInt32(&c.srcFilesMissing, 1)
|
atomic.AddInt32(&c.srcFilesMissing, 1)
|
||||||
case fs.Directory:
|
case fs.Directory:
|
||||||
|
@ -734,7 +734,7 @@ func (c *checkMarch) SrcOnly(src fs.DirEntry) (recurse bool) {
|
||||||
case fs.Object:
|
case fs.Object:
|
||||||
err := errors.Errorf("File not in %v", c.fdst)
|
err := errors.Errorf("File not in %v", c.fdst)
|
||||||
fs.Errorf(src, "%v", err)
|
fs.Errorf(src, "%v", err)
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
atomic.AddInt32(&c.differences, 1)
|
atomic.AddInt32(&c.differences, 1)
|
||||||
atomic.AddInt32(&c.dstFilesMissing, 1)
|
atomic.AddInt32(&c.dstFilesMissing, 1)
|
||||||
case fs.Directory:
|
case fs.Directory:
|
||||||
|
@ -756,7 +756,6 @@ func (c *checkMarch) checkIdentical(ctx context.Context, dst, src fs.Object) (di
|
||||||
if sizeDiffers(src, dst) {
|
if sizeDiffers(src, dst) {
|
||||||
err = errors.Errorf("Sizes differ")
|
err = errors.Errorf("Sizes differ")
|
||||||
fs.Errorf(src, "%v", err)
|
fs.Errorf(src, "%v", err)
|
||||||
fs.CountError(err)
|
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
if fs.Config.SizeOnly {
|
if fs.Config.SizeOnly {
|
||||||
|
@ -784,7 +783,7 @@ func (c *checkMarch) Match(ctx context.Context, dst, src fs.DirEntry) (recurse b
|
||||||
} else {
|
} else {
|
||||||
err := errors.Errorf("is file on %v but directory on %v", c.fsrc, c.fdst)
|
err := errors.Errorf("is file on %v but directory on %v", c.fsrc, c.fdst)
|
||||||
fs.Errorf(src, "%v", err)
|
fs.Errorf(src, "%v", err)
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
atomic.AddInt32(&c.differences, 1)
|
atomic.AddInt32(&c.differences, 1)
|
||||||
atomic.AddInt32(&c.dstFilesMissing, 1)
|
atomic.AddInt32(&c.dstFilesMissing, 1)
|
||||||
}
|
}
|
||||||
|
@ -796,7 +795,7 @@ func (c *checkMarch) Match(ctx context.Context, dst, src fs.DirEntry) (recurse b
|
||||||
}
|
}
|
||||||
err := errors.Errorf("is file on %v but directory on %v", c.fdst, c.fsrc)
|
err := errors.Errorf("is file on %v but directory on %v", c.fdst, c.fsrc)
|
||||||
fs.Errorf(dst, "%v", err)
|
fs.Errorf(dst, "%v", err)
|
||||||
fs.CountError(err)
|
_ = fs.CountError(err)
|
||||||
atomic.AddInt32(&c.differences, 1)
|
atomic.AddInt32(&c.differences, 1)
|
||||||
atomic.AddInt32(&c.srcFilesMissing, 1)
|
atomic.AddInt32(&c.srcFilesMissing, 1)
|
||||||
|
|
||||||
|
@ -923,7 +922,7 @@ func CheckDownload(ctx context.Context, fdst, fsrc fs.Fs, oneway bool) error {
|
||||||
check := func(ctx context.Context, a, b fs.Object) (differ bool, noHash bool) {
|
check := func(ctx context.Context, a, b fs.Object) (differ bool, noHash bool) {
|
||||||
differ, err := CheckIdentical(ctx, a, b)
|
differ, err := CheckIdentical(ctx, a, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(a, "Failed to download: %v", err)
|
fs.Errorf(a, "Failed to download: %v", err)
|
||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
|
@ -1070,7 +1069,7 @@ func Mkdir(ctx context.Context, f fs.Fs, dir string) error {
|
||||||
fs.Debugf(fs.LogDirName(f, dir), "Making directory")
|
fs.Debugf(fs.LogDirName(f, dir), "Making directory")
|
||||||
err := f.Mkdir(ctx, dir)
|
err := f.Mkdir(ctx, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1091,7 +1090,7 @@ func TryRmdir(ctx context.Context, f fs.Fs, dir string) error {
|
||||||
func Rmdir(ctx context.Context, f fs.Fs, dir string) error {
|
func Rmdir(ctx context.Context, f fs.Fs, dir string) error {
|
||||||
err := TryRmdir(ctx, f, dir)
|
err := TryRmdir(ctx, f, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
@ -1124,7 +1123,7 @@ func Purge(ctx context.Context, f fs.Fs, dir string) error {
|
||||||
err = Rmdirs(ctx, f, dir, false)
|
err = Rmdirs(ctx, f, dir, false)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -1167,7 +1166,7 @@ func listToChan(ctx context.Context, f fs.Fs, dir string) fs.ObjectsChan {
|
||||||
})
|
})
|
||||||
if err != nil && err != fs.ErrorDirNotFound {
|
if err != nil && err != fs.ErrorDirNotFound {
|
||||||
err = errors.Wrap(err, "failed to list")
|
err = errors.Wrap(err, "failed to list")
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(nil, "%v", err)
|
fs.Errorf(nil, "%v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -1223,7 +1222,7 @@ func Cat(ctx context.Context, f fs.Fs, w io.Writer, offset, count int64) error {
|
||||||
}
|
}
|
||||||
in, err := o.Open(ctx, options...)
|
in, err := o.Open(ctx, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(o, "Failed to open: %v", err)
|
fs.Errorf(o, "Failed to open: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1236,7 +1235,7 @@ func Cat(ctx context.Context, f fs.Fs, w io.Writer, offset, count int64) error {
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
_, err = io.Copy(w, in)
|
_, err = io.Copy(w, in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(o, "Failed to send to output: %v", err)
|
fs.Errorf(o, "Failed to send to output: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1263,7 +1262,7 @@ func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser,
|
||||||
src := object.NewStaticObjectInfo(dstFileName, modTime, int64(readCounter.BytesRead()), false, hash.Sums(), fdst)
|
src := object.NewStaticObjectInfo(dstFileName, modTime, int64(readCounter.BytesRead()), false, hash.Sums(), fdst)
|
||||||
if !Equal(ctx, src, dst) {
|
if !Equal(ctx, src, dst) {
|
||||||
err = errors.Errorf("corrupted on transfer")
|
err = errors.Errorf("corrupted on transfer")
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dst, "%v", err)
|
fs.Errorf(dst, "%v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1338,7 +1337,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||||
dirEmpty[dir] = !leaveRoot
|
dirEmpty[dir] = !leaveRoot
|
||||||
err := walk.Walk(ctx, f, dir, true, fs.Config.MaxDepth, func(dirPath string, entries fs.DirEntries, err error) error {
|
err := walk.Walk(ctx, f, dir, true, fs.Config.MaxDepth, func(dirPath string, entries fs.DirEntries, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(f, "Failed to list %q: %v", dirPath, err)
|
fs.Errorf(f, "Failed to list %q: %v", dirPath, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1385,7 +1384,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||||
dir := toDelete[i]
|
dir := toDelete[i]
|
||||||
err := TryRmdir(ctx, f, dir)
|
err := TryRmdir(ctx, f, dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dir, "Failed to rmdir: %v", err)
|
fs.Errorf(dir, "Failed to rmdir: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -926,7 +926,7 @@ func MoveDir(ctx context.Context, fdst, fsrc fs.Fs, deleteEmptySrcDirs bool, cop
|
||||||
fs.Infof(fdst, "Server side directory move succeeded")
|
fs.Infof(fdst, "Server side directory move succeeded")
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(fdst, "Server side directory move failed: %v", err)
|
fs.Errorf(fdst, "Server side directory move failed: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -490,7 +490,7 @@ func TestSyncIgnoreErrors(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
accounting.GlobalStats().ResetCounters()
|
accounting.GlobalStats().ResetCounters()
|
||||||
fs.CountError(errors.New("boom"))
|
_ = fs.CountError(errors.New("boom"))
|
||||||
assert.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
|
assert.NoError(t, Sync(context.Background(), r.Fremote, r.Flocal, false))
|
||||||
|
|
||||||
fstest.CheckListingWithPrecision(
|
fstest.CheckListingWithPrecision(
|
||||||
|
@ -800,7 +800,7 @@ func TestSyncAfterRemovingAFileAndAddingAFileSubDirWithErrors(t *testing.T) {
|
||||||
)
|
)
|
||||||
|
|
||||||
accounting.GlobalStats().ResetCounters()
|
accounting.GlobalStats().ResetCounters()
|
||||||
fs.CountError(errors.New("boom"))
|
_ = fs.CountError(errors.New("boom"))
|
||||||
err := Sync(context.Background(), r.Fremote, r.Flocal, false)
|
err := Sync(context.Background(), r.Fremote, r.Flocal, false)
|
||||||
assert.Equal(t, fs.ErrorNotDeleting, err)
|
assert.Equal(t, fs.ErrorNotDeleting, err)
|
||||||
|
|
||||||
|
@ -1763,5 +1763,7 @@ func TestAbort(t *testing.T) {
|
||||||
accounting.GlobalStats().ResetCounters()
|
accounting.GlobalStats().ResetCounters()
|
||||||
|
|
||||||
err := Sync(context.Background(), r.Fremote, r.Flocal, false)
|
err := Sync(context.Background(), r.Fremote, r.Flocal, false)
|
||||||
assert.Equal(t, accounting.ErrorMaxTransferLimitReached, err)
|
expectedErr := fserrors.FsError(accounting.ErrorMaxTransferLimitReached)
|
||||||
|
fserrors.Count(expectedErr)
|
||||||
|
assert.Equal(t, expectedErr, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ func listRwalk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLe
|
||||||
// Carry on listing but return the error at the end
|
// Carry on listing but return the error at the end
|
||||||
if err != nil {
|
if err != nil {
|
||||||
listErr = err
|
listErr = err
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(path, "error listing: %v", err)
|
fs.Errorf(path, "error listing: %v", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -404,7 +404,7 @@ func walk(ctx context.Context, f fs.Fs, path string, includeAll bool, maxLevel i
|
||||||
// NB once we have passed entries to fn we mustn't touch it again
|
// NB once we have passed entries to fn we mustn't touch it again
|
||||||
if err != nil && err != ErrorSkipDir {
|
if err != nil && err != ErrorSkipDir {
|
||||||
traversing.Done()
|
traversing.Done()
|
||||||
fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(job.remote, "error listing: %v", err)
|
fs.Errorf(job.remote, "error listing: %v", err)
|
||||||
closeQuit()
|
closeQuit()
|
||||||
// Send error to error channel if space
|
// Send error to error channel if space
|
||||||
|
|
|
@ -10,7 +10,9 @@ import (
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
|
_ "github.com/rclone/rclone/fs/accounting"
|
||||||
"github.com/rclone/rclone/fs/filter"
|
"github.com/rclone/rclone/fs/filter"
|
||||||
|
"github.com/rclone/rclone/fs/fserrors"
|
||||||
"github.com/rclone/rclone/fstest/mockdir"
|
"github.com/rclone/rclone/fstest/mockdir"
|
||||||
"github.com/rclone/rclone/fstest/mockfs"
|
"github.com/rclone/rclone/fstest/mockfs"
|
||||||
"github.com/rclone/rclone/fstest/mockobject"
|
"github.com/rclone/rclone/fstest/mockobject"
|
||||||
|
@ -18,6 +20,15 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errDirNotFound, errorBoom error
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
errDirNotFound = fserrors.FsError(fs.ErrorDirNotFound)
|
||||||
|
fserrors.Count(errDirNotFound)
|
||||||
|
errorBoom = fserrors.FsError(errors.New("boom"))
|
||||||
|
fserrors.Count(errorBoom)
|
||||||
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
listResult struct {
|
listResult struct {
|
||||||
entries fs.DirEntries
|
entries fs.DirEntries
|
||||||
|
@ -196,12 +207,12 @@ func TestWalkREmptySkip(t *testing.T) { testWalkEmptySkip(t).WalkR() }
|
||||||
func testWalkNotFound(t *testing.T) *listDirs {
|
func testWalkNotFound(t *testing.T) *listDirs {
|
||||||
return newListDirs(t, nil, true,
|
return newListDirs(t, nil, true,
|
||||||
listResults{
|
listResults{
|
||||||
"": {err: fs.ErrorDirNotFound},
|
"": {err: errDirNotFound},
|
||||||
},
|
},
|
||||||
errorMap{
|
errorMap{
|
||||||
"": fs.ErrorDirNotFound,
|
"": errDirNotFound,
|
||||||
},
|
},
|
||||||
fs.ErrorDirNotFound,
|
errDirNotFound,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
func TestWalkNotFound(t *testing.T) { testWalkNotFound(t).Walk() }
|
func TestWalkNotFound(t *testing.T) { testWalkNotFound(t).Walk() }
|
||||||
|
@ -211,7 +222,7 @@ func TestWalkNotFoundMaskError(t *testing.T) {
|
||||||
// this doesn't work for WalkR
|
// this doesn't work for WalkR
|
||||||
newListDirs(t, nil, true,
|
newListDirs(t, nil, true,
|
||||||
listResults{
|
listResults{
|
||||||
"": {err: fs.ErrorDirNotFound},
|
"": {err: errDirNotFound},
|
||||||
},
|
},
|
||||||
errorMap{
|
errorMap{
|
||||||
"": nil,
|
"": nil,
|
||||||
|
@ -224,7 +235,7 @@ func TestWalkNotFoundSkipError(t *testing.T) {
|
||||||
// this doesn't work for WalkR
|
// this doesn't work for WalkR
|
||||||
newListDirs(t, nil, true,
|
newListDirs(t, nil, true,
|
||||||
listResults{
|
listResults{
|
||||||
"": {err: fs.ErrorDirNotFound},
|
"": {err: errDirNotFound},
|
||||||
},
|
},
|
||||||
errorMap{
|
errorMap{
|
||||||
"": ErrorSkipDir,
|
"": ErrorSkipDir,
|
||||||
|
@ -342,7 +353,7 @@ func testWalkSkip(t *testing.T) *listDirs {
|
||||||
func TestWalkSkip(t *testing.T) { testWalkSkip(t).Walk() }
|
func TestWalkSkip(t *testing.T) { testWalkSkip(t).Walk() }
|
||||||
func TestWalkRSkip(t *testing.T) { testWalkSkip(t).WalkR() }
|
func TestWalkRSkip(t *testing.T) { testWalkSkip(t).WalkR() }
|
||||||
|
|
||||||
func testWalkErrors(t *testing.T) *listDirs {
|
func walkErrors(t *testing.T, expectedErr error) *listDirs {
|
||||||
lr := listResults{}
|
lr := listResults{}
|
||||||
em := errorMap{}
|
em := errorMap{}
|
||||||
de := make(fs.DirEntries, 10)
|
de := make(fs.DirEntries, 10)
|
||||||
|
@ -357,13 +368,20 @@ func testWalkErrors(t *testing.T) *listDirs {
|
||||||
return newListDirs(t, nil, true,
|
return newListDirs(t, nil, true,
|
||||||
lr,
|
lr,
|
||||||
em,
|
em,
|
||||||
fs.ErrorDirNotFound,
|
expectedErr,
|
||||||
).NoCheckMaps()
|
).NoCheckMaps()
|
||||||
}
|
}
|
||||||
func TestWalkErrors(t *testing.T) { testWalkErrors(t).Walk() }
|
|
||||||
func TestWalkRErrors(t *testing.T) { testWalkErrors(t).WalkR() }
|
|
||||||
|
|
||||||
var errorBoom = errors.New("boom")
|
func testWalkErrors(t *testing.T) *listDirs {
|
||||||
|
return walkErrors(t, errDirNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testWalkRErrors(t *testing.T) *listDirs {
|
||||||
|
return walkErrors(t, fs.ErrorDirNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWalkErrors(t *testing.T) { testWalkErrors(t).Walk() }
|
||||||
|
func TestWalkRErrors(t *testing.T) { testWalkRErrors(t).WalkR() }
|
||||||
|
|
||||||
func makeTree(level int, terminalErrors bool) (listResults, errorMap) {
|
func makeTree(level int, terminalErrors bool) (listResults, errorMap) {
|
||||||
lr := listResults{}
|
lr := listResults{}
|
||||||
|
|
Loading…
Reference in a new issue