summaryrefslogtreecommitdiff
path: root/object.go
diff options
context:
space:
mode:
Diffstat (limited to 'object.go')
-rw-r--r--object.go173
1 files changed, 121 insertions, 52 deletions
diff --git a/object.go b/object.go
index 6ecebf8..1981980 100644
--- a/object.go
+++ b/object.go
@@ -4,7 +4,11 @@ package git
#include <git2.h>
*/
import "C"
-import "runtime"
+import (
+ "errors"
+ "fmt"
+ "runtime"
+)
type ObjectType int
@@ -17,15 +21,7 @@ const (
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 @@ func (t ObjectType) String() string {
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 @@ func (o *gitObject) Free() {
//
// 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 @@ func (o *gitObject) Peel(t ObjectType) (Object, error) {
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
}