summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Martín Nieto <[email protected]>2013-09-11 19:17:45 +0200
committerCarlos Martín Nieto <[email protected]>2013-09-11 19:25:40 +0200
commit621397026ce94dc3a536b7dbdde31ad00b0b14a8 (patch)
tree6dc4babaa434c35c6feff31c232dc61b4a06b20b
parent3cbfdf37f48c7b2f8726ad7e60a963cae1d8fd21 (diff)
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.
-rw-r--r--odb.go92
-rw-r--r--odb_test.go35
2 files changed, 127 insertions, 0 deletions
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