diff --git a/repository.go b/repository.go index 8cc966c..5b4e806 100644 --- a/repository.go +++ b/repository.go @@ -469,23 +469,6 @@ func (v *Repository) TreeBuilderFromTree(tree *Tree) (*TreeBuilder, error) { return bld, nil } -func (v *Repository) RevparseSingle(spec string) (Object, error) { - cspec := C.CString(spec) - defer C.free(unsafe.Pointer(cspec)) - - var ptr *C.git_object - - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - ecode := C.git_revparse_single(&ptr, v.ptr, cspec) - if ecode < 0 { - return nil, MakeGitError(ecode) - } - - return allocObject(ptr, v), nil -} - // EnsureLog ensures that there is a reflog for the given reference // name and creates an empty one if necessary. func (v *Repository) EnsureLog(name string) error { diff --git a/revparse.go b/revparse.go new file mode 100644 index 0000000..9e0070e --- /dev/null +++ b/revparse.go @@ -0,0 +1,114 @@ +package git + +/* +#include +#include + +extern void _go_git_revspec_free(git_revspec *revspec); +*/ +import "C" +import ( + "runtime" + "unsafe" +) + +type RevparseFlag int + +const ( + RevparseSingle RevparseFlag = C.GIT_REVPARSE_SINGLE + RevparseRange = C.GIT_REVPARSE_RANGE + RevparseMergeBase = C.GIT_REVPARSE_MERGE_BASE +) + +type Revspec struct { + to Object + from Object + flags RevparseFlag +} + +func (rs *Revspec) To() Object { + return rs.to +} + +func (rs *Revspec) From() Object { + return rs.from +} + +func (rs *Revspec) Flags() RevparseFlag { + return rs.flags +} + +func newRevspecFromC(ptr *C.git_revspec, repo *Repository) *Revspec { + var to Object + var from Object + + if ptr.to != nil { + to = allocObject(ptr.to, repo) + } + + if ptr.from != nil { + from = allocObject(ptr.from, repo) + } + + return &Revspec{ + to: to, + from: from, + flags: RevparseFlag(ptr.flags), + } +} + +func (r *Repository) Revparse(spec string) (*Revspec, error) { + cspec := C.CString(spec) + defer C.free(unsafe.Pointer(cspec)) + + var crevspec C.git_revspec + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_revparse(&crevspec, r.ptr, cspec) + if ecode != 0 { + return nil, MakeGitError(ecode) + } + + return newRevspecFromC(&crevspec, r), nil +} + +func (v *Repository) RevparseSingle(spec string) (Object, error) { + cspec := C.CString(spec) + defer C.free(unsafe.Pointer(cspec)) + + var ptr *C.git_object + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_revparse_single(&ptr, v.ptr, cspec) + if ecode < 0 { + return nil, MakeGitError(ecode) + } + + return allocObject(ptr, v), nil +} + +func (r *Repository) RevparseExt(spec string) (Object, *Reference, error) { + cspec := C.CString(spec) + defer C.free(unsafe.Pointer(cspec)) + + var obj *C.git_object + var ref *C.git_reference + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_revparse_ext(&obj, &ref, r.ptr, cspec) + if ecode != 0 { + return nil, nil, MakeGitError(ecode) + } + + if ref == nil { + return allocObject(obj, r), nil, nil + } + + return allocObject(obj, r), newReferenceFromC(ref, r), nil +} diff --git a/revparse_test.go b/revparse_test.go new file mode 100644 index 0000000..c046a20 --- /dev/null +++ b/revparse_test.go @@ -0,0 +1,58 @@ +package git + +import ( + "os" + "testing" +) + +func TestRevparse(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + commitId, _ := seedTestRepo(t, repo) + + revSpec, err := repo.Revparse("HEAD") + checkFatal(t, err) + + checkObject(t, revSpec.From(), commitId) +} + +func TestRevparseSingle(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + commitId, _ := seedTestRepo(t, repo) + + obj, err := repo.RevparseSingle("HEAD") + checkFatal(t, err) + + checkObject(t, obj, commitId) +} + +func TestRevparseExt(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + + _, treeId := seedTestRepo(t, repo) + + ref, err := repo.CreateReference("refs/heads/master", treeId, true, nil, "") + checkFatal(t, err) + + obj, ref, err := repo.RevparseExt("master") + checkFatal(t, err) + + checkObject(t, obj, treeId) + if ref == nil { + t.Fatalf("bad reference") + } +} + +func checkObject(t *testing.T, obj Object, id *Oid) { + if obj == nil { + t.Fatalf("bad object") + } + + if !obj.Id().Equal(id) { + t.Fatalf("bad object, expected %s, got %s", id.String(), obj.Id().String()) + } +}