Skip to content

Commit 62f65d0

Browse files
author
Vicent Martí
committed
Merge pull request libgit2#13 from libgit2/polymorphism-take-2
My take on polymorphism
2 parents 01d1a5c + 5766c4a commit 62f65d0

File tree

10 files changed

+259
-110
lines changed

10 files changed

+259
-110
lines changed

blob.go

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,18 @@ package git
77
*/
88
import "C"
99
import (
10-
"runtime"
1110
"unsafe"
1211
)
1312

1413
type Blob struct {
15-
ptr *C.git_object
14+
gitObject
1615
}
1716

18-
func (v *Blob) Free() {
19-
runtime.SetFinalizer(v, nil)
20-
C.git_object_free(v.ptr)
21-
}
22-
23-
func (v *Blob) Size() int64 {
17+
func (v Blob) Size() int64 {
2418
return int64(C.git_blob_rawsize(v.ptr))
2519
}
2620

27-
func (v *Blob) Contents() []byte {
21+
func (v Blob) Contents() []byte {
2822
size := C.int(C.git_blob_rawsize(v.ptr))
2923
buffer := unsafe.Pointer(C.git_blob_rawcontent(v.ptr))
3024
return C.GoBytes(buffer, size)

commit.go

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,46 +9,40 @@ extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
99
import "C"
1010

1111
import (
12-
"runtime"
1312
"unsafe"
1413
"time"
1514
)
1615

1716
// Commit
1817
type Commit struct {
19-
ptr *C.git_commit
18+
gitObject
2019
}
2120

22-
func (c *Commit) Id() *Oid {
23-
return newOidFromC(C.git_commit_id(c.ptr))
24-
}
25-
26-
func (c *Commit) Message() string {
21+
func (c Commit) Message() string {
2722
return C.GoString(C.git_commit_message(c.ptr))
2823
}
2924

30-
func (c *Commit) Tree() (*Tree, error) {
31-
tree := new(Tree)
25+
func (c Commit) Tree() (*Tree, error) {
26+
var ptr *C.git_object
3227

33-
err := C.git_commit_tree(&tree.ptr, c.ptr)
28+
err := C.git_commit_tree(&ptr, c.ptr)
3429
if err < 0 {
3530
return nil, LastError()
3631
}
3732

38-
runtime.SetFinalizer(tree, (*Tree).Free)
39-
return tree, nil
33+
return allocObject(ptr).(*Tree), nil
4034
}
4135

42-
func (c *Commit) TreeId() *Oid {
36+
func (c Commit) TreeId() *Oid {
4337
return newOidFromC(C.git_commit_tree_id(c.ptr))
4438
}
4539

46-
func (c *Commit) Author() *Signature {
40+
func (c Commit) Author() *Signature {
4741
ptr := C.git_commit_author(c.ptr)
4842
return newSignatureFromC(ptr)
4943
}
5044

51-
func (c *Commit) Committer() *Signature {
45+
func (c Commit) Committer() *Signature {
5246
ptr := C.git_commit_committer(c.ptr)
5347
return newSignatureFromC(ptr)
5448
}

git_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package git
2+
3+
import (
4+
"testing"
5+
"io/ioutil"
6+
"time"
7+
)
8+
9+
func createTestRepo(t *testing.T) *Repository {
10+
// figure out where we can create the test repo
11+
path, err := ioutil.TempDir("", "git2go")
12+
checkFatal(t, err)
13+
repo, err := InitRepository(path, false)
14+
checkFatal(t, err)
15+
16+
tmpfile := "README"
17+
err = ioutil.WriteFile(path + "/" + tmpfile, []byte("foo\n"), 0644)
18+
checkFatal(t, err)
19+
20+
return repo
21+
}
22+
23+
func seedTestRepo(t *testing.T, repo *Repository) (*Oid, *Oid) {
24+
loc, err := time.LoadLocation("Europe/Berlin")
25+
checkFatal(t, err)
26+
sig := &Signature{
27+
Name: "Rand Om Hacker",
28+
29+
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
30+
}
31+
32+
idx, err := repo.Index()
33+
checkFatal(t, err)
34+
err = idx.AddByPath("README")
35+
checkFatal(t, err)
36+
treeId, err := idx.WriteTree()
37+
checkFatal(t, err)
38+
39+
message := "This is a commit\n"
40+
tree, err := repo.LookupTree(treeId)
41+
checkFatal(t, err)
42+
commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree)
43+
checkFatal(t, err)
44+
45+
return commitId, treeId
46+
}
47+

index_test.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,8 @@ import (
44
"os"
55
"runtime"
66
"testing"
7-
"io/ioutil"
87
)
98

10-
func createTestRepo(t *testing.T) *Repository {
11-
// figure out where we can create the test repo
12-
path, err := ioutil.TempDir("", "git2go")
13-
checkFatal(t, err)
14-
repo, err := InitRepository(path, false)
15-
checkFatal(t, err)
16-
17-
tmpfile := "README"
18-
err = ioutil.WriteFile(path + "/" + tmpfile, []byte("foo\n"), 0644)
19-
checkFatal(t, err)
20-
21-
return repo
22-
}
23-
249
func TestCreateRepoAndStage(t *testing.T) {
2510
repo := createTestRepo(t)
2611
defer os.RemoveAll(repo.Workdir())

object.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package git
2+
3+
/*
4+
#cgo pkg-config: libgit2
5+
#include <git2.h>
6+
#include <git2/errors.h>
7+
*/
8+
import "C"
9+
import "runtime"
10+
11+
type ObjectType int
12+
13+
var (
14+
OBJ_ANY ObjectType = C.GIT_OBJ_ANY
15+
OBJ_BAD ObjectType = C.GIT_OBJ_BAD
16+
OBJ_COMMIT ObjectType = C.GIT_OBJ_COMMIT
17+
OBJ_TREE ObjectType = C.GIT_OBJ_TREE
18+
OBJ_BLOB ObjectType = C.GIT_OBJ_BLOB
19+
OBJ_TAG ObjectType = C.GIT_OBJ_TAG
20+
)
21+
22+
type Object interface {
23+
Free()
24+
Id() *Oid
25+
Type() ObjectType
26+
}
27+
28+
type gitObject struct {
29+
ptr *C.git_object
30+
}
31+
32+
func (t ObjectType) String() (string) {
33+
switch (t) {
34+
case OBJ_ANY:
35+
return "Any"
36+
case OBJ_BAD:
37+
return "Bad"
38+
case OBJ_COMMIT:
39+
return "Commit"
40+
case OBJ_TREE:
41+
return "Tree"
42+
case OBJ_BLOB:
43+
return "Blob"
44+
case OBJ_TAG:
45+
return "tag"
46+
}
47+
// Never reached
48+
return ""
49+
}
50+
51+
func (o gitObject) Id() *Oid {
52+
return newOidFromC(C.git_commit_id(o.ptr))
53+
}
54+
55+
func (o gitObject) Type() ObjectType {
56+
return ObjectType(C.git_object_type(o.ptr))
57+
}
58+
59+
func (o *gitObject) Free() {
60+
runtime.SetFinalizer(o, nil)
61+
C.git_commit_free(o.ptr)
62+
}
63+
64+
func allocObject(cobj *C.git_object) Object {
65+
66+
switch ObjectType(C.git_object_type(cobj)) {
67+
case OBJ_COMMIT:
68+
commit := &Commit{gitObject{cobj}}
69+
runtime.SetFinalizer(commit, (*Commit).Free)
70+
return commit
71+
72+
case OBJ_TREE:
73+
tree := &Tree{gitObject{cobj}}
74+
runtime.SetFinalizer(tree, (*Tree).Free)
75+
return tree
76+
77+
case OBJ_BLOB:
78+
blob := &Blob{gitObject{cobj}}
79+
runtime.SetFinalizer(blob, (*Blob).Free)
80+
return blob
81+
}
82+
83+
return nil
84+
}

object_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package git
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestObjectPoymorphism(t *testing.T) {
9+
repo := createTestRepo(t)
10+
defer os.RemoveAll(repo.Workdir())
11+
commitId, treeId := seedTestRepo(t, repo)
12+
13+
var obj Object
14+
15+
commit, err := repo.LookupCommit(commitId)
16+
checkFatal(t, err)
17+
18+
obj = commit
19+
if obj.Type() != OBJ_COMMIT {
20+
t.Fatalf("Wrong object type, expected commit, have %v", obj.Type())
21+
}
22+
23+
tree, err := repo.LookupTree(treeId)
24+
checkFatal(t, err)
25+
26+
obj = tree
27+
if obj.Type() != OBJ_TREE {
28+
t.Fatalf("Wrong object type, expected tree, have %v", obj.Type())
29+
}
30+
31+
tree2, ok := obj.(*Tree)
32+
if !ok {
33+
t.Fatalf("Converting back to *Tree is not ok")
34+
}
35+
36+
if tree2.EntryByName("README") == nil {
37+
t.Fatalf("Tree did not have expected \"README\" entry")
38+
}
39+
40+
_, ok = obj.(*Commit)
41+
if ok {
42+
t.Fatalf("*Tree is somehow the same as *Commit")
43+
}
44+
45+
obj, err = repo.Lookup(tree.Id())
46+
checkFatal(t, err)
47+
48+
_, ok = obj.(*Tree)
49+
if !ok {
50+
t.Fatalf("Lookup creates the wrong type")
51+
}
52+
53+
if obj.Type() != OBJ_TREE {
54+
t.Fatalf("Type() doesn't agree with dynamic type")
55+
}
56+
57+
obj, err = repo.RevparseSingle("HEAD")
58+
checkFatal(t, err)
59+
if obj.Type() != OBJ_COMMIT || obj.Id().String() != commit.Id().String() {
60+
t.Fatalf("Failed to parse the right revision")
61+
}
62+
63+
obj, err = repo.RevparseSingle("HEAD^{tree}")
64+
checkFatal(t, err)
65+
if obj.Type() != OBJ_TREE || obj.Id().String() != tree.Id().String() {
66+
t.Fatalf("Failed to parse the right revision")
67+
}
68+
}

odb.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,6 @@ import (
1414
"runtime"
1515
)
1616

17-
var (
18-
OBJ_ANY = C.GIT_OBJ_ANY
19-
OBJ_BAD = C.GIT_OBJ_BAD
20-
OBJ_COMMIT = C.GIT_OBJ_COMMIT
21-
OBJ_TREE = C.GIT_OBJ_TREE
22-
OBJ_BLOB = C.GIT_OBJ_BLOB
23-
OBJ_TAG = C.GIT_OBJ_TAG
24-
)
25-
2617
type Odb struct {
2718
ptr *C.git_odb
2819
}

reference_test.go

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,15 @@ import (
55
"runtime"
66
"sort"
77
"testing"
8-
"time"
98
)
109

1110
func TestRefModification(t *testing.T) {
1211
repo := createTestRepo(t)
1312
defer os.RemoveAll(repo.Workdir())
1413

15-
loc, err := time.LoadLocation("Europe/Berlin")
16-
checkFatal(t, err)
17-
sig := &Signature{
18-
Name: "Rand Om Hacker",
19-
20-
When: time.Date(2013, 03, 06, 14, 30, 0, 0, loc),
21-
}
22-
23-
idx, err := repo.Index()
24-
checkFatal(t, err)
25-
err = idx.AddByPath("README")
26-
checkFatal(t, err)
27-
treeId, err := idx.WriteTree()
28-
checkFatal(t, err)
29-
30-
message := "This is a commit\n"
31-
tree, err := repo.LookupTree(treeId)
32-
checkFatal(t, err)
33-
commitId, err := repo.CreateCommit("HEAD", sig, sig, message, tree)
34-
checkFatal(t, err)
14+
commitId, treeId := seedTestRepo(t, repo)
3515

36-
_, err = repo.CreateReference("refs/tags/tree", treeId, true)
16+
_, err := repo.CreateReference("refs/tags/tree", treeId, true)
3717
checkFatal(t, err)
3818

3919
tag, err := repo.LookupReference("refs/tags/tree")

0 commit comments

Comments
 (0)