Skip to content

Commit 58ac863

Browse files
authored
Merge pull request go-git#121 from riking/cache-seek
plumbing: memoryobject, make blob reader seekable
2 parents ee580ee + d0d47c3 commit 58ac863

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

plumbing/memory.go

+14-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package plumbing
33
import (
44
"bytes"
55
"io"
6-
"io/ioutil"
76
)
87

98
// MemoryObject on memory Object implementation
@@ -39,9 +38,11 @@ func (o *MemoryObject) Size() int64 { return o.sz }
3938
// afterwards
4039
func (o *MemoryObject) SetSize(s int64) { o.sz = s }
4140

42-
// Reader returns a ObjectReader used to read the object's content.
41+
// Reader returns an io.ReadCloser used to read the object's content.
42+
//
43+
// For a MemoryObject, this reader is seekable.
4344
func (o *MemoryObject) Reader() (io.ReadCloser, error) {
44-
return ioutil.NopCloser(bytes.NewBuffer(o.cont)), nil
45+
return nopCloser{bytes.NewReader(o.cont)}, nil
4546
}
4647

4748
// 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) {
5960
// Close releases any resources consumed by the object when it is acting as a
6061
// ObjectWriter.
6162
func (o *MemoryObject) Close() error { return nil }
63+
64+
// nopCloser exposes the extra methods of bytes.Reader while nopping Close().
65+
//
66+
// This allows clients to attempt seeking in a cached Blob's Reader.
67+
type nopCloser struct {
68+
*bytes.Reader
69+
}
70+
71+
// Close does nothing.
72+
func (nc nopCloser) Close() error { return nil }

plumbing/memory_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package plumbing
22

33
import (
4+
"io"
45
"io/ioutil"
56

67
. "gopkg.in/check.v1"
@@ -56,6 +57,33 @@ func (s *MemoryObjectSuite) TestReader(c *C) {
5657
c.Assert(b, DeepEquals, []byte("foo"))
5758
}
5859

60+
func (s *MemoryObjectSuite) TestSeekableReader(c *C) {
61+
const pageSize = 4096
62+
const payload = "foo"
63+
content := make([]byte, pageSize+len(payload))
64+
copy(content[pageSize:], []byte(payload))
65+
66+
o := &MemoryObject{cont: content}
67+
68+
reader, err := o.Reader()
69+
c.Assert(err, IsNil)
70+
defer func() { c.Assert(reader.Close(), IsNil) }()
71+
72+
rs, ok := reader.(io.ReadSeeker)
73+
c.Assert(ok, Equals, true)
74+
75+
_, err = rs.Seek(pageSize, io.SeekStart)
76+
c.Assert(err, IsNil)
77+
78+
b, err := ioutil.ReadAll(rs)
79+
c.Assert(err, IsNil)
80+
c.Assert(b, DeepEquals, []byte(payload))
81+
82+
// Check that our Reader isn't also accidentally writable
83+
_, ok = reader.(io.WriteSeeker)
84+
c.Assert(ok, Equals, false)
85+
}
86+
5987
func (s *MemoryObjectSuite) TestWriter(c *C) {
6088
o := &MemoryObject{}
6189

0 commit comments

Comments
 (0)