mirror of
https://github.com/rclone/rclone
synced 2024-11-28 06:41:41 +01:00
errcount: factor errcount abstraction from operations
This commit is contained in:
parent
8f0e9f9f6b
commit
71a1bbb2be
@ -35,6 +35,7 @@ import (
|
||||
"github.com/rclone/rclone/fs/object"
|
||||
"github.com/rclone/rclone/fs/walk"
|
||||
"github.com/rclone/rclone/lib/atexit"
|
||||
"github.com/rclone/rclone/lib/errcount"
|
||||
"github.com/rclone/rclone/lib/random"
|
||||
"github.com/rclone/rclone/lib/readers"
|
||||
"golang.org/x/sync/errgroup"
|
||||
@ -1353,9 +1354,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||
}
|
||||
|
||||
var (
|
||||
errMu sync.Mutex
|
||||
errCount int
|
||||
lastError error
|
||||
errCount = errcount.New()
|
||||
)
|
||||
// Delete all directories at the same level in parallel
|
||||
for level := len(toDelete) - 1; level >= 0; level-- {
|
||||
@ -1378,10 +1377,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||
if err != nil {
|
||||
err = fs.CountError(err)
|
||||
fs.Errorf(dir, "Failed to rmdir: %v", err)
|
||||
errMu.Lock()
|
||||
lastError = err
|
||||
errCount += 1
|
||||
errMu.Unlock()
|
||||
errCount.Add(err)
|
||||
}
|
||||
return nil // don't return errors, just count them
|
||||
})
|
||||
@ -1391,10 +1387,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if lastError != nil {
|
||||
return fmt.Errorf("failed to remove %d directories: last error: %w", errCount, lastError)
|
||||
}
|
||||
return nil
|
||||
return errCount.Err("failed to remove directories")
|
||||
}
|
||||
|
||||
// GetCompareDest sets up --compare-dest
|
||||
|
58
lib/errcount/errcount.go
Normal file
58
lib/errcount/errcount.go
Normal file
@ -0,0 +1,58 @@
|
||||
// Package errcount provides an easy to use error counter which
|
||||
// returns error count and last error so as to not overwhelm the user
|
||||
// with errors.
|
||||
package errcount
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ErrCount stores the state of the error counter.
|
||||
type ErrCount struct {
|
||||
mu sync.Mutex
|
||||
lastErr error
|
||||
count int
|
||||
}
|
||||
|
||||
// New makes a new error counter
|
||||
func New() *ErrCount {
|
||||
return new(ErrCount)
|
||||
}
|
||||
|
||||
// Add an error to the error count.
|
||||
//
|
||||
// err may be nil.
|
||||
//
|
||||
// Thread safe.
|
||||
func (ec *ErrCount) Add(err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
ec.mu.Lock()
|
||||
ec.count++
|
||||
ec.lastErr = err
|
||||
ec.mu.Unlock()
|
||||
}
|
||||
|
||||
// Err returns the error summary so far - may be nil
|
||||
//
|
||||
// txt is put in front of the error summary
|
||||
//
|
||||
// txt: %d errors: last error: %w
|
||||
//
|
||||
// or this if only one error
|
||||
//
|
||||
// txt: %w
|
||||
//
|
||||
// Thread safe.
|
||||
func (ec *ErrCount) Err(txt string) error {
|
||||
ec.mu.Lock()
|
||||
defer ec.mu.Unlock()
|
||||
if ec.count == 0 {
|
||||
return nil
|
||||
} else if ec.count == 1 {
|
||||
return fmt.Errorf("%s: %w", txt, ec.lastErr)
|
||||
}
|
||||
return fmt.Errorf("%s: %d errors: last error: %w", txt, ec.count, ec.lastErr)
|
||||
}
|
27
lib/errcount/errcount_test.go
Normal file
27
lib/errcount/errcount_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package errcount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestErrCount(t *testing.T) {
|
||||
ec := New()
|
||||
assert.Equal(t, nil, ec.Err("none"))
|
||||
|
||||
e1 := errors.New("one")
|
||||
ec.Add(e1)
|
||||
|
||||
err := ec.Err("stuff")
|
||||
assert.True(t, errors.Is(err, e1), err)
|
||||
assert.Equal(t, "stuff: one", err.Error())
|
||||
|
||||
e2 := errors.New("two")
|
||||
ec.Add(e2)
|
||||
|
||||
err = ec.Err("stuff")
|
||||
assert.True(t, errors.Is(err, e2), err)
|
||||
assert.Equal(t, "stuff: 2 errors: last error: two", err.Error())
|
||||
}
|
Loading…
Reference in New Issue
Block a user