aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2016-02-17 00:24:31 +0100
committerMáximo Cuadros <mcuadros@gmail.com>2016-02-17 11:46:00 +0100
commita964e32d92c53a47ce7c46d589a18c62133b8c50 (patch)
tree4c094cd6afb95cb2832f866b9411276418435819
parent1ac00554c3b5f88d2ddc2e28e7cfcdcad9d9f4bb (diff)
downloadgo-git-a964e32d92c53a47ce7c46d589a18c62133b8c50.tar.gz
storages: memory object
-rw-r--r--commit.go4
-rw-r--r--core/hash.go3
-rw-r--r--core/object.go87
-rw-r--r--formats/packfile/reader.go4
-rw-r--r--formats/packfile/reader_test.go11
-rw-r--r--objects.go7
-rw-r--r--objects_test.go3
-rw-r--r--remote_test.go4
-rw-r--r--repository.go3
-rw-r--r--storage/memory/object.go55
-rw-r--r--storage/memory/object_test.go67
-rw-r--r--storage/memory/storage.go83
-rw-r--r--storage/memory/storage_test.go51
-rw-r--r--tree.go4
14 files changed, 289 insertions, 97 deletions
diff --git a/commit.go b/commit.go
index 47e48fe..cdfc902 100644
--- a/commit.go
+++ b/commit.go
@@ -51,6 +51,10 @@ func (c *Commit) File(path string) (file *File, err error) {
// Decode transform an core.Object into a Blob struct
func (c *Commit) Decode(o core.Object) error {
+ if o.Type() != core.CommitObject {
+ return ErrUnsupportedObject
+ }
+
c.Hash = o.Hash()
r := bufio.NewReader(o.Reader())
diff --git a/core/hash.go b/core/hash.go
index 0b6f274..9b30b6e 100644
--- a/core/hash.go
+++ b/core/hash.go
@@ -9,6 +9,9 @@ import (
// Hash SHA1 hased content
type Hash [20]byte
+// ZeroHash is Hash with value zero
+var ZeroHash Hash
+
// ComputeHash compute the hash for a given ObjectType and content
func ComputeHash(t ObjectType, content []byte) Hash {
h := t.Bytes()
diff --git a/core/object.go b/core/object.go
index 857c6df..e64f650 100644
--- a/core/object.go
+++ b/core/object.go
@@ -2,7 +2,6 @@
package core
import (
- "bytes"
"errors"
"io"
)
@@ -13,11 +12,11 @@ var (
// Object is a generic representation of any git object
type Object interface {
+ Hash() Hash
Type() ObjectType
SetType(ObjectType)
Size() int64
SetSize(int64)
- Hash() Hash
Reader() io.Reader
Writer() io.Writer
}
@@ -147,87 +146,3 @@ func (iter *ObjectSliceIter) Next() (Object, error) {
func (iter *ObjectSliceIter) Close() {
iter.pos = len(iter.series)
}
-
-type RAWObject struct {
- b []byte
- t ObjectType
- s int64
-}
-
-func (o *RAWObject) Type() ObjectType { return o.t }
-func (o *RAWObject) SetType(t ObjectType) { o.t = t }
-func (o *RAWObject) Size() int64 { return o.s }
-func (o *RAWObject) SetSize(s int64) { o.s = s }
-func (o *RAWObject) Reader() io.Reader { return bytes.NewBuffer(o.b) }
-func (o *RAWObject) Hash() Hash { return ComputeHash(o.t, o.b) }
-func (o *RAWObject) Writer() io.Writer { return o }
-func (o *RAWObject) Write(p []byte) (n int, err error) {
- o.b = append(o.b, p...)
- return len(p), nil
-}
-
-type RAWObjectStorage struct {
- Objects map[Hash]Object
- Commits map[Hash]Object
- Trees map[Hash]Object
- Blobs map[Hash]Object
-}
-
-func NewRAWObjectStorage() *RAWObjectStorage {
- return &RAWObjectStorage{
- Objects: make(map[Hash]Object, 0),
- Commits: make(map[Hash]Object, 0),
- Trees: make(map[Hash]Object, 0),
- Blobs: make(map[Hash]Object, 0),
- }
-}
-
-func (o *RAWObjectStorage) New() (Object, error) {
- return &RAWObject{}, nil
-}
-
-func (o *RAWObjectStorage) Set(obj Object) (Hash, error) {
- h := obj.Hash()
- o.Objects[h] = obj
-
- switch obj.Type() {
- case CommitObject:
- o.Commits[h] = o.Objects[h]
- case TreeObject:
- o.Trees[h] = o.Objects[h]
- case BlobObject:
- o.Blobs[h] = o.Objects[h]
- }
-
- return h, nil
-}
-
-func (o *RAWObjectStorage) Get(h Hash) (Object, error) {
- obj, ok := o.Objects[h]
- if !ok {
- return nil, ObjectNotFoundErr
- }
-
- return obj, nil
-}
-
-func (o *RAWObjectStorage) Iter(t ObjectType) ObjectIter {
- var series []Object
- switch t {
- case CommitObject:
- series = flattenObjectMap(o.Commits)
- case TreeObject:
- series = flattenObjectMap(o.Trees)
- case BlobObject:
- series = flattenObjectMap(o.Blobs)
- }
- return NewObjectSliceIter(series)
-}
-
-func flattenObjectMap(m map[Hash]Object) []Object {
- objects := make([]Object, 0, len(m))
- for _, obj := range m {
- objects = append(objects, obj)
- }
- return objects
-}
diff --git a/formats/packfile/reader.go b/formats/packfile/reader.go
index 91aef21..e981d72 100644
--- a/formats/packfile/reader.go
+++ b/formats/packfile/reader.go
@@ -125,7 +125,7 @@ func (r *Reader) readObjects(count uint32) error {
// of which 12-20 % is _not_ zlib inflation (ie. is our code).
for i := 0; i < int(count); i++ {
start := r.r.position
- obj, err := r.newRAWObject()
+ obj, err := r.newObject()
if err != nil && err != io.EOF {
return err
}
@@ -143,7 +143,7 @@ func (r *Reader) readObjects(count uint32) error {
return nil
}
-func (r *Reader) newRAWObject() (core.Object, error) {
+func (r *Reader) newObject() (core.Object, error) {
raw, err := r.s.New()
if err != nil {
return nil, err
diff --git a/formats/packfile/reader_test.go b/formats/packfile/reader_test.go
index f460614..69069c8 100644
--- a/formats/packfile/reader_test.go
+++ b/formats/packfile/reader_test.go
@@ -10,6 +10,7 @@ import (
"time"
"gopkg.in/src-d/go-git.v2/core"
+ "gopkg.in/src-d/go-git.v2/storages/memory"
"github.com/dustin/go-humanize"
. "gopkg.in/check.v1"
@@ -29,7 +30,7 @@ func (s *ReaderSuite) TestReadPackfile(c *C) {
r := NewReader(d)
- storage := core.NewRAWObjectStorage()
+ storage := memory.NewObjectStorage()
_, err := r.Read(storage)
c.Assert(err, IsNil)
@@ -63,7 +64,7 @@ func (s *ReaderSuite) testReadPackfileGitFixture(c *C, file string, f Format) {
r := NewReader(d)
r.Format = f
- storage := core.NewRAWObjectStorage()
+ storage := memory.NewObjectStorage()
_, err = r.Read(storage)
c.Assert(err, IsNil)
@@ -99,7 +100,7 @@ func (s *ReaderSuite) testReadPackfileGitFixture(c *C, file string, f Format) {
})
}
-func AssertObjects(c *C, s *core.RAWObjectStorage, expects []string) {
+func AssertObjects(c *C, s *memory.ObjectStorage, expects []string) {
c.Assert(len(expects), Equals, len(s.Objects))
for _, expected := range expects {
obtained, err := s.Get(core.NewHash(expected))
@@ -174,14 +175,14 @@ func (s *ReaderSuite) _TestMemoryREF(c *C) {
fmt.Println("time", time.Since(start))
}
-func readFromFile(c *C, file string, f Format) *core.RAWObjectStorage {
+func readFromFile(c *C, file string, f Format) *memory.ObjectStorage {
d, err := os.Open(file)
c.Assert(err, IsNil)
r := NewReader(d)
r.Format = f
- storage := core.NewRAWObjectStorage()
+ storage := memory.NewObjectStorage()
_, err = r.Read(storage)
c.Assert(err, IsNil)
diff --git a/objects.go b/objects.go
index 9397bc8..cf2c1ff 100644
--- a/objects.go
+++ b/objects.go
@@ -1,6 +1,7 @@
package git
import (
+ "errors"
"fmt"
"io"
"strconv"
@@ -17,8 +18,14 @@ type Blob struct {
obj core.Object
}
+var ErrUnsupportedObject = errors.New("unsupported object type")
+
// Decode transform an core.Object into a Blob struct
func (b *Blob) Decode(o core.Object) error {
+ if o.Type() != core.BlobObject {
+ return ErrUnsupportedObject
+ }
+
b.Hash = o.Hash()
b.Size = o.Size()
b.obj = o
diff --git a/objects_test.go b/objects_test.go
index bc83cb7..683ab15 100644
--- a/objects_test.go
+++ b/objects_test.go
@@ -6,6 +6,7 @@ import (
. "gopkg.in/check.v1"
"gopkg.in/src-d/go-git.v2/core"
+ "gopkg.in/src-d/go-git.v2/storages/memory"
)
type ObjectsSuite struct {
@@ -71,7 +72,7 @@ func (s *ObjectsSuite) TestParseTree(c *C) {
}
func (s *ObjectsSuite) TestBlobHash(c *C) {
- o := &core.RAWObject{}
+ o := &memory.Object{}
o.SetType(core.BlobObject)
o.SetSize(3)
o.Writer().Write([]byte{'F', 'O', 'O'})
diff --git a/remote_test.go b/remote_test.go
index 7a40deb..14c7ec1 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -2,8 +2,8 @@ package git
import (
"gopkg.in/src-d/go-git.v2/clients/http"
- "gopkg.in/src-d/go-git.v2/core"
"gopkg.in/src-d/go-git.v2/formats/packfile"
+ "gopkg.in/src-d/go-git.v2/storages/memory"
. "gopkg.in/check.v1"
)
@@ -57,7 +57,7 @@ func (s *SuiteRemote) TestFetchDefaultBranch(c *C) {
pr := packfile.NewReader(reader)
- storage := core.NewRAWObjectStorage()
+ storage := memory.NewObjectStorage()
_, err = pr.Read(storage)
c.Assert(err, IsNil)
c.Assert(storage.Objects, HasLen, 28)
diff --git a/repository.go b/repository.go
index 2532c8d..c2665ff 100644
--- a/repository.go
+++ b/repository.go
@@ -7,6 +7,7 @@ import (
"gopkg.in/src-d/go-git.v2/clients/common"
"gopkg.in/src-d/go-git.v2/core"
"gopkg.in/src-d/go-git.v2/formats/packfile"
+ "gopkg.in/src-d/go-git.v2/storages/memory"
)
var (
@@ -49,7 +50,7 @@ func NewRepository(url string, auth common.AuthMethod) (*Repository, error) {
func NewPlainRepository() *Repository {
return &Repository{
Remotes: map[string]*Remote{},
- Storage: core.NewRAWObjectStorage(),
+ Storage: memory.NewObjectStorage(),
}
}
diff --git a/storage/memory/object.go b/storage/memory/object.go
new file mode 100644
index 0000000..7fee252
--- /dev/null
+++ b/storage/memory/object.go
@@ -0,0 +1,55 @@
+package memory
+
+import (
+ "bytes"
+ "io"
+
+ "gopkg.in/src-d/go-git.v2/core"
+)
+
+// Object on memory core.Object implementation
+type Object struct {
+ t core.ObjectType
+ h core.Hash
+ content []byte
+ size int64
+}
+
+// Hash return the object Hash, the hash is calculated on-the-fly the first
+// time is called, the subsequent calls the same Hash is returned even in the
+// type or the content has changed. The Hash is only generated if the size of
+// the content is exactly the Object.Size
+func (o *Object) Hash() core.Hash {
+ if o.h == core.ZeroHash && int64(len(o.content)) == o.size {
+ o.h = core.ComputeHash(o.t, o.content)
+ }
+
+ return o.h
+}
+
+// Type return the core.ObjectType
+func (o *Object) Type() core.ObjectType { return o.t }
+
+// SetType sets the core.ObjectType
+func (o *Object) SetType(t core.ObjectType) { o.t = t }
+
+// Size return the size of the object
+func (o *Object) Size() int64 { return o.size }
+
+// SetSize set the object size, the given size should be written afterwards
+func (o *Object) SetSize(s int64) { o.size = s }
+
+// Reader returns a io.Reader used to read the object content
+func (o *Object) Reader() io.Reader {
+ return bytes.NewBuffer(o.content)
+}
+
+// Writer returns a io.Writed used to write the object content
+func (o *Object) Writer() io.Writer {
+ return o
+}
+
+func (o *Object) Write(p []byte) (n int, err error) {
+ o.content = append(o.content, p...)
+ return len(p), nil
+}
diff --git a/storage/memory/object_test.go b/storage/memory/object_test.go
new file mode 100644
index 0000000..b606eb2
--- /dev/null
+++ b/storage/memory/object_test.go
@@ -0,0 +1,67 @@
+package memory
+
+import (
+ "io/ioutil"
+ "testing"
+
+ . "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git.v2/core"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type ObjectSuite struct{}
+
+var _ = Suite(&ObjectSuite{})
+
+func (s *ObjectSuite) TestHash(c *C) {
+ o := &Object{}
+ o.SetType(core.BlobObject)
+ o.SetSize(14)
+
+ _, err := o.Write([]byte("Hello, World!\n"))
+ c.Assert(err, IsNil)
+
+ c.Assert(o.Hash().String(), Equals, "8ab686eafeb1f44702738c8b0f24f2567c36da6d")
+
+ o.SetType(core.CommitObject)
+ c.Assert(o.Hash().String(), Equals, "8ab686eafeb1f44702738c8b0f24f2567c36da6d")
+}
+
+func (s *ObjectSuite) TestHashNotFilled(c *C) {
+ o := &Object{}
+ o.SetType(core.BlobObject)
+ o.SetSize(14)
+
+ c.Assert(o.Hash(), Equals, core.ZeroHash)
+}
+
+func (s *ObjectSuite) TestType(c *C) {
+ o := &Object{}
+ o.SetType(core.BlobObject)
+ c.Assert(o.Type(), Equals, core.BlobObject)
+}
+
+func (s *ObjectSuite) TestSize(c *C) {
+ o := &Object{}
+ o.SetSize(42)
+ c.Assert(o.Size(), Equals, int64(42))
+}
+
+func (s *ObjectSuite) TestReader(c *C) {
+ o := &Object{content: []byte("foo")}
+
+ b, err := ioutil.ReadAll(o.Reader())
+ c.Assert(err, IsNil)
+ c.Assert(b, DeepEquals, []byte("foo"))
+}
+
+func (s *ObjectSuite) TestWriter(c *C) {
+ o := &Object{}
+
+ n, err := o.Writer().Write([]byte("foo"))
+ c.Assert(err, IsNil)
+ c.Assert(n, Equals, 3)
+
+ c.Assert(o.content, DeepEquals, []byte("foo"))
+}
diff --git a/storage/memory/storage.go b/storage/memory/storage.go
new file mode 100644
index 0000000..4c106cc
--- /dev/null
+++ b/storage/memory/storage.go
@@ -0,0 +1,83 @@
+package memory
+
+import (
+ "fmt"
+
+ "gopkg.in/src-d/go-git.v2/core"
+)
+
+var ErrUnsupportedObjectType = fmt.Errorf("unsupported object type")
+
+// ObjectStorage is the implementation of core.ObjectStorage for memory.Object
+type ObjectStorage struct {
+ Objects map[core.Hash]core.Object
+ Commits map[core.Hash]core.Object
+ Trees map[core.Hash]core.Object
+ Blobs map[core.Hash]core.Object
+}
+
+// NewObjectStorage returns a new empty ObjectStorage
+func NewObjectStorage() *ObjectStorage {
+ return &ObjectStorage{
+ Objects: make(map[core.Hash]core.Object, 0),
+ Commits: make(map[core.Hash]core.Object, 0),
+ Trees: make(map[core.Hash]core.Object, 0),
+ Blobs: make(map[core.Hash]core.Object, 0),
+ }
+}
+
+// New returns a new empty memory.Object
+func (o *ObjectStorage) New() (core.Object, error) {
+ return &Object{}, nil
+}
+
+// Set stores an object, the object should be properly filled before set it.
+func (o *ObjectStorage) Set(obj core.Object) (core.Hash, error) {
+ h := obj.Hash()
+ o.Objects[h] = obj
+
+ switch obj.Type() {
+ case core.CommitObject:
+ o.Commits[h] = o.Objects[h]
+ case core.TreeObject:
+ o.Trees[h] = o.Objects[h]
+ case core.BlobObject:
+ o.Blobs[h] = o.Objects[h]
+ default:
+ return h, ErrUnsupportedObjectType
+ }
+
+ return h, nil
+}
+
+// Get returns a object with the given hash
+func (o *ObjectStorage) Get(h core.Hash) (core.Object, error) {
+ obj, ok := o.Objects[h]
+ if !ok {
+ return nil, core.ObjectNotFoundErr
+ }
+
+ return obj, nil
+}
+
+// Iter returns a core.ObjectIter for the given core.ObjectTybe
+func (o *ObjectStorage) Iter(t core.ObjectType) core.ObjectIter {
+ var series []core.Object
+ switch t {
+ case core.CommitObject:
+ series = flattenObjectMap(o.Commits)
+ case core.TreeObject:
+ series = flattenObjectMap(o.Trees)
+ case core.BlobObject:
+ series = flattenObjectMap(o.Blobs)
+ }
+ return core.NewObjectSliceIter(series)
+}
+
+func flattenObjectMap(m map[core.Hash]core.Object) []core.Object {
+ objects := make([]core.Object, 0, len(m))
+ for _, obj := range m {
+ objects = append(objects, obj)
+ }
+ return objects
+}
diff --git a/storage/memory/storage_test.go b/storage/memory/storage_test.go
new file mode 100644
index 0000000..4059dfa
--- /dev/null
+++ b/storage/memory/storage_test.go
@@ -0,0 +1,51 @@
+package memory
+
+import (
+ . "gopkg.in/check.v1"
+ "gopkg.in/src-d/go-git.v2/core"
+)
+
+type ObjectStorageSuite struct{}
+
+var _ = Suite(&ObjectStorageSuite{})
+
+func (s *ObjectStorageSuite) TestNew(c *C) {
+ os := NewObjectStorage()
+
+ o, err := os.New()
+ c.Assert(err, IsNil)
+ c.Assert(o.Size(), Equals, int64(0))
+}
+
+func (s *ObjectStorageSuite) TestSet(c *C) {
+ os := NewObjectStorage()
+
+ o, err := os.New()
+ c.Assert(err, IsNil)
+
+ o.SetType(core.CommitObject)
+ o.SetSize(3)
+ o.Writer().Write([]byte("foo"))
+
+ h, err := os.Set(o)
+ c.Assert(h.String(), Equals, "bc9968d75e48de59f0870ffb71f5e160bbbdcf52")
+}
+
+func (s *ObjectStorageSuite) TestGet(c *C) {
+ os := NewObjectStorage()
+
+ o, err := os.New()
+ c.Assert(err, IsNil)
+
+ o.SetType(core.CommitObject)
+ o.SetSize(3)
+ o.Writer().Write([]byte("foo"))
+
+ h, err := os.Set(o)
+ c.Assert(err, IsNil)
+
+ ro, err := os.Get(h)
+ c.Assert(err, IsNil)
+
+ c.Assert(ro, DeepEquals, o)
+}
diff --git a/tree.go b/tree.go
index 4a964a4..e57d315 100644
--- a/tree.go
+++ b/tree.go
@@ -151,6 +151,10 @@ func (t *Tree) walkEntries(base string, ch chan *File) {
// Decode transform an core.Object into a Tree struct
func (t *Tree) Decode(o core.Object) error {
+ if o.Type() != core.TreeObject {
+ return ErrUnsupportedObject
+ }
+
t.Hash = o.Hash()
if o.Size() == 0 {
return nil