7 "github.com/pkg/errors"
10 // IsFatalError indicates that the error is fatal and the process should exit
11 // immediately after handling the error.
12 func IsFatalError(err error) bool {
13 if e, ok := err.(interface {
18 if parent := parentOf(err); parent != nil {
19 return IsFatalError(parent)
24 // IsNotImplementedError indicates the client attempted to use a feature the
25 // server has not implemented (e.g. the batch endpoint).
26 func IsNotImplementedError(err error) bool {
27 if e, ok := err.(interface {
30 return e.NotImplemented()
32 if parent := parentOf(err); parent != nil {
33 return IsNotImplementedError(parent)
38 // IsAuthError indicates the client provided a request with invalid or no
39 // authentication credentials when credentials are required (e.g. HTTP 401).
40 func IsAuthError(err error) bool {
41 if e, ok := err.(interface {
46 if parent := parentOf(err); parent != nil {
47 return IsAuthError(parent)
52 // IsSmudgeError indicates an error while smudging a files.
53 func IsSmudgeError(err error) bool {
54 if e, ok := err.(interface {
57 return e.SmudgeError()
59 if parent := parentOf(err); parent != nil {
60 return IsSmudgeError(parent)
65 // IsCleanPointerError indicates an error while cleaning a file.
66 func IsCleanPointerError(err error) bool {
67 if e, ok := err.(interface {
68 CleanPointerError() bool
70 return e.CleanPointerError()
72 if parent := parentOf(err); parent != nil {
73 return IsCleanPointerError(parent)
78 // IsNotAPointerError indicates the parsed data is not an LFS pointer.
79 func IsNotAPointerError(err error) bool {
80 if e, ok := err.(interface {
81 NotAPointerError() bool
83 return e.NotAPointerError()
85 if parent := parentOf(err); parent != nil {
86 return IsNotAPointerError(parent)
91 // IsBadPointerKeyError indicates that the parsed data has an invalid key.
92 func IsBadPointerKeyError(err error) bool {
93 if e, ok := err.(interface {
94 BadPointerKeyError() bool
96 return e.BadPointerKeyError()
99 if parent := parentOf(err); parent != nil {
100 return IsBadPointerKeyError(parent)
105 // If an error is abad pointer error of any type, returns NotAPointerError
106 func StandardizeBadPointerError(err error) error {
107 if IsBadPointerKeyError(err) {
108 badErr := err.(badPointerKeyError)
109 if badErr.Expected == "version" {
110 return NewNotAPointerError(err)
116 // IsDownloadDeclinedError indicates that the smudge operation should not download.
117 // TODO: I don't really like using errors to control that flow, it should be refactored.
118 func IsDownloadDeclinedError(err error) bool {
119 if e, ok := err.(interface {
120 DownloadDeclinedError() bool
122 return e.DownloadDeclinedError()
124 if parent := parentOf(err); parent != nil {
125 return IsDownloadDeclinedError(parent)
130 // IsRetriableError indicates the low level transfer had an error but the
131 // caller may retry the operation.
132 func IsRetriableError(err error) bool {
133 if e, ok := err.(interface {
134 RetriableError() bool
136 return e.RetriableError()
138 if cause, ok := Cause(err).(*url.Error); ok {
139 return cause.Temporary() || cause.Timeout()
141 if parent := parentOf(err); parent != nil {
142 return IsRetriableError(parent)
147 type errorWithCause interface {
149 StackTrace() errors.StackTrace
154 // wrappedError is the base error wrapper. It provides a Message string, a
155 // stack, and a context map around a regular Go error.
156 type wrappedError struct {
158 context map[string]interface{}
161 // newWrappedError creates a wrappedError.
162 func newWrappedError(err error, message string) *wrappedError {
164 err = errors.New("Error")
167 var errWithCause errorWithCause
169 if len(message) > 0 {
170 errWithCause = errors.Wrap(err, message).(errorWithCause)
171 } else if ewc, ok := err.(errorWithCause); ok {
174 errWithCause = errors.Wrap(err, "LFS").(errorWithCause)
177 return &wrappedError{
178 context: make(map[string]interface{}),
179 errorWithCause: errWithCause,
183 // Set sets the value for the key in the context.
184 func (e wrappedError) Set(key string, val interface{}) {
188 // Get gets the value for a key in the context.
189 func (e wrappedError) Get(key string) interface{} {
190 return e.context[key]
193 // Del removes a key from the context.
194 func (e wrappedError) Del(key string) {
195 delete(e.context, key)
198 // Context returns the underlying context.
199 func (e wrappedError) Context() map[string]interface{} {
203 // Definitions for IsFatalError()
205 type fatalError struct {
209 func (e fatalError) Fatal() bool {
213 func NewFatalError(err error) error {
214 return fatalError{newWrappedError(err, "Fatal error")}
217 // Definitions for IsNotImplementedError()
219 type notImplementedError struct {
223 func (e notImplementedError) NotImplemented() bool {
227 func NewNotImplementedError(err error) error {
228 return notImplementedError{newWrappedError(err, "Not implemented")}
231 // Definitions for IsAuthError()
233 type authError struct {
237 func (e authError) AuthError() bool {
241 func NewAuthError(err error) error {
242 return authError{newWrappedError(err, "Authentication required")}
245 // Definitions for IsSmudgeError()
247 type smudgeError struct {
251 func (e smudgeError) SmudgeError() bool {
255 func NewSmudgeError(err error, oid, filename string) error {
256 e := smudgeError{newWrappedError(err, "Smudge error")}
257 SetContext(e, "OID", oid)
258 SetContext(e, "FileName", filename)
262 // Definitions for IsCleanPointerError()
264 type cleanPointerError struct {
268 func (e cleanPointerError) CleanPointerError() bool {
272 func NewCleanPointerError(pointer interface{}, bytes []byte) error {
273 err := New("pointer error")
274 e := cleanPointerError{newWrappedError(err, "clean")}
275 SetContext(e, "pointer", pointer)
276 SetContext(e, "bytes", bytes)
280 // Definitions for IsNotAPointerError()
282 type notAPointerError struct {
286 func (e notAPointerError) NotAPointerError() bool {
290 func NewNotAPointerError(err error) error {
291 return notAPointerError{newWrappedError(err, "Pointer file error")}
294 type badPointerKeyError struct {
301 func (e badPointerKeyError) BadPointerKeyError() bool {
305 func NewBadPointerKeyError(expected, actual string) error {
306 err := Errorf("Expected key %s, got %s", expected, actual)
307 return badPointerKeyError{expected, actual, newWrappedError(err, "pointer parsing")}
310 // Definitions for IsDownloadDeclinedError()
312 type downloadDeclinedError struct {
316 func (e downloadDeclinedError) DownloadDeclinedError() bool {
320 func NewDownloadDeclinedError(err error, msg string) error {
321 return downloadDeclinedError{newWrappedError(err, msg)}
324 // Definitions for IsRetriableError()
326 type retriableError struct {
330 func (e retriableError) RetriableError() bool {
334 func NewRetriableError(err error) error {
335 return retriableError{newWrappedError(err, "")}
338 func parentOf(err error) error {
339 type causer interface {
343 if c, ok := err.(causer); ok {
344 if innerC, innerOk := c.Cause().(causer); innerOk {
345 return innerC.Cause()