aboutsummaryrefslogblamecommitdiffstats
path: root/plumbing/storer/object.go
blob: c7841b6017a8df3733239e620cde63ae19e35bf5 (plain) (tree)
1
2
3
4
5
6
7
8
9
              

        
                
            
 
                                           

 


                                                               

 












































                                                                                    

 






                                                                            

 






                                                                              
                              
                            

                                   




                                                                             

                                                                                                


                                 
                           



                                                                              
                                                                             


                                                                             


                                         
 
                                     
                                                     

                          
         
 
                       

 

                                                                            
                                                                          
                                                                             
                                        

 




                                                     




                                                                              
                             
                                



                                                                                
                                                                    







                                                                              
                                                              
                                  

                                  



                                     


                       

                                                                            
                                                                          
                                                                            
                                        

 

                                                     
                                         
 
















                                                                                
                                                              
















                                                                            
                                                                            










                                                     
                                       




                                                                          
                                                                               















                                               
                                  


                 
package storer

import (
	"errors"
	"io"

	"gopkg.in/src-d/go-git.v4/plumbing"
)

var (
	//ErrStop is used to stop a ForEach function in an Iter
	ErrStop = errors.New("stop iter")
)

// ObjectStorer generic storage of objects
type ObjectStorer interface {
	// NewObject returns a new plumbing.Object, the real type of the object can
	// be a custom implementation or the defaul one, plumbing.MemoryObject
	NewObject() plumbing.Object
	// SetObject save an object into the storage, the object shuld be create
	// with the NewObject, method, and file if the type is not supported.
	SetObject(plumbing.Object) (plumbing.Hash, error)
	// Object get an object by hash with the given plumbing.ObjectType.
	// Implementors should return (nil, plumbing.ErrObjectNotFound) if an object
	// doesn't exist with both the given hash and object type.
	//
	// Valid plumbing.ObjectType values are CommitObject, BlobObject, TagObject,
	// TreeObject and AnyObject. If plumbing.AnyObject is given, the object must
	// be looked up regardless of its type.
	Object(plumbing.ObjectType, plumbing.Hash) (plumbing.Object, error)
	// IterObjects returns a custom ObjectIter over all the object on the
	// storage.
	//
	// Valid plumbing.ObjectType values are CommitObject, BlobObject, TagObject,
	IterObjects(plumbing.ObjectType) (ObjectIter, error)
}

// Transactioner is a optional method for ObjectStorer, it enable transaction
// base write and read operations in the storage
type Transactioner interface {
	// Begin starts a transaction.
	Begin() Transaction
}

// PackfileWriter is a optional method for ObjectStorer, it enable direct write
// of packfile to the storage
type PackfileWriter interface {
	// PackfileWriter retuns a writer for writing a packfile to the storage
	//
	// If the Storer not implements PackfileWriter the objects should be written
	// using the Set method.
	PackfileWriter() (io.WriteCloser, error)
}

// ObjectIter is a generic closable interface for iterating over objects.
type ObjectIter interface {
	Next() (plumbing.Object, error)
	ForEach(func(plumbing.Object) error) error
	Close()
}

// Transaction is an in-progress storage transaction. A transaction must end
// with a call to Commit or Rollback.
type Transaction interface {
	SetObject(plumbing.Object) (plumbing.Hash, error)
	Object(plumbing.ObjectType, plumbing.Hash) (plumbing.Object, error)
	Commit() error
	Rollback() error
}

// 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 ObjectStorer
	series  []plumbing.Hash
	t       plumbing.ObjectType
	pos     int
}

// NewObjectLookupIter returns an object iterator given an object storage and
// a slice of object hashes.
func NewObjectLookupIter(
	storage ObjectStorer, t plumbing.ObjectType, series []plumbing.Hash) *ObjectLookupIter {
	return &ObjectLookupIter{
		storage: storage,
		series:  series,
		t:       t,
	}
}

// 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 plumbing.ErrObjectNotFound as an error.
// If the object is retreieved successfully error will be nil.
func (iter *ObjectLookupIter) Next() (plumbing.Object, error) {
	if iter.pos >= len(iter.series) {
		return nil, io.EOF
	}

	hash := iter.series[iter.pos]
	obj, err := iter.storage.Object(iter.t, hash)
	if err == nil {
		iter.pos++
	}

	return obj, err
}

// ForEach call the cb function for each object contained on this iter until
// an error happends 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 *ObjectLookupIter) ForEach(cb func(plumbing.Object) error) error {
	return ForEachIterator(iter, cb)
}

// 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 []plumbing.Object
	pos    int
}

// NewObjectSliceIter returns an object iterator for the given slice of objects.
func NewObjectSliceIter(series []plumbing.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() (plumbing.Object, error) {
	if len(iter.series) == 0 {
		return nil, io.EOF
	}

	obj := iter.series[0]
	iter.series = iter.series[1:]

	return obj, nil
}

// ForEach call the cb function for each object contained on this iter until
// an error happends 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 *ObjectSliceIter) ForEach(cb func(plumbing.Object) error) error {
	return ForEachIterator(iter, cb)
}

// Close releases any resources used by the iterator.
func (iter *ObjectSliceIter) Close() {
	iter.series = []plumbing.Object{}
}

// MultiObjectIter implements ObjectIter. It iterates over several ObjectIter,
//
// The MultiObjectIter must be closed with a call to Close() when it is no
// longer needed.
type MultiObjectIter struct {
	iters []ObjectIter
	pos   int
}

// NewMultiObjectIter returns an object iterator for the given slice of objects.
func NewMultiObjectIter(iters []ObjectIter) ObjectIter {
	return &MultiObjectIter{iters: iters}
}

// Next returns the next object from the iterator, if one iterator reach io.EOF
// is removed and the next one is used.
func (iter *MultiObjectIter) Next() (plumbing.Object, 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 object contained on this iter until
// an error happends 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 *MultiObjectIter) ForEach(cb func(plumbing.Object) error) error {
	return ForEachIterator(iter, cb)
}

// Close releases any resources used by the iterator.
func (iter *MultiObjectIter) Close() {
	for _, i := range iter.iters {
		i.Close()
	}
}

type bareIterator interface {
	Next() (plumbing.Object, error)
	Close()
}

// ForEachIterator is a helper function to build iterators without need to
// rewrite the same ForEach function each time.
func ForEachIterator(iter bareIterator, cb func(plumbing.Object) 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
		}
	}
}