This repository has been archived by the owner on Dec 4, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
errors.go
151 lines (137 loc) · 3.59 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Package errors is an extension of and drop in replacement for the standard
// library errors package. Multiple errors can be composed into a single error,
// and single errors can be extended with new errors or with context. You can
// also check whether any of the extensions or compositions contains a certain
// error, allowing for more flexible error handling for complex processes.
package errors
import (
"errors"
"os"
)
// Error satisfies the error interface, and additionally keeps track of all
// extensions and compositions that have happened to the underlying errors.
type Error struct {
ErrSet []error
}
// Error returns the composed error string of the Error, clustering errors by
// their composition and extension.
func (r Error) Error() string {
s := "["
for i, err := range r.ErrSet {
if i != 0 {
s = s "; "
}
s = s err.Error()
}
return s "]"
}
// AddContext will add a string context to an error if the error is not nil. If
// the error is nil, then nil will be returned regardless of the context.
func AddContext(err error, context string) error {
if err == nil {
return nil
}
return Extend(err, New(context))
}
// Compose will compose all errors together into a single error, remembering
// each component error so that they can be checked for matches later using the
// `Contains` function.
//
// Any `nil` input errors will be ignored. If all input errors are `nil`, then
// `nil` will be returned.
func Compose(errs ...error) error {
var r Error
for _, err := range errs {
// Handle nil errors.
if err == nil {
continue
}
r.ErrSet = append(r.ErrSet, err)
}
if len(r.ErrSet) == 0 {
return nil
}
return r
}
// Contains will check whether the base error contains the cmp error. If the
// base err is a Error, then it will check whether there is a match on any of
// the underlying errors.
func Contains(base, cmp error) bool {
// Check for the easy edge cases.
if cmp == nil || base == nil {
return false
}
if base == cmp {
return true
}
switch v := base.(type) {
case Error:
for _, err := range v.ErrSet {
if Contains(err, cmp) {
return true
}
}
return false
default:
return false
}
}
// Extend will extend the first error with the second error, remembering each
// component error so that they can be checked for matches later using the
// `Contains` function.
//
// Any `nil` input will be ignored. If both inputs are `nil, then `nil` will be
// returned.
func Extend(err, extension error) error {
// Check for nil edge cases. If both are nil, nil will be returned.
if err == nil {
return extension
}
if extension == nil {
return err
}
var r Error
// Check the original error for richness.
switch v := err.(type) {
case Error:
r = v
default:
r.ErrSet = []error{v}
}
// Check the extension error for richness.
switch v := extension.(type) {
case Error:
r.ErrSet = append(v.ErrSet, r.ErrSet...)
default:
r.ErrSet = append([]error{v}, r.ErrSet...)
}
// Return nil if the result has no underlying errors.
if len(r.ErrSet) == 0 {
return nil
}
return r
}
// IsOSNotExist returns true if any of the errors in the underlying composition
// return true for os.IsNotExist.
func IsOSNotExist(err error) bool {
if err == nil {
return false
}
switch v := err.(type) {
case Error:
for _, err := range v.ErrSet {
if IsOSNotExist(err) {
return true
}
}
return false
default:
return os.IsNotExist(err)
}
}
// New is a passthrough to the stdlib errors package, allowing
// NebulousLabs/errors to be a drop in replacement for the standard library
// errors package.
func New(s string) error {
return errors.New(s)
}