errcount: factor errcount abstraction from operations
This commit is contained in:
parent
8f0e9f9f6b
commit
71a1bbb2be
3 changed files with 89 additions and 11 deletions
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/object"
|
"github.com/rclone/rclone/fs/object"
|
||||||
"github.com/rclone/rclone/fs/walk"
|
"github.com/rclone/rclone/fs/walk"
|
||||||
"github.com/rclone/rclone/lib/atexit"
|
"github.com/rclone/rclone/lib/atexit"
|
||||||
|
"github.com/rclone/rclone/lib/errcount"
|
||||||
"github.com/rclone/rclone/lib/random"
|
"github.com/rclone/rclone/lib/random"
|
||||||
"github.com/rclone/rclone/lib/readers"
|
"github.com/rclone/rclone/lib/readers"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
@ -1353,9 +1354,7 @@ func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errMu sync.Mutex
|
errCount = errcount.New()
|
||||||
errCount int
|
|
||||||
lastError error
|
|
||||||
)
|
)
|
||||||
// Delete all directories at the same level in parallel
|
// Delete all directories at the same level in parallel
|
||||||
for level := len(toDelete) - 1; level >= 0; level-- {
|
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 {
|
if err != nil {
|
||||||
err = fs.CountError(err)
|
err = fs.CountError(err)
|
||||||
fs.Errorf(dir, "Failed to rmdir: %v", err)
|
fs.Errorf(dir, "Failed to rmdir: %v", err)
|
||||||
errMu.Lock()
|
errCount.Add(err)
|
||||||
lastError = err
|
|
||||||
errCount += 1
|
|
||||||
errMu.Unlock()
|
|
||||||
}
|
}
|
||||||
return nil // don't return errors, just count them
|
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
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lastError != nil {
|
return errCount.Err("failed to remove directories")
|
||||||
return fmt.Errorf("failed to remove %d directories: last error: %w", errCount, lastError)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCompareDest sets up --compare-dest
|
// 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 a new issue