|
- package storer
-
- import (
- "errors"
- "io"
-
- "gopkg.in/src-d/go-git.v4/plumbing"
- )
-
- const MaxResolveRecursion = 1024
-
- // ErrMaxResolveRecursion is returned by ResolveReference is MaxResolveRecursion
- // is exceeded
- var ErrMaxResolveRecursion = errors.New("max. recursion level reached")
-
- // ReferenceStorer is a generic storage of references.
- type ReferenceStorer interface {
- SetReference(*plumbing.Reference) error
- // CheckAndSetReference sets the reference `new`, but if `old` is
- // not `nil`, it first checks that the current stored value for
- // `old.Name()` matches the given reference value in `old`. If
- // not, it returns an error and doesn't update `new`.
- CheckAndSetReference(new, old *plumbing.Reference) error
- Reference(plumbing.ReferenceName) (*plumbing.Reference, error)
- IterReferences() (ReferenceIter, error)
- RemoveReference(plumbing.ReferenceName) error
- CountLooseRefs() (int, error)
- PackRefs() error
- }
-
- // ReferenceIter is a generic closable interface for iterating over references.
- type ReferenceIter interface {
- Next() (*plumbing.Reference, error)
- ForEach(func(*plumbing.Reference) error) error
- Close()
- }
-
- type referenceFilteredIter struct {
- ff func(r *plumbing.Reference) bool
- iter ReferenceIter
- }
-
- // NewReferenceFilteredIter returns a reference iterator for the given reference
- // Iterator. This iterator will iterate only references that accomplish the
- // provided function.
- func NewReferenceFilteredIter(
- ff func(r *plumbing.Reference) bool, iter ReferenceIter) ReferenceIter {
- return &referenceFilteredIter{ff, iter}
- }
-
- // Next returns the next reference from the iterator. If the iterator has reached
- // the end it will return io.EOF as an error.
- func (iter *referenceFilteredIter) Next() (*plumbing.Reference, error) {
- for {
- r, err := iter.iter.Next()
- if err != nil {
- return nil, err
- }
-
- if iter.ff(r) {
- return r, nil
- }
-
- continue
- }
- }
-
- // ForEach call the cb function for each reference contained on this iter until
- // an error happens or the end of the iter is reached. If ErrStop is sent
- // the iteration is stopped but no error is returned. The iterator is closed.
- func (iter *referenceFilteredIter) ForEach(cb func(*plumbing.Reference) error) error {
- defer iter.Close()
- for {
- r, err := iter.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- return err
- }
-
- if err := cb(r); err != nil {
- if err == ErrStop {
- break
- }
-
- return err
- }
- }
-
- return nil
- }
-
- // Close releases any resources used by the iterator.
- func (iter *referenceFilteredIter) Close() {
- iter.iter.Close()
- }
-
- // ReferenceSliceIter implements ReferenceIter. It iterates over a series of
- // references stored in a slice and yields each one in turn when Next() is
- // called.
- //
- // The ReferenceSliceIter must be closed with a call to Close() when it is no
- // longer needed.
- type ReferenceSliceIter struct {
- series []*plumbing.Reference
- pos int
- }
-
- // NewReferenceSliceIter returns a reference iterator for the given slice of
- // objects.
- func NewReferenceSliceIter(series []*plumbing.Reference) ReferenceIter {
- return &ReferenceSliceIter{
- series: series,
- }
- }
-
- // Next returns the next reference from the iterator. If the iterator has
- // reached the end it will return io.EOF as an error.
- func (iter *ReferenceSliceIter) Next() (*plumbing.Reference, error) {
- if iter.pos >= len(iter.series) {
- return nil, io.EOF
- }
-
- obj := iter.series[iter.pos]
- iter.pos++
- return obj, nil
- }
-
- // ForEach call the cb function for each reference contained on this iter until
- // an error happens or the end of the iter is reached. If ErrStop is sent
- // the iteration is stop but no error is returned. The iterator is closed.
- func (iter *ReferenceSliceIter) ForEach(cb func(*plumbing.Reference) error) error {
- return forEachReferenceIter(iter, cb)
- }
-
- type bareReferenceIterator interface {
- Next() (*plumbing.Reference, error)
- Close()
- }
-
- func forEachReferenceIter(iter bareReferenceIterator, cb func(*plumbing.Reference) error) error {
- defer iter.Close()
- for {
- obj, err := iter.Next()
- if err != nil {
- if err == io.EOF {
- return nil
- }
-
- return err
- }
-
- if err := cb(obj); err != nil {
- if err == ErrStop {
- return nil
- }
-
- return err
- }
- }
- }
-
- // Close releases any resources used by the iterator.
- func (iter *ReferenceSliceIter) Close() {
- iter.pos = len(iter.series)
- }
-
- // MultiReferenceIter implements ReferenceIter. It iterates over several
- // ReferenceIter,
- //
- // The MultiReferenceIter must be closed with a call to Close() when it is no
- // longer needed.
- type MultiReferenceIter struct {
- iters []ReferenceIter
- }
-
- // NewMultiReferenceIter returns an reference iterator for the given slice of
- // EncodedObjectIters.
- func NewMultiReferenceIter(iters []ReferenceIter) ReferenceIter {
- return &MultiReferenceIter{iters: iters}
- }
-
- // Next returns the next reference from the iterator, if one iterator reach
- // io.EOF is removed and the next one is used.
- func (iter *MultiReferenceIter) Next() (*plumbing.Reference, error) {
- if len(iter.iters) == 0 {
- return nil, io.EOF
- }
-
- obj, err := iter.iters[0].Next()
- if err == io.EOF {
- iter.iters[0].Close()
- iter.iters = iter.iters[1:]
- return iter.Next()
- }
-
- return obj, err
- }
-
- // ForEach call the cb function for each reference contained on this iter until
- // an error happens or the end of the iter is reached. If ErrStop is sent
- // the iteration is stop but no error is returned. The iterator is closed.
- func (iter *MultiReferenceIter) ForEach(cb func(*plumbing.Reference) error) error {
- return forEachReferenceIter(iter, cb)
- }
-
- // Close releases any resources used by the iterator.
- func (iter *MultiReferenceIter) Close() {
- for _, i := range iter.iters {
- i.Close()
- }
- }
-
- // ResolveReference resolves a SymbolicReference to a HashReference.
- func ResolveReference(s ReferenceStorer, n plumbing.ReferenceName) (*plumbing.Reference, error) {
- r, err := s.Reference(n)
- if err != nil || r == nil {
- return r, err
- }
- return resolveReference(s, r, 0)
- }
-
- func resolveReference(s ReferenceStorer, r *plumbing.Reference, recursion int) (*plumbing.Reference, error) {
- if r.Type() != plumbing.SymbolicReference {
- return r, nil
- }
-
- if recursion > MaxResolveRecursion {
- return nil, ErrMaxResolveRecursion
- }
-
- t, err := s.Reference(r.Target())
- if err != nil {
- return nil, err
- }
-
- recursion++
- return resolveReference(s, t, recursion)
- }
|