From 621397026ce94dc3a536b7dbdde31ad00b0b14a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 11 Sep 2013 19:17:45 +0200 Subject: [PATCH] Wrap the odb streams The interface to these streams should be what you expect from Go, and both have Write and Close functions so they implement Reader/ReadCloser and Write/WriteCloser respectively. --- odb.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++ odb_test.go | 35 ++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 odb_test.go diff --git a/odb.go b/odb.go index 9d7d02e..8e6f0cc 100644 --- a/odb.go +++ b/odb.go @@ -72,6 +72,33 @@ func (v *Odb) ForEach() chan *Oid { return ch } +// 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 } @@ -102,3 +129,68 @@ 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) +} diff --git a/odb_test.go b/odb_test.go new file mode 100644 index 0000000..bf1f847 --- /dev/null +++ b/odb_test.go @@ -0,0 +1,35 @@ +package git + +import ( + "io" + "os" + "testing" +) + +func TestOdbStream(t *testing.T) { + repo := createTestRepo(t) + defer os.RemoveAll(repo.Workdir()) + _, _ = seedTestRepo(t, repo) + + odb, error := repo.Odb() + checkFatal(t, error) + + str := "hello, world!" + + stream, error := odb.NewWriteStream(len(str), OBJ_BLOB) + checkFatal(t, error) + n, error := io.WriteString(stream, str) + checkFatal(t, error) + if n != len(str) { + t.Fatalf("Bad write length %v != %v", n, len(str)) + } + + error = stream.Close() + checkFatal(t, error) + + expectedId, error := NewOidFromString("30f51a3fba5274d53522d0f19748456974647b4f") + checkFatal(t, error) + if stream.Id.Cmp(expectedId) != 0 { + t.Fatal("Wrong data written") + } +} \ No newline at end of file