aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorMáximo Cuadros <mcuadros@gmail.com>2016-02-16 17:58:07 +0100
committerMáximo Cuadros <mcuadros@gmail.com>2016-02-16 17:58:07 +0100
commita9896315a1b37b66865a0eb7e94e768ef45ff3db (patch)
tree8c4012969e4a5f430d385aa908f369fa843e815e /core
parent1931dfbf38508e790e9f129873bc073aacc6a50f (diff)
parente82d4918b403a641a5295b3f199586b0ab26b15c (diff)
downloadgo-git-a9896315a1b37b66865a0eb7e94e768ef45ff3db.tar.gz
Merge pull request #20 from scjalliance/generic-object-storage
Iterable ObjectStorage interface for use in Repository struct
Diffstat (limited to 'core')
-rw-r--r--core/object.go131
1 files changed, 122 insertions, 9 deletions
diff --git a/core/object.go b/core/object.go
index ffc561b..857c6df 100644
--- a/core/object.go
+++ b/core/object.go
@@ -3,9 +3,14 @@ package core
import (
"bytes"
+ "errors"
"io"
)
+var (
+ ObjectNotFoundErr = errors.New("object not found")
+)
+
// Object is a generic representation of any git object
type Object interface {
Type() ObjectType
@@ -19,9 +24,10 @@ type Object interface {
// ObjectStorage generic storage of objects
type ObjectStorage interface {
- New() Object
- Set(Object) Hash
- Get(Hash) (Object, bool)
+ New() (Object, error)
+ Set(Object) (Hash, error)
+ Get(Hash) (Object, error)
+ Iter(ObjectType) ObjectIter
}
// ObjectType internal object type's
@@ -59,6 +65,89 @@ func (t ObjectType) Bytes() []byte {
return []byte(t.String())
}
+// ObjectIter is a generic closable interface for iterating over objects.
+type ObjectIter interface {
+ Next() (Object, error)
+ Close()
+}
+
+// ObjectLookupIter implements ObjectIter. It iterates over a series of object
+// hashes and yields their associated objects by retrieving each one from
+// object storage. The retrievals are lazy and only occur when the iterator
+// moves forward with a call to Next().
+//
+// The ObjectLookupIter must be closed with a call to Close() when it is no
+// longer needed.
+type ObjectLookupIter struct {
+ storage ObjectStorage
+ series []Hash
+ pos int
+}
+
+// NewObjectLookupIter returns an object iterator given an object storage and
+// a slice of object hashes.
+func NewObjectLookupIter(storage ObjectStorage, series []Hash) *ObjectLookupIter {
+ return &ObjectLookupIter{
+ storage: storage,
+ series: series,
+ }
+}
+
+// Next returns the next object from the iterator. If the iterator has reached
+// the end it will return io.EOF as an error. If the object can't be found in
+// the object storage, it will return ObjectNotFoundErr as an error. If the
+// object is retreieved successfully error will be nil.
+func (iter *ObjectLookupIter) Next() (Object, error) {
+ if iter.pos >= len(iter.series) {
+ return nil, io.EOF
+ }
+ hash := iter.series[iter.pos]
+ obj, err := iter.storage.Get(hash)
+ if err == nil {
+ iter.pos++
+ }
+ return obj, err
+}
+
+// Close releases any resources used by the iterator.
+func (iter *ObjectLookupIter) Close() {
+ iter.pos = len(iter.series)
+}
+
+// ObjectSliceIter implements ObjectIter. It iterates over a series of objects
+// stored in a slice and yields each one in turn when Next() is called.
+//
+// The ObjectSliceIter must be closed with a call to Close() when it is no
+// longer needed.
+type ObjectSliceIter struct {
+ series []Object
+ pos int
+}
+
+// NewObjectSliceIter returns an object iterator for the given slice of objects.
+func NewObjectSliceIter(series []Object) *ObjectSliceIter {
+ return &ObjectSliceIter{
+ series: series,
+ }
+}
+
+// Next returns the next object from the iterator. If the iterator has reached
+// the end it will return io.EOF as an error. If the object is retreieved
+// successfully error will be nil.
+func (iter *ObjectSliceIter) Next() (Object, error) {
+ if iter.pos >= len(iter.series) {
+ return nil, io.EOF
+ }
+ obj := iter.series[iter.pos]
+ iter.pos++
+ return obj, nil
+}
+
+// Close releases any resources used by the iterator.
+func (iter *ObjectSliceIter) Close() {
+ iter.pos = len(iter.series)
+}
+
type RAWObject struct {
b []byte
t ObjectType
@@ -93,11 +182,11 @@ func NewRAWObjectStorage() *RAWObjectStorage {
}
}
-func (o *RAWObjectStorage) New() Object {
- return &RAWObject{}
+func (o *RAWObjectStorage) New() (Object, error) {
+ return &RAWObject{}, nil
}
-func (o *RAWObjectStorage) Set(obj Object) Hash {
+func (o *RAWObjectStorage) Set(obj Object) (Hash, error) {
h := obj.Hash()
o.Objects[h] = obj
@@ -110,11 +199,35 @@ func (o *RAWObjectStorage) Set(obj Object) Hash {
o.Blobs[h] = o.Objects[h]
}
- return h
+ return h, nil
}
-func (o *RAWObjectStorage) Get(h Hash) (Object, bool) {
+func (o *RAWObjectStorage) Get(h Hash) (Object, error) {
obj, ok := o.Objects[h]
+ if !ok {
+ return nil, ObjectNotFoundErr
+ }
+
+ return obj, nil
+}
- return obj, ok
+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
}