Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 1ae588f

Browse files
committed
core: ObjectStorage.Writer
1 parent 2da64ea commit 1ae588f

File tree

6 files changed

+118
-14
lines changed

6 files changed

+118
-14
lines changed

core/storage.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
package core
22

3-
import "errors"
3+
import (
4+
"errors"
5+
"io"
6+
)
47

5-
//ErrStop is used to stop a ForEach function in an Iter
6-
var ErrStop = errors.New("stop iter")
8+
var (
9+
//ErrStop is used to stop a ForEach function in an Iter
10+
ErrStop = errors.New("stop iter")
11+
ErrNotImplemented = errors.New("method not-implemented")
12+
)
713

814
// ObjectStorage generic storage of objects
915
type ObjectStorage interface {
1016
// NewObject returns a new Object, the real type of the object can be a
1117
// custom implementation or the defaul one, MemoryObject
1218
NewObject() Object
19+
// Writer retuns a writer for writing a packfile to the Storage, this method
20+
// is optional, if not implemented the ObjectStorage should return a
21+
// ErrNotImplemented error.
22+
//
23+
// If the implementation not implements Writer the objects should be written
24+
// using the Set method.
25+
Writer() (io.WriteCloser, error)
1326
// Set save an object into the storage, the object shuld be create with
1427
// the NewObject, method, and file if the type is not supported.
1528
Set(Object) (Hash, error)
1629
// Get an object by hash with the given ObjectType. Implementors should
1730
// return (nil, ErrObjectNotFound) if an object doesn't exist with both the
1831
// given hash and object type.
1932
//
20-
// Valid ObjectType values are CommitObject, BlobObject, TagObject, TreeObject
21-
// and AnyObject.
33+
// Valid ObjectType values are CommitObject, BlobObject, TagObject,
34+
// TreeObject and AnyObject.
2235
//
2336
// If AnyObject is given, the object must be looked up regardless of its type.
2437
Get(ObjectType, Hash) (Object, error)
2538
// Iter returns a custom ObjectIter over all the object on the storage.
2639
//
27-
// Valid ObjectType values are CommitObject, BlobObject, TagObject, TreeObject
28-
// and AnyObject.
40+
// Valid ObjectType values are CommitObject, BlobObject, TagObject,
2941
Iter(ObjectType) (ObjectIter, error)
3042
// Begin starts a transaction.
3143
Begin() TxObjectStorage

examples/storage/aerospike/storage.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ func (s *ObjectStorage) NewObject() core.Object {
7070
return &core.MemoryObject{}
7171
}
7272

73+
// Writer method not supported, this method is optional to implemented.
74+
func (s *ObjectStorage) Writer() (io.WriteCloser, error) {
75+
return nil, core.ErrNotImplemented
76+
}
77+
7378
func (s *ObjectStorage) Set(obj core.Object) (core.Hash, error) {
7479
key, err := s.buildKey(obj.Hash(), obj.Type())
7580
if err != nil {

storage/filesystem/internal/index/index.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,26 @@ func NewFromIdx(r io.Reader) (Index, error) {
3535

3636
// NewFrompackfile returns a new index from a packfile reader.
3737
func NewFromPackfile(rs io.ReadSeeker) (Index, error) {
38-
index := make(Index)
38+
s := packfile.NewSeekable(rs)
39+
return newFromPackfile(rs, s)
40+
}
3941

40-
r := packfile.NewSeekable(rs)
41-
p := packfile.NewParser(r)
42+
func NewFromPackfileInMemory(rs io.Reader) (Index, error) {
43+
s := packfile.NewStream(rs)
44+
return newFromPackfile(rs, s)
45+
}
4246

47+
func newFromPackfile(r io.Reader, s packfile.ReadRecaller) (Index, error) {
48+
index := make(Index)
49+
50+
p := packfile.NewParser(s)
4351
count, err := p.ReadHeader()
4452
if err != nil {
4553
return nil, err
4654
}
4755

4856
for i := 0; i < int(count); i++ {
49-
offset, err := r.Offset()
57+
offset, err := s.Offset()
5058
if err != nil {
5159
return nil, err
5260
}
@@ -56,17 +64,19 @@ func NewFromPackfile(rs io.ReadSeeker) (Index, error) {
5664
return nil, err
5765
}
5866

59-
err = r.Remember(offset, obj)
67+
err = s.Remember(offset, obj)
6068
if err != nil {
6169
return nil, err
6270
}
6371

64-
err = index.Set(obj.Hash(), offset)
65-
if err != nil {
72+
if err = index.Set(obj.Hash(), offset); err != nil {
6673
return nil, err
6774
}
6875
}
6976

77+
//The trailer records 20-byte SHA-1 checksum of all of the above.
78+
p.ReadHash()
79+
7080
return index, nil
7181
}
7282

storage/filesystem/object.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package filesystem
22

33
import (
4+
"bytes"
45
"fmt"
6+
"io"
57
"os"
68

79
"gopkg.in/src-d/go-git.v4/core"
@@ -30,6 +32,58 @@ func (s *ObjectStorage) NewObject() core.Object {
3032
return &core.MemoryObject{}
3133
}
3234

35+
// Writer method not supported on Memory storage
36+
func (o *ObjectStorage) Writer() (io.WriteCloser, error) {
37+
file := bytes.NewBuffer(nil)
38+
return newPackWrite(o, file), nil
39+
}
40+
41+
type packWriter struct {
42+
writer io.Writer
43+
pipeReader io.ReadCloser
44+
pipeWriter io.WriteCloser
45+
file io.Writer
46+
result chan error
47+
}
48+
49+
func newPackWrite(o *ObjectStorage, file io.Writer) io.WriteCloser {
50+
r, w := io.Pipe()
51+
52+
ch := make(chan error)
53+
go func(r io.ReadCloser) {
54+
defer r.Close()
55+
index, err := index.NewFromPackfileInMemory(r)
56+
o.index = index
57+
58+
ch <- err
59+
}(r)
60+
61+
return &packWriter{
62+
writer: io.MultiWriter(w, file),
63+
pipeReader: r,
64+
pipeWriter: w,
65+
file: file,
66+
result: ch,
67+
}
68+
69+
}
70+
71+
func (w *packWriter) Write(p []byte) (int, error) {
72+
return w.writer.Write(p)
73+
}
74+
75+
func (w *packWriter) Close() error {
76+
defer func() {
77+
close(w.result)
78+
}()
79+
80+
if err := w.pipeWriter.Close(); err != nil {
81+
return err
82+
}
83+
84+
return <-w.result
85+
}
86+
3387
// Set adds a new object to the storage. As this functionality is not
3488
// yet supported, this method always returns a "not implemented yet"
3589
// error an zero hash.

storage/filesystem/object_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package filesystem
22

33
import (
44
"fmt"
5+
"io"
56
"io/ioutil"
67
"os"
78
"reflect"
@@ -62,6 +63,22 @@ func (s *FsSuite) TearDownSuite(c *C) {
6263
}
6364
}
6465

66+
func (s *FsSuite) TestWriter(c *C) {
67+
r, err := os.Open("../../formats/packfile/fixtures/git-fixture.ofs-delta")
68+
c.Assert(err, IsNil)
69+
70+
o := &ObjectStorage{}
71+
w, err := o.Writer()
72+
c.Assert(err, IsNil)
73+
74+
n, err := io.Copy(w, r)
75+
c.Assert(err, IsNil)
76+
c.Check(n, Equals, int64(85300))
77+
78+
c.Assert(o.index, HasLen, 28)
79+
c.Assert(w.Close(), IsNil)
80+
}
81+
6582
func (s *FsSuite) TestHashNotFound(c *C) {
6683
sto := s.newObjectStorage(c, "binary-relations")
6784
types := []core.ObjectType{core.AnyObject, core.TagObject, core.CommitObject, core.BlobObject, core.TreeObject}

storage/memory/storage.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package memory
33

44
import (
55
"fmt"
6+
"io"
67

78
"gopkg.in/src-d/go-git.v4/config"
89
"gopkg.in/src-d/go-git.v4/core"
@@ -109,6 +110,11 @@ func (o *ObjectStorage) NewObject() core.Object {
109110
return &core.MemoryObject{}
110111
}
111112

113+
// Writer method not supported on Memory storage
114+
func (o *ObjectStorage) Writer() (io.WriteCloser, error) {
115+
return nil, core.ErrNotImplemented
116+
}
117+
112118
// Set stores an object, the object should be properly filled before set it.
113119
func (o *ObjectStorage) Set(obj core.Object) (core.Hash, error) {
114120
h := obj.Hash()

0 commit comments

Comments
 (0)