Add branch iterator #66

Merged
jezell merged 9 commits from branch-iterator into master 2014-04-26 13:25:26 -05:00
7 changed files with 115 additions and 34 deletions
Showing only changes of commit fc999289a2 - Show all commits

121
git.go
View File

@ -15,14 +15,78 @@ import (
"unsafe" "unsafe"
) )
type ErrorClass int
const ( const (
ITEROVER = C.GIT_ITEROVER ErrClassNone ErrorClass = C.GITERR_NONE
EEXISTS = C.GIT_EEXISTS ErrClassNoMemory = C.GITERR_NOMEMORY
ENOTFOUND = C.GIT_ENOTFOUND 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 ( type ErrorCode int
ErrIterOver = errors.New("Iteration is over")
const (
// No error
ErrOk ErrorCode = C.GIT_OK
// Generic error
ErrGeneric = C.GIT_ERROR
// Requested object could not be found
ErrNotFound = C.GIT_ENOTFOUND
// Object exists preventing operation
ErrExists = C.GIT_EEXISTS
// More than one object matches
ErrAmbigious = C.GIT_EAMBIGUOUS
// Output buffer too short to hold data
ErrBuffs = C.GIT_EBUFS
// 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
// Operation not allowed on bare repository
ErrBareRepo = C.GIT_EBAREREPO
// HEAD refers to branch with no commits
ErrUnbornBranch = C.GIT_EUNBORNBRANCH
// Merge in progress prevented operation
ErrUnmerged = C.GIT_EUNMERGED
// Reference was not fast-forwardable
ErrNonFastForward = C.GIT_ENONFASTFORWARD
// Name/ref spec was not in a valid format
ErrInvalidSpec = C.GIT_EINVALIDSPEC
// Merge conflicts prevented operation
ErrMergeConflict = C.GIT_EMERGECONFLICT
// Lock file prevented operation
ErrLocked = C.GIT_ELOCKED
// Reference value does not match expected
ErrModified = C.GIT_EMODIFIED
// Internal only
ErrPassthrough = C.GIT_PASSTHROUGH
// Signals end of iteration with iterator
ErrIterOver = C.GIT_ITEROVER
) )
func init() { func init() {
@ -64,6 +128,10 @@ func NewOid(s string) (*Oid, error) {
return nil, error return nil, error
} }
if len(slice) != 20 {
return nil, &GitError{"Invalid Oid", ErrClassNone, ErrGeneric}
}
copy(o[:], slice[:20]) copy(o[:], slice[:20])
return o, nil return o, nil
} }
@ -124,29 +192,50 @@ func ShortenOids(ids []*Oid, minlen int) (int, error) {
} }
type GitError struct { type GitError struct {
Message string Message string
Class int Class ErrorClass
ErrorCode int Code ErrorCode
} }
func (e GitError) Error() string { func (e GitError) Error() string {
return e.Message return e.Message
} }
func IsNotExist(err error) bool { func IsErrorClass(err error, c ErrorClass) bool {
return err.(*GitError).ErrorCode == C.GIT_ENOTFOUND
if err == nil {
return false
}
if gitError, ok := err.(*GitError); ok {
return gitError.Class == c
}
return false
} }
func IsExist(err error) bool { func IsErrorCode(err error, c ErrorCode) bool {
return err.(*GitError).ErrorCode == C.GIT_EEXISTS if err == nil {
return false
}
if gitError, ok := err.(*GitError); ok {
return gitError.Code == c
}
return false
} }
func MakeGitError(errorCode C.int) error { func MakeGitError(errorCode C.int) error {
err := C.giterr_last()
if err == nil { var errMessage string
return &GitError{"No message", C.GITERR_INVALID, C.GIT_ERROR} 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 { func MakeGitError2(err int) error {

View File

@ -62,3 +62,10 @@ func TestOidZero(t *testing.T) {
t.Error("Zero Oid is not zero") 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() defer runtime.UnlockOSThread()
ecode := C.git_index_conflict_next(&cancestor, &cour, &ctheir, v.ptr) ecode := C.git_index_conflict_next(&cancestor, &cour, &ctheir, v.ptr)
if ecode == C.GIT_ITEROVER {
return IndexConflict{}, ErrIterOver
}
if ecode < 0 { if ecode < 0 {
return IndexConflict{}, MakeGitError(ecode) return IndexConflict{}, MakeGitError(ecode)
} }

View File

@ -1,7 +1,6 @@
package git package git
import ( import (
"log"
"os" "os"
"testing" "testing"
"time" "time"
@ -45,7 +44,6 @@ func Test_Push_ToRemote(t *testing.T) {
checkFatal(t, err) checkFatal(t, err)
err = push.StatusForeach(func(ref string, msg string) int { err = push.StatusForeach(func(ref string, msg string) int {
log.Printf("%s -> %s", ref, msg)
return 0 return 0
}) })
checkFatal(t, err) checkFatal(t, err)

View File

@ -261,9 +261,6 @@ func (v *ReferenceNameIterator) Next() (string, error) {
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
ret := C.git_reference_next_name(&ptr, v.ptr) ret := C.git_reference_next_name(&ptr, v.ptr)
if ret == ITEROVER {
return "", ErrIterOver
}
if ret < 0 { if ret < 0 {
return "", MakeGitError(ret) return "", MakeGitError(ret)
} }
@ -276,9 +273,6 @@ func (v *ReferenceNameIterator) Next() (string, error) {
func (v *ReferenceIterator) Next() (*Reference, error) { func (v *ReferenceIterator) Next() (*Reference, error) {
var ptr *C.git_reference var ptr *C.git_reference
ret := C.git_reference_next(&ptr, v.ptr) ret := C.git_reference_next(&ptr, v.ptr)
if ret == ITEROVER {
return nil, ErrIterOver
}
if ret < 0 { if ret < 0 {
return nil, MakeGitError(ret) return nil, MakeGitError(ret)
} }

View File

@ -112,7 +112,7 @@ func TestReferenceIterator(t *testing.T) {
list = append(list, name) list = append(list, name)
name, err = nameIter.Next() name, err = nameIter.Next()
} }
if err != ErrIterOver { if !IsErrorCode(err, ErrIterOver) {
t.Fatal("Iteration not over") t.Fatal("Iteration not over")
} }
@ -128,7 +128,7 @@ func TestReferenceIterator(t *testing.T) {
count++ count++
_, err = iter.Next() _, err = iter.Next()
} }
if err != ErrIterOver { if !IsErrorCode(err, ErrIterOver) {
t.Fatal("Iteration not over") t.Fatal("Iteration not over")
} }

View File

@ -7,7 +7,6 @@ package git
import "C" import "C"
import ( import (
"io"
"runtime" "runtime"
"unsafe" "unsafe"
) )
@ -158,8 +157,6 @@ func (v *RevWalk) Next(id *Oid) (err error) {
ret := C.git_revwalk_next(id.toC(), v.ptr) ret := C.git_revwalk_next(id.toC(), v.ptr)
switch { switch {
case ret == ITEROVER:
err = io.EOF
case ret < 0: case ret < 0:
err = MakeGitError(ret) err = MakeGitError(ret)
} }
@ -173,7 +170,7 @@ func (v *RevWalk) Iterate(fun RevWalkIterator) (err error) {
oid := new(Oid) oid := new(Oid)
for { for {
err = v.Next(oid) err = v.Next(oid)
if err == io.EOF { if IsErrorCode(err, ErrIterOver) {
return nil return nil
} }
if err != nil { if err != nil {