Skip to content

Commit 686fe1b

Browse files
committed
pack: add a storage wrapper for packs
Add a wrapper around a pack set that provides a storage interface as defined by the fs module. This allows us to emulate object storage from packs in an abstract way.
1 parent d0a722e commit 686fe1b

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

pack/delayed_object.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package pack
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
"strings"
8+
)
9+
10+
// delayedObjectReader provides an interface for reading from an Object while
11+
// loading object data into memory only on demand. It implements io.ReadCloser.
12+
type delayedObjectReader struct {
13+
obj *Object
14+
mr io.Reader
15+
}
16+
17+
// Read implements the io.Reader method by instantiating a new underlying reader
18+
// only on demand.
19+
func (d *delayedObjectReader) Read(b []byte) (int, error) {
20+
if d.mr == nil {
21+
data, err := d.obj.Unpack()
22+
if err != nil {
23+
return 0, err
24+
}
25+
d.mr = io.MultiReader(
26+
// Git object header:
27+
strings.NewReader(fmt.Sprintf("%s %d\x00",
28+
d.obj.Type(), len(data),
29+
)),
30+
31+
// Git object (uncompressed) contents:
32+
bytes.NewReader(data),
33+
)
34+
}
35+
return d.mr.Read(b)
36+
}
37+
38+
// Close implements the io.Closer interface.
39+
func (d *delayedObjectReader) Close() error {
40+
return nil
41+
}

pack/storage.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package pack
2+
3+
import (
4+
"io"
5+
)
6+
7+
// Storage implements the storage.Storage interface.
8+
type Storage struct {
9+
packs *Set
10+
}
11+
12+
// NewStorage returns a new storage object based on a pack set.
13+
func NewStorage(root string) (*Storage, error) {
14+
packs, err := NewSet(root)
15+
if err != nil {
16+
return nil, err
17+
}
18+
return &Storage{packs: packs}, nil
19+
}
20+
21+
// Open implements the storage.Storage.Open interface.
22+
func (f *Storage) Open(oid []byte) (r io.ReadCloser, err error) {
23+
obj, err := f.packs.Object(oid)
24+
if err != nil {
25+
return nil, err
26+
}
27+
return &delayedObjectReader{obj: obj}, nil
28+
}
29+
30+
// Open implements the storage.Storage.Open interface.
31+
func (f *Storage) Close() error {
32+
return f.packs.Close()
33+
}
34+
35+
// IsCompressed returns false, because data returned is already decompressed.
36+
func (f *Storage) IsCompressed() bool {
37+
return false
38+
}

0 commit comments

Comments
 (0)