aboutsummaryrefslogtreecommitdiffstats
path: root/cshared
diff options
context:
space:
mode:
authorVadim Markovtsev <vadim@sourced.tech>2016-06-21 17:14:53 +0300
committerVadim Markovtsev <vadim@sourced.tech>2016-06-21 17:14:53 +0300
commitda07dca4523ebd25c634152a62cae4a72eb5783f (patch)
tree028122b562ce464ae4410525b5b3d3dfcea4846c /cshared
parentbea415417e87fbb403095e8cd3fb8512a1a97af8 (diff)
downloadgo-git-da07dca4523ebd25c634152a62cae4a72eb5783f.tar.gz
Wrap more objects with CGo
Diffstat (limited to 'cshared')
-rw-r--r--cshared/README.md8
-rw-r--r--cshared/blame_cshared.go51
-rw-r--r--cshared/commit_cshared.go41
-rw-r--r--cshared/file_cshared.go67
-rw-r--r--cshared/objects.go7
-rw-r--r--cshared/objects_cshared.go2
-rw-r--r--cshared/remote_cshared.go4
-rw-r--r--cshared/std_cshared.go2
-rw-r--r--cshared/tag_cshared.go183
-rw-r--r--cshared/tree_cshared.go142
10 files changed, 498 insertions, 9 deletions
diff --git a/cshared/README.md b/cshared/README.md
index 51e424e..ea32b4b 100644
--- a/cshared/README.md
+++ b/cshared/README.md
@@ -72,8 +72,8 @@ and it is the responsibility of the other side to `free()` it or it will leak
otherwise.
Another tricky part is in `c_std_map_get_str_str` and similar places
-where you need to return `*C.char` from an unaddressed array accessed under
+where you need to return `*C.char` from an unaddressable array accessed under
a pseudonym type through reflection. The only way I've found working
-is using `reflect.Copy` to byte slice (copy) and then conversion to
-`string` (copy), then `C.CString` (copy) and finally another (copy) on the
-receiving side because the latter must be `free()`-d. Extremely efficient. \ No newline at end of file
+is using `reflect.Copy` to byte slice (copy), then `CBytes` (copy) and
+finally another (copy) on the receiving side because the latter must be
+`free()`-d. \ No newline at end of file
diff --git a/cshared/blame_cshared.go b/cshared/blame_cshared.go
new file mode 100644
index 0000000..2da2e42
--- /dev/null
+++ b/cshared/blame_cshared.go
@@ -0,0 +1,51 @@
+// +build ignore
+package main
+
+import (
+ "C"
+
+ "gopkg.in/src-d/go-git.v3"
+)
+
+//export c_Blame_get_Path
+func c_Blame_get_Path(b uint64) *C.char {
+ obj, ok := GetObject(Handle(b))
+ if !ok {
+ return nil
+ }
+ blame := obj.(*git.Blame)
+ return C.CString(blame.Path)
+}
+
+//export c_Blame_get_Rev
+func c_Blame_get_Rev(b uint64) *C.char {
+ obj, ok := GetObject(Handle(b))
+ if !ok {
+ return nil
+ }
+ blame := obj.(*git.Blame)
+ return CBytes(blame.Rev[:])
+}
+
+
+//export c_Blame_get_Lines_len
+func c_Blame_get_Lines_len(b uint64) int {
+ obj, ok := GetObject(Handle(b))
+ if !ok {
+ return 0
+ }
+ blame := obj.(*git.Blame)
+ return len(blame.Lines)
+}
+
+//export c_Blame_get_Lines_item
+func c_Blame_get_Lines_item(b uint64, i int) {
+ obj, ok := GetObject(Handle(b))
+ if !ok {
+ return
+ }
+ blame := obj.(*git.Blame)
+ line := blame.Lines[i]
+ _ = line
+}
+
diff --git a/cshared/commit_cshared.go b/cshared/commit_cshared.go
index 791660b..51b2c1a 100644
--- a/cshared/commit_cshared.go
+++ b/cshared/commit_cshared.go
@@ -4,6 +4,8 @@ package main
import (
"C"
"io"
+ "reflect"
+ "unsafe"
"gopkg.in/src-d/go-git.v3"
"gopkg.in/src-d/go-git.v3/core"
@@ -16,7 +18,7 @@ func c_Commit_get_Hash(c uint64) *C.char {
return nil
}
commit := obj.(*git.Commit)
- return C.CString(string(commit.Hash[:]))
+ return CBytes(commit.Hash[:])
}
//export c_Commit_get_Author
@@ -142,6 +144,43 @@ func c_Commit_String(c uint64) *C.char {
return C.CString(commit.String())
}
+//export c_Commit_References
+func c_Commit_References(c uint64, path string) (*C.char, int, int, *C.char) {
+ obj, ok := GetObject(Handle(c))
+ if !ok {
+ return nil, 0, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ commit := obj.(*git.Commit)
+ refs, err := commit.References(CopyString(path))
+ if err != nil {
+ return nil, 0, ErrorCodeInternal, C.CString(err.Error())
+ }
+ handles := make([]uint64, len(refs))
+ for i, c := range(refs) {
+ handles[i] = uint64(RegisterObject(c))
+ }
+ size := 8 * len(handles)
+ dest := C.malloc(C.size_t(size))
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&handles))
+ header.Len *= 8
+ copy((*[1<<30]byte)(dest)[:], *(*[]byte)(unsafe.Pointer(header)))
+ return (*C.char)(dest), size / 8, ErrorCodeSuccess, nil
+}
+
+//export c_Commit_Blame
+func c_Commit_Blame(c uint64, path string) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(c))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ commit := obj.(*git.Commit)
+ blame, err := commit.Blame(CopyString(path))
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(blame)), ErrorCodeSuccess, nil
+}
+
//export c_NewCommitIter
func c_NewCommitIter(r uint64, iter uint64) uint64 {
obj, ok := GetObject(Handle(r))
diff --git a/cshared/file_cshared.go b/cshared/file_cshared.go
new file mode 100644
index 0000000..7f7c917
--- /dev/null
+++ b/cshared/file_cshared.go
@@ -0,0 +1,67 @@
+package main
+
+import (
+ "C"
+
+ "gopkg.in/src-d/go-git.v3"
+)
+
+//export c_File_get_Name
+func c_File_get_Name(f uint64) *C.char {
+ obj, ok := GetObject(Handle(f))
+ if !ok {
+ return nil
+ }
+ file := obj.(*git.File)
+ return C.CString(file.Name)
+}
+
+//export c_File_get_Mode
+func c_File_get_Mode(f uint64) uint32 {
+ obj, ok := GetObject(Handle(f))
+ if !ok {
+ return 0
+ }
+ file := obj.(*git.File)
+ return uint32(file.Mode)
+}
+
+//export c_NewFileIter
+func c_NewFileIter(r uint64, t uint64) uint64 {
+ obj, ok := GetObject(Handle(r))
+ if !ok {
+ return IH
+ }
+ repo := obj.(*git.Repository)
+ obj, ok = GetObject(Handle(t))
+ if !ok {
+ return IH
+ }
+ tree := obj.(*git.Tree)
+ iter := git.NewFileIter(repo, tree)
+ return uint64(RegisterObject(iter))
+}
+
+//export c_FileIter_Next
+func c_FileIter_Next(i uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(i))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ iter := obj.(*git.FileIter)
+ file, err := iter.Next()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(file)), ErrorCodeSuccess, nil
+}
+
+//export c_FileIter_Close
+func c_FileIter_Close(i uint64) {
+ obj, ok := GetObject(Handle(i))
+ if !ok {
+ return
+ }
+ iter := obj.(*git.FileIter)
+ iter.Close()
+}
diff --git a/cshared/objects.go b/cshared/objects.go
index 0517449..ae3440d 100644
--- a/cshared/objects.go
+++ b/cshared/objects.go
@@ -140,6 +140,13 @@ func CopyString(str string) string {
return string(buf)
}
+// https://github.com/golang/go/issues/14838
+func CBytes(bytes []byte) *C.char {
+ ptr := C.malloc(C.size_t(len(bytes)))
+ copy((*[1<<30]byte)(ptr)[:], bytes)
+ return (*C.char)(ptr)
+}
+
func SafeIsNil(v reflect.Value) bool {
defer func() { recover() }()
return v.IsNil()
diff --git a/cshared/objects_cshared.go b/cshared/objects_cshared.go
index 5c794c3..9f14598 100644
--- a/cshared/objects_cshared.go
+++ b/cshared/objects_cshared.go
@@ -54,7 +54,7 @@ func c_Blob_get_Hash(b uint64) *C.char {
return nil
}
blob := obj.(*git.Blob)
- return C.CString(string(blob.Hash[:]))
+ return CBytes(blob.Hash[:])
}
//export c_Blob_Size
diff --git a/cshared/remote_cshared.go b/cshared/remote_cshared.go
index 04a26de..9ae72f3 100644
--- a/cshared/remote_cshared.go
+++ b/cshared/remote_cshared.go
@@ -130,7 +130,7 @@ func c_Remote_Head(r uint64) (*C.char, int, *C.char) {
if err != nil {
return nil, ErrorCodeInternal, C.CString(err.Error())
}
- return C.CString(string(hash[:])), ErrorCodeSuccess, nil
+ return CBytes(hash[:]), ErrorCodeSuccess, nil
}
//export c_Remote_Fetch
@@ -177,7 +177,7 @@ func c_Remote_Ref(r uint64, refName string) (*C.char, int, *C.char) {
if err != nil {
return nil, ErrorCodeInternal, C.CString(err.Error())
}
- return C.CString(string(hash[:])), ErrorCodeSuccess, nil
+ return CBytes(hash[:]), ErrorCodeSuccess, nil
}
//export c_Remote_Refs
diff --git a/cshared/std_cshared.go b/cshared/std_cshared.go
index 5df9a21..ca93993 100644
--- a/cshared/std_cshared.go
+++ b/cshared/std_cshared.go
@@ -28,7 +28,7 @@ func c_std_map_get_str_str(m uint64, key string) *C.char {
val.Type().Elem().Kind() == reflect.Uint8 {
arr := make([]byte, val.Len(), val.Len())
reflect.Copy(reflect.ValueOf(arr), val)
- return C.CString(string(arr))
+ return CBytes(arr)
}
return C.CString(val.String())
}
diff --git a/cshared/tag_cshared.go b/cshared/tag_cshared.go
new file mode 100644
index 0000000..2a8db65
--- /dev/null
+++ b/cshared/tag_cshared.go
@@ -0,0 +1,183 @@
+// +build ignore
+package main
+
+import (
+ "C"
+
+ "gopkg.in/src-d/go-git.v3"
+ "gopkg.in/src-d/go-git.v3/core"
+)
+
+func c_Tag_get_Hash(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tag := obj.(*git.Tag)
+ return CBytes(tag.Hash[:])
+}
+
+func c_Tag_get_Name(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tag := obj.(*git.Tag)
+ return C.CString(tag.Name)
+}
+
+func c_Tag_get_Tagger(t uint64) uint64 {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH
+ }
+ tag := obj.(*git.Tag)
+ return uint64(RegisterObject(&tag.Tagger))
+}
+
+func c_Tag_get_Message(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tag := obj.(*git.Tag)
+ return C.CString(tag.Message)
+}
+
+func c_Tag_get_TargetType(t uint64) int8 {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return -1
+ }
+ tag := obj.(*git.Tag)
+ return int8(tag.TargetType)
+}
+
+func c_Tag_get_Target(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tag := obj.(*git.Tag)
+ return CBytes(tag.Target[:])
+}
+
+//export c_Tag_Type
+func c_Tag_Type(t uint64) int8 {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return -1
+ }
+ tag := obj.(*git.Tag)
+ return int8(tag.Type())
+}
+
+//export c_Tag_Decode
+func c_Tag_Decode(o uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(o))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ cobj := obj.(*core.Object)
+ tag := git.Tag{}
+ err := tag.Decode(*cobj)
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(&tag)), ErrorCodeSuccess, nil
+}
+
+//export c_Tag_Commit
+func c_Tag_Commit(t uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tag := obj.(*git.Tag)
+ commit, err := tag.Commit()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(commit)), ErrorCodeSuccess, nil
+}
+
+//export c_Tag_Tree
+func c_Tag_Tree(t uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tag := obj.(*git.Tag)
+ tree, err := tag.Tree()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(tree)), ErrorCodeSuccess, nil
+}
+
+//export c_Tag_Blob
+func c_Tag_Blob(t uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tag := obj.(*git.Tag)
+ blob, err := tag.Blob()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(blob)), ErrorCodeSuccess, nil
+}
+
+//export c_Tag_Object
+func c_Tag_Object(t uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tag := obj.(*git.Tag)
+ object, err := tag.Object()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(&object)), ErrorCodeSuccess, nil
+}
+
+//export c_Tag_String
+func c_Tag_String(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tag := obj.(*git.Tag)
+ return C.CString(tag.String())
+}
+
+//export c_NewTagIter
+func c_NewTagIter(r uint64, i uint64) uint64 {
+ obj, ok := GetObject(Handle(r))
+ if !ok {
+ return IH
+ }
+ repo := obj.(*git.Repository)
+ obj, ok = GetObject(Handle(i))
+ if !ok {
+ return IH
+ }
+ iter := obj.(*core.ObjectIter)
+ return uint64(RegisterObject(git.NewTagIter(repo, *iter)))
+}
+
+//export c_TagIter_Next
+func c_TagIter_Next(i uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(i))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tagiter := obj.(*git.TagIter)
+ tag, err := tagiter.Next()
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(tag)), ErrorCodeSuccess, nil
+}
diff --git a/cshared/tree_cshared.go b/cshared/tree_cshared.go
new file mode 100644
index 0000000..0d4191c
--- /dev/null
+++ b/cshared/tree_cshared.go
@@ -0,0 +1,142 @@
+// +build ignore
+package main
+
+import (
+ "C"
+
+ "gopkg.in/src-d/go-git.v3"
+ "gopkg.in/src-d/go-git.v3/core"
+)
+
+//export c_Tree_get_Entries_len
+func c_Tree_get_Entries_len(t uint64) int {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return 0
+ }
+ tree := obj.(*git.Tree)
+ return len(tree.Entries)
+}
+
+//export c_Tree_get_Entries_item
+func c_Tree_get_Entries_item(t uint64, index int) (*C.char, uint32, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil, 0, nil
+ }
+ tree := obj.(*git.Tree)
+ item := tree.Entries[index]
+ return C.CString(item.Name), uint32(item.Mode), CBytes(item.Hash[:])
+}
+
+//export c_Tree_get_Hash
+func c_Tree_get_Hash(t uint64) *C.char {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return nil
+ }
+ tree := obj.(*git.Tree)
+ return CBytes(tree.Hash[:])
+}
+
+func c_Tree_File(t uint64, path string) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ tree := obj.(*git.Tree)
+ file, err := tree.File(CopyString(path))
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(file)), ErrorCodeSuccess, nil
+}
+
+//export c_Tree_Type
+func c_Tree_Type(t uint64) int8 {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return -1
+ }
+ tree := obj.(*git.Tree)
+ return int8(tree.Type())
+}
+
+//export c_Tree_Files
+func c_Tree_Files(t uint64) uint64 {
+ obj, ok := GetObject(Handle(t))
+ if !ok {
+ return IH
+ }
+ tree := obj.(*git.Tree)
+ iter := tree.Files()
+ return uint64(RegisterObject(iter))
+}
+
+//export c_Tree_Decode
+func c_Tree_Decode(o uint64) (uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(o))
+ if !ok {
+ return IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ cobj := obj.(*core.Object)
+ tree := git.Tree{}
+ err := tree.Decode(*cobj)
+ if err != nil {
+ return IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return uint64(RegisterObject(&tree)), ErrorCodeSuccess, nil
+}
+
+//export c_NewTreeWalker
+func c_NewTreeWalker(r uint64, t uint64) uint64 {
+ obj, ok := GetObject(Handle(r))
+ if !ok {
+ return IH
+ }
+ repo := obj.(*git.Repository)
+ obj, ok = GetObject(Handle(t))
+ if !ok {
+ return IH
+ }
+ tree := obj.(*git.Tree)
+ walker := git.NewTreeWalker(repo, tree)
+ return uint64(RegisterObject(walker))
+}
+
+//export c_TreeWalker_Next
+func c_TreeWalker_Next(tw uint64) (*C.char, *C.char, uint32, *C.char,
+ uint64, int, *C.char) {
+ obj, ok := GetObject(Handle(tw))
+ if !ok {
+ return nil, nil, 0, nil, IH, ErrorCodeNotFound, C.CString(MessageNotFound)
+ }
+ walker := obj.(*git.TreeWalker)
+ name, entry, object, err := walker.Next()
+ if err != nil {
+ return nil, nil, 0, nil, IH, ErrorCodeInternal, C.CString(err.Error())
+ }
+ return C.CString(name), C.CString(entry.Name), uint32(entry.Mode),
+ CBytes(entry.Hash[:]), uint64(RegisterObject(&object)),
+ ErrorCodeSuccess, nil
+}
+
+//export c_TreeWalker_Tree
+func c_TreeWalker_Tree(tw uint64) uint64 {
+ obj, ok := GetObject(Handle(tw))
+ if !ok {
+ return IH
+ }
+ walker := obj.(*git.TreeWalker)
+ return uint64(RegisterObject(walker.Tree()))
+}
+
+//export c_TreeWalker_Close
+func c_TreeWalker_Close(tw uint64) {
+ obj, ok := GetObject(Handle(tw))
+ if !ok {
+ return
+ }
+ walker := obj.(*git.TreeWalker)
+ walker.Close()
+} \ No newline at end of file