| /* | |
| Copyright The containerd Authors. | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| package errdefs | |
| import "context" | |
| // Resolve returns the first error found in the error chain which matches an | |
| // error defined in this package or context error. A raw, unwrapped error is | |
| // returned or ErrUnknown if no matching error is found. | |
| // | |
| // This is useful for determining a response code based on the outermost wrapped | |
| // error rather than the original cause. For example, a not found error deep | |
| // in the code may be wrapped as an invalid argument. When determining status | |
| // code from Is* functions, the depth or ordering of the error is not | |
| // considered. | |
| // | |
| // The search order is depth first, a wrapped error returned from any part of | |
| // the chain from `Unwrap() error` will be returned before any joined errors | |
| // as returned by `Unwrap() []error`. | |
| func Resolve(err error) error { | |
| if err == nil { | |
| return nil | |
| } | |
| err = firstError(err) | |
| if err == nil { | |
| err = ErrUnknown | |
| } | |
| return err | |
| } | |
| func firstError(err error) error { | |
| for { | |
| switch err { | |
| case ErrUnknown, | |
| ErrInvalidArgument, | |
| ErrNotFound, | |
| ErrAlreadyExists, | |
| ErrPermissionDenied, | |
| ErrResourceExhausted, | |
| ErrFailedPrecondition, | |
| ErrConflict, | |
| ErrNotModified, | |
| ErrAborted, | |
| ErrOutOfRange, | |
| ErrNotImplemented, | |
| ErrInternal, | |
| ErrUnavailable, | |
| ErrDataLoss, | |
| ErrUnauthenticated, | |
| context.DeadlineExceeded, | |
| context.Canceled: | |
| return err | |
| } | |
| switch e := err.(type) { | |
| case customMessage: | |
| err = e.err | |
| case unknown: | |
| return ErrUnknown | |
| case invalidParameter: | |
| return ErrInvalidArgument | |
| case notFound: | |
| return ErrNotFound | |
| case alreadyExists: | |
| return ErrAlreadyExists | |
| case forbidden: | |
| return ErrPermissionDenied | |
| case resourceExhausted: | |
| return ErrResourceExhausted | |
| case failedPrecondition: | |
| return ErrFailedPrecondition | |
| case conflict: | |
| return ErrConflict | |
| case notModified: | |
| return ErrNotModified | |
| case aborted: | |
| return ErrAborted | |
| case errOutOfRange: | |
| return ErrOutOfRange | |
| case notImplemented: | |
| return ErrNotImplemented | |
| case system: | |
| return ErrInternal | |
| case unavailable: | |
| return ErrUnavailable | |
| case dataLoss: | |
| return ErrDataLoss | |
| case unauthorized: | |
| return ErrUnauthenticated | |
| case deadlineExceeded: | |
| return context.DeadlineExceeded | |
| case cancelled: | |
| return context.Canceled | |
| case interface{ Unwrap() error }: | |
| err = e.Unwrap() | |
| if err == nil { | |
| return nil | |
| } | |
| case interface{ Unwrap() []error }: | |
| for _, ue := range e.Unwrap() { | |
| if fe := firstError(ue); fe != nil { | |
| return fe | |
| } | |
| } | |
| return nil | |
| case interface{ Is(error) bool }: | |
| for _, target := range []error{ErrUnknown, | |
| ErrInvalidArgument, | |
| ErrNotFound, | |
| ErrAlreadyExists, | |
| ErrPermissionDenied, | |
| ErrResourceExhausted, | |
| ErrFailedPrecondition, | |
| ErrConflict, | |
| ErrNotModified, | |
| ErrAborted, | |
| ErrOutOfRange, | |
| ErrNotImplemented, | |
| ErrInternal, | |
| ErrUnavailable, | |
| ErrDataLoss, | |
| ErrUnauthenticated, | |
| context.DeadlineExceeded, | |
| context.Canceled} { | |
| if e.Is(target) { | |
| return target | |
| } | |
| } | |
| return nil | |
| default: | |
| return nil | |
| } | |
| } | |
| } |