diff options
Diffstat (limited to 'vendor/github.com/libgit2/git2go/object.go')
-rw-r--r-- | vendor/github.com/libgit2/git2go/object.go | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/vendor/github.com/libgit2/git2go/object.go b/vendor/github.com/libgit2/git2go/object.go new file mode 100644 index 000000000..5505e356e --- /dev/null +++ b/vendor/github.com/libgit2/git2go/object.go @@ -0,0 +1,237 @@ +package git + +/* +#include <git2.h> +*/ +import "C" +import ( + "errors" + "fmt" + "runtime" +) + +type ObjectType int + +const ( + ObjectAny ObjectType = C.GIT_OBJ_ANY + ObjectBad ObjectType = C.GIT_OBJ_BAD + ObjectCommit ObjectType = C.GIT_OBJ_COMMIT + ObjectTree ObjectType = C.GIT_OBJ_TREE + ObjectBlob ObjectType = C.GIT_OBJ_BLOB + ObjectTag ObjectType = C.GIT_OBJ_TAG +) + +type Object struct { + ptr *C.git_object + repo *Repository +} + +// Objecter lets us accept any kind of Git object in functions. +type Objecter interface { + AsObject() *Object +} + +func (t ObjectType) String() string { + switch t { + case ObjectAny: + return "Any" + case ObjectBad: + return "Bad" + case ObjectCommit: + return "Commit" + case ObjectTree: + return "Tree" + case ObjectBlob: + return "Blob" + case ObjectTag: + return "Tag" + } + // Never reached + return "" +} + +func (o *Object) Id() *Oid { + ret := newOidFromC(C.git_object_id(o.ptr)) + runtime.KeepAlive(o) + return ret +} + +func (o *Object) ShortId() (string, error) { + resultBuf := C.git_buf{} + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + ecode := C.git_object_short_id(&resultBuf, o.ptr) + runtime.KeepAlive(o) + if ecode < 0 { + return "", MakeGitError(ecode) + } + defer C.git_buf_free(&resultBuf) + return C.GoString(resultBuf.ptr), nil +} + +func (o *Object) Type() ObjectType { + ret := ObjectType(C.git_object_type(o.ptr)) + runtime.KeepAlive(o) + return ret +} + +// Owner returns a weak reference to the repository which owns this +// object. This won't keep the underlying repository alive. +func (o *Object) Owner() *Repository { + ret := &Repository{ + ptr: C.git_object_owner(o.ptr), + } + runtime.KeepAlive(o) + return ret +} + +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() + + err := C.git_object_dup(&cobj, obj.ptr) + runtime.KeepAlive(obj) + if 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) +} + +// Peel recursively peels an object until an object of the specified type is met. +// +// If the query cannot be satisfied due to the object model, ErrInvalidSpec +// will be returned (e.g. trying to peel a blob to a tree). +// +// If you pass ObjectAny as the target type, then the object will be peeled +// until the type changes. A tag will be peeled until the referenced object +// is no longer a tag, and a commit will be peeled to a tree. Any other object +// type will return ErrInvalidSpec. +// +// 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 *Object) Peel(t ObjectType) (*Object, error) { + var cobj *C.git_object + + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t)) + runtime.KeepAlive(o) + if err < 0 { + return nil, MakeGitError(err) + } + + return allocObject(cobj, o.repo), nil +} + +func allocObject(cobj *C.git_object, repo *Repository) *Object { + obj := &Object{ + ptr: cobj, + repo: repo, + } + runtime.SetFinalizer(obj, (*Object).Free) + + return obj +} |