Merge pull request #237 from libgit2/object-type
Move from an Object interface to a type
diff --git a/blob.go b/blob.go
index b1fc78a..16ec183 100644
--- a/blob.go
+++ b/blob.go
@@ -18,7 +18,7 @@
)
type Blob struct {
- gitObject
+ Object
cast_ptr *C.git_blob
}
diff --git a/commit.go b/commit.go
index 52f7c01..6830da3 100644
--- a/commit.go
+++ b/commit.go
@@ -14,7 +14,7 @@
// Commit
type Commit struct {
- gitObject
+ Object
cast_ptr *C.git_commit
}
@@ -37,7 +37,7 @@
return nil, MakeGitError(err)
}
- return allocObject((*C.git_object)(ptr), c.repo).(*Tree), nil
+ return allocTree(ptr, c.repo), nil
}
func (c Commit) TreeId() *Oid {
@@ -61,7 +61,7 @@
return nil
}
- return allocObject((*C.git_object)(cobj), c.repo).(*Commit)
+ return allocCommit(cobj, c.repo)
}
func (c *Commit) ParentId(n uint) *Oid {
diff --git a/describe.go b/describe.go
index c6f9a79..d75dbcb 100644
--- a/describe.go
+++ b/describe.go
@@ -127,7 +127,7 @@
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ecode := C.git_describe_commit(&resultPtr, c.gitObject.ptr, cDescribeOpts)
+ ecode := C.git_describe_commit(&resultPtr, c.ptr, cDescribeOpts)
if ecode < 0 {
return nil, MakeGitError(ecode)
}
diff --git a/index_test.go b/index_test.go
index 7c65f4f..5f6b375 100644
--- a/index_test.go
+++ b/index_test.go
@@ -32,10 +32,11 @@
ref, err := repo.Head()
checkFatal(t, err)
- obj, err := ref.Peel(ObjectTree);
+ obj, err := ref.Peel(ObjectTree)
checkFatal(t, err)
- tree := obj.(*Tree)
+ tree, err := obj.AsTree()
+ checkFatal(t, err)
idx, err := NewIndex()
checkFatal(t, err)
diff --git a/object.go b/object.go
index 6ecebf8..1981980 100644
--- a/object.go
+++ b/object.go
@@ -4,7 +4,11 @@
#include <git2.h>
*/
import "C"
-import "runtime"
+import (
+ "errors"
+ "fmt"
+ "runtime"
+)
type ObjectType int
@@ -17,15 +21,7 @@
ObjectTag ObjectType = C.GIT_OBJ_TAG
)
-type Object interface {
- Free()
- Id() *Oid
- Type() ObjectType
- Owner() *Repository
- Peel(t ObjectType) (Object, error)
-}
-
-type gitObject struct {
+type Object struct {
ptr *C.git_object
repo *Repository
}
@@ -49,23 +45,128 @@
return ""
}
-func (o gitObject) Id() *Oid {
+func (o *Object) Id() *Oid {
return newOidFromC(C.git_object_id(o.ptr))
}
-func (o gitObject) Type() ObjectType {
+func (o *Object) Type() ObjectType {
return ObjectType(C.git_object_type(o.ptr))
}
// Owner returns a weak reference to the repository which owns this
-// object
-func (o gitObject) Owner() *Repository {
+// object. This won't keep the underlying repository alive.
+func (o *Object) Owner() *Repository {
return &Repository{
ptr: C.git_object_owner(o.ptr),
}
}
-func (o *gitObject) Free() {
+func dupObject(obj *Object, kind ObjectType) (*C.git_object, error) {
+ if obj.Type() != kind {
+ return nil, errors.New(fmt.Sprintf("object is not a %v", kind))
+ }
+
+ var cobj *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if err := C.git_object_dup(&cobj, obj.ptr); err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return cobj, nil
+}
+
+func allocTree(ptr *C.git_tree, repo *Repository) *Tree {
+ tree := &Tree{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(tree, (*Tree).Free)
+
+ return tree
+}
+
+func (o *Object) AsTree() (*Tree, error) {
+ cobj, err := dupObject(o, ObjectTree)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocTree((*C.git_tree)(cobj), o.repo), nil
+}
+
+func allocCommit(ptr *C.git_commit, repo *Repository) *Commit {
+ commit := &Commit{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(commit, (*Commit).Free)
+
+ return commit
+}
+
+func (o *Object) AsCommit() (*Commit, error) {
+ cobj, err := dupObject(o, ObjectCommit)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocCommit((*C.git_commit)(cobj), o.repo), nil
+}
+
+func allocBlob(ptr *C.git_blob, repo *Repository) *Blob {
+ blob := &Blob{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(blob, (*Blob).Free)
+
+ return blob
+}
+
+func (o *Object) AsBlob() (*Blob, error) {
+ cobj, err := dupObject(o, ObjectBlob)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocBlob((*C.git_blob)(cobj), o.repo), nil
+}
+
+func allocTag(ptr *C.git_tag, repo *Repository) *Tag {
+ tag := &Tag{
+ Object: Object{
+ ptr: (*C.git_object)(ptr),
+ repo: repo,
+ },
+ cast_ptr: ptr,
+ }
+ runtime.SetFinalizer(tag, (*Tag).Free)
+
+ return tag
+}
+
+func (o *Object) AsTag() (*Tag, error) {
+ cobj, err := dupObject(o, ObjectTag)
+ if err != nil {
+ return nil, err
+ }
+
+ return allocTag((*C.git_tag)(cobj), o.repo), nil
+}
+
+func (o *Object) Free() {
runtime.SetFinalizer(o, nil)
C.git_object_free(o.ptr)
}
@@ -82,7 +183,7 @@
//
// If peeling a tag we discover an object which cannot be peeled to the target
// type due to the object model, an error will be returned.
-func (o *gitObject) Peel(t ObjectType) (Object, error) {
+func (o *Object) Peel(t ObjectType) (*Object, error) {
var cobj *C.git_object
runtime.LockOSThread()
@@ -95,44 +196,12 @@
return allocObject(cobj, o.repo), nil
}
-func allocObject(cobj *C.git_object, repo *Repository) Object {
- obj := gitObject{
+func allocObject(cobj *C.git_object, repo *Repository) *Object {
+ obj := &Object{
ptr: cobj,
repo: repo,
}
+ runtime.SetFinalizer(obj, (*Object).Free)
- switch ObjectType(C.git_object_type(cobj)) {
- case ObjectCommit:
- commit := &Commit{
- gitObject: obj,
- cast_ptr: (*C.git_commit)(cobj),
- }
- runtime.SetFinalizer(commit, (*Commit).Free)
- return commit
-
- case ObjectTree:
- tree := &Tree{
- gitObject: obj,
- cast_ptr: (*C.git_tree)(cobj),
- }
- runtime.SetFinalizer(tree, (*Tree).Free)
- return tree
-
- case ObjectBlob:
- blob := &Blob{
- gitObject: obj,
- cast_ptr: (*C.git_blob)(cobj),
- }
- runtime.SetFinalizer(blob, (*Blob).Free)
- return blob
- case ObjectTag:
- tag := &Tag{
- gitObject: obj,
- cast_ptr: (*C.git_tag)(cobj),
- }
- runtime.SetFinalizer(tag, (*Tag).Free)
- return tag
- }
-
- return nil
+ return obj
}
diff --git a/object_test.go b/object_test.go
index ef6c5a1..2ae2a6a 100644
--- a/object_test.go
+++ b/object_test.go
@@ -10,12 +10,12 @@
commitId, treeId := seedTestRepo(t, repo)
- var obj Object
+ var obj *Object
commit, err := repo.LookupCommit(commitId)
checkFatal(t, err)
- obj = commit
+ obj = &commit.Object
if obj.Type() != ObjectCommit {
t.Fatalf("Wrong object type, expected commit, have %v", obj.Type())
}
@@ -27,13 +27,13 @@
tree, err := repo.LookupTree(treeId)
checkFatal(t, err)
- obj = tree
+ obj = &tree.Object
if obj.Type() != ObjectTree {
t.Fatalf("Wrong object type, expected tree, have %v", obj.Type())
}
- tree2, ok := obj.(*Tree)
- if !ok {
+ tree2, err := obj.AsTree()
+ if err != nil {
t.Fatalf("Converting back to *Tree is not ok")
}
@@ -46,16 +46,16 @@
t.Fatal("Wrong filemode for \"README\"")
}
- _, ok = obj.(*Commit)
- if ok {
+ _, err = obj.AsCommit()
+ if err == nil {
t.Fatalf("*Tree is somehow the same as *Commit")
}
obj, err = repo.Lookup(tree.Id())
checkFatal(t, err)
- _, ok = obj.(*Tree)
- if !ok {
+ _, err = obj.AsTree()
+ if err != nil {
t.Fatalf("Lookup creates the wrong type")
}
@@ -99,8 +99,8 @@
tree, err := repo.LookupTree(treeId)
checkFatal(t, err)
- checkOwner(t, repo, commit)
- checkOwner(t, repo, tree)
+ checkOwner(t, repo, commit.Object)
+ checkOwner(t, repo, tree.Object)
}
func TestObjectPeel(t *testing.T) {
@@ -109,7 +109,7 @@
commitID, treeID := seedTestRepo(t, repo)
- var obj Object
+ var obj *Object
commit, err := repo.LookupCommit(commitID)
checkFatal(t, err)
diff --git a/reference.go b/reference.go
index 140082f..463f2fc 100644
--- a/reference.go
+++ b/reference.go
@@ -263,7 +263,7 @@
return nil
}
-func (v *Reference) Peel(t ObjectType) (Object, error) {
+func (v *Reference) Peel(t ObjectType) (*Object, error) {
var cobj *C.git_object
runtime.LockOSThread()
diff --git a/repository.go b/repository.go
index 62fde6d..2e05780 100644
--- a/repository.go
+++ b/repository.go
@@ -145,7 +145,7 @@
return newIndexFromC(ptr), nil
}
-func (v *Repository) lookupType(id *Oid, t ObjectType) (Object, error) {
+func (v *Repository) lookupType(id *Oid, t ObjectType) (*Object, error) {
var ptr *C.git_object
runtime.LockOSThread()
@@ -159,7 +159,7 @@
return allocObject(ptr, v), nil
}
-func (v *Repository) Lookup(id *Oid) (Object, error) {
+func (v *Repository) Lookup(id *Oid) (*Object, error) {
return v.lookupType(id, ObjectAny)
}
@@ -169,7 +169,7 @@
return nil, err
}
- return obj.(*Tree), nil
+ return obj.AsTree()
}
func (v *Repository) LookupCommit(id *Oid) (*Commit, error) {
@@ -178,7 +178,7 @@
return nil, err
}
- return obj.(*Commit), nil
+ return obj.AsCommit()
}
func (v *Repository) LookupBlob(id *Oid) (*Blob, error) {
@@ -187,7 +187,7 @@
return nil, err
}
- return obj.(*Blob), nil
+ return obj.AsBlob()
}
func (v *Repository) LookupTag(id *Oid) (*Tag, error) {
@@ -196,7 +196,7 @@
return nil, err
}
- return obj.(*Tag), nil
+ return obj.AsTag()
}
func (v *Repository) Head() (*Reference, error) {
diff --git a/reset.go b/reset.go
index b5b7435..9da7625 100644
--- a/reset.go
+++ b/reset.go
@@ -17,7 +17,7 @@
func (r *Repository) ResetToCommit(commit *Commit, resetType ResetType, opts *CheckoutOpts) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- ret := C.git_reset(r.ptr, commit.gitObject.ptr, C.git_reset_t(resetType), opts.toC())
+ ret := C.git_reset(r.ptr, commit.ptr, C.git_reset_t(resetType), opts.toC())
if ret < 0 {
return MakeGitError(ret)
diff --git a/revparse.go b/revparse.go
index 7eb04f1..950932b 100644
--- a/revparse.go
+++ b/revparse.go
@@ -20,16 +20,16 @@
)
type Revspec struct {
- to Object
- from Object
+ to *Object
+ from *Object
flags RevparseFlag
}
-func (rs *Revspec) To() Object {
+func (rs *Revspec) To() *Object {
return rs.to
}
-func (rs *Revspec) From() Object {
+func (rs *Revspec) From() *Object {
return rs.from
}
@@ -38,8 +38,8 @@
}
func newRevspecFromC(ptr *C.git_revspec, repo *Repository) *Revspec {
- var to Object
- var from Object
+ var to *Object
+ var from *Object
if ptr.to != nil {
to = allocObject(ptr.to, repo)
@@ -73,7 +73,7 @@
return newRevspecFromC(&crevspec, r), nil
}
-func (v *Repository) RevparseSingle(spec string) (Object, error) {
+func (v *Repository) RevparseSingle(spec string) (*Object, error) {
cspec := C.CString(spec)
defer C.free(unsafe.Pointer(cspec))
@@ -90,7 +90,7 @@
return allocObject(ptr, v), nil
}
-func (r *Repository) RevparseExt(spec string) (Object, *Reference, error) {
+func (r *Repository) RevparseExt(spec string) (*Object, *Reference, error) {
cspec := C.CString(spec)
defer C.free(unsafe.Pointer(cspec))
diff --git a/revparse_test.go b/revparse_test.go
index 091a76b..75e9ffd 100644
--- a/revparse_test.go
+++ b/revparse_test.go
@@ -46,7 +46,7 @@
}
}
-func checkObject(t *testing.T, obj Object, id *Oid) {
+func checkObject(t *testing.T, obj *Object, id *Oid) {
if obj == nil {
t.Fatalf("bad object")
}
diff --git a/tag.go b/tag.go
index ca85156..8957430 100644
--- a/tag.go
+++ b/tag.go
@@ -13,7 +13,7 @@
// Tag
type Tag struct {
- gitObject
+ Object
cast_ptr *C.git_tag
}
@@ -30,7 +30,7 @@
return newSignatureFromC(cast_ptr)
}
-func (t Tag) Target() Object {
+func (t Tag) Target() *Object {
var ptr *C.git_object
ret := C.git_tag_target(&ptr, t.cast_ptr)
@@ -70,7 +70,7 @@
}
defer C.git_signature_free(taggerSig)
- ctarget := commit.gitObject.ptr
+ ctarget := commit.ptr
runtime.LockOSThread()
defer runtime.UnlockOSThread()
@@ -102,7 +102,7 @@
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
- ctarget := commit.gitObject.ptr
+ ctarget := commit.ptr
runtime.LockOSThread()
defer runtime.UnlockOSThread()
diff --git a/tree.go b/tree.go
index f543c11..8288176 100644
--- a/tree.go
+++ b/tree.go
@@ -23,7 +23,7 @@
)
type Tree struct {
- gitObject
+ Object
cast_ptr *C.git_tree
}