From 6d954f502eb89cd315e4baae5b0e0db516d6f787 Mon Sep 17 00:00:00 2001 From: Sherlock Holo Date: Fri, 3 Jan 2020 19:25:31 +0800 Subject: [PATCH 1/5] 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 0000000..be0d10d --- /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 39263b0..4ea37e6 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 2/5] 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 c1fc13e..7d0e286 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 1acd719..aa10a72 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 3/5] 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 0000000..566f88b --- /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 161aea2..a9840ec 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 be0d10d..ed0dc7a 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 4ea37e6..7da3788 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 4/5] 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 566f88b..0000000 --- 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 a9840ec..161aea2 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 ed0dc7a..be0d10d 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 7da3788..4ea37e6 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 5/5] 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 9159de0..81e650b 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: