aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Sjoding <joshs@scjalliance.com>2016-01-23 00:50:29 -0800
committerJoshua Sjoding <joshs@scjalliance.com>2016-01-23 00:50:29 -0800
commit7ba1014b73e4d466320a29f7e3f47fcefe58695d (patch)
treebe9ff334eaae5547651d2084021fcfd4b70a9db9
parent050fb78d77b30014acd0b6eefc88ec8a49c20371 (diff)
downloadgo-git-7ba1014b73e4d466320a29f7e3f47fcefe58695d.tar.gz
Repository now works against the generic ObjectStore interface
-rw-r--r--commit.go57
-rw-r--r--commit_test.go3
-rw-r--r--core/object.go98
-rw-r--r--repository.go12
-rw-r--r--tree.go17
5 files changed, 122 insertions, 65 deletions
diff --git a/commit.go b/commit.go
index ea6419f..47e48fe 100644
--- a/commit.go
+++ b/commit.go
@@ -34,16 +34,7 @@ func (c *Commit) Tree() *Tree {
}
func (c *Commit) Parents() *CommitIter {
- i := NewCommitIter(c.r)
- go func() {
- defer i.Close()
- for _, hash := range c.parents {
- obj, _ := c.r.Storage.Get(hash)
- i.Add(obj)
- }
- }()
-
- return i
+ return NewCommitIter(c.r, core.NewObjectLookupIter(c.r.Storage, c.parents))
}
// NumParents returns the number of parents in a commit.
@@ -106,52 +97,24 @@ func (c *Commit) String() string {
}
type CommitIter struct {
- iter
+ core.ObjectIter
+ r *Repository
}
-func NewCommitIter(r *Repository) *CommitIter {
- return &CommitIter{newIter(r)}
+func NewCommitIter(r *Repository, iter core.ObjectIter) *CommitIter {
+ return &CommitIter{iter, r}
}
-func (i *CommitIter) Next() (*Commit, error) {
- obj := <-i.ch
- if obj == nil {
- return nil, io.EOF
+func (iter *CommitIter) Next() (*Commit, error) {
+ obj, err := iter.ObjectIter.Next()
+ if err != nil {
+ return nil, err
}
- commit := &Commit{r: i.r}
+ commit := &Commit{r: iter.r}
return commit, commit.Decode(obj)
}
-type iter struct {
- ch chan core.Object
- r *Repository
-
- IsClosed bool
-}
-
-func newIter(r *Repository) iter {
- ch := make(chan core.Object, 1)
- return iter{ch: ch, r: r}
-}
-
-func (i *iter) Add(o core.Object) {
- if i.IsClosed {
- return
- }
-
- i.ch <- o
-}
-
-func (i *iter) Close() {
- if i.IsClosed {
- return
- }
-
- defer func() { i.IsClosed = true }()
- close(i.ch)
-}
-
type commitSorterer struct {
l []*Commit
}
diff --git a/commit_test.go b/commit_test.go
index 67b9e77..1202d59 100644
--- a/commit_test.go
+++ b/commit_test.go
@@ -40,11 +40,14 @@ func (s *SuiteCommit) SetUpSuite(c *C) {
}
}
+// FIXME: Test the new CommitIter
+/*
func (s *SuiteCommit) TestIterClose(c *C) {
i := &iter{ch: make(chan core.Object, 1)}
i.Close()
i.Close()
}
+*/
var fileTests = []struct {
repo string // the repo name as in localRepos
diff --git a/core/object.go b/core/object.go
index 4e8a587..205de95 100644
--- a/core/object.go
+++ b/core/object.go
@@ -21,6 +21,7 @@ type ObjectStorage interface {
New() Object
Set(Object) Hash
Get(Hash) (Object, bool)
+ Iter(ObjectType) ObjectIter
}
// ObjectType internal object type's
@@ -52,6 +53,82 @@ 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 yields a series of objects by retrieving each one from
+// object storage.
+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 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, ok := iter.storage.Get(hash)
+ if !ok {
+ // FIXME: Consider making ObjectStorage.Get return an actual error that we
+ // could pass back here.
+ return nil, io.EOF
+ }
+ iter.pos++
+ return obj, nil
+}
+
+// Close releases any resources used by the iterator.
+func (iter *ObjectLookupIter) Close() {
+ iter.pos = len(iter.series)
+}
+
+// ObjectSliceIter yields a series of objects from a slice of objects.
+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
@@ -111,3 +188,24 @@ func (o *RAWObjectStorage) Get(h Hash) (Object, bool) {
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
+}
diff --git a/repository.go b/repository.go
index 5deddfb..d0bc103 100644
--- a/repository.go
+++ b/repository.go
@@ -19,7 +19,7 @@ const (
type Repository struct {
Remotes map[string]*Remote
- Storage *core.RAWObjectStorage
+ Storage core.ObjectStorage
URL string
}
@@ -100,15 +100,7 @@ func (r *Repository) Commit(h core.Hash) (*Commit, error) {
// Commits decode the objects into commits
func (r *Repository) Commits() *CommitIter {
- i := NewCommitIter(r)
- go func() {
- defer i.Close()
- for _, obj := range r.Storage.Commits {
- i.Add(obj)
- }
- }()
-
- return i
+ return NewCommitIter(r, r.Storage.Iter(core.CommitObject))
}
// Tree return the tree with the given hash
diff --git a/tree.go b/tree.go
index e88b1e6..8398725 100644
--- a/tree.go
+++ b/tree.go
@@ -187,19 +187,20 @@ func (t *Tree) Decode(o core.Object) error {
}
type TreeIter struct {
- iter
+ core.ObjectIter
+ r *Repository
}
-func NewTreeIter(r *Repository) *TreeIter {
- return &TreeIter{newIter(r)}
+func NewTreeIter(r *Repository, iter core.ObjectIter) *TreeIter {
+ return &TreeIter{iter, r}
}
-func (i *TreeIter) Next() (*Tree, error) {
- obj := <-i.ch
- if obj == nil {
- return nil, io.EOF
+func (iter *TreeIter) Next() (*Tree, error) {
+ obj, err := iter.ObjectIter.Next()
+ if err != nil {
+ return nil, err
}
- tree := &Tree{r: i.r}
+ tree := &Tree{r: iter.r}
return tree, tree.Decode(obj)
}