-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patherror.go
172 lines (152 loc) · 4.31 KB
/
error.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package errors
import (
"fmt"
"log"
"runtime"
"strconv"
"strings"
)
const separator = ": "
var _ error = (*Error)(nil)
// Op describes an operation, usually as the package and method,
// such as "key/server.Lookup".
type Op string
// Kind defines the kind of error this is, mostly for use by systems
// such as FUSE that must act differently depending on the error.
type Kind int
func (k Kind) String() string {
return strconv.Itoa(int(k))
}
// Kinds of errors.
//
// The values of the error kinds are common between both
// clients and servers. Do not reorder this list or remove
// any items since that will change their values.
// New items must be added only to the end.
const (
Internal Kind = iota // Internal error or inconsistency.
Invalid // Invalid operation for this type of item.
Permission // Permission denied.
IO // External I/O error such as network failure.
AlreadyExist // Item already exists.
NotExist // Item does not exist.
NotImplemented // Method not implemented
)
// Error is the type that implements the error interface.
// It contains a number of fields, each of different type.
// An Error value may leave some values unset.
type Error struct {
kind Kind
msg string
cause error
}
func (e *Error) isZero() bool {
return e.msg == "" && e.kind == Internal && e.cause == nil
}
func (e *Error) Error() string {
b := new(strings.Builder)
if e.msg != "" {
pad(b, separator)
b.WriteString(string(e.msg))
}
if e.cause != nil {
pad(b, separator)
b.WriteString(e.cause.Error())
}
if b.Len() == 0 {
return "no error"
}
return b.String()
}
// Cause specifies the Cause of the underlying error wrapped inside
func (e *Error) Cause() error {
if e.isZero() {
return nil
}
return e.cause
}
// Kind specifies the Kind of the error
func (e *Error) Kind() Kind {
return e.kind
}
// New builds an error value from its arguments.
// There must be at least one argument or New panics.
// The type of each argument determines its meaning.
// If more than one argument of a given type is presented,
// only the last one is recorded.
//
// The types are:
// errors.op
// The operation being performed, usually the method
// being invoked (Get, Put, etc.).
// errors.kind
// The class of error, such as permission failure.
// error
// The underlying error that triggered this one.
//
// If the error is printed, only those items that have been
// set to non-zero values will appear in the result.
//
// If Kind is not specified or Internal, we set it to the Kind of
// the underlying error.
//
func New(msg string, args ...interface{}) error {
e := &Error{
msg: msg,
kind: Internal,
}
var op Op
for _, arg := range args {
switch arg := arg.(type) {
case Op:
op = arg
case Kind:
e.kind = arg
case error:
e.cause = arg
case *Error:
e.cause = arg
// The previous error was also one of ours. Suppress duplications
// so the message won't contain the same kind twice.
// If this error has Kind unset or Other, pull up the inner one.
if e.kind != arg.kind && e.kind == Internal {
e.kind = arg.kind
}
default:
_, file, line, _ := runtime.Caller(1)
log.Printf("errors.E: bad call from %s:%d: %v", file, line, args)
return Errorf("unknown type %T, value %v in error call", arg, arg)
}
}
return WithOp(e, op)
}
// Recreate the errors.New functionality of the standard Go errors package
// so we can create simple text errors when needed.
// Str returns an error that formats as the given text. It is intended to
// be used as the error-typed argument to the E function.
func Str(text string) error {
if text == "" {
_, file, line, _ := runtime.Caller(1)
return Errorf("errors.E: bad call from %s:%d", file, line)
}
return &stringerr{text}
}
// stringerr is a trivial implementation of error.
type stringerr struct {
msg string
}
func (e *stringerr) Error() string {
return e.msg
}
// Errorf is equivalent to fmt.Errorf, but allows clients to import only this
// package for all error handling.
func Errorf(format string, args ...interface{}) error {
return &stringerr{msg: fmt.Sprintf(format, args...)}
}
// pad appends str to the buffer if the buffer already has some data.
func pad(b *strings.Builder, str string) {
if b.Len() == 0 {
return
}
b.WriteString(str)
}