From b660db0a4bf82af893e7eb120c3001cecf593fa0 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 2 Apr 2014 10:31:48 -0700 Subject: [PATCH] make it possible to handle errors --- git.go | 109 +++++++++++++++++++++++++++++++++++++++------- git_test.go | 7 +++ index.go | 4 -- push_test.go | 2 - reference.go | 6 --- reference_test.go | 4 +- walk.go | 5 +-- 7 files changed, 103 insertions(+), 34 deletions(-) diff --git a/git.go b/git.go index 8159244..d6b7dc0 100644 --- a/git.go +++ b/git.go @@ -15,14 +15,66 @@ import ( "unsafe" ) +type ErrorClass int + const ( - ITEROVER = C.GIT_ITEROVER - EEXISTS = C.GIT_EEXISTS - ENOTFOUND = C.GIT_ENOTFOUND + ErrClassNone ErrorClass = C.GITERR_NONE + ErrClassNoMemory = C.GITERR_NOMEMORY + ErrClassOs = C.GITERR_OS + ErrClassInvalid = C.GITERR_INVALID + ErrClassReference = C.GITERR_REFERENCE + ErrClassZlib = C.GITERR_ZLIB + ErrClassRepository = C.GITERR_REPOSITORY + ErrClassConfig = C.GITERR_CONFIG + ErrClassRegex = C.GITERR_REGEX + ErrClassOdb = C.GITERR_ODB + ErrClassIndex = C.GITERR_INDEX + ErrClassObject = C.GITERR_OBJECT + ErrClassNet = C.GITERR_NET + ErrClassTag = C.GITERR_TAG + ErrClassTree = C.GITERR_TREE + ErrClassIndexer = C.GITERR_INDEXER + ErrClassSSL = C.GITERR_SSL + ErrClassSubmodule = C.GITERR_SUBMODULE + ErrClassThread = C.GITERR_THREAD + ErrClassStash = C.GITERR_STASH + ErrClassCheckout = C.GITERR_CHECKOUT + ErrClassFetchHead = C.GITERR_FETCHHEAD + ErrClassMerge = C.GITERR_MERGE + ErrClassSsh = C.GITERR_SSH + ErrClassFilter = C.GITERR_FILTER + ErrClassRevert = C.GITERR_REVERT + ErrClassCallback = C.GITERR_CALLBACK ) -var ( - ErrIterOver = errors.New("Iteration is over") +type ErrorCode int + +const ( + ErrOk ErrorCode = C.GIT_OK /*< No error */ + + ErrGeneric = C.GIT_ERROR /*< Generic error */ + ErrNotFound = C.GIT_ENOTFOUND /*< Requested object could not be found */ + ErrExists = C.GIT_EEXISTS /*< Object exists preventing operation */ + ErrAmbigious = C.GIT_EAMBIGUOUS /*< More than one object matches */ + ErrBuffs = C.GIT_EBUFS /*< Output buffer too short to hold data */ + + /* GIT_EUSER is a special error that is never generated by libgit2 + * code. You can return it from a callback (e.g to stop an iteration) + * to know that it was generated by the callback and not by libgit2. + */ + ErrUser = C.GIT_EUSER + + ErrBareRepo = C.GIT_EBAREREPO /*< Operation not allowed on bare repository */ + ErrUnbornBranch = C.GIT_EUNBORNBRANCH /*< HEAD refers to branch with no commits */ + ErrUnmerged = C.GIT_EUNMERGED /*< Merge in progress prevented operation */ + ErrNonFastForward = C.GIT_ENONFASTFORWARD /*< Reference was not fast-forwardable */ + ErrInvalidSpec = C.GIT_EINVALIDSPEC /*< Name/ref spec was not in a valid format */ + ErrMergeConflict = C.GIT_EMERGECONFLICT /*< Merge conflicts prevented operation */ + ErrLocked = C.GIT_ELOCKED /*< Lock file prevented operation */ + ErrModified = C.GIT_EMODIFIED /*< Reference value does not match expected */ + + ErrPassthrough = C.GIT_PASSTHROUGH /*< Internal only */ + ErrIterOver = C.GIT_ITEROVER /*< Signals end of iteration with iterator */ ) func init() { @@ -64,6 +116,10 @@ func NewOid(s string) (*Oid, error) { return nil, error } + if len(slice) != 20 { + return nil, &GitError{"Invalid Oid", ErrClassNone, ErrGeneric} + } + copy(o[:], slice[:20]) return o, nil } @@ -124,29 +180,50 @@ func ShortenOids(ids []*Oid, minlen int) (int, error) { } type GitError struct { - Message string - Class int - ErrorCode int + Message string + Class ErrorClass + Code ErrorCode } func (e GitError) Error() string { return e.Message } -func IsNotExist(err error) bool { - return err.(*GitError).ErrorCode == C.GIT_ENOTFOUND +func IsErrorClass(err error, c ErrorClass) bool { + + if err == nil { + return false + } + if gitError, ok := err.(*GitError); ok { + return gitError.Class == c + } + return false } -func IsExist(err error) bool { - return err.(*GitError).ErrorCode == C.GIT_EEXISTS +func IsErrorCode(err error, c ErrorCode) bool { + if err == nil { + return false + } + if gitError, ok := err.(*GitError); ok { + return gitError.Code == c + } + return false } func MakeGitError(errorCode C.int) error { - err := C.giterr_last() - if err == nil { - return &GitError{"No message", C.GITERR_INVALID, C.GIT_ERROR} + + var errMessage string + var errClass ErrorClass + if errorCode != ErrIterOver { + err := C.giterr_last() + if err != nil { + errMessage = C.GoString(err.message) + errClass = ErrorClass(err.klass) + } else { + errClass = ErrClassInvalid + } } - return &GitError{C.GoString(err.message), int(err.klass), int(errorCode)} + return &GitError{errMessage, errClass, ErrorCode(errorCode)} } func MakeGitError2(err int) error { diff --git a/git_test.go b/git_test.go index 6542ca0..f4515a6 100644 --- a/git_test.go +++ b/git_test.go @@ -62,3 +62,10 @@ func TestOidZero(t *testing.T) { t.Error("Zero Oid is not zero") } } + +func TestEmptyOid(t *testing.T) { + _, err := NewOid("") + if err == nil || !IsErrorCode(err, ErrGeneric) { + t.Fatal("Should have returned invalid error") + } +} diff --git a/index.go b/index.go index d3178a2..f20dc31 100644 --- a/index.go +++ b/index.go @@ -266,10 +266,6 @@ func (v *IndexConflictIterator) Next() (IndexConflict, error) { defer runtime.UnlockOSThread() ecode := C.git_index_conflict_next(&cancestor, &cour, &ctheir, v.ptr) - if ecode == C.GIT_ITEROVER { - return IndexConflict{}, ErrIterOver - } - if ecode < 0 { return IndexConflict{}, MakeGitError(ecode) } diff --git a/push_test.go b/push_test.go index c1e6a22..65f4dd2 100644 --- a/push_test.go +++ b/push_test.go @@ -1,7 +1,6 @@ package git import ( - "log" "os" "testing" "time" @@ -45,7 +44,6 @@ func Test_Push_ToRemote(t *testing.T) { checkFatal(t, err) err = push.StatusForeach(func(ref string, msg string) int { - log.Printf("%s -> %s", ref, msg) return 0 }) checkFatal(t, err) diff --git a/reference.go b/reference.go index d246c55..a7cc29e 100644 --- a/reference.go +++ b/reference.go @@ -237,9 +237,6 @@ func (v *ReferenceIterator) NextName() (string, error) { defer runtime.UnlockOSThread() ret := C.git_reference_next_name(&ptr, v.ptr) - if ret == ITEROVER { - return "", ErrIterOver - } if ret < 0 { return "", MakeGitError(ret) } @@ -269,9 +266,6 @@ func (v *ReferenceIterator) NameIter() <-chan string { func (v *ReferenceIterator) Next() (*Reference, error) { var ptr *C.git_reference ret := C.git_reference_next(&ptr, v.ptr) - if ret == ITEROVER { - return nil, ErrIterOver - } if ret < 0 { return nil, MakeGitError(ret) } diff --git a/reference_test.go b/reference_test.go index ffa9f35..c8c7262 100644 --- a/reference_test.go +++ b/reference_test.go @@ -111,7 +111,7 @@ func TestIterator(t *testing.T) { list = append(list, name) name, err = iter.NextName() } - if err != ErrIterOver { + if !IsErrorCode(err, ErrIterOver) { t.Fatal("Iteration not over") } @@ -127,7 +127,7 @@ func TestIterator(t *testing.T) { count++ _, err = iter.Next() } - if err != ErrIterOver { + if !IsErrorCode(err, ErrIterOver) { t.Fatal("Iteration not over") } diff --git a/walk.go b/walk.go index f7c147d..9e07411 100644 --- a/walk.go +++ b/walk.go @@ -7,7 +7,6 @@ package git import "C" import ( - "io" "runtime" "unsafe" ) @@ -158,8 +157,6 @@ func (v *RevWalk) Next(id *Oid) (err error) { ret := C.git_revwalk_next(id.toC(), v.ptr) switch { - case ret == ITEROVER: - err = io.EOF case ret < 0: err = MakeGitError(ret) } @@ -173,7 +170,7 @@ func (v *RevWalk) Iterate(fun RevWalkIterator) (err error) { oid := new(Oid) for { err = v.Next(oid) - if err == io.EOF { + if IsErrorCode(err, ErrIterOver) { return nil } if err != nil {