summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCalin Seciu <[email protected]>2015-08-01 14:28:20 +0200
committerCalin Seciu <[email protected]>2015-08-01 14:28:20 +0200
commit17950c198b0d1495091a5784e454a4ca9800e927 (patch)
treecb262b2cf422ef8c584500f106c5549962fa2671
parentc0c6caed3a9564602af1f1881933229f99f4729f (diff)
Add ability to peel any git object
Includes support for 'git_object_peel'.
-rw-r--r--object.go26
-rw-r--r--object_test.go60
2 files changed, 86 insertions, 0 deletions
diff --git a/object.go b/object.go
index 20cee85..6ecebf8 100644
--- a/object.go
+++ b/object.go
@@ -22,6 +22,7 @@ type Object interface {
Id() *Oid
Type() ObjectType
Owner() *Repository
+ Peel(t ObjectType) (Object, error)
}
type gitObject struct {
@@ -69,6 +70,31 @@ func (o *gitObject) Free() {
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 *gitObject) Peel(t ObjectType) (Object, error) {
+ var cobj *C.git_object
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ if err := C.git_object_peel(&cobj, o.ptr, C.git_otype(t)); err < 0 {
+ return nil, MakeGitError(err)
+ }
+
+ return allocObject(cobj, o.repo), nil
+}
+
func allocObject(cobj *C.git_object, repo *Repository) Object {
obj := gitObject{
ptr: cobj,
diff --git a/object_test.go b/object_test.go
index aa295e5..ef6c5a1 100644
--- a/object_test.go
+++ b/object_test.go
@@ -102,3 +102,63 @@ func TestObjectOwner(t *testing.T) {
checkOwner(t, repo, commit)
checkOwner(t, repo, tree)
}
+
+func TestObjectPeel(t *testing.T) {
+ repo := createTestRepo(t)
+ defer cleanupTestRepo(t, repo)
+
+ commitID, treeID := seedTestRepo(t, repo)
+
+ var obj Object
+
+ commit, err := repo.LookupCommit(commitID)
+ checkFatal(t, err)
+
+ obj, err = commit.Peel(ObjectAny)
+ checkFatal(t, err)
+
+ if obj.Type() != ObjectTree {
+ t.Fatalf("Wrong object type when peeling a commit, expected tree, have %v", obj.Type())
+ }
+
+ obj, err = commit.Peel(ObjectTag)
+
+ if !IsErrorCode(err, ErrInvalidSpec) {
+ t.Fatalf("Wrong error when peeling a commit to a tag, expected ErrInvalidSpec, have %v", err)
+ }
+
+ tree, err := repo.LookupTree(treeID)
+ checkFatal(t, err)
+
+ obj, err = tree.Peel(ObjectAny)
+
+ if !IsErrorCode(err, ErrInvalidSpec) {
+ t.Fatalf("Wrong error when peeling a tree, expected ErrInvalidSpec, have %v", err)
+ }
+
+ entry := tree.EntryByName("README")
+
+ blob, err := repo.LookupBlob(entry.Id)
+ checkFatal(t, err)
+
+ obj, err = blob.Peel(ObjectAny)
+
+ if !IsErrorCode(err, ErrInvalidSpec) {
+ t.Fatalf("Wrong error when peeling a blob, expected ErrInvalidSpec, have %v", err)
+ }
+
+ tagID := createTestTag(t, repo, commit)
+
+ tag, err := repo.LookupTag(tagID)
+ checkFatal(t, err)
+
+ obj, err = tag.Peel(ObjectAny)
+ checkFatal(t, err)
+
+ if obj.Type() != ObjectCommit {
+ t.Fatalf("Wrong object type when peeling a tag, expected commit, have %v", obj.Type())
+ }
+
+ // TODO: Should test a tag that annotates a different object than a commit
+ // but it's impossible at the moment to tag such an object.
+}