From 5f01bd7abdd39b4d8c701c8a73f3c3e49fcd70b9 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 12 Mar 2014 15:49:11 -0700 Subject: [PATCH 1/7] add branch iterator / remove useless repo from reference iterator --- branch.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ branch_test.go | 28 +++++++++++++++++++++++++ reference.go | 7 +++---- 3 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 branch_test.go diff --git a/branch.go b/branch.go index aee23e4..a11f948 100644 --- a/branch.go +++ b/branch.go @@ -23,6 +23,61 @@ type Branch struct { Reference } +type BranchIterator struct { + ptr *C.git_branch_iterator +} + +func newBranchIteratorFromC(ptr *C.git_branch_iterator) *BranchIterator { + i := &BranchIterator{ptr: ptr} + runtime.SetFinalizer(i, (*BranchIterator).Free) + return i +} + +func (i *BranchIterator) Next() (*Reference, error) { + ref, _, err := i.NextWithType() + return ref, err +} + +func (i *BranchIterator) NextWithType() (*Reference, BranchType, error) { + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + var refPtr *C.git_reference + var refType C.git_branch_t + + ecode := C.git_branch_next(&refPtr, &refType, i.ptr) + + if ecode == C.GIT_ITEROVER { + return nil, BranchLocal, ErrIterOver + } else if ecode < 0 { + return nil, BranchLocal, MakeGitError(ecode) + } + + return newReferenceFromC(refPtr), BranchType(refType), nil +} + +func (i *BranchIterator) Free() { + runtime.SetFinalizer(i, nil) + C.git_branch_iterator_free(i.ptr) +} + +func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, error) { + + refType := C.git_branch_t(flags) + var ptr *C.git_branch_iterator + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_branch_iterator_new(&ptr, repo.ptr, refType) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + + return newBranchIteratorFromC(ptr), nil +} + func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Reference, error) { ref := new(Reference) diff --git a/branch_test.go b/branch_test.go new file mode 100644 index 0000000..e95c877 --- /dev/null +++ b/branch_test.go @@ -0,0 +1,28 @@ +package git + +import ( + "testing" +) + +func Test_List_Branches(t *testing.T) { + + repo := createTestRepo(t) + seedTestRepo(t, repo) + + i, err := repo.NewBranchIterator(BranchLocal) + checkFatal(t, err) + + ref, err := i.Next() + checkFatal(t, err) + if ref.Name() != "refs/heads/master" { + t.Fatalf("expected refs/heads/master, not %v", ref.Name()) + } + ref, err = i.Next() + if ref != nil { + t.Fatal("expected nil") + } + + if err != ErrIterOver { + t.Fatal("expected iterover") + } +} diff --git a/reference.go b/reference.go index d246c55..5722db2 100644 --- a/reference.go +++ b/reference.go @@ -186,8 +186,7 @@ func (v *Reference) Free() { } type ReferenceIterator struct { - ptr *C.git_reference_iterator - repo *Repository + ptr *C.git_reference_iterator } // NewReferenceIterator creates a new iterator over reference names @@ -202,7 +201,7 @@ func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { return nil, MakeGitError(ret) } - iter := &ReferenceIterator{repo: repo, ptr: ptr} + iter := &ReferenceIterator{ptr: ptr} runtime.SetFinalizer(iter, (*ReferenceIterator).Free) return iter, nil } @@ -223,7 +222,7 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterato return nil, MakeGitError(ret) } - iter := &ReferenceIterator{repo: repo, ptr: ptr} + iter := &ReferenceIterator{ptr: ptr} runtime.SetFinalizer(iter, (*ReferenceIterator).Free) return iter, nil } -- 2.45.2 From 006286edb75849a38a33cfbe341d8c92de0e119d Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 19 Mar 2014 00:19:02 -0700 Subject: [PATCH 2/7] remove Branch struct, unify reference iterators --- branch.go | 68 ++++++++++++++++++++++++----------------------- branch_test.go | 21 ++++++++++++++- reference.go | 40 ++++++++++++++++------------ reference_test.go | 6 ++--- 4 files changed, 81 insertions(+), 54 deletions(-) diff --git a/branch.go b/branch.go index a11f948..6c6c3bc 100644 --- a/branch.go +++ b/branch.go @@ -19,26 +19,27 @@ const ( BranchRemote = C.GIT_BRANCH_REMOTE ) -type Branch struct { - Reference -} - -type BranchIterator struct { +type branchIterator struct { ptr *C.git_branch_iterator } -func newBranchIteratorFromC(ptr *C.git_branch_iterator) *BranchIterator { - i := &BranchIterator{ptr: ptr} - runtime.SetFinalizer(i, (*BranchIterator).Free) +func newBranchIteratorFromC(ptr *C.git_branch_iterator) ReferenceIterator { + i := &branchIterator{ptr: ptr} + runtime.SetFinalizer(i, (*branchIterator).Free) return i } -func (i *BranchIterator) Next() (*Reference, error) { - ref, _, err := i.NextWithType() - return ref, err +func (i *branchIterator) NextName() (string, error) { + ref, err := i.Next() + if err != nil { + return "", err + } + defer ref.Free() + + return ref.Name(), err } -func (i *BranchIterator) NextWithType() (*Reference, BranchType, error) { +func (i *branchIterator) Next() (*Reference, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -49,20 +50,20 @@ func (i *BranchIterator) NextWithType() (*Reference, BranchType, error) { ecode := C.git_branch_next(&refPtr, &refType, i.ptr) if ecode == C.GIT_ITEROVER { - return nil, BranchLocal, ErrIterOver + return nil, ErrIterOver } else if ecode < 0 { - return nil, BranchLocal, MakeGitError(ecode) + return nil, MakeGitError(ecode) } - return newReferenceFromC(refPtr), BranchType(refType), nil + return newReferenceFromC(refPtr), nil } -func (i *BranchIterator) Free() { +func (i *branchIterator) Free() { runtime.SetFinalizer(i, nil) C.git_branch_iterator_free(i.ptr) } -func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, error) { +func (repo *Repository) NewBranchIterator(flags BranchType) (ReferenceIterator, error) { refType := C.git_branch_t(flags) var ptr *C.git_branch_iterator @@ -105,7 +106,7 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo return ref, nil } -func (b *Branch) Delete() error { +func (b *Reference) DeleteBranch() error { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -116,8 +117,8 @@ func (b *Branch) Delete() error { return nil } -func (b *Branch) Move(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) { - newBranch := new(Branch) +func (b *Reference) MoveBranch(newBranchName string, force bool, signature *Signature, msg string) (*Reference, error) { + var ptr *C.git_reference cNewBranchName := C.CString(newBranchName) cForce := cbool(force) @@ -135,14 +136,14 @@ func (b *Branch) Move(newBranchName string, force bool, signature *Signature, ms runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_move(&newBranch.ptr, b.ptr, cNewBranchName, cForce, cSignature, cmsg) + ret := C.git_branch_move(&ptr, b.ptr, cNewBranchName, cForce, cSignature, cmsg) if ret < 0 { return nil, MakeGitError(ret) } - return newBranch, nil + return newReferenceFromC(ptr), nil } -func (b *Branch) IsHead() (bool, error) { +func (b *Reference) IsBranchHead() (bool, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -158,21 +159,22 @@ func (b *Branch) IsHead() (bool, error) { } -func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, error) { - branch := new(Branch) +func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Reference, error) { + var ptr *C.git_reference + cName := C.CString(branchName) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_lookup(&branch.ptr, repo.ptr, cName, C.git_branch_t(bt)) + ret := C.git_branch_lookup(&ptr, repo.ptr, cName, C.git_branch_t(bt)) if ret < 0 { return nil, MakeGitError(ret) } - return branch, nil + return newReferenceFromC(ptr), nil } -func (b *Branch) Name() (string, error) { +func (b *Reference) BranchName() (string, error) { var cName *C.char defer C.free(unsafe.Pointer(cName)) @@ -204,7 +206,7 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { return C.GoString(nameBuf.ptr), nil } -func (b *Branch) SetUpstream(upstreamName string) error { +func (b *Reference) SetUpstream(upstreamName string) error { cName := C.CString(upstreamName) runtime.LockOSThread() @@ -217,17 +219,17 @@ func (b *Branch) SetUpstream(upstreamName string) error { return nil } -func (b *Branch) Upstream() (*Branch, error) { - upstream := new(Branch) +func (b *Reference) Upstream() (*Reference, error) { + var ptr *C.git_reference runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_upstream(&upstream.ptr, b.ptr) + ret := C.git_branch_upstream(&ptr, b.ptr) if ret < 0 { return nil, MakeGitError(ret) } - return upstream, nil + return newReferenceFromC(ptr), nil } func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) { diff --git a/branch_test.go b/branch_test.go index e95c877..7db509b 100644 --- a/branch_test.go +++ b/branch_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func Test_List_Branches(t *testing.T) { +func TestBranchIterator(t *testing.T) { repo := createTestRepo(t) seedTestRepo(t, repo) @@ -25,4 +25,23 @@ func Test_List_Branches(t *testing.T) { if err != ErrIterOver { t.Fatal("expected iterover") } + + // test channel iterator + + i, err = repo.NewBranchIterator(BranchLocal) + checkFatal(t, err) + + list := make([]string, 0) + for ref := range ReferenceNameIteratorChannel(i) { + list = append(list, ref) + } + + if len(list) != 1 { + t.Fatal("expected single match") + } + + if list[0] != "refs/heads/master" { + t.Fatal("expected refs/heads/master") + } + } diff --git a/reference.go b/reference.go index 5722db2..7d28115 100644 --- a/reference.go +++ b/reference.go @@ -185,12 +185,18 @@ func (v *Reference) Free() { C.git_reference_free(v.ptr) } -type ReferenceIterator struct { +type ReferenceIterator interface { + Next() (*Reference, error) + NextName() (string, error) + Free() +} + +type gitReferenceIterator struct { ptr *C.git_reference_iterator } // NewReferenceIterator creates a new iterator over reference names -func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { +func (repo *Repository) NewReferenceIterator() (ReferenceIterator, error) { var ptr *C.git_reference_iterator runtime.LockOSThread() @@ -201,15 +207,15 @@ func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { return nil, MakeGitError(ret) } - iter := &ReferenceIterator{ptr: ptr} - runtime.SetFinalizer(iter, (*ReferenceIterator).Free) + iter := &gitReferenceIterator{ptr: ptr} + runtime.SetFinalizer(iter, (*gitReferenceIterator).Free) return iter, nil } // NewReferenceIteratorGlob creates an iterator over reference names // that match the speicified glob. The glob is of the usual fnmatch // type. -func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterator, error) { +func (repo *Repository) NewReferenceIteratorGlob(glob string) (ReferenceIterator, error) { cstr := C.CString(glob) defer C.free(unsafe.Pointer(cstr)) var ptr *C.git_reference_iterator @@ -222,14 +228,14 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterato return nil, MakeGitError(ret) } - iter := &ReferenceIterator{ptr: ptr} - runtime.SetFinalizer(iter, (*ReferenceIterator).Free) + iter := &gitReferenceIterator{ptr: ptr} + runtime.SetFinalizer(iter, (*gitReferenceIterator).Free) return iter, nil } // NextName retrieves the next reference name. If the iteration is over, // the returned error is git.ErrIterOver -func (v *ReferenceIterator) NextName() (string, error) { +func (v *gitReferenceIterator) NextName() (string, error) { var ptr *C.char runtime.LockOSThread() @@ -249,7 +255,7 @@ func (v *ReferenceIterator) NextName() (string, error) { // Create a channel from the iterator. You can use range on the // returned channel to iterate over all the references names. The channel // will be closed in case any error is found. -func (v *ReferenceIterator) NameIter() <-chan string { +func ReferenceNameIteratorChannel(v ReferenceIterator) <-chan string { ch := make(chan string) go func() { defer close(ch) @@ -265,7 +271,7 @@ func (v *ReferenceIterator) NameIter() <-chan string { // Next retrieves the next reference. If the iterationis over, the // returned error is git.ErrIterOver -func (v *ReferenceIterator) Next() (*Reference, error) { +func (v *gitReferenceIterator) Next() (*Reference, error) { var ptr *C.git_reference ret := C.git_reference_next(&ptr, v.ptr) if ret == ITEROVER { @@ -278,10 +284,16 @@ func (v *ReferenceIterator) Next() (*Reference, error) { return newReferenceFromC(ptr), nil } +// Free the reference iterator +func (v *gitReferenceIterator) Free() { + runtime.SetFinalizer(v, nil) + C.git_reference_iterator_free(v.ptr) +} + // Create a channel from the iterator. You can use range on the // returned channel to iterate over all the references names. The channel // will be closed in case any error is found. -func (v *ReferenceIterator) Iter() <-chan *Reference { +func ReferenceIteratorChannel(v ReferenceIterator) <-chan *Reference { ch := make(chan *Reference) go func() { defer close(ch) @@ -294,9 +306,3 @@ func (v *ReferenceIterator) Iter() <-chan *Reference { return ch } - -// Free the reference iterator -func (v *ReferenceIterator) Free() { - runtime.SetFinalizer(v, nil) - C.git_reference_iterator_free(v.ptr) -} diff --git a/reference_test.go b/reference_test.go index ffa9f35..331bc74 100644 --- a/reference_test.go +++ b/reference_test.go @@ -60,7 +60,7 @@ func TestRefModification(t *testing.T) { } -func TestIterator(t *testing.T) { +func TestReferenceIterator(t *testing.T) { repo := createTestRepo(t) defer os.RemoveAll(repo.Workdir()) @@ -138,7 +138,7 @@ func TestIterator(t *testing.T) { // test the channel iteration list = []string{} iter, err = repo.NewReferenceIterator() - for name := range iter.NameIter() { + for name := range ReferenceNameIteratorChannel(iter) { list = append(list, name) } @@ -152,7 +152,7 @@ func TestIterator(t *testing.T) { } list = []string{} - for name := range iter.NameIter() { + for name := range ReferenceNameIteratorChannel(iter) { list = append(list, name) } -- 2.45.2 From 27bea93efeba771b72d7c4850067a5dc1339caa6 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 19 Mar 2014 00:36:00 -0700 Subject: [PATCH 3/7] split out name iterator --- branch_test.go | 2 +- reference.go | 10 +++++++--- reference_test.go | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/branch_test.go b/branch_test.go index 7db509b..ee65b07 100644 --- a/branch_test.go +++ b/branch_test.go @@ -32,7 +32,7 @@ func TestBranchIterator(t *testing.T) { checkFatal(t, err) list := make([]string, 0) - for ref := range ReferenceNameIteratorChannel(i) { + for ref := range NameIteratorChannel(i) { list = append(list, ref) } diff --git a/reference.go b/reference.go index 7d28115..493663a 100644 --- a/reference.go +++ b/reference.go @@ -185,12 +185,16 @@ func (v *Reference) Free() { C.git_reference_free(v.ptr) } -type ReferenceIterator interface { - Next() (*Reference, error) +type NameIterator interface { NextName() (string, error) Free() } +type ReferenceIterator interface { + NameIterator + Next() (*Reference, error) +} + type gitReferenceIterator struct { ptr *C.git_reference_iterator } @@ -255,7 +259,7 @@ func (v *gitReferenceIterator) NextName() (string, error) { // Create a channel from the iterator. You can use range on the // returned channel to iterate over all the references names. The channel // will be closed in case any error is found. -func ReferenceNameIteratorChannel(v ReferenceIterator) <-chan string { +func NameIteratorChannel(v NameIterator) <-chan string { ch := make(chan string) go func() { defer close(ch) diff --git a/reference_test.go b/reference_test.go index 331bc74..b4ff588 100644 --- a/reference_test.go +++ b/reference_test.go @@ -138,7 +138,7 @@ func TestReferenceIterator(t *testing.T) { // test the channel iteration list = []string{} iter, err = repo.NewReferenceIterator() - for name := range ReferenceNameIteratorChannel(iter) { + for name := range NameIteratorChannel(iter) { list = append(list, name) } @@ -152,7 +152,7 @@ func TestReferenceIterator(t *testing.T) { } list = []string{} - for name := range ReferenceNameIteratorChannel(iter) { + for name := range NameIteratorChannel(iter) { list = append(list, name) } -- 2.45.2 From 37b950bc90aeefac38ef611273f9590eb2cabb68 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Wed, 19 Mar 2014 20:24:19 -0700 Subject: [PATCH 4/7] various improvements to interface --- branch.go | 106 ++++++++++++++++++++++++++++++++-------------- branch_test.go | 17 ++++---- reference.go | 16 +++---- reference_test.go | 4 +- 4 files changed, 93 insertions(+), 50 deletions(-) diff --git a/branch.go b/branch.go index 6c6c3bc..76f7bf0 100644 --- a/branch.go +++ b/branch.go @@ -19,27 +19,44 @@ const ( BranchRemote = C.GIT_BRANCH_REMOTE ) -type branchIterator struct { - ptr *C.git_branch_iterator +type Branch struct { + *Reference } -func newBranchIteratorFromC(ptr *C.git_branch_iterator) ReferenceIterator { - i := &branchIterator{ptr: ptr} +func (r *Reference) Branch() *Branch { + return &Branch{Reference: r} +} + +type branchIterator struct { + ptr *C.git_branch_iterator + repo *Repository +} + +type BranchIterator interface { + ReferenceIterator + NextBranch() (BranchInfo, error) +} + +type BranchInfo struct { + Branch *Branch + Type BranchType +} + +func newBranchIteratorFromC(repo *Repository, ptr *C.git_branch_iterator) BranchIterator { + i := &branchIterator{repo: repo, ptr: ptr} runtime.SetFinalizer(i, (*branchIterator).Free) return i } func (i *branchIterator) NextName() (string, error) { - ref, err := i.Next() + b, err := i.NextBranch() if err != nil { return "", err } - defer ref.Free() - - return ref.Name(), err + return b.Branch.Name() } -func (i *branchIterator) Next() (*Reference, error) { +func (i *branchIterator) NextBranch() (BranchInfo, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -50,12 +67,22 @@ func (i *branchIterator) Next() (*Reference, error) { ecode := C.git_branch_next(&refPtr, &refType, i.ptr) if ecode == C.GIT_ITEROVER { - return nil, ErrIterOver + return BranchInfo{}, ErrIterOver } else if ecode < 0 { - return nil, MakeGitError(ecode) + return BranchInfo{}, MakeGitError(ecode) } - return newReferenceFromC(refPtr), nil + branch := newReferenceFromC(refPtr).Branch() + + return BranchInfo{branch, BranchType(refType)}, nil +} + +func (i *branchIterator) NextReference() (*Reference, error) { + b, err := i.NextBranch() + if err != nil { + return nil, err + } + return b.Branch.Reference, err } func (i *branchIterator) Free() { @@ -63,7 +90,7 @@ func (i *branchIterator) Free() { C.git_branch_iterator_free(i.ptr) } -func (repo *Repository) NewBranchIterator(flags BranchType) (ReferenceIterator, error) { +func (repo *Repository) NewBranchIterator(flags BranchType) (BranchIterator, error) { refType := C.git_branch_t(flags) var ptr *C.git_branch_iterator @@ -76,10 +103,10 @@ func (repo *Repository) NewBranchIterator(flags BranchType) (ReferenceIterator, return nil, MakeGitError(ecode) } - return newBranchIteratorFromC(ptr), nil + return newBranchIteratorFromC(repo, ptr), nil } -func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Reference, error) { +func (repo *Repository) CreateBranch(branchName string, target *Commit, force bool, signature *Signature, msg string) (*Branch, error) { ref := new(Reference) cBranchName := C.CString(branchName) @@ -103,21 +130,21 @@ func (repo *Repository) CreateBranch(branchName string, target *Commit, force bo if ret < 0 { return nil, MakeGitError(ret) } - return ref, nil + return ref.Branch(), nil } -func (b *Reference) DeleteBranch() error { +func (b *Branch) Delete() error { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_delete(b.ptr) + ret := C.git_branch_delete(b.Reference.ptr) if ret < 0 { return MakeGitError(ret) } return nil } -func (b *Reference) MoveBranch(newBranchName string, force bool, signature *Signature, msg string) (*Reference, error) { +func (b *Branch) MoveBranch(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) { var ptr *C.git_reference cNewBranchName := C.CString(newBranchName) cForce := cbool(force) @@ -136,19 +163,19 @@ func (b *Reference) MoveBranch(newBranchName string, force bool, signature *Sign runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_move(&ptr, b.ptr, cNewBranchName, cForce, cSignature, cmsg) + ret := C.git_branch_move(&ptr, b.Reference.ptr, cNewBranchName, cForce, cSignature, cmsg) if ret < 0 { return nil, MakeGitError(ret) } - return newReferenceFromC(ptr), nil + return newReferenceFromC(ptr).Branch(), nil } -func (b *Reference) IsBranchHead() (bool, error) { +func (b *Branch) IsHead() (bool, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_is_head(b.ptr) + ret := C.git_branch_is_head(b.Reference.ptr) switch ret { case 1: return true, nil @@ -159,7 +186,7 @@ func (b *Reference) IsBranchHead() (bool, error) { } -func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Reference, error) { +func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Branch, error) { var ptr *C.git_reference cName := C.CString(branchName) @@ -171,17 +198,17 @@ func (repo *Repository) LookupBranch(branchName string, bt BranchType) (*Referen if ret < 0 { return nil, MakeGitError(ret) } - return newReferenceFromC(ptr), nil + return newReferenceFromC(ptr).Branch(), nil } -func (b *Reference) BranchName() (string, error) { +func (b *Branch) Name() (string, error) { var cName *C.char defer C.free(unsafe.Pointer(cName)) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_name(&cName, b.ptr) + ret := C.git_branch_name(&cName, b.Reference.ptr) if ret < 0 { return "", MakeGitError(ret) } @@ -206,26 +233,26 @@ func (repo *Repository) RemoteName(canonicalBranchName string) (string, error) { return C.GoString(nameBuf.ptr), nil } -func (b *Reference) SetUpstream(upstreamName string) error { +func (b *Branch) SetUpstream(upstreamName string) error { cName := C.CString(upstreamName) runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_set_upstream(b.ptr, cName) + ret := C.git_branch_set_upstream(b.Reference.ptr, cName) if ret < 0 { return MakeGitError(ret) } return nil } -func (b *Reference) Upstream() (*Reference, error) { +func (b *Branch) Upstream() (*Reference, error) { var ptr *C.git_reference runtime.LockOSThread() defer runtime.UnlockOSThread() - ret := C.git_branch_upstream(&ptr, b.ptr) + ret := C.git_branch_upstream(&ptr, b.Reference.ptr) if ret < 0 { return nil, MakeGitError(ret) } @@ -248,3 +275,20 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) return C.GoString(nameBuf.ptr), nil } + +// Create a channel from the iterator. You can use range on the +// returned channel to iterate over all the branches. The channel +// will be closed in case any error is found. +func BranchIteratorChannel(v BranchIterator) <-chan BranchInfo { + ch := make(chan BranchInfo) + go func() { + defer close(ch) + b, err := v.NextBranch() + for err == nil { + ch <- b + b, err = v.NextBranch() + } + }() + + return ch +} diff --git a/branch_test.go b/branch_test.go index ee65b07..6c4a037 100644 --- a/branch_test.go +++ b/branch_test.go @@ -12,16 +12,15 @@ func TestBranchIterator(t *testing.T) { i, err := repo.NewBranchIterator(BranchLocal) checkFatal(t, err) - ref, err := i.Next() + b, err := i.NextBranch() checkFatal(t, err) - if ref.Name() != "refs/heads/master" { - t.Fatalf("expected refs/heads/master, not %v", ref.Name()) + if name, _ := b.Branch.Name(); name != "master" { + t.Fatalf("expected master") } - ref, err = i.Next() - if ref != nil { - t.Fatal("expected nil") + if b.Type != BranchLocal { + t.Fatalf("expected BranchLocal, not %v", t) } - + b, err = i.NextBranch() if err != ErrIterOver { t.Fatal("expected iterover") } @@ -40,8 +39,8 @@ func TestBranchIterator(t *testing.T) { t.Fatal("expected single match") } - if list[0] != "refs/heads/master" { - t.Fatal("expected refs/heads/master") + if list[0] != "master" { + t.Fatal("expected master") } } diff --git a/reference.go b/reference.go index 493663a..a04d97a 100644 --- a/reference.go +++ b/reference.go @@ -22,9 +22,8 @@ type Reference struct { } func newReferenceFromC(ptr *C.git_reference) *Reference { - ref := &Reference{ptr} + ref := &Reference{ptr: ptr} runtime.SetFinalizer(ref, (*Reference).Free) - return ref } @@ -192,11 +191,12 @@ type NameIterator interface { type ReferenceIterator interface { NameIterator - Next() (*Reference, error) + NextReference() (*Reference, error) } type gitReferenceIterator struct { - ptr *C.git_reference_iterator + ptr *C.git_reference_iterator + repo *Repository } // NewReferenceIterator creates a new iterator over reference names @@ -211,7 +211,7 @@ func (repo *Repository) NewReferenceIterator() (ReferenceIterator, error) { return nil, MakeGitError(ret) } - iter := &gitReferenceIterator{ptr: ptr} + iter := &gitReferenceIterator{ptr: ptr, repo: repo} runtime.SetFinalizer(iter, (*gitReferenceIterator).Free) return iter, nil } @@ -275,7 +275,7 @@ func NameIteratorChannel(v NameIterator) <-chan string { // Next retrieves the next reference. If the iterationis over, the // returned error is git.ErrIterOver -func (v *gitReferenceIterator) Next() (*Reference, error) { +func (v *gitReferenceIterator) NextReference() (*Reference, error) { var ptr *C.git_reference ret := C.git_reference_next(&ptr, v.ptr) if ret == ITEROVER { @@ -301,10 +301,10 @@ func ReferenceIteratorChannel(v ReferenceIterator) <-chan *Reference { ch := make(chan *Reference) go func() { defer close(ch) - name, err := v.Next() + name, err := v.NextReference() for err == nil { ch <- name - name, err = v.Next() + name, err = v.NextReference() } }() diff --git a/reference_test.go b/reference_test.go index b4ff588..911263a 100644 --- a/reference_test.go +++ b/reference_test.go @@ -122,10 +122,10 @@ func TestReferenceIterator(t *testing.T) { iter, err = repo.NewReferenceIterator() checkFatal(t, err) count := 0 - _, err = iter.Next() + _, err = iter.NextReference() for err == nil { count++ - _, err = iter.Next() + _, err = iter.NextReference() } if err != ErrIterOver { t.Fatal("Iteration not over") -- 2.45.2 From 5590078e6ff04be425b4a833adb44a0845c0b52f Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Thu, 20 Mar 2014 01:27:03 -0700 Subject: [PATCH 5/7] remove channel based iteration for branch / ref. Add ReferenceNameIterator. All iterators use Next(). Remove interfaces. --- branch.go | 60 ++++++-------------------------- branch_test.go | 28 +++------------ reference.go | 89 +++++++++++++++++++---------------------------- reference_test.go | 31 +++-------------- 4 files changed, 55 insertions(+), 153 deletions(-) diff --git a/branch.go b/branch.go index 76f7bf0..bb01f91 100644 --- a/branch.go +++ b/branch.go @@ -27,36 +27,23 @@ func (r *Reference) Branch() *Branch { return &Branch{Reference: r} } -type branchIterator struct { +type BranchIterator struct { ptr *C.git_branch_iterator repo *Repository } -type BranchIterator interface { - ReferenceIterator - NextBranch() (BranchInfo, error) -} - type BranchInfo struct { Branch *Branch Type BranchType } -func newBranchIteratorFromC(repo *Repository, ptr *C.git_branch_iterator) BranchIterator { - i := &branchIterator{repo: repo, ptr: ptr} - runtime.SetFinalizer(i, (*branchIterator).Free) +func newBranchIteratorFromC(repo *Repository, ptr *C.git_branch_iterator) *BranchIterator { + i := &BranchIterator{repo: repo, ptr: ptr} + runtime.SetFinalizer(i, (*BranchIterator).Free) return i } -func (i *branchIterator) NextName() (string, error) { - b, err := i.NextBranch() - if err != nil { - return "", err - } - return b.Branch.Name() -} - -func (i *branchIterator) NextBranch() (BranchInfo, error) { +func (i *BranchIterator) Next() (*Branch, BranchType, error) { runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -67,30 +54,22 @@ func (i *branchIterator) NextBranch() (BranchInfo, error) { ecode := C.git_branch_next(&refPtr, &refType, i.ptr) if ecode == C.GIT_ITEROVER { - return BranchInfo{}, ErrIterOver + return nil, BranchLocal, ErrIterOver } else if ecode < 0 { - return BranchInfo{}, MakeGitError(ecode) + return nil, BranchLocal, MakeGitError(ecode) } branch := newReferenceFromC(refPtr).Branch() - return BranchInfo{branch, BranchType(refType)}, nil + return branch, BranchType(refType), nil } -func (i *branchIterator) NextReference() (*Reference, error) { - b, err := i.NextBranch() - if err != nil { - return nil, err - } - return b.Branch.Reference, err -} - -func (i *branchIterator) Free() { +func (i *BranchIterator) Free() { runtime.SetFinalizer(i, nil) C.git_branch_iterator_free(i.ptr) } -func (repo *Repository) NewBranchIterator(flags BranchType) (BranchIterator, error) { +func (repo *Repository) NewBranchIterator(flags BranchType) (*BranchIterator, error) { refType := C.git_branch_t(flags) var ptr *C.git_branch_iterator @@ -144,7 +123,7 @@ func (b *Branch) Delete() error { return nil } -func (b *Branch) MoveBranch(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) { +func (b *Branch) Move(newBranchName string, force bool, signature *Signature, msg string) (*Branch, error) { var ptr *C.git_reference cNewBranchName := C.CString(newBranchName) cForce := cbool(force) @@ -275,20 +254,3 @@ func (repo *Repository) UpstreamName(canonicalBranchName string) (string, error) return C.GoString(nameBuf.ptr), nil } - -// Create a channel from the iterator. You can use range on the -// returned channel to iterate over all the branches. The channel -// will be closed in case any error is found. -func BranchIteratorChannel(v BranchIterator) <-chan BranchInfo { - ch := make(chan BranchInfo) - go func() { - defer close(ch) - b, err := v.NextBranch() - for err == nil { - ch <- b - b, err = v.NextBranch() - } - }() - - return ch -} diff --git a/branch_test.go b/branch_test.go index 6c4a037..2b168f5 100644 --- a/branch_test.go +++ b/branch_test.go @@ -12,35 +12,15 @@ func TestBranchIterator(t *testing.T) { i, err := repo.NewBranchIterator(BranchLocal) checkFatal(t, err) - b, err := i.NextBranch() + b, bt, err := i.Next() checkFatal(t, err) - if name, _ := b.Branch.Name(); name != "master" { + if name, _ := b.Name(); name != "master" { t.Fatalf("expected master") - } - if b.Type != BranchLocal { + } else if bt != BranchLocal { t.Fatalf("expected BranchLocal, not %v", t) } - b, err = i.NextBranch() + b, bt, err = i.Next() if err != ErrIterOver { t.Fatal("expected iterover") } - - // test channel iterator - - i, err = repo.NewBranchIterator(BranchLocal) - checkFatal(t, err) - - list := make([]string, 0) - for ref := range NameIteratorChannel(i) { - list = append(list, ref) - } - - if len(list) != 1 { - t.Fatal("expected single match") - } - - if list[0] != "master" { - t.Fatal("expected master") - } - } diff --git a/reference.go b/reference.go index a04d97a..58d48c0 100644 --- a/reference.go +++ b/reference.go @@ -184,23 +184,17 @@ func (v *Reference) Free() { C.git_reference_free(v.ptr) } -type NameIterator interface { - NextName() (string, error) - Free() -} - -type ReferenceIterator interface { - NameIterator - NextReference() (*Reference, error) -} - -type gitReferenceIterator struct { +type ReferenceIterator struct { ptr *C.git_reference_iterator repo *Repository } +type ReferenceNameIterator struct { + *ReferenceIterator +} + // NewReferenceIterator creates a new iterator over reference names -func (repo *Repository) NewReferenceIterator() (ReferenceIterator, error) { +func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { var ptr *C.git_reference_iterator runtime.LockOSThread() @@ -211,15 +205,32 @@ func (repo *Repository) NewReferenceIterator() (ReferenceIterator, error) { return nil, MakeGitError(ret) } - iter := &gitReferenceIterator{ptr: ptr, repo: repo} - runtime.SetFinalizer(iter, (*gitReferenceIterator).Free) + iter := &ReferenceIterator{ptr: ptr, repo: repo} + runtime.SetFinalizer(iter, (*ReferenceIterator).Free) + return iter, nil +} + +// NewReferenceIterator creates a new bane iterator over reference names +func (repo *Repository) NewReferenceNameIterator() (*ReferenceIterator, error) { + var ptr *C.git_reference_iterator + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_reference_iterator_new(&ptr, repo.ptr) + if ret < 0 { + return nil, MakeGitError(ret) + } + + iter := &ReferenceIterator{ptr: ptr, repo: repo} + runtime.SetFinalizer(iter, (*ReferenceIterator).Free) return iter, nil } // NewReferenceIteratorGlob creates an iterator over reference names // that match the speicified glob. The glob is of the usual fnmatch // type. -func (repo *Repository) NewReferenceIteratorGlob(glob string) (ReferenceIterator, error) { +func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterator, error) { cstr := C.CString(glob) defer C.free(unsafe.Pointer(cstr)) var ptr *C.git_reference_iterator @@ -232,14 +243,18 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (ReferenceIterator return nil, MakeGitError(ret) } - iter := &gitReferenceIterator{ptr: ptr} - runtime.SetFinalizer(iter, (*gitReferenceIterator).Free) + iter := &ReferenceIterator{ptr: ptr} + runtime.SetFinalizer(iter, (*ReferenceIterator).Free) return iter, nil } +func (i *ReferenceIterator) Names() *ReferenceNameIterator { + return &ReferenceNameIterator{i} +} + // NextName retrieves the next reference name. If the iteration is over, // the returned error is git.ErrIterOver -func (v *gitReferenceIterator) NextName() (string, error) { +func (v *ReferenceNameIterator) Next() (string, error) { var ptr *C.char runtime.LockOSThread() @@ -256,26 +271,9 @@ func (v *gitReferenceIterator) NextName() (string, error) { return C.GoString(ptr), nil } -// Create a channel from the iterator. You can use range on the -// returned channel to iterate over all the references names. The channel -// will be closed in case any error is found. -func NameIteratorChannel(v NameIterator) <-chan string { - ch := make(chan string) - go func() { - defer close(ch) - name, err := v.NextName() - for err == nil { - ch <- name - name, err = v.NextName() - } - }() - - return ch -} - // Next retrieves the next reference. If the iterationis over, the // returned error is git.ErrIterOver -func (v *gitReferenceIterator) NextReference() (*Reference, error) { +func (v *ReferenceIterator) Next() (*Reference, error) { var ptr *C.git_reference ret := C.git_reference_next(&ptr, v.ptr) if ret == ITEROVER { @@ -289,24 +287,7 @@ func (v *gitReferenceIterator) NextReference() (*Reference, error) { } // Free the reference iterator -func (v *gitReferenceIterator) Free() { +func (v *ReferenceIterator) Free() { runtime.SetFinalizer(v, nil) C.git_reference_iterator_free(v.ptr) } - -// Create a channel from the iterator. You can use range on the -// returned channel to iterate over all the references names. The channel -// will be closed in case any error is found. -func ReferenceIteratorChannel(v ReferenceIterator) <-chan *Reference { - ch := make(chan *Reference) - go func() { - defer close(ch) - name, err := v.NextReference() - for err == nil { - ch <- name - name, err = v.NextReference() - } - }() - - return ch -} diff --git a/reference_test.go b/reference_test.go index 911263a..bc970bf 100644 --- a/reference_test.go +++ b/reference_test.go @@ -106,10 +106,11 @@ func TestReferenceIterator(t *testing.T) { } // test some manual iteration - name, err := iter.NextName() + nameIter := iter.Names() + name, err := nameIter.Next() for err == nil { list = append(list, name) - name, err = iter.NextName() + name, err = nameIter.Next() } if err != ErrIterOver { t.Fatal("Iteration not over") @@ -122,10 +123,10 @@ func TestReferenceIterator(t *testing.T) { iter, err = repo.NewReferenceIterator() checkFatal(t, err) count := 0 - _, err = iter.NextReference() + _, err = iter.Next() for err == nil { count++ - _, err = iter.NextReference() + _, err = iter.Next() } if err != ErrIterOver { t.Fatal("Iteration not over") @@ -135,28 +136,6 @@ func TestReferenceIterator(t *testing.T) { t.Fatalf("Wrong number of references returned %v", count) } - // test the channel iteration - list = []string{} - iter, err = repo.NewReferenceIterator() - for name := range NameIteratorChannel(iter) { - list = append(list, name) - } - - sort.Strings(list) - compareStringList(t, expected, list) - - iter, err = repo.NewReferenceIteratorGlob("refs/heads/t*") - expected = []string{ - "refs/heads/three", - "refs/heads/two", - } - - list = []string{} - for name := range NameIteratorChannel(iter) { - list = append(list, name) - } - - compareStringList(t, expected, list) } func TestUtil(t *testing.T) { -- 2.45.2 From 39f59d921b7acc0bea40e1cadb7fb7bceabfbc6e Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 4 Apr 2014 00:27:07 -0700 Subject: [PATCH 6/7] fix typo / return name iterator --- reference.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference.go b/reference.go index 58d48c0..e165f2a 100644 --- a/reference.go +++ b/reference.go @@ -210,8 +210,8 @@ func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) { return iter, nil } -// NewReferenceIterator creates a new bane iterator over reference names -func (repo *Repository) NewReferenceNameIterator() (*ReferenceIterator, error) { +// NewReferenceIterator creates a new branch iterator over reference names +func (repo *Repository) NewReferenceNameIterator() (*ReferenceNameIterator, error) { var ptr *C.git_reference_iterator runtime.LockOSThread() @@ -224,7 +224,7 @@ func (repo *Repository) NewReferenceNameIterator() (*ReferenceIterator, error) { iter := &ReferenceIterator{ptr: ptr, repo: repo} runtime.SetFinalizer(iter, (*ReferenceIterator).Free) - return iter, nil + return iter.Names(), nil } // NewReferenceIteratorGlob creates an iterator over reference names -- 2.45.2 From a7d3c5955ac9426dd57bf4d3df87ca1eba049789 Mon Sep 17 00:00:00 2001 From: Jesse Ezell Date: Fri, 4 Apr 2014 00:56:58 -0700 Subject: [PATCH 7/7] merge with improved error handling logic --- branch.go | 4 +--- branch_test.go | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/branch.go b/branch.go index a0c1dbd..af21140 100644 --- a/branch.go +++ b/branch.go @@ -53,9 +53,7 @@ func (i *BranchIterator) Next() (*Branch, BranchType, error) { ecode := C.git_branch_next(&refPtr, &refType, i.ptr) - if ecode == C.GIT_ITEROVER { - return nil, BranchLocal, ErrIterOver - } else if ecode < 0 { + if ecode < 0 { return nil, BranchLocal, MakeGitError(ecode) } diff --git a/branch_test.go b/branch_test.go index 2b168f5..44f6338 100644 --- a/branch_test.go +++ b/branch_test.go @@ -20,7 +20,7 @@ func TestBranchIterator(t *testing.T) { t.Fatalf("expected BranchLocal, not %v", t) } b, bt, err = i.Next() - if err != ErrIterOver { + if !IsErrorCode(err, ErrIterOver) { t.Fatal("expected iterover") } } -- 2.45.2