github.com/catandhorse/git-lfs@v2.5.2+incompatible/errors/types.go (about) 1 package errors 2 3 import ( 4 "fmt" 5 "net/url" 6 7 "github.com/pkg/errors" 8 ) 9 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 { 14 Fatal() bool 15 }); ok { 16 return e.Fatal() 17 } 18 if parent := parentOf(err); parent != nil { 19 return IsFatalError(parent) 20 } 21 return false 22 } 23 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 { 28 NotImplemented() bool 29 }); ok { 30 return e.NotImplemented() 31 } 32 if parent := parentOf(err); parent != nil { 33 return IsNotImplementedError(parent) 34 } 35 return false 36 } 37 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 { 42 AuthError() bool 43 }); ok { 44 return e.AuthError() 45 } 46 if parent := parentOf(err); parent != nil { 47 return IsAuthError(parent) 48 } 49 return false 50 } 51 52 // IsSmudgeError indicates an error while smudging a files. 53 func IsSmudgeError(err error) bool { 54 if e, ok := err.(interface { 55 SmudgeError() bool 56 }); ok { 57 return e.SmudgeError() 58 } 59 if parent := parentOf(err); parent != nil { 60 return IsSmudgeError(parent) 61 } 62 return false 63 } 64 65 // IsCleanPointerError indicates an error while cleaning a file. 66 func IsCleanPointerError(err error) bool { 67 if e, ok := err.(interface { 68 CleanPointerError() bool 69 }); ok { 70 return e.CleanPointerError() 71 } 72 if parent := parentOf(err); parent != nil { 73 return IsCleanPointerError(parent) 74 } 75 return false 76 } 77 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 82 }); ok { 83 return e.NotAPointerError() 84 } 85 if parent := parentOf(err); parent != nil { 86 return IsNotAPointerError(parent) 87 } 88 return false 89 } 90 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 95 }); ok { 96 return e.BadPointerKeyError() 97 } 98 99 if parent := parentOf(err); parent != nil { 100 return IsBadPointerKeyError(parent) 101 } 102 return false 103 } 104 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) 111 } 112 } 113 return err 114 } 115 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 121 }); ok { 122 return e.DownloadDeclinedError() 123 } 124 if parent := parentOf(err); parent != nil { 125 return IsDownloadDeclinedError(parent) 126 } 127 return false 128 } 129 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 135 }); ok { 136 return e.UnprocessableEntityError() 137 } 138 if parent := parentOf(err); parent != nil { 139 return IsUnprocessableEntityError(parent) 140 } 141 return false 142 } 143 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 149 }); ok { 150 return e.RetriableError() 151 } 152 if cause, ok := Cause(err).(*url.Error); ok { 153 return cause.Temporary() || cause.Timeout() 154 } 155 if parent := parentOf(err); parent != nil { 156 return IsRetriableError(parent) 157 } 158 return false 159 } 160 161 type errorWithCause interface { 162 Cause() error 163 StackTrace() errors.StackTrace 164 error 165 fmt.Formatter 166 } 167 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 { 171 errorWithCause 172 context map[string]interface{} 173 } 174 175 // newWrappedError creates a wrappedError. 176 func newWrappedError(err error, message string) *wrappedError { 177 if err == nil { 178 err = errors.New("Error") 179 } 180 181 var errWithCause errorWithCause 182 183 if len(message) > 0 { 184 errWithCause = errors.Wrap(err, message).(errorWithCause) 185 } else if ewc, ok := err.(errorWithCause); ok { 186 errWithCause = ewc 187 } else { 188 errWithCause = errors.Wrap(err, "LFS").(errorWithCause) 189 } 190 191 return &wrappedError{ 192 context: make(map[string]interface{}), 193 errorWithCause: errWithCause, 194 } 195 } 196 197 // Set sets the value for the key in the context. 198 func (e wrappedError) Set(key string, val interface{}) { 199 e.context[key] = val 200 } 201 202 // Get gets the value for a key in the context. 203 func (e wrappedError) Get(key string) interface{} { 204 return e.context[key] 205 } 206 207 // Del removes a key from the context. 208 func (e wrappedError) Del(key string) { 209 delete(e.context, key) 210 } 211 212 // Context returns the underlying context. 213 func (e wrappedError) Context() map[string]interface{} { 214 return e.context 215 } 216 217 // Definitions for IsFatalError() 218 219 type fatalError struct { 220 *wrappedError 221 } 222 223 func (e fatalError) Fatal() bool { 224 return true 225 } 226 227 func NewFatalError(err error) error { 228 return fatalError{newWrappedError(err, "Fatal error")} 229 } 230 231 // Definitions for IsNotImplementedError() 232 233 type notImplementedError struct { 234 *wrappedError 235 } 236 237 func (e notImplementedError) NotImplemented() bool { 238 return true 239 } 240 241 func NewNotImplementedError(err error) error { 242 return notImplementedError{newWrappedError(err, "Not implemented")} 243 } 244 245 // Definitions for IsAuthError() 246 247 type authError struct { 248 *wrappedError 249 } 250 251 func (e authError) AuthError() bool { 252 return true 253 } 254 255 func NewAuthError(err error) error { 256 return authError{newWrappedError(err, "Authentication required")} 257 } 258 259 // Definitions for IsSmudgeError() 260 261 type smudgeError struct { 262 *wrappedError 263 } 264 265 func (e smudgeError) SmudgeError() bool { 266 return true 267 } 268 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) 273 return e 274 } 275 276 // Definitions for IsCleanPointerError() 277 278 type cleanPointerError struct { 279 *wrappedError 280 } 281 282 func (e cleanPointerError) CleanPointerError() bool { 283 return true 284 } 285 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) 291 return e 292 } 293 294 // Definitions for IsNotAPointerError() 295 296 type notAPointerError struct { 297 *wrappedError 298 } 299 300 func (e notAPointerError) NotAPointerError() bool { 301 return true 302 } 303 304 func NewNotAPointerError(err error) error { 305 return notAPointerError{newWrappedError(err, "Pointer file error")} 306 } 307 308 type badPointerKeyError struct { 309 Expected string 310 Actual string 311 312 *wrappedError 313 } 314 315 func (e badPointerKeyError) BadPointerKeyError() bool { 316 return true 317 } 318 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")} 322 } 323 324 // Definitions for IsDownloadDeclinedError() 325 326 type downloadDeclinedError struct { 327 *wrappedError 328 } 329 330 func (e downloadDeclinedError) DownloadDeclinedError() bool { 331 return true 332 } 333 334 func NewDownloadDeclinedError(err error, msg string) error { 335 return downloadDeclinedError{newWrappedError(err, msg)} 336 } 337 338 // Definitions for IsUnprocessableEntityError() 339 340 type unprocessableEntityError struct { 341 *wrappedError 342 } 343 344 func (e unprocessableEntityError) UnprocessableEntityError() bool { 345 return true 346 } 347 348 func NewUnprocessableEntityError(err error) error { 349 return unprocessableEntityError{newWrappedError(err, "")} 350 } 351 352 // Definitions for IsRetriableError() 353 354 type retriableError struct { 355 *wrappedError 356 } 357 358 func (e retriableError) RetriableError() bool { 359 return true 360 } 361 362 func NewRetriableError(err error) error { 363 return retriableError{newWrappedError(err, "")} 364 } 365 366 func parentOf(err error) error { 367 type causer interface { 368 Cause() error 369 } 370 371 if c, ok := err.(causer); ok { 372 if innerC, innerOk := c.Cause().(causer); innerOk { 373 return innerC.Cause() 374 } 375 } 376 377 return nil 378 }