diff options
Diffstat (limited to 'reference.go')
| -rw-r--r-- | reference.go | 188 |
1 files changed, 176 insertions, 12 deletions
diff --git a/reference.go b/reference.go index 820d166..a2f1636 100644 --- a/reference.go +++ b/reference.go @@ -1,7 +1,6 @@ package git /* -#cgo pkg-config: libgit2 #include <git2.h> #include <git2/errors.h> */ @@ -11,9 +10,11 @@ import ( "unsafe" ) -var ( - SYMBOLIC = C.GIT_REF_SYMBOLIC - OID = C.GIT_REF_OID +type ReferenceType int + +const ( + ReferenceSymbolic ReferenceType = C.GIT_REF_SYMBOLIC + ReferenceOid = C.GIT_REF_OID ) type Reference struct { @@ -27,12 +28,22 @@ func newReferenceFromC(ptr *C.git_reference) *Reference { return ref } -func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) { +func (v *Reference) SetSymbolicTarget(target string, sig *Signature, msg string) (*Reference, error) { var ptr *C.git_reference + ctarget := C.CString(target) defer C.free(unsafe.Pointer(ctarget)) - ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget, csig, cmsg) if ret < 0 { return nil, LastError() } @@ -40,10 +51,19 @@ func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) { return newReferenceFromC(ptr), nil } -func (v *Reference) SetTarget(target *Oid) (*Reference, error) { +func (v *Reference) SetTarget(target *Oid, sig *Signature, msg string) (*Reference, error) { var ptr *C.git_reference - ret := C.git_reference_set_target(&ptr, v.ptr, target.toC()) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + ret := C.git_reference_set_target(&ptr, v.ptr, target.toC(), csig, cmsg) if ret < 0 { return nil, LastError() } @@ -54,6 +74,9 @@ func (v *Reference) SetTarget(target *Oid) (*Reference, error) { func (v *Reference) Resolve() (*Reference, error) { var ptr *C.git_reference + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_reference_resolve(&ptr, v.ptr) if ret < 0 { return nil, LastError() @@ -62,12 +85,21 @@ func (v *Reference) Resolve() (*Reference, error) { return newReferenceFromC(ptr), nil } -func (v *Reference) Rename(name string, force bool) (*Reference, error) { +func (v *Reference) Rename(name string, force bool, sig *Signature, msg string) (*Reference, error) { var ptr *C.git_reference cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) - ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force)) + csig := sig.toC() + defer C.free(unsafe.Pointer(csig)) + + cmsg := C.CString(msg) + defer C.free(unsafe.Pointer(cmsg)) + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force), csig, cmsg) if ret < 0 { return nil, LastError() @@ -90,6 +122,9 @@ func (v *Reference) SymbolicTarget() string { } func (v *Reference) Delete() error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + ret := C.git_reference_delete(v.ptr) if ret < 0 { @@ -103,11 +138,140 @@ func (v *Reference) Name() string { return C.GoString(C.git_reference_name(v.ptr)) } -func (v *Reference) Type() int { - return int(C.git_reference_type(v.ptr)) +func (v *Reference) Type() ReferenceType { + return ReferenceType(C.git_reference_type(v.ptr)) +} + +func (v *Reference) IsBranch() bool { + return C.git_reference_is_branch(v.ptr) == 1 +} + +func (v *Reference) IsRemote() bool { + return C.git_reference_is_remote(v.ptr) == 1 +} + +func (v *Reference) IsTag() bool { + return C.git_reference_is_tag(v.ptr) == 1 } func (v *Reference) Free() { runtime.SetFinalizer(v, nil) C.git_reference_free(v.ptr) } + +type ReferenceIterator struct { + ptr *C.git_reference_iterator + repo *Repository +} + +// NewReferenceIterator creates a new iterator over reference names +func (repo *Repository) NewReferenceIterator() (*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, LastError() + } + + iter := &ReferenceIterator{repo: repo, ptr: ptr} + 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) { + cstr := C.CString(glob) + defer C.free(unsafe.Pointer(cstr)) + var ptr *C.git_reference_iterator + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_reference_iterator_glob_new(&ptr, repo.ptr, cstr) + if ret < 0 { + return nil, LastError() + } + + iter := &ReferenceIterator{repo: repo, ptr: ptr} + runtime.SetFinalizer(iter, (*ReferenceIterator).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) { + var ptr *C.char + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ret := C.git_reference_next_name(&ptr, v.ptr) + if ret == ITEROVER { + return "", ErrIterOver + } + if ret < 0 { + return "", LastError() + } + + 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 (v *ReferenceIterator) NameIter() <-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 *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, LastError() + } + + return newReferenceFromC(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 (v *ReferenceIterator) Iter() <-chan *Reference { + ch := make(chan *Reference) + go func() { + defer close(ch) + name, err := v.Next() + for err == nil { + ch <- name + name, err = v.Next() + } + }() + + return ch +} + +// Free the reference iterator +func (v *ReferenceIterator) Free() { + runtime.SetFinalizer(v, nil) + C.git_reference_iterator_free(v.ptr) +} |
