github.com/saracen/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  }