summaryrefslogtreecommitdiff
path: root/odb.go
diff options
context:
space:
mode:
Diffstat (limited to 'odb.go')
-rw-r--r--odb.go155
1 files changed, 144 insertions, 11 deletions
diff --git a/odb.go b/odb.go
index bf17171..953791c 100644
--- a/odb.go
+++ b/odb.go
@@ -1,9 +1,10 @@
package git
/*
-#cgo pkg-config: libgit2
#include <git2.h>
#include <git2/errors.h>
+
+extern int _go_git_odb_foreach(git_odb *db, void *payload);
*/
import "C"
import (
@@ -12,15 +13,6 @@ import (
"runtime"
)
-var (
- OBJ_ANY = C.GIT_OBJ_ANY
- OBJ_BAD = C.GIT_OBJ_BAD
- OBJ_COMMIT = C.GIT_OBJ_COMMIT
- OBJ_TREE = C.GIT_OBJ_TREE
- OBJ_BLOB = C.GIT_OBJ_BLOB
- OBJ_TAG = C.GIT_OBJ_TAG
-)
-
type Odb struct {
ptr *C.git_odb
}
@@ -30,9 +22,13 @@ func (v *Odb) Exists(oid *Oid) bool {
return ret != 0
}
-func (v *Odb) Write(data []byte, otype int) (oid *Oid, err error) {
+func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
oid = new(Oid)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(hdr.Data), C.size_t(hdr.Len), C.git_otype(otype))
if ret < 0 {
@@ -44,6 +40,10 @@ func (v *Odb) Write(data []byte, otype int) (oid *Oid, err error) {
func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
obj = new(OdbObject)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
if ret < 0 {
return nil, LastError()
@@ -53,6 +53,75 @@ func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
return
}
+//export odbForEachCb
+func odbForEachCb(id *C.git_oid, payload unsafe.Pointer) int {
+ ch := *(*chan *Oid)(payload)
+ oid := newOidFromC(id)
+ // Because the channel is unbuffered, we never read our own data. If ch is
+ // readable, the user has sent something on it, which means we should
+ // abort.
+ select {
+ case ch <- oid:
+ case <-ch:
+ return -1
+ }
+ return 0;
+}
+
+func (v *Odb) forEachWrap(ch chan *Oid) {
+ C._go_git_odb_foreach(v.ptr, unsafe.Pointer(&ch))
+ close(ch)
+}
+
+func (v *Odb) ForEach() chan *Oid {
+ ch := make(chan *Oid, 0)
+ go v.forEachWrap(ch)
+ return ch
+}
+
+// Hash determines the object-ID (sha1) of a data buffer.
+func (v *Odb) Hash(data []byte, otype ObjectType) (oid *Oid, err error) {
+ oid = new(Oid)
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := unsafe.Pointer(header.Data)
+
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype));
+ if ret < 0 {
+ err = LastError()
+ }
+ return
+}
+
+// NewReadStream opens a read stream from the ODB. Reading from it will give you the
+// contents of the object.
+func (v *Odb) NewReadStream(id *Oid) (*OdbReadStream, error) {
+ stream := new(OdbReadStream)
+ ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC())
+ if ret < 0 {
+ return nil, LastError()
+ }
+
+ runtime.SetFinalizer(stream, (*OdbReadStream).Free)
+ return stream, nil
+}
+
+// NewWriteStream opens a write stream to the ODB, which allows you to
+// create a new object in the database. The size and type must be
+// known in advance
+func (v *Odb) NewWriteStream(size int, otype ObjectType) (*OdbWriteStream, error) {
+ stream := new(OdbWriteStream)
+ ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.size_t(size), C.git_otype(otype))
+ if ret < 0 {
+ return nil, LastError()
+ }
+
+ runtime.SetFinalizer(stream, (*OdbWriteStream).Free)
+ return stream, nil
+}
+
type OdbObject struct {
ptr *C.git_odb_object
}
@@ -84,3 +153,67 @@ func (object *OdbObject) Data() (data []byte) {
return blob
}
+type OdbReadStream struct {
+ ptr *C.git_odb_stream
+}
+
+// Read reads from the stream
+func (stream *OdbReadStream) Read(data []byte) (int, error) {
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := (*C.char)(unsafe.Pointer(header.Data))
+ size := C.size_t(header.Cap)
+ ret := C.git_odb_stream_read(stream.ptr, ptr, size)
+ if ret < 0 {
+ return 0, LastError()
+ }
+
+ header.Len = int(ret)
+
+ return len(data), nil
+}
+
+// Close is a dummy function in order to implement the Closer and
+// ReadCloser interfaces
+func (stream *OdbReadStream) Close() error {
+ return nil
+}
+
+func (stream *OdbReadStream) Free() {
+ runtime.SetFinalizer(stream, nil)
+ C.git_odb_stream_free(stream.ptr)
+}
+
+type OdbWriteStream struct {
+ ptr *C.git_odb_stream
+ Id Oid
+}
+
+// Write writes to the stream
+func (stream *OdbWriteStream) Write(data []byte) (int, error) {
+ header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ ptr := (*C.char)(unsafe.Pointer(header.Data))
+ size := C.size_t(header.Len)
+
+ ret := C.git_odb_stream_write(stream.ptr, ptr, size)
+ if ret < 0 {
+ return 0, LastError()
+ }
+
+ return len(data), nil
+}
+
+// Close signals that all the data has been written and stores the
+// resulting object id in the stream's Id field.
+func (stream *OdbWriteStream) Close() error {
+ ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr)
+ if ret < 0 {
+ return LastError()
+ }
+
+ return nil
+}
+
+func (stream *OdbWriteStream) Free() {
+ runtime.SetFinalizer(stream, nil)
+ C.git_odb_stream_free(stream.ptr)
+}