Add support for indexers and alternate odb packfiles #358
|
@ -0,0 +1,92 @@
|
||||||
|
package git
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <git2.h>
|
||||||
|
|
||||||
|
extern const git_oid * git_indexer_hash(const git_indexer *idx);
|
||||||
|
extern int git_indexer_append(git_indexer *idx, const void *data, size_t size, git_transfer_progress *stats);
|
||||||
|
extern int git_indexer_commit(git_indexer *idx, git_transfer_progress *stats);
|
||||||
|
extern int _go_git_indexer_new(git_indexer **out, const char *path, unsigned int mode, git_odb *odb, void *progress_cb_payload);
|
||||||
|
extern void git_indexer_free(git_indexer *idx);
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Indexer can post-process packfiles and create an .idx file for efficient
|
||||||
|
// lookup.
|
||||||
|
type Indexer struct {
|
||||||
|
ptr *C.git_indexer
|
||||||
|
stats C.git_transfer_progress
|
||||||
|
callbacks RemoteCallbacks
|
||||||
|
callbacksHandle unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIndexer creates a new indexer instance.
|
||||||
|
func NewIndexer(packfilePath string, odb *Odb, callback TransferProgressCallback) (indexer *Indexer, err error) {
|
||||||
|
indexer = new(Indexer)
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
var odbPtr *C.git_odb = nil
|
||||||
|
if odb != nil {
|
||||||
|
odbPtr = odb.ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
indexer.callbacks.TransferProgressCallback = callback
|
||||||
|
indexer.callbacksHandle = pointerHandles.Track(&indexer.callbacks)
|
||||||
|
|
||||||
|
ret := C._go_git_indexer_new(&indexer.ptr, C.CString(packfilePath), 0, odbPtr, indexer.callbacksHandle)
|
||||||
|
if ret < 0 {
|
||||||
|
pointerHandles.Untrack(indexer.callbacksHandle)
|
||||||
|
return nil, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.SetFinalizer(indexer, (*Indexer).Free)
|
||||||
|
return indexer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write adds data to the indexer.
|
||||||
|
func (indexer *Indexer) Write(data []byte) (int, error) {
|
||||||
|
header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||||
|
ptr := unsafe.Pointer(header.Data)
|
||||||
|
size := C.size_t(header.Len)
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C.git_indexer_append(indexer.ptr, ptr, size, &indexer.stats)
|
||||||
|
if ret < 0 {
|
||||||
|
return 0, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit finalizes the pack and index. It resolves any pending deltas and
|
||||||
|
// writes out the index file.
|
||||||
|
//
|
||||||
|
// It also returns the packfile's hash. A packfile's name is derived from the
|
||||||
|
// sorted hashing of all object names.
|
||||||
|
func (indexer *Indexer) Commit() (*Oid, error) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C.git_indexer_commit(indexer.ptr, &indexer.stats)
|
||||||
|
if ret < 0 {
|
||||||
|
return nil, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newOidFromC(C.git_indexer_hash(indexer.ptr)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free frees the indexer and its resources.
|
||||||
|
func (indexer *Indexer) Free() {
|
||||||
|
pointerHandles.Untrack(indexer.callbacksHandle)
|
||||||
|
runtime.SetFinalizer(indexer, nil)
|
||||||
|
C.git_indexer_free(indexer.ptr)
|
||||||
|
}
|
102
odb.go
102
odb.go
|
@ -3,8 +3,13 @@ package git
|
||||||
/*
|
/*
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
extern int git_odb_backend_one_pack(git_odb_backend **out, const char *index_file);
|
||||||
extern int _go_git_odb_foreach(git_odb *db, void *payload);
|
extern int _go_git_odb_foreach(git_odb *db, void *payload);
|
||||||
extern void _go_git_odb_backend_free(git_odb_backend *backend);
|
extern void _go_git_odb_backend_free(git_odb_backend *backend);
|
||||||
|
extern int _go_git_odb_write_pack(git_odb_writepack **out, git_odb *db, void *progress_payload);
|
||||||
|
extern int _go_git_odb_writepack_append(git_odb_writepack *writepack, const void *, size_t, git_transfer_progress *);
|
||||||
|
extern int _go_git_odb_writepack_commit(git_odb_writepack *writepack, git_transfer_progress *);
|
||||||
|
extern void _go_git_odb_writepack_free(git_odb_writepack *writepack);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
|
@ -41,8 +46,19 @@ func NewOdbBackendFromC(ptr *C.git_odb_backend) (backend *OdbBackend) {
|
||||||
return backend
|
return backend
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {
|
func (v *Odb) AddAlternate(backend *OdbBackend, priority int) (err error) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C.git_odb_add_alternate(v.ptr, backend.ptr, C.int(priority))
|
||||||
|
if ret < 0 {
|
||||||
|
backend.Free()
|
||||||
|
return MakeGitError(ret)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
@ -54,12 +70,24 @@ func (v *Odb) AddBackend(backend *OdbBackend, priority int) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewOdbBackendOnePack(packfileIndexPath string) (backend *OdbBackend, err error) {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
var odbOnePack *C.git_odb_backend = nil
|
||||||
|
ret := C.git_odb_backend_one_pack(&odbOnePack, C.CString(packfileIndexPath))
|
||||||
|
if ret < 0 {
|
||||||
|
return nil, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
return NewOdbBackendFromC(odbOnePack), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
|
func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
var sz C.size_t
|
var sz C.size_t
|
||||||
var cotype C.git_otype
|
var cotype C.git_otype
|
||||||
|
|
||||||
ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
|
ret := C.git_odb_read_header(&sz, &cotype, v.ptr, oid.toC())
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
|
@ -68,7 +96,7 @@ func (v *Odb) ReadHeader(oid *Oid) (uint64, ObjectType, error) {
|
||||||
|
|
||||||
return uint64(sz), ObjectType(cotype), nil
|
return uint64(sz), ObjectType(cotype), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Odb) Exists(oid *Oid) bool {
|
func (v *Odb) Exists(oid *Oid) bool {
|
||||||
ret := C.git_odb_exists(v.ptr, oid.toC())
|
ret := C.git_odb_exists(v.ptr, oid.toC())
|
||||||
return ret != 0
|
return ret != 0
|
||||||
|
@ -205,6 +233,30 @@ func (v *Odb) NewWriteStream(size int64, otype ObjectType) (*OdbWriteStream, err
|
||||||
return stream, nil
|
return stream, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewWritePack opens a stream for writing a pack file to the ODB. If the ODB
|
||||||
|
// layer understands pack files, then the given packfile will likely be
|
||||||
|
// streamed directly to disk (and a corresponding index created). If the ODB
|
||||||
|
// layer does not understand pack files, the objects will be stored in whatever
|
||||||
|
// format the ODB layer uses.
|
||||||
|
func (v *Odb) NewWritePack(callback TransferProgressCallback) (*OdbWritepack, error) {
|
||||||
|
writepack := new(OdbWritepack)
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
writepack.callbacks.TransferProgressCallback = callback
|
||||||
|
writepack.callbacksHandle = pointerHandles.Track(&writepack.callbacks)
|
||||||
|
|
||||||
|
ret := C._go_git_odb_write_pack(&writepack.ptr, v.ptr, writepack.callbacksHandle)
|
||||||
|
if ret < 0 {
|
||||||
|
pointerHandles.Untrack(writepack.callbacksHandle)
|
||||||
|
return nil, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.SetFinalizer(writepack, (*OdbWritepack).Free)
|
||||||
|
return writepack, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (v *OdbBackend) Free() {
|
func (v *OdbBackend) Free() {
|
||||||
C._go_git_odb_backend_free(v.ptr)
|
C._go_git_odb_backend_free(v.ptr)
|
||||||
}
|
}
|
||||||
|
@ -318,3 +370,45 @@ func (stream *OdbWriteStream) Free() {
|
||||||
runtime.SetFinalizer(stream, nil)
|
runtime.SetFinalizer(stream, nil)
|
||||||
C.git_odb_stream_free(stream.ptr)
|
C.git_odb_stream_free(stream.ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OdbWritepack is a stream to write a packfile to the ODB.
|
||||||
|
type OdbWritepack struct {
|
||||||
|
ptr *C.git_odb_writepack
|
||||||
|
stats C.git_transfer_progress
|
||||||
|
callbacks RemoteCallbacks
|
||||||
|
callbacksHandle unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (writepack *OdbWritepack) Write(data []byte) (int, error) {
|
||||||
|
header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
|
||||||
|
ptr := unsafe.Pointer(header.Data)
|
||||||
|
size := C.size_t(header.Len)
|
||||||
|
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C._go_git_odb_writepack_append(writepack.ptr, ptr, size, &writepack.stats)
|
||||||
|
if ret < 0 {
|
||||||
|
return 0, MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(data), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (writepack *OdbWritepack) Commit() error {
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
ret := C._go_git_odb_writepack_commit(writepack.ptr, &writepack.stats)
|
||||||
|
if ret < 0 {
|
||||||
|
return MakeGitError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (writepack *OdbWritepack) Free() {
|
||||||
|
pointerHandles.Untrack(writepack.callbacksHandle)
|
||||||
|
runtime.SetFinalizer(writepack, nil)
|
||||||
|
C._go_git_odb_writepack_free(writepack.ptr)
|
||||||
|
}
|
||||||
|
|
25
wrapper.c
25
wrapper.c
|
@ -174,4 +174,29 @@ void _go_git_writestream_free(git_writestream *stream)
|
||||||
stream->free(stream);
|
stream->free(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int _go_git_odb_write_pack(git_odb_writepack **out, git_odb *db, void *progress_payload)
|
||||||
|
{
|
||||||
|
return git_odb_write_pack(out, db, (git_transfer_progress_cb)transferProgressCallback, progress_payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _go_git_odb_writepack_append(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats)
|
||||||
|
{
|
||||||
|
return writepack->append(writepack, data, size, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _go_git_odb_writepack_commit(git_odb_writepack *writepack, git_transfer_progress *stats)
|
||||||
|
{
|
||||||
|
return writepack->commit(writepack, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _go_git_odb_writepack_free(git_odb_writepack *writepack)
|
||||||
|
{
|
||||||
|
writepack->free(writepack);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _go_git_indexer_new(git_indexer **out, const char *path, unsigned int mode, git_odb *odb, void *progress_cb_payload)
|
||||||
|
{
|
||||||
|
return git_indexer_new(out, path, mode, odb, (git_transfer_progress_cb)transferProgressCallback, progress_cb_payload);
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in New Issue