2013-03-05 13:53:04 -06:00
|
|
|
package git
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <git2.h>
|
|
|
|
#include <git2/errors.h>
|
2013-05-21 14:37:08 -05:00
|
|
|
|
|
|
|
extern int _go_git_odb_foreach(git_odb *db, void *payload);
|
2014-01-29 17:55:17 -06:00
|
|
|
extern void _go_git_odb_backend_free(git_odb_backend *backend);
|
2013-03-05 13:53:04 -06:00
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"runtime"
|
2014-01-29 17:55:17 -06:00
|
|
|
"unsafe"
|
2013-03-05 13:53:04 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type Odb struct {
|
|
|
|
ptr *C.git_odb
|
|
|
|
}
|
|
|
|
|
2013-12-18 16:25:54 -06:00
|
|
|
type OdbBackend struct {
|
2014-01-29 17:55:17 -06:00
|
|
|
ptr *C.git_odb_backend
|
2013-12-18 23:33:23 -06:00
|
|
|
}
|
|
|
|
|
2013-12-19 16:24:44 -06:00
|
|
|
func NewOdb() (odb *Odb, err error) {
|
2014-01-29 17:55:17 -06:00
|
|
|
odb = new(Odb)
|
2013-12-18 23:33:23 -06:00
|
|
|
|
2014-01-29 17:55:17 -06:00
|
|
|
ret := C.git_odb_new(&odb.ptr)
|
|
|
|
if ret < 0 {
|
2014-04-03 15:49:22 -05:00
|
|
|
return nil, MakeGitError(ret)
|
2014-01-29 17:55:17 -06:00
|
|
|
}
|
2013-12-18 23:33:23 -06:00
|
|
|
|
2014-01-29 17:55:17 -06:00
|
|
|
runtime.SetFinalizer(odb, (*Odb).Free)
|
2014-04-03 15:39:21 -05:00
|
|
|
return odb, nil
|
2013-12-18 23:33:23 -06:00
|
|
|
}
|
|
|
|
|
2013-12-20 13:11:24 -06:00
|
|
|
func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) {
|
2014-01-29 17:55:17 -06:00
|
|
|
backend = &OdbBackend{ptr}
|
2014-04-03 15:39:21 -05:00
|
|
|
return backend
|
2013-12-20 13:11:24 -06:00
|
|
|
}
|
|
|
|
|
2013-12-18 23:33:23 -06:00
|
|
|
func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {
|
2014-01-29 17:55:17 -06:00
|
|
|
ret := C.git_odb_add_backend(v.ptr, backend.ptr, C.int(priority))
|
|
|
|
if ret < 0 {
|
|
|
|
backend.Free()
|
2014-04-03 15:49:22 -05:00
|
|
|
return MakeGitError(ret)
|
2014-01-29 17:55:17 -06:00
|
|
|
}
|
|
|
|
return nil
|
2013-12-18 16:25:54 -06:00
|
|
|
}
|
|
|
|
|
2013-03-05 13:53:04 -06:00
|
|
|
func (v *Odb) Exists(oid *Oid) bool {
|
|
|
|
ret := C.git_odb_exists(v.ptr, oid.toC())
|
|
|
|
return ret != 0
|
|
|
|
}
|
|
|
|
|
2013-09-11 16:01:27 -05:00
|
|
|
func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
|
2013-03-05 13:53:04 -06:00
|
|
|
oid = new(Oid)
|
|
|
|
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
2013-09-18 02:23:47 -05:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2013-03-05 13:53:04 -06:00
|
|
|
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 {
|
2014-04-03 15:41:43 -05:00
|
|
|
return nil, MakeGitError(ret)
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
2014-04-03 15:39:21 -05:00
|
|
|
return oid, nil
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
|
|
|
|
obj = new(OdbObject)
|
2013-09-18 02:23:47 -05:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2013-03-05 13:53:04 -06:00
|
|
|
ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
|
|
|
|
if ret < 0 {
|
2013-07-07 09:43:44 -05:00
|
|
|
return nil, MakeGitError(ret)
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
2013-03-05 18:43:48 -06:00
|
|
|
runtime.SetFinalizer(obj, (*OdbObject).Free)
|
2014-04-03 15:39:21 -05:00
|
|
|
return obj, nil
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
2014-05-06 07:19:34 -05:00
|
|
|
type OdbForEachCallback func(id *Oid) error
|
|
|
|
|
|
|
|
type foreachData struct {
|
|
|
|
callback OdbForEachCallback
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
2013-05-21 14:37:08 -05:00
|
|
|
//export odbForEachCb
|
|
|
|
func odbForEachCb(id *C.git_oid, payload unsafe.Pointer) int {
|
2014-05-06 07:19:34 -05:00
|
|
|
data := (*foreachData)(payload)
|
|
|
|
|
|
|
|
err := data.callback(newOidFromC(id))
|
|
|
|
if err != nil {
|
|
|
|
data.err = err
|
|
|
|
return C.GIT_EUSER
|
2013-05-21 14:37:08 -05:00
|
|
|
}
|
2014-05-06 07:19:34 -05:00
|
|
|
|
2014-01-29 17:55:17 -06:00
|
|
|
return 0
|
2013-05-21 14:37:08 -05:00
|
|
|
}
|
|
|
|
|
2014-05-06 07:19:34 -05:00
|
|
|
func (v *Odb) ForEach(callback OdbForEachCallback) error {
|
|
|
|
data := foreachData {
|
|
|
|
callback: callback,
|
|
|
|
err: nil,
|
|
|
|
}
|
2013-05-21 14:37:08 -05:00
|
|
|
|
2014-05-06 07:19:34 -05:00
|
|
|
ret := C._go_git_odb_foreach(v.ptr, unsafe.Pointer(&data))
|
|
|
|
if ret == C.GIT_EUSER {
|
|
|
|
return data.err
|
|
|
|
} else if ret < 0 {
|
|
|
|
return MakeGitError(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2013-05-21 14:37:08 -05:00
|
|
|
}
|
|
|
|
|
2014-01-25 15:18:32 -06:00
|
|
|
// 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))
|
2014-01-26 05:36:05 -06:00
|
|
|
ptr := unsafe.Pointer(header.Data)
|
2014-01-25 15:18:32 -06:00
|
|
|
|
|
|
|
runtime.LockOSThread()
|
|
|
|
defer runtime.UnlockOSThread()
|
|
|
|
|
2014-01-26 05:36:05 -06:00
|
|
|
ret := C.git_odb_hash(oid.toC(), ptr, C.size_t(header.Len), C.git_otype(otype));
|
2014-01-25 15:18:32 -06:00
|
|
|
if ret < 0 {
|
2014-04-03 15:41:43 -05:00
|
|
|
return nil, MakeGitError(ret)
|
2014-01-25 15:18:32 -06:00
|
|
|
}
|
2014-04-03 15:39:21 -05:00
|
|
|
return oid, nil
|
2014-01-25 15:18:32 -06:00
|
|
|
}
|
|
|
|
|
2013-09-11 12:17:45 -05:00
|
|
|
// 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 {
|
2014-02-26 09:14:31 -06:00
|
|
|
return nil, MakeGitError(ret)
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2014-02-26 09:14:31 -06:00
|
|
|
return nil, MakeGitError(ret)
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
runtime.SetFinalizer(stream, (*OdbWriteStream).Free)
|
|
|
|
return stream, nil
|
|
|
|
}
|
|
|
|
|
2014-01-29 17:55:17 -06:00
|
|
|
func (v *OdbBackend) Free() {
|
|
|
|
C._go_git_odb_backend_free(v.ptr)
|
|
|
|
}
|
|
|
|
|
2013-03-05 13:53:04 -06:00
|
|
|
type OdbObject struct {
|
|
|
|
ptr *C.git_odb_object
|
|
|
|
}
|
|
|
|
|
2013-03-05 18:43:48 -06:00
|
|
|
func (v *OdbObject) Free() {
|
|
|
|
runtime.SetFinalizer(v, nil)
|
|
|
|
C.git_odb_object_free(v.ptr)
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
2013-03-06 10:15:28 -06:00
|
|
|
func (object *OdbObject) Id() (oid *Oid) {
|
|
|
|
return newOidFromC(C.git_odb_object_id(object.ptr))
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
|
|
|
|
2013-03-06 10:15:28 -06:00
|
|
|
func (object *OdbObject) Len() (len uint64) {
|
|
|
|
return uint64(C.git_odb_object_size(object.ptr))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (object *OdbObject) Data() (data []byte) {
|
|
|
|
var c_blob unsafe.Pointer = C.git_odb_object_data(object.ptr)
|
|
|
|
var blob []byte
|
|
|
|
|
|
|
|
len := int(C.git_odb_object_size(object.ptr))
|
|
|
|
|
|
|
|
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&blob)))
|
|
|
|
sliceHeader.Cap = len
|
|
|
|
sliceHeader.Len = len
|
|
|
|
sliceHeader.Data = uintptr(c_blob)
|
|
|
|
|
|
|
|
return blob
|
2013-03-05 13:53:04 -06:00
|
|
|
}
|
2013-09-11 12:17:45 -05:00
|
|
|
|
|
|
|
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 {
|
2014-02-26 09:14:31 -06:00
|
|
|
return 0, MakeGitError(ret)
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2014-01-29 17:55:17 -06:00
|
|
|
Id Oid
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2014-02-26 09:14:31 -06:00
|
|
|
return 0, MakeGitError(ret)
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2014-02-26 09:14:31 -06:00
|
|
|
return MakeGitError(ret)
|
2013-09-11 12:17:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (stream *OdbWriteStream) Free() {
|
|
|
|
runtime.SetFinalizer(stream, nil)
|
|
|
|
C.git_odb_stream_free(stream.ptr)
|
|
|
|
}
|