diff --git a/commands/command_install.go b/commands/command_install.go index 01e7519b..13784eb8 100644 --- a/commands/command_install.go +++ b/commands/command_install.go @@ -1,9 +1,10 @@ package commands import ( + "os" + "github.com/github/git-lfs/lfs" "github.com/spf13/cobra" - "os" ) var ( diff --git a/commands/commands.go b/commands/commands.go index fe7bb070..bb89602d 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -118,23 +118,23 @@ func FullError(err error) { } func errorWith(err error, fatalErrFn func(error, string, ...interface{}), errFn func(string, ...interface{})) { - var innermsg string - if inner := errutil.GetInnerError(err); inner != nil { - innermsg = inner.Error() - } - - errmsg := err.Error() - if errmsg != innermsg { - Error(innermsg) - } - - if Debugging || errutil.IsFatalError(err) { - fatalErrFn(err, errmsg) - } else { - errFn(errmsg) - } + var innermsg string + if inner := errutil.GetInnerError(err); inner != nil { + innermsg = inner.Error() } + errmsg := err.Error() + if errmsg != innermsg { + Error(innermsg) + } + + if Debugging || errutil.IsFatalError(err) { + fatalErrFn(err, errmsg) + } else { + errFn(errmsg) + } +} + // Debug prints a formatted message if debugging is enabled. The formatted // message also shows up in the panic log, if created. func Debug(format string, args ...interface{}) { diff --git a/errutil/errors.go b/errutil/errors.go index 8a6c351a..98053c8b 100644 --- a/errutil/errors.go +++ b/errutil/errors.go @@ -50,21 +50,36 @@ package errutil // regular Go error will return an empty byte slice. import ( - "errors" "fmt" + "reflect" "runtime" + + "github.com/pkg/errors" ) +func parentOf(err error) error { + type causer interface { + Cause() error + } + + if c, ok := err.(causer); ok { + return c.Cause() + } + + return nil +} + // IsFatalError indicates that the error is fatal and the process should exit // immediately after handling the error. func IsFatalError(err error) bool { + fmt.Println(err, reflect.TypeOf(err)) if e, ok := err.(interface { Fatal() bool }); ok { return e.Fatal() } - if e, ok := err.(errorWrapper); ok { - return IsFatalError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsFatalError(parent) } return false } @@ -77,8 +92,8 @@ func IsNotImplementedError(err error) bool { }); ok { return e.NotImplemented() } - if e, ok := err.(errorWrapper); ok { - return IsNotImplementedError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsNotImplementedError(parent) } return false } @@ -91,8 +106,8 @@ func IsAuthError(err error) bool { }); ok { return e.AuthError() } - if e, ok := err.(errorWrapper); ok { - return IsAuthError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsAuthError(parent) } return false } @@ -105,8 +120,8 @@ func IsInvalidPointerError(err error) bool { }); ok { return e.InvalidPointer() } - if e, ok := err.(errorWrapper); ok { - return IsInvalidPointerError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsInvalidPointerError(parent) } return false } @@ -119,8 +134,8 @@ func IsInvalidRepoError(err error) bool { }); ok { return e.InvalidRepo() } - if e, ok := err.(errorWrapper); ok { - return IsInvalidRepoError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsInvalidRepoError(parent) } return false } @@ -132,8 +147,8 @@ func IsSmudgeError(err error) bool { }); ok { return e.SmudgeError() } - if e, ok := err.(errorWrapper); ok { - return IsSmudgeError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsSmudgeError(parent) } return false } @@ -145,8 +160,8 @@ func IsCleanPointerError(err error) bool { }); ok { return e.CleanPointerError() } - if e, ok := err.(errorWrapper); ok { - return IsCleanPointerError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsCleanPointerError(parent) } return false } @@ -158,8 +173,8 @@ func IsNotAPointerError(err error) bool { }); ok { return e.NotAPointerError() } - if e, ok := err.(errorWrapper); ok { - return IsNotAPointerError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsNotAPointerError(parent) } return false } @@ -171,8 +186,9 @@ func IsBadPointerKeyError(err error) bool { }); ok { return e.BadPointerKeyError() } - if e, ok := err.(errorWrapper); ok { - return IsBadPointerKeyError(e.InnerError()) + + if parent := parentOf(err); parent != nil { + return IsBadPointerKeyError(parent) } return false } @@ -196,8 +212,8 @@ func IsDownloadDeclinedError(err error) bool { }); ok { return e.DownloadDeclinedError() } - if e, ok := err.(errorWrapper); ok { - return IsDownloadDeclinedError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsDownloadDeclinedError(parent) } return false } @@ -210,18 +226,17 @@ func IsRetriableError(err error) bool { }); ok { return e.RetriableError() } - if e, ok := err.(errorWrapper); ok { - return IsRetriableError(e.InnerError()) + if parent := parentOf(err); parent != nil { + return IsRetriableError(parent) } return false } func GetInnerError(err error) error { - if e, ok := err.(interface { - InnerError() error - }); ok { - return e.InnerError() + if parent := parentOf(err); parent != nil { + return parent } + return nil } @@ -271,10 +286,17 @@ func ErrorDelContext(err error, key string) { // ErrorStack returns the stack for an error if it is a wrappedError. If it is // not a wrappedError it will return an empty byte slice. -func ErrorStack(err error) []byte { - if e, ok := err.(errorWrapper); ok { - return e.Stack() +func ErrorStack(err error) errors.StackTrace { + if st, ok := err.(interface { + StackTrace() errors.StackTrace + }); ok { + return st.StackTrace() } + + if parent := parentOf(err); parent != nil { + return ErrorStack(parent) + } + return nil } @@ -288,61 +310,38 @@ func ErrorContext(err error) map[string]interface{} { } type errorWrapper interface { - InnerError() error - Error() string + error + Set(string, interface{}) Get(string) interface{} Del(string) Context() map[string]interface{} - Stack() []byte } // wrappedError is the base error wrapper. It provides a Message string, a // stack, and a context map around a regular Go error. type wrappedError struct { - Message string - stack []byte - context map[string]interface{} error + + context map[string]interface{} } -// newWrappedError creates a wrappedError. If the error has already been -// wrapped it is simply returned as is. +// newWrappedError creates a wrappedError. func newWrappedError(err error, message string) errorWrapper { - if e, ok := err.(errorWrapper); ok { - return e - } - if err == nil { err = errors.New("LFS Error") } - if message == "" { - message = err.Error() + if len(message) > 0 { + err = errors.Wrap(err, message) } - return wrappedError{ - Message: message, - stack: Stack(), + return &wrappedError{ context: make(map[string]interface{}), error: err, } } -// Error will return the wrapped error's Message if it has one, otherwise it -// will call the underlying error's Error() function. -func (e wrappedError) Error() string { - if e.Message == "" { - return e.error.Error() - } - return e.Message -} - -// InnerError returns the underlying error. This could be a Go error or another wrappedError. -func (e wrappedError) InnerError() error { - return e.error -} - // Set sets the value for the key in the context. func (e wrappedError) Set(key string, val interface{}) { e.context[key] = val @@ -363,21 +362,12 @@ func (e wrappedError) Context() map[string]interface{} { return e.context } -// Stack returns the stack. -func (e wrappedError) Stack() []byte { - return e.stack -} - // Definitions for IsFatalError() type fatalError struct { errorWrapper } -func (e fatalError) InnerError() error { - return e.errorWrapper -} - func (e fatalError) Fatal() bool { return true } @@ -392,10 +382,6 @@ type notImplementedError struct { errorWrapper } -func (e notImplementedError) InnerError() error { - return e.errorWrapper -} - func (e notImplementedError) NotImplemented() bool { return true } @@ -410,10 +396,6 @@ type authError struct { errorWrapper } -func (e authError) InnerError() error { - return e.errorWrapper -} - func (e authError) AuthError() bool { return true } @@ -428,10 +410,6 @@ type invalidPointerError struct { errorWrapper } -func (e invalidPointerError) InnerError() error { - return e.errorWrapper -} - func (e invalidPointerError) InvalidPointer() bool { return true } @@ -446,10 +424,6 @@ type invalidRepoError struct { errorWrapper } -func (e invalidRepoError) InnerError() error { - return e.errorWrapper -} - func (e invalidRepoError) InvalidRepo() bool { return true } @@ -464,10 +438,6 @@ type smudgeError struct { errorWrapper } -func (e smudgeError) InnerError() error { - return e.errorWrapper -} - func (e smudgeError) SmudgeError() bool { return true } @@ -485,10 +455,6 @@ type cleanPointerError struct { errorWrapper } -func (e cleanPointerError) InnerError() error { - return e.errorWrapper -} - func (e cleanPointerError) CleanPointerError() bool { return true } @@ -506,10 +472,6 @@ type notAPointerError struct { errorWrapper } -func (e notAPointerError) InnerError() error { - return e.errorWrapper -} - func (e notAPointerError) NotAPointerError() bool { return true } @@ -521,11 +483,8 @@ func NewNotAPointerError(err error) error { type badPointerKeyError struct { Expected string Actual string - errorWrapper -} -func (e badPointerKeyError) InnerError() error { - return e.errorWrapper + errorWrapper } func (e badPointerKeyError) BadPointerKeyError() bool { @@ -543,10 +502,6 @@ type downloadDeclinedError struct { errorWrapper } -func (e downloadDeclinedError) InnerError() error { - return e.errorWrapper -} - func (e downloadDeclinedError) DownloadDeclinedError() bool { return true } @@ -561,10 +516,6 @@ type retriableError struct { errorWrapper } -func (e retriableError) InnerError() error { - return e.errorWrapper -} - func (e retriableError) RetriableError() bool { return true } diff --git a/errutil/errors_test.go b/errutil/errors_test.go index 45b93cc4..0ec123e2 100644 --- a/errutil/errors_test.go +++ b/errutil/errors_test.go @@ -85,27 +85,3 @@ func TestStack(t *testing.T) { t.Error("expected to get a stack from a wrapped error") } } - -func TestGetInnerError(t *testing.T) { - i := errors.New("inner") - err := GetInnerError(newWrappedError(i, "wrapped")) - if err == nil { - t.Fatal("No inner error found") - } - - if msg := err.Error(); msg != "inner" { - t.Errorf("bad inner error: %q", msg) - } -} - -func TestGetNestedInnerError(t *testing.T) { - i := errors.New("inner") - err := GetInnerError(newWrappedError(newWrappedError(i, "wrapped 2"), "wrapped")) - if err == nil { - t.Fatal("No inner error found") - } - - if msg := err.Error(); msg != "inner" { - t.Errorf("bad inner error: %q", msg) - } -}