forked from TrueCloudLab/restic
errors: Drop Cause in favor of Go 1.13 error handling
The only use cases in the code were in errors.IsFatal, backend/b2, which needs a workaround, and backend.ParseLayout. The last of these requires all backends to implement error unwrapping in IsNotExist. All backends except gs already did that.
This commit is contained in:
parent
83cb58b4f3
commit
07e5c38361
7 changed files with 34 additions and 58 deletions
|
@ -1197,7 +1197,7 @@ func TestRestoreFilter(t *testing.T) {
|
||||||
if ok, _ := filter.Match(pat, filepath.Base(testFile.name)); !ok {
|
if ok, _ := filter.Match(pat, filepath.Base(testFile.name)); !ok {
|
||||||
rtest.OK(t, err)
|
rtest.OK(t, err)
|
||||||
} else {
|
} else {
|
||||||
rtest.Assert(t, os.IsNotExist(errors.Cause(err)),
|
rtest.Assert(t, os.IsNotExist(err),
|
||||||
"expected %v to not exist in restore step %v, but it exists, err %v", testFile.name, i+1, err)
|
"expected %v to not exist in restore step %v, but it exists, err %v", testFile.name, i+1, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1283,15 +1283,15 @@ func TestRestoreLatest(t *testing.T) {
|
||||||
|
|
||||||
testRunRestoreLatest(t, env.gopts, filepath.Join(env.base, "restore1"), []string{filepath.Dir(p1)}, nil)
|
testRunRestoreLatest(t, env.gopts, filepath.Join(env.base, "restore1"), []string{filepath.Dir(p1)}, nil)
|
||||||
rtest.OK(t, testFileSize(p1rAbs, int64(102)))
|
rtest.OK(t, testFileSize(p1rAbs, int64(102)))
|
||||||
if _, err := os.Stat(p2rAbs); os.IsNotExist(errors.Cause(err)) {
|
if _, err := os.Stat(p2rAbs); os.IsNotExist(err) {
|
||||||
rtest.Assert(t, os.IsNotExist(errors.Cause(err)),
|
rtest.Assert(t, os.IsNotExist(err),
|
||||||
"expected %v to not exist in restore, but it exists, err %v", p2rAbs, err)
|
"expected %v to not exist in restore, but it exists, err %v", p2rAbs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
testRunRestoreLatest(t, env.gopts, filepath.Join(env.base, "restore2"), []string{filepath.Dir(p2)}, nil)
|
testRunRestoreLatest(t, env.gopts, filepath.Join(env.base, "restore2"), []string{filepath.Dir(p2)}, nil)
|
||||||
rtest.OK(t, testFileSize(p2rAbs, int64(103)))
|
rtest.OK(t, testFileSize(p2rAbs, int64(103)))
|
||||||
if _, err := os.Stat(p1rAbs); os.IsNotExist(errors.Cause(err)) {
|
if _, err := os.Stat(p1rAbs); os.IsNotExist(err) {
|
||||||
rtest.Assert(t, os.IsNotExist(errors.Cause(err)),
|
rtest.Assert(t, os.IsNotExist(err),
|
||||||
"expected %v to not exist in restore, but it exists, err %v", p1rAbs, err)
|
"expected %v to not exist in restore, but it exists, err %v", p1rAbs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1861,7 +1861,7 @@ func TestHardLink(t *testing.T) {
|
||||||
|
|
||||||
datafile := filepath.Join("testdata", "test.hl.tar.gz")
|
datafile := filepath.Join("testdata", "test.hl.tar.gz")
|
||||||
fd, err := os.Open(datafile)
|
fd, err := os.Open(datafile)
|
||||||
if os.IsNotExist(errors.Cause(err)) {
|
if os.IsNotExist(err) {
|
||||||
t.Skipf("unable to find data file %q, skipping", datafile)
|
t.Skipf("unable to find data file %q, skipping", datafile)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,14 @@ func (be *b2Backend) HasAtomicReplace() bool {
|
||||||
|
|
||||||
// IsNotExist returns true if the error is caused by a non-existing file.
|
// IsNotExist returns true if the error is caused by a non-existing file.
|
||||||
func (be *b2Backend) IsNotExist(err error) bool {
|
func (be *b2Backend) IsNotExist(err error) bool {
|
||||||
return b2.IsNotExist(errors.Cause(err))
|
// blazer/b2 does not export its error types and values,
|
||||||
|
// so we can't use errors.{As,Is}.
|
||||||
|
for ; err != nil; err = errors.Unwrap(err) {
|
||||||
|
if b2.IsNotExist(err) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load runs fn with a reader that yields the contents of the file at h at the
|
// Load runs fn with a reader that yields the contents of the file at h at the
|
||||||
|
@ -386,7 +393,7 @@ func (be *b2Backend) Delete(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := be.Remove(ctx, restic.Handle{Type: restic.ConfigFile})
|
err := be.Remove(ctx, restic.Handle{Type: restic.ConfigFile})
|
||||||
if err != nil && b2.IsNotExist(errors.Cause(err)) {
|
if err != nil && be.IsNotExist(err) {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,13 +174,8 @@ func (be *Backend) IsNotExist(err error) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if er, ok := err.(*googleapi.Error); ok {
|
var gerr *googleapi.Error
|
||||||
if er.Code == 404 {
|
return errors.As(err, &gerr) && gerr.Code == 404
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join combines path components with slashes.
|
// Join combines path components with slashes.
|
||||||
|
|
|
@ -71,7 +71,7 @@ var backendFilename = regexp.MustCompile(fmt.Sprintf("^[a-fA-F0-9]{%d}$", backen
|
||||||
|
|
||||||
func hasBackendFile(ctx context.Context, fs Filesystem, dir string) (bool, error) {
|
func hasBackendFile(ctx context.Context, fs Filesystem, dir string) (bool, error) {
|
||||||
entries, err := fs.ReadDir(ctx, dir)
|
entries, err := fs.ReadDir(ctx, dir)
|
||||||
if err != nil && fs.IsNotExist(errors.Cause(err)) {
|
if err != nil && fs.IsNotExist(err) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package errors
|
package errors
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
stderrors "errors"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,29 +28,10 @@ var WithMessage = errors.WithMessage
|
||||||
|
|
||||||
var WithStack = errors.WithStack
|
var WithStack = errors.WithStack
|
||||||
|
|
||||||
// Cause returns the cause of an error. It will also unwrap certain errors,
|
|
||||||
// e.g. *url.Error returned by the net/http client.
|
|
||||||
func Cause(err error) error {
|
|
||||||
type Causer interface {
|
|
||||||
Cause() error
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
switch e := err.(type) {
|
|
||||||
case Causer: // github.com/pkg/errors
|
|
||||||
err = e.Cause()
|
|
||||||
case *backoff.PermanentError:
|
|
||||||
err = e.Err
|
|
||||||
case *url.Error:
|
|
||||||
err = e.Err
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go 1.13-style error handling.
|
// Go 1.13-style error handling.
|
||||||
|
|
||||||
func As(err error, tgt interface{}) bool { return errors.As(err, tgt) }
|
func As(err error, tgt interface{}) bool { return stderrors.As(err, tgt) }
|
||||||
|
|
||||||
func Is(x, y error) bool { return errors.Is(x, y) }
|
func Is(x, y error) bool { return stderrors.Is(x, y) }
|
||||||
|
|
||||||
|
func Unwrap(err error) error { return stderrors.Unwrap(err) }
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package errors
|
package errors
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// fatalError is an error that should be printed to the user, then the program
|
// fatalError is an error that should be printed to the user, then the program
|
||||||
// should exit with an error code.
|
// should exit with an error code.
|
||||||
|
@ -10,31 +13,19 @@ func (e fatalError) Error() string {
|
||||||
return string(e)
|
return string(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e fatalError) Fatal() bool {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fataler is an error which should be printed to the user directly.
|
|
||||||
// Afterwards, the program should exit with an error.
|
|
||||||
type Fataler interface {
|
|
||||||
Fatal() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsFatal returns true if err is a fatal message that should be printed to the
|
// IsFatal returns true if err is a fatal message that should be printed to the
|
||||||
// user. Then, the program should exit.
|
// user. Then, the program should exit.
|
||||||
func IsFatal(err error) bool {
|
func IsFatal(err error) bool {
|
||||||
// unwrap "Wrap" method
|
var fatal fatalError
|
||||||
err = Cause(err)
|
return errors.As(err, &fatal)
|
||||||
e, ok := err.(Fataler)
|
|
||||||
return ok && e.Fatal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatal returns a wrapped error which implements the Fataler interface.
|
// Fatal returns an error that is marked fatal.
|
||||||
func Fatal(s string) error {
|
func Fatal(s string) error {
|
||||||
return Wrap(fatalError(s), "Fatal")
|
return Wrap(fatalError(s), "Fatal")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf returns an error which implements the Fataler interface.
|
// Fatalf returns an error that is marked fatal.
|
||||||
func Fatalf(s string, data ...interface{}) error {
|
func Fatalf(s string, data ...interface{}) error {
|
||||||
return Wrap(fatalError(fmt.Sprintf(s, data...)), "Fatal")
|
return Wrap(fatalError(fmt.Sprintf(s, data...)), "Fatal")
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,9 @@ type Backend interface {
|
||||||
|
|
||||||
// IsNotExist returns true if the error was caused by a non-existing file
|
// IsNotExist returns true if the error was caused by a non-existing file
|
||||||
// in the backend.
|
// in the backend.
|
||||||
|
//
|
||||||
|
// The argument may be a wrapped error. The implementation is responsible
|
||||||
|
// for unwrapping it.
|
||||||
IsNotExist(err error) bool
|
IsNotExist(err error) bool
|
||||||
|
|
||||||
// Delete removes all data in the backend.
|
// Delete removes all data in the backend.
|
||||||
|
|
Loading…
Reference in a new issue