diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2016-02-16 17:58:07 +0100 |
---|---|---|
committer | Máximo Cuadros <mcuadros@gmail.com> | 2016-02-16 17:58:07 +0100 |
commit | a9896315a1b37b66865a0eb7e94e768ef45ff3db (patch) | |
tree | 8c4012969e4a5f430d385aa908f369fa843e815e /core | |
parent | 1931dfbf38508e790e9f129873bc073aacc6a50f (diff) | |
parent | e82d4918b403a641a5295b3f199586b0ab26b15c (diff) | |
download | go-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.go | 131 |
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 } |