From a964e32d92c53a47ce7c46d589a18c62133b8c50 Mon Sep 17 00:00:00 2001 From: Máximo Cuadros Date: Wed, 17 Feb 2016 00:24:31 +0100 Subject: storages: memory object --- storage/memory/object.go | 55 ++++++++++++++++++++++++++++ storage/memory/object_test.go | 67 ++++++++++++++++++++++++++++++++++ storage/memory/storage.go | 83 ++++++++++++++++++++++++++++++++++++++++++ storage/memory/storage_test.go | 51 ++++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 storage/memory/object.go create mode 100644 storage/memory/object_test.go create mode 100644 storage/memory/storage.go create mode 100644 storage/memory/storage_test.go (limited to 'storage/memory') 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) +} -- cgit