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 // IsDownloadDeclinedError indicates that the upload operation failed because of
131 // an HTTP 422 response code.
132 func IsUnprocessableEntityError(err error) bool {
133 if e, ok := err.(interface {
134 UnprocessableEntityError() bool
136 return e.UnprocessableEntityError()
138 if parent := parentOf(err); parent != nil {
139 return IsUnprocessableEntityError(parent)
144 // IsRetriableError indicates the low level transfer had an error but the
145 // caller may retry the operation.
146 func IsRetriableError(err error) bool {
147 if e, ok := err.(interface {
148 RetriableError() bool
150 return e.RetriableError()
152 if cause, ok := Cause(err).(*url.Error); ok {
153 return cause.Temporary() || cause.Timeout()
155 if parent := parentOf(err); parent != nil {
156 return IsRetriableError(parent)
161 type errorWithCause interface {
163 StackTrace() errors.StackTrace
168 // wrappedError is the base error wrapper. It provides a Message string, a
169 // stack, and a context map around a regular Go error.
170 type wrappedError struct {
172 context map[string]interface{}
175 // newWrappedError creates a wrappedError.
176 func newWrappedError(err error, message string) *wrappedError {
178 err = errors.New("Error")
181 var errWithCause errorWithCause
183 if len(message) > 0 {
184 errWithCause = errors.Wrap(err, message).(errorWithCause)
185 } else if ewc, ok := err.(errorWithCause); ok {
188 errWithCause = errors.Wrap(err, "LFS").(errorWithCause)
191 return &wrappedError{
192 context: make(map[string]interface{}),
193 errorWithCause: errWithCause,
197 // Set sets the value for the key in the context.
198 func (e wrappedError) Set(key string, val interface{}) {
202 // Get gets the value for a key in the context.
203 func (e wrappedError) Get(key string) interface{} {
204 return e.context[key]
207 // Del removes a key from the context.
208 func (e wrappedError) Del(key string) {
209 delete(e.context, key)
212 // Context returns the underlying context.
213 func (e wrappedError) Context() map[string]interface{} {
217 // Definitions for IsFatalError()
219 type fatalError struct {
223 func (e fatalError) Fatal() bool {
227 func NewFatalError(err error) error {
228 return fatalError{newWrappedError(err, "Fatal error")}
231 // Definitions for IsNotImplementedError()
233 type notImplementedError struct {
237 func (e notImplementedError) NotImplemented() bool {
241 func NewNotImplementedError(err error) error {
242 return notImplementedError{newWrappedError(err, "Not implemented")}
245 // Definitions for IsAuthError()
247 type authError struct {
251 func (e authError) AuthError() bool {
255 func NewAuthError(err error) error {
256 return authError{newWrappedError(err, "Authentication required")}
259 // Definitions for IsSmudgeError()
261 type smudgeError struct {
265 func (e smudgeError) SmudgeError() bool {
269 func NewSmudgeError(err error, oid, filename string) error {
270 e := smudgeError{newWrappedError(err, "Smudge error")}
271 SetContext(e, "OID", oid)
272 SetContext(e, "FileName", filename)
276 // Definitions for IsCleanPointerError()
278 type cleanPointerError struct {
282 func (e cleanPointerError) CleanPointerError() bool {
286 func NewCleanPointerError(pointer interface{}, bytes []byte) error {
287 err := New("pointer error")
288 e := cleanPointerError{newWrappedError(err, "clean")}
289 SetContext(e, "pointer", pointer)
290 SetContext(e, "bytes", bytes)
294 // Definitions for IsNotAPointerError()
296 type notAPointerError struct {
300 func (e notAPointerError) NotAPointerError() bool {
304 func NewNotAPointerError(err error) error {
305 return notAPointerError{newWrappedError(err, "Pointer file error")}
308 type badPointerKeyError struct {
315 func (e badPointerKeyError) BadPointerKeyError() bool {
319 func NewBadPointerKeyError(expected, actual string) error {
320 err := Errorf("Expected key %s, got %s", expected, actual)
321 return badPointerKeyError{expected, actual, newWrappedError(err, "pointer parsing")}
324 // Definitions for IsDownloadDeclinedError()
326 type downloadDeclinedError struct {
330 func (e downloadDeclinedError) DownloadDeclinedError() bool {
334 func NewDownloadDeclinedError(err error, msg string) error {
335 return downloadDeclinedError{newWrappedError(err, msg)}
338 // Definitions for IsUnprocessableEntityError()
340 type unprocessableEntityError struct {
344 func (e unprocessableEntityError) UnprocessableEntityError() bool {
348 func NewUnprocessableEntityError(err error) error {
349 return unprocessableEntityError{newWrappedError(err, "")}
352 // Definitions for IsRetriableError()
354 type retriableError struct {
358 func (e retriableError) RetriableError() bool {
362 func NewRetriableError(err error) error {
363 return retriableError{newWrappedError(err, "")}
366 func parentOf(err error) error {
367 type causer interface {
371 if c, ok := err.(causer); ok {
372 if innerC, innerOk := c.Cause().(causer); innerOk {
373 return innerC.Cause()