make it possible to handle errors

This commit is contained in:
Jesse Ezell 2014-04-02 10:31:48 -07:00
parent 9cd1d129bc
commit b660db0a4b
7 changed files with 103 additions and 34 deletions

109
git.go
View File

@ -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 {

View File

@ -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")
}
}

View File

@ -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)
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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 {