Skip to content

Commit 2682980

Browse files
committed
Consolidate error types into a single error type
This consolidates the various error types to a single error type with a code that designates the type of error. This reduces the amount and complexity of the overall code. The individual methods like `IsInvalidArgument` that support both errors from this package and moby errors are now moved to the `compat.go` file to organize them together. Signed-off-by: Jonathan A. Sternberg <[email protected]>
1 parent 124d0dc commit 2682980

File tree

4 files changed

+299
-390
lines changed

4 files changed

+299
-390
lines changed

compat.go

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package errdefs
18+
19+
import (
20+
"context"
21+
"errors"
22+
)
23+
24+
// IsCanceled returns true if the error is due to `context.Canceled`.
25+
func IsCanceled(err error) bool {
26+
return errors.Is(err, context.Canceled) || isInterface[cancelled](err)
27+
}
28+
29+
// IsUnknown returns true if the error is due to an unknown error,
30+
// unhandled condition or unexpected response.
31+
func IsUnknown(err error) bool {
32+
return errors.Is(err, ErrUnknown) || isInterface[unknown](err)
33+
}
34+
35+
// IsInvalidArgument returns true if the error is due to an invalid argument
36+
func IsInvalidArgument(err error) bool {
37+
return errors.Is(err, ErrInvalidArgument) || isInterface[invalidParameter](err)
38+
}
39+
40+
// IsDeadlineExceeded returns true if the error is due to
41+
// `context.DeadlineExceeded`.
42+
func IsDeadlineExceeded(err error) bool {
43+
return errors.Is(err, context.DeadlineExceeded) || isInterface[deadlineExceeded](err)
44+
}
45+
46+
// IsNotFound returns true if the error is due to a missing object
47+
func IsNotFound(err error) bool {
48+
return errors.Is(err, ErrNotFound) || isInterface[notFound](err)
49+
}
50+
51+
// IsAlreadyExists returns true if the error is due to an already existing
52+
// metadata item
53+
func IsAlreadyExists(err error) bool {
54+
return errors.Is(err, ErrAlreadyExists)
55+
}
56+
57+
// IsPermissionDenied returns true if the error is due to permission denied
58+
// or forbidden (403) response
59+
func IsPermissionDenied(err error) bool {
60+
return errors.Is(err, ErrPermissionDenied) || isInterface[forbidden](err)
61+
}
62+
63+
// IsResourceExhausted returns true if the error is due to
64+
// a lack of resources or too many attempts.
65+
func IsResourceExhausted(err error) bool {
66+
return errors.Is(err, ErrResourceExhausted)
67+
}
68+
69+
// IsFailedPrecondition returns true if an operation could not proceed due to
70+
// the lack of a particular condition
71+
func IsFailedPrecondition(err error) bool {
72+
return errors.Is(err, ErrFailedPrecondition)
73+
}
74+
75+
// IsConflict returns true if an operation could not proceed due to
76+
// a conflict.
77+
func IsConflict(err error) bool {
78+
return errors.Is(err, ErrConflict) || isInterface[conflict](err)
79+
}
80+
81+
// IsNotModified returns true if an operation could not proceed due
82+
// to an object not modified from a previous state.
83+
func IsNotModified(err error) bool {
84+
return errors.Is(err, ErrNotModified) || isInterface[notModified](err)
85+
}
86+
87+
// IsAborted returns true if an operation was aborted.
88+
func IsAborted(err error) bool {
89+
return errors.Is(err, ErrAborted)
90+
}
91+
92+
// IsOutOfRange returns true if an operation could not proceed due
93+
// to data being out of the expected range.
94+
func IsOutOfRange(err error) bool {
95+
return errors.Is(err, ErrOutOfRange)
96+
}
97+
98+
// IsNotImplemented returns true if the error is due to not being implemented
99+
func IsNotImplemented(err error) bool {
100+
return errors.Is(err, ErrNotImplemented) || isInterface[notImplemented](err)
101+
}
102+
103+
// IsInternal returns true if the error returns to an internal or system error
104+
func IsInternal(err error) bool {
105+
return errors.Is(err, ErrInternal) || isInterface[system](err)
106+
}
107+
108+
// IsUnavailable returns true if the error is due to a resource being unavailable
109+
func IsUnavailable(err error) bool {
110+
return errors.Is(err, ErrUnavailable) || isInterface[unavailable](err)
111+
}
112+
113+
// IsDataLoss returns true if data during an operation was lost or corrupted
114+
func IsDataLoss(err error) bool {
115+
return errors.Is(err, ErrDataLoss) || isInterface[dataLoss](err)
116+
}
117+
118+
// IsUnauthorized returns true if the error indicates that the user was
119+
// unauthenticated or unauthorized.
120+
func IsUnauthorized(err error) bool {
121+
// Intentional change. Old name was Unauthorized, but the grpc error
122+
// code is named Unauthenticated. The name is changing to Unauthenticated
123+
// but the old function name was IsUnauthorized.
124+
return errors.Is(err, ErrUnauthenticated) || isInterface[unauthorized](err)
125+
}
126+
127+
// cancelled maps to Moby's "ErrCancelled"
128+
type cancelled interface {
129+
Cancelled()
130+
}
131+
132+
// unknown maps to Moby's "ErrUnknown"
133+
type unknown interface {
134+
Unknown()
135+
}
136+
137+
// invalidParameter maps to Moby's "ErrInvalidParameter"
138+
type invalidParameter interface {
139+
InvalidParameter()
140+
}
141+
142+
// deadlineExceed maps to Moby's "ErrDeadline"
143+
type deadlineExceeded interface {
144+
DeadlineExceeded()
145+
}
146+
147+
// notFound maps to Moby's "ErrNotFound"
148+
type notFound interface {
149+
NotFound()
150+
}
151+
152+
// forbidden maps to Moby's "ErrForbidden"
153+
type forbidden interface {
154+
Forbidden()
155+
}
156+
157+
// conflict maps to Moby's "ErrConflict"
158+
type conflict interface {
159+
Conflict()
160+
}
161+
162+
// notModified maps to Moby's "ErrNotModified"
163+
type notModified interface {
164+
NotModified()
165+
}
166+
167+
// notImplemented maps to Moby's "ErrNotImplemented"
168+
type notImplemented interface {
169+
NotImplemented()
170+
}
171+
172+
// system maps to Moby's "ErrSystem"
173+
type system interface {
174+
System()
175+
}
176+
177+
// unavailable maps to Moby's "ErrUnavailable"
178+
type unavailable interface {
179+
Unavailable()
180+
}
181+
182+
// dataLoss maps to Moby's "ErrDataLoss"
183+
type dataLoss interface {
184+
DataLoss()
185+
}
186+
187+
// unauthorized maps to Moby's "ErrUnauthorized"
188+
type unauthorized interface {
189+
Unauthorized()
190+
}
191+
192+
func isInterface[T any](err error) bool {
193+
for {
194+
switch x := err.(type) {
195+
case T:
196+
return true
197+
case interface{ Unwrap() error }:
198+
err = x.Unwrap()
199+
if err == nil {
200+
return false
201+
}
202+
case interface{ Unwrap() []error }:
203+
for _, err := range x.Unwrap() {
204+
if isInterface[T](err) {
205+
return true
206+
}
207+
}
208+
return false
209+
default:
210+
return false
211+
}
212+
}
213+
}

0 commit comments

Comments
 (0)