From ca0248e19befb8f46baae51a5a9951dd47740db5 Mon Sep 17 00:00:00 2001 From: aperezg Date: Fri, 1 Nov 2019 17:49:06 +0100 Subject: [PATCH 1/8] fix travis, 1.10 doesnt support by unconvert anymore --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d2dfad40..eb23af5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,13 @@ language: go go_import_path: github.com/pkg/errors go: - - 1.10.x - 1.11.x - 1.12.x + - 1.13.x - tip +env: + - GO111MODULE=off + script: - make check From 91f169312d9bf0c7709dc198651b9505ba85a239 Mon Sep 17 00:00:00 2001 From: aperezg Date: Sat, 9 Nov 2019 09:18:04 +0100 Subject: [PATCH 2/8] travis.yml: add Go 1.13 --- .travis.yml | 3 --- README.md | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index eb23af5a..9159de03 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,5 @@ go: - 1.13.x - tip -env: - - GO111MODULE=off - script: - make check diff --git a/README.md b/README.md index cf771e7d..54dfdcb1 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ default: With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows: -- 0.9. Remove pre Go 1.9 support, address outstanding pull requests (if possible) +- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible) - 1.0. Final release. ## Contributing From 7f95ac13edff643b8ce5398b6ccab125f8a20c1a Mon Sep 17 00:00:00 2001 From: Jay Petacat Date: Sat, 9 Nov 2019 05:23:16 -0500 Subject: [PATCH 3/8] Add support for Go 1.13 error chains (#206) * Add support for Go 1.13 error chains Go 1.13 adds support for error chains to the standard libary's errors package. The new standard library functions require an Unwrap method to be provided by an error type. This change adds a new Unwrap method (identical to the existing Cause method) to the unexported error types. --- errors.go | 6 ++++++ go113_test.go | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 go113_test.go diff --git a/errors.go b/errors.go index 8617beef..161aea25 100644 --- a/errors.go +++ b/errors.go @@ -159,6 +159,9 @@ type withStack struct { func (w *withStack) Cause() error { return w.error } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withStack) Unwrap() error { return w.error } + func (w *withStack) Format(s fmt.State, verb rune) { switch verb { case 'v': @@ -241,6 +244,9 @@ type withMessage struct { func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } func (w *withMessage) Cause() error { return w.cause } +// Unwrap provides compatibility for Go 1.13 error chains. +func (w *withMessage) Unwrap() error { return w.cause } + func (w *withMessage) Format(s fmt.State, verb rune) { switch verb { case 'v': diff --git a/go113_test.go b/go113_test.go new file mode 100644 index 00000000..39263b03 --- /dev/null +++ b/go113_test.go @@ -0,0 +1,16 @@ +// +build go1.13 + +package errors + +import ( + stdlib_errors "errors" + "testing" +) + +func TestErrorChainCompat(t *testing.T) { + err := stdlib_errors.New("error that gets wrapped") + wrapped := Wrap(err, "wrapped up") + if !stdlib_errors.Is(wrapped, err) { + t.Errorf("Wrap does not support Go 1.13 error chains") + } +} From 6d954f502eb89cd315e4baae5b0e0db516d6f787 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Fri, 3 Jan 2020 19:25:31 +0800 Subject: [PATCH 4/8] feat: support std errors functions (#213) * feat: support std errors functions add function `Is`, `As` and `Unwrap`, like std errors, so that we can continue to use pkg/errors with go1.13 compatibility Signed-off-by: Sherlock Holo * style: delete useless comments Signed-off-by: Sherlock Holo * build: update makefile update makefile to download dependencies before test anything Signed-off-by: Sherlock Holo * build: fix makefile Signed-off-by: Sherlock Holo * chore: delete useless comments Signed-off-by: Sherlock Holo * Restore Makefile * revert: revert some change some change are doing by PR #206 and #212 , so I don't need to do it Signed-off-by: Sherlock Holo * test: add more check for As unit test Signed-off-by: Sherlock Holo * revert: only support Is As Unwrap for >=go1.13 Signed-off-by: Sherlock Holo * feat(Unwrap): allow * test: add go1.13 errors compatibility check Signed-off-by: Sherlock Holo * refactor(Unwrap): don't allow --- go113.go | 38 ++++++++++++ go113_test.go | 168 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 go113.go diff --git a/go113.go b/go113.go new file mode 100644 index 00000000..be0d10d0 --- /dev/null +++ b/go113.go @@ -0,0 +1,38 @@ +// +build go1.13 + +package errors + +import ( + stderrors "errors" +) + +// Is reports whether any error in err's chain matches target. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error is considered to match a target if it is equal to that target or if +// it implements a method Is(error) bool such that Is(target) returns true. +func Is(err, target error) bool { return stderrors.Is(err, target) } + +// As finds the first error in err's chain that matches target, and if so, sets +// target to that error value and returns true. +// +// The chain consists of err itself followed by the sequence of errors obtained by +// repeatedly calling Unwrap. +// +// An error matches target if the error's concrete value is assignable to the value +// pointed to by target, or if the error has a method As(interface{}) bool such that +// As(target) returns true. In the latter case, the As method is responsible for +// setting target. +// +// As will panic if target is not a non-nil pointer to either a type that implements +// error, or to any interface type. As returns false if err is nil. +func As(err error, target interface{}) bool { return stderrors.As(err, target) } + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +func Unwrap(err error) error { + return stderrors.Unwrap(err) +} diff --git a/go113_test.go b/go113_test.go index 39263b03..4ea37e61 100644 --- a/go113_test.go +++ b/go113_test.go @@ -3,14 +3,176 @@ package errors import ( - stdlib_errors "errors" + stderrors "errors" + "fmt" + "reflect" "testing" ) func TestErrorChainCompat(t *testing.T) { - err := stdlib_errors.New("error that gets wrapped") + err := stderrors.New("error that gets wrapped") wrapped := Wrap(err, "wrapped up") - if !stdlib_errors.Is(wrapped, err) { + if !stderrors.Is(wrapped, err) { t.Errorf("Wrap does not support Go 1.13 error chains") } } + +func TestIs(t *testing.T) { + err := New("test") + + type args struct { + err error + target error + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: err, + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: err, + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: err, + }, + want: true, + }, + { + name: "std errors compatibility", + args: args{ + err: fmt.Errorf("wrap it: %w", err), + target: err, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Is(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("Is() = %v, want %v", got, tt.want) + } + }) + } +} + +type customErr struct { + msg string +} + +func (c customErr) Error() string { return c.msg } + +func TestAs(t *testing.T) { + var err = customErr{msg: "test message"} + + type args struct { + err error + target interface{} + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "with stack", + args: args{ + err: WithStack(err), + target: new(customErr), + }, + want: true, + }, + { + name: "with message", + args: args{ + err: WithMessage(err, "test"), + target: new(customErr), + }, + want: true, + }, + { + name: "with message format", + args: args{ + err: WithMessagef(err, "%s", "test"), + target: new(customErr), + }, + want: true, + }, + { + name: "std errors compatibility", + args: args{ + err: fmt.Errorf("wrap it: %w", err), + target: new(customErr), + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := As(tt.args.err, tt.args.target); got != tt.want { + t.Errorf("As() = %v, want %v", got, tt.want) + } + + ce := tt.args.target.(*customErr) + if !reflect.DeepEqual(err, *ce) { + t.Errorf("set target error failed, target error is %v", *ce) + } + }) + } +} + +func TestUnwrap(t *testing.T) { + err := New("test") + + type args struct { + err error + } + tests := []struct { + name string + args args + want error + }{ + { + name: "with stack", + args: args{err: WithStack(err)}, + want: err, + }, + { + name: "with message", + args: args{err: WithMessage(err, "test")}, + want: err, + }, + { + name: "with message format", + args: args{err: WithMessagef(err, "%s", "test")}, + want: err, + }, + { + name: "std errors compatibility", + args: args{err: fmt.Errorf("wrap: %w", err)}, + want: err, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := Unwrap(tt.args.err); !reflect.DeepEqual(err, tt.want) { + t.Errorf("Unwrap() error = %v, want %v", err, tt.want) + } + }) + } +} From 004deef56200d8bd57ebfd6f8734c08fbd003f6d Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Fri, 3 Jan 2020 13:36:54 +0100 Subject: [PATCH 5/8] remove unnecessary use of fmt.Sprintf (#217) * remove unnecessary use of fmt.Sprintf --- example_test.go | 2 +- stack_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example_test.go b/example_test.go index c1fc13e3..7d0e286f 100644 --- a/example_test.go +++ b/example_test.go @@ -195,7 +195,7 @@ func Example_stackTrace() { func ExampleCause_printf() { err := errors.Wrap(func() error { return func() error { - return errors.Errorf("hello %s", fmt.Sprintf("world")) + return errors.New("hello world") }() }(), "failed") diff --git a/stack_test.go b/stack_test.go index 1acd719b..aa10a72e 100644 --- a/stack_test.go +++ b/stack_test.go @@ -142,7 +142,7 @@ func TestStackTrace(t *testing.T) { }, { Cause(func() error { return func() error { - return Errorf("hello %s", fmt.Sprintf("world")) + return Errorf("hello %s", fmt.Sprintf("world: %s", "ooh")) }() }()), []string{ `github.com/pkg/errors.TestStackTrace.func2.1` + From 49f8f617296114c890ae0b7ac18c5953d2b1ca0f Mon Sep 17 00:00:00 2001 From: Jay Petacat Date: Tue, 7 Jan 2020 16:33:24 -0500 Subject: [PATCH 6/8] Support Go 1.13 error chains in `Cause` (#215) --- cause.go | 29 +++++++++++++++++++++++++++++ errors.go | 26 -------------------------- go113.go | 33 +++++++++++++++++++++++++++++++++ go113_test.go | 24 +++++++++++++++++++++++- 4 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 cause.go diff --git a/cause.go b/cause.go new file mode 100644 index 00000000..566f88bb --- /dev/null +++ b/cause.go @@ -0,0 +1,29 @@ +// +build !go1.13 + +package errors + +// Cause recursively unwraps an error chain and returns the underlying cause of +// the error, if possible. An error value has a cause if it implements the +// following interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} diff --git a/errors.go b/errors.go index 161aea25..a9840ece 100644 --- a/errors.go +++ b/errors.go @@ -260,29 +260,3 @@ func (w *withMessage) Format(s fmt.State, verb rune) { io.WriteString(s, w.Error()) } } - -// Cause returns the underlying cause of the error, if possible. -// An error value has a cause if it implements the following -// interface: -// -// type causer interface { -// Cause() error -// } -// -// If the error does not implement Cause, the original error will -// be returned. If the error is nil, nil will be returned without further -// investigation. -func Cause(err error) error { - type causer interface { - Cause() error - } - - for err != nil { - cause, ok := err.(causer) - if !ok { - break - } - err = cause.Cause() - } - return err -} diff --git a/go113.go b/go113.go index be0d10d0..ed0dc7a6 100644 --- a/go113.go +++ b/go113.go @@ -36,3 +36,36 @@ func As(err error, target interface{}) bool { return stderrors.As(err, target) } func Unwrap(err error) error { return stderrors.Unwrap(err) } + +// Cause recursively unwraps an error chain and returns the underlying cause of +// the error, if possible. There are two ways that an error value may provide a +// cause. First, the error may implement the following interface: +// +// type causer interface { +// Cause() error +// } +// +// Second, the error may return a non-nil value when passed as an argument to +// the Unwrap function. This makes Cause forwards-compatible with Go 1.13 error +// chains. +// +// If an error value satisfies both methods of unwrapping, Cause will use the +// causer interface. +// +// If the error is nil, nil will be returned without further investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + if cause, ok := err.(causer); ok { + err = cause.Cause() + } else if unwrapped := Unwrap(err); unwrapped != nil { + err = unwrapped + } else { + break + } + } + return err +} diff --git a/go113_test.go b/go113_test.go index 4ea37e61..7da37883 100644 --- a/go113_test.go +++ b/go113_test.go @@ -9,7 +9,29 @@ import ( "testing" ) -func TestErrorChainCompat(t *testing.T) { +func TestCauseErrorChainCompat(t *testing.T) { + err := stderrors.New("the cause!") + + // Wrap error using the standard library + wrapped := fmt.Errorf("wrapped with stdlib: %w", err) + if Cause(wrapped) != err { + t.Errorf("Cause does not support Go 1.13 error chains") + } + + // Wrap in another layer using pkg/errors + wrapped = WithMessage(wrapped, "wrapped with pkg/errors") + if Cause(wrapped) != err { + t.Errorf("Cause does not support Go 1.13 error chains") + } + + // Wrap in another layer using the standard library + wrapped = fmt.Errorf("wrapped with stdlib: %w", wrapped) + if Cause(wrapped) != err { + t.Errorf("Cause does not support Go 1.13 error chains") + } +} + +func TestWrapErrorChainCompat(t *testing.T) { err := stderrors.New("error that gets wrapped") wrapped := Wrap(err, "wrapped up") if !stderrors.Is(wrapped, err) { From 614d223910a179a466c1767a985424175c39b465 Mon Sep 17 00:00:00 2001 From: Adrian Perez Date: Tue, 14 Jan 2020 20:47:44 +0100 Subject: [PATCH 7/8] Revert "Support Go 1.13 error chains in `Cause` (#215)" (#220) This reverts commit 49f8f617296114c890ae0b7ac18c5953d2b1ca0f. --- cause.go | 29 ----------------------------- errors.go | 26 ++++++++++++++++++++++++++ go113.go | 33 --------------------------------- go113_test.go | 24 +----------------------- 4 files changed, 27 insertions(+), 85 deletions(-) delete mode 100644 cause.go diff --git a/cause.go b/cause.go deleted file mode 100644 index 566f88bb..00000000 --- a/cause.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build !go1.13 - -package errors - -// Cause recursively unwraps an error chain and returns the underlying cause of -// the error, if possible. An error value has a cause if it implements the -// following interface: -// -// type causer interface { -// Cause() error -// } -// -// If the error does not implement Cause, the original error will -// be returned. If the error is nil, nil will be returned without further -// investigation. -func Cause(err error) error { - type causer interface { - Cause() error - } - - for err != nil { - cause, ok := err.(causer) - if !ok { - break - } - err = cause.Cause() - } - return err -} diff --git a/errors.go b/errors.go index a9840ece..161aea25 100644 --- a/errors.go +++ b/errors.go @@ -260,3 +260,29 @@ func (w *withMessage) Format(s fmt.State, verb rune) { io.WriteString(s, w.Error()) } } + +// Cause returns the underlying cause of the error, if possible. +// An error value has a cause if it implements the following +// interface: +// +// type causer interface { +// Cause() error +// } +// +// If the error does not implement Cause, the original error will +// be returned. If the error is nil, nil will be returned without further +// investigation. +func Cause(err error) error { + type causer interface { + Cause() error + } + + for err != nil { + cause, ok := err.(causer) + if !ok { + break + } + err = cause.Cause() + } + return err +} diff --git a/go113.go b/go113.go index ed0dc7a6..be0d10d0 100644 --- a/go113.go +++ b/go113.go @@ -36,36 +36,3 @@ func As(err error, target interface{}) bool { return stderrors.As(err, target) } func Unwrap(err error) error { return stderrors.Unwrap(err) } - -// Cause recursively unwraps an error chain and returns the underlying cause of -// the error, if possible. There are two ways that an error value may provide a -// cause. First, the error may implement the following interface: -// -// type causer interface { -// Cause() error -// } -// -// Second, the error may return a non-nil value when passed as an argument to -// the Unwrap function. This makes Cause forwards-compatible with Go 1.13 error -// chains. -// -// If an error value satisfies both methods of unwrapping, Cause will use the -// causer interface. -// -// If the error is nil, nil will be returned without further investigation. -func Cause(err error) error { - type causer interface { - Cause() error - } - - for err != nil { - if cause, ok := err.(causer); ok { - err = cause.Cause() - } else if unwrapped := Unwrap(err); unwrapped != nil { - err = unwrapped - } else { - break - } - } - return err -} diff --git a/go113_test.go b/go113_test.go index 7da37883..4ea37e61 100644 --- a/go113_test.go +++ b/go113_test.go @@ -9,29 +9,7 @@ import ( "testing" ) -func TestCauseErrorChainCompat(t *testing.T) { - err := stderrors.New("the cause!") - - // Wrap error using the standard library - wrapped := fmt.Errorf("wrapped with stdlib: %w", err) - if Cause(wrapped) != err { - t.Errorf("Cause does not support Go 1.13 error chains") - } - - // Wrap in another layer using pkg/errors - wrapped = WithMessage(wrapped, "wrapped with pkg/errors") - if Cause(wrapped) != err { - t.Errorf("Cause does not support Go 1.13 error chains") - } - - // Wrap in another layer using the standard library - wrapped = fmt.Errorf("wrapped with stdlib: %w", wrapped) - if Cause(wrapped) != err { - t.Errorf("Cause does not support Go 1.13 error chains") - } -} - -func TestWrapErrorChainCompat(t *testing.T) { +func TestErrorChainCompat(t *testing.T) { err := stderrors.New("error that gets wrapped") wrapped := Wrap(err, "wrapped up") if !stderrors.Is(wrapped, err) { From 5dd12d0cfe7f152f80558d591504ce685299311e Mon Sep 17 00:00:00 2001 From: santosh653 <70637961+santosh653@users.noreply.github.com> Date: Mon, 14 Dec 2020 01:45:52 -0500 Subject: [PATCH 8/8] AddingPowerSupport_CI/Testing (#234) * Update .travis.yml Adding Power & Updating the go versions to 1.13/1.14/1.15 as lower versions are not supported. * Update .travis.yml Removing go 1.13 as desired in the comment section, * Update .travis.yml As desired taking out the power(ppc64le) related support., --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9159de03..81e650b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,11 @@ +arch: + - amd64 + language: go go_import_path: github.com/pkg/errors go: - - 1.11.x - - 1.12.x - - 1.13.x + - 1.14 + - 1.15 - tip script: