aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing
diff options
context:
space:
mode:
Diffstat (limited to 'plumbing')
-rw-r--r--plumbing/memory.go17
-rw-r--r--plumbing/memory_test.go28
2 files changed, 42 insertions, 3 deletions
diff --git a/plumbing/memory.go b/plumbing/memory.go
index b8e1e1b..21337cc 100644
--- a/plumbing/memory.go
+++ b/plumbing/memory.go
@@ -3,7 +3,6 @@ package plumbing
import (
"bytes"
"io"
- "io/ioutil"
)
// MemoryObject on memory Object implementation
@@ -39,9 +38,11 @@ func (o *MemoryObject) Size() int64 { return o.sz }
// afterwards
func (o *MemoryObject) SetSize(s int64) { o.sz = s }
-// Reader returns a ObjectReader used to read the object's content.
+// Reader returns an io.ReadCloser used to read the object's content.
+//
+// For a MemoryObject, this reader is seekable.
func (o *MemoryObject) Reader() (io.ReadCloser, error) {
- return ioutil.NopCloser(bytes.NewBuffer(o.cont)), nil
+ return nopCloser{bytes.NewReader(o.cont)}, nil
}
// Writer returns a ObjectWriter used to write the object's content.
@@ -59,3 +60,13 @@ func (o *MemoryObject) Write(p []byte) (n int, err error) {
// Close releases any resources consumed by the object when it is acting as a
// ObjectWriter.
func (o *MemoryObject) Close() error { return nil }
+
+// nopCloser exposes the extra methods of bytes.Reader while nopping Close().
+//
+// This allows clients to attempt seeking in a cached Blob's Reader.
+type nopCloser struct {
+ *bytes.Reader
+}
+
+// Close does nothing.
+func (nc nopCloser) Close() error { return nil }
diff --git a/plumbing/memory_test.go b/plumbing/memory_test.go
index 879ed37..2a141f4 100644
--- a/plumbing/memory_test.go
+++ b/plumbing/memory_test.go
@@ -1,6 +1,7 @@
package plumbing
import (
+ "io"
"io/ioutil"
. "gopkg.in/check.v1"
@@ -56,6 +57,33 @@ func (s *MemoryObjectSuite) TestReader(c *C) {
c.Assert(b, DeepEquals, []byte("foo"))
}
+func (s *MemoryObjectSuite) TestSeekableReader(c *C) {
+ const pageSize = 4096
+ const payload = "foo"
+ content := make([]byte, pageSize+len(payload))
+ copy(content[pageSize:], []byte(payload))
+
+ o := &MemoryObject{cont: content}
+
+ reader, err := o.Reader()
+ c.Assert(err, IsNil)
+ defer func() { c.Assert(reader.Close(), IsNil) }()
+
+ rs, ok := reader.(io.ReadSeeker)
+ c.Assert(ok, Equals, true)
+
+ _, err = rs.Seek(pageSize, io.SeekStart)
+ c.Assert(err, IsNil)
+
+ b, err := ioutil.ReadAll(rs)
+ c.Assert(err, IsNil)
+ c.Assert(b, DeepEquals, []byte(payload))
+
+ // Check that our Reader isn't also accidentally writable
+ _, ok = reader.(io.WriteSeeker)
+ c.Assert(ok, Equals, false)
+}
+
func (s *MemoryObjectSuite) TestWriter(c *C) {
o := &MemoryObject{}