| package git |
| |
| /* |
| #include <git2.h> |
| |
| extern int _go_git_odb_foreach(git_odb *db, void *payload); |
| extern void _go_git_odb_backend_free(git_odb_backend *backend); |
| */ |
| import "C" |
| import ( |
| "reflect" |
| "runtime" |
| "unsafe" |
| ) |
| |
| type Odb struct { |
| ptr *C.git_odb |
| } |
| |
| type OdbBackend struct { |
| ptr *C.git_odb_backend |
| } |
| |
| func NewOdb() (odb *Odb, err error) { |
| odb = new(Odb) |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_new(&odb.ptr) |
| if ret < 0 { |
| return nil, MakeGitError(ret) |
| } |
| |
| runtime.SetFinalizer(odb, (*Odb).Free) |
| return odb, nil |
| } |
| |
| func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) { |
| backend = &OdbBackend{ptr} |
| return backend |
| } |
| |
| func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) { |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_add_backend(v.ptr, backend.ptr, C.int(priority)) |
| if ret < 0 { |
| backend.Free() |
| return MakeGitError(ret) |
| } |
| return nil |
| } |
| |
| func (v *Odb) Exists(oid *Oid) bool { |
| ret := C.git_odb_exists(v.ptr, oid.toC()) |
| return ret != 0 |
| } |
| |
| 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 { |
| return nil, MakeGitError(ret) |
| } |
| |
| return oid, nil |
| } |
| |
| 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, MakeGitError(ret) |
| } |
| |
| runtime.SetFinalizer(obj, (*OdbObject).Free) |
| return obj, nil |
| } |
| |
| type OdbForEachCallback func(id *Oid) error |
| |
| type foreachData struct { |
| callback OdbForEachCallback |
| err error |
| } |
| |
| //export odbForEachCb |
| func odbForEachCb(id *C.git_oid, payload unsafe.Pointer) int { |
| data := (*foreachData)(payload) |
| |
| err := data.callback(newOidFromC(id)) |
| if err != nil { |
| data.err = err |
| return C.GIT_EUSER |
| } |
| |
| return 0 |
| } |
| |
| func (v *Odb) ForEach(callback OdbForEachCallback) error { |
| data := foreachData{ |
| callback: callback, |
| err: nil, |
| } |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| 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 |
| } |
| |
| // 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 { |
| return nil, MakeGitError(ret) |
| } |
| return oid, nil |
| } |
| |
| // 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) |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_open_rstream(&stream.ptr, v.ptr, id.toC()) |
| if ret < 0 { |
| return nil, MakeGitError(ret) |
| } |
| |
| 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) |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_open_wstream(&stream.ptr, v.ptr, C.size_t(size), C.git_otype(otype)) |
| if ret < 0 { |
| return nil, MakeGitError(ret) |
| } |
| |
| runtime.SetFinalizer(stream, (*OdbWriteStream).Free) |
| return stream, nil |
| } |
| |
| func (v *OdbBackend) Free() { |
| C._go_git_odb_backend_free(v.ptr) |
| } |
| |
| type OdbObject struct { |
| ptr *C.git_odb_object |
| } |
| |
| func (v *OdbObject) Free() { |
| runtime.SetFinalizer(v, nil) |
| C.git_odb_object_free(v.ptr) |
| } |
| |
| func (object *OdbObject) Id() (oid *Oid) { |
| return newOidFromC(C.git_odb_object_id(object.ptr)) |
| } |
| |
| 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 |
| } |
| |
| 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) |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_stream_read(stream.ptr, ptr, size) |
| if ret < 0 { |
| return 0, MakeGitError(ret) |
| } |
| |
| 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) |
| |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_stream_write(stream.ptr, ptr, size) |
| if ret < 0 { |
| return 0, MakeGitError(ret) |
| } |
| |
| 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 { |
| runtime.LockOSThread() |
| defer runtime.UnlockOSThread() |
| |
| ret := C.git_odb_stream_finalize_write(stream.Id.toC(), stream.ptr) |
| if ret < 0 { |
| return MakeGitError(ret) |
| } |
| |
| return nil |
| } |
| |
| func (stream *OdbWriteStream) Free() { |
| runtime.SetFinalizer(stream, nil) |
| C.git_odb_stream_free(stream.ptr) |
| } |