forked from gitea/gitea
289 lines
9.6 KiB
Go
289 lines
9.6 KiB
Go
package storer
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"time"
|
|
|
|
"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")
|
|
)
|
|
|
|
// EncodedObjectStorer generic storage of objects
|
|
type EncodedObjectStorer interface {
|
|
// NewEncodedObject returns a new plumbing.EncodedObject, the real type
|
|
// of the object can be a custom implementation or the default one,
|
|
// plumbing.MemoryObject.
|
|
NewEncodedObject() plumbing.EncodedObject
|
|
// SetEncodedObject saves an object into the storage, the object should
|
|
// be create with the NewEncodedObject, method, and file if the type is
|
|
// not supported.
|
|
SetEncodedObject(plumbing.EncodedObject) (plumbing.Hash, error)
|
|
// EncodedObject gets 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.
|
|
EncodedObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, error)
|
|
// IterObjects returns a custom EncodedObjectStorer over all the object
|
|
// on the storage.
|
|
//
|
|
// Valid plumbing.ObjectType values are CommitObject, BlobObject, TagObject,
|
|
IterEncodedObjects(plumbing.ObjectType) (EncodedObjectIter, error)
|
|
// HasEncodedObject returns ErrObjNotFound if the object doesn't
|
|
// exist. If the object does exist, it returns nil.
|
|
HasEncodedObject(plumbing.Hash) error
|
|
// EncodedObjectSize returns the plaintext size of the encoded object.
|
|
EncodedObjectSize(plumbing.Hash) (int64, error)
|
|
}
|
|
|
|
// DeltaObjectStorer is an EncodedObjectStorer that can return delta
|
|
// objects.
|
|
type DeltaObjectStorer interface {
|
|
// DeltaObject is the same as EncodedObject but without resolving deltas.
|
|
// Deltas will be returned as plumbing.DeltaObject instances.
|
|
DeltaObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, 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
|
|
}
|
|
|
|
// LooseObjectStorer is an optional interface for managing "loose"
|
|
// objects, i.e. those not in packfiles.
|
|
type LooseObjectStorer interface {
|
|
// ForEachObjectHash iterates over all the (loose) object hashes
|
|
// in the repository without necessarily having to read those objects.
|
|
// Objects only inside pack files may be omitted.
|
|
// If ErrStop is sent the iteration is stop but no error is returned.
|
|
ForEachObjectHash(func(plumbing.Hash) error) error
|
|
// LooseObjectTime looks up the (m)time associated with the
|
|
// loose object (that is not in a pack file). Some
|
|
// implementations (e.g. without loose objects)
|
|
// always return an error.
|
|
LooseObjectTime(plumbing.Hash) (time.Time, error)
|
|
// DeleteLooseObject deletes a loose object if it exists.
|
|
DeleteLooseObject(plumbing.Hash) error
|
|
}
|
|
|
|
// PackedObjectStorer is an optional interface for managing objects in
|
|
// packfiles.
|
|
type PackedObjectStorer interface {
|
|
// ObjectPacks returns hashes of object packs if the underlying
|
|
// implementation has pack files.
|
|
ObjectPacks() ([]plumbing.Hash, error)
|
|
// DeleteOldObjectPackAndIndex deletes an object pack and the corresponding index file if they exist.
|
|
// Deletion is only performed if the pack is older than the supplied time (or the time is zero).
|
|
DeleteOldObjectPackAndIndex(plumbing.Hash, time.Time) error
|
|
}
|
|
|
|
// PackfileWriter is a optional method for ObjectStorer, it enable direct write
|
|
// of packfile to the storage
|
|
type PackfileWriter interface {
|
|
// PackfileWriter returns 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)
|
|
}
|
|
|
|
// EncodedObjectIter is a generic closable interface for iterating over objects.
|
|
type EncodedObjectIter interface {
|
|
Next() (plumbing.EncodedObject, error)
|
|
ForEach(func(plumbing.EncodedObject) error) error
|
|
Close()
|
|
}
|
|
|
|
// Transaction is an in-progress storage transaction. A transaction must end
|
|
// with a call to Commit or Rollback.
|
|
type Transaction interface {
|
|
SetEncodedObject(plumbing.EncodedObject) (plumbing.Hash, error)
|
|
EncodedObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, error)
|
|
Commit() error
|
|
Rollback() error
|
|
}
|
|
|
|
// EncodedObjectLookupIter implements EncodedObjectIter. 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 EncodedObjectLookupIter must be closed with a call to Close() when it is
|
|
// no longer needed.
|
|
type EncodedObjectLookupIter struct {
|
|
storage EncodedObjectStorer
|
|
series []plumbing.Hash
|
|
t plumbing.ObjectType
|
|
pos int
|
|
}
|
|
|
|
// NewEncodedObjectLookupIter returns an object iterator given an object storage
|
|
// and a slice of object hashes.
|
|
func NewEncodedObjectLookupIter(
|
|
storage EncodedObjectStorer, t plumbing.ObjectType, series []plumbing.Hash) *EncodedObjectLookupIter {
|
|
return &EncodedObjectLookupIter{
|
|
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 *EncodedObjectLookupIter) Next() (plumbing.EncodedObject, error) {
|
|
if iter.pos >= len(iter.series) {
|
|
return nil, io.EOF
|
|
}
|
|
|
|
hash := iter.series[iter.pos]
|
|
obj, err := iter.storage.EncodedObject(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 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 *EncodedObjectLookupIter) ForEach(cb func(plumbing.EncodedObject) error) error {
|
|
return ForEachIterator(iter, cb)
|
|
}
|
|
|
|
// Close releases any resources used by the iterator.
|
|
func (iter *EncodedObjectLookupIter) Close() {
|
|
iter.pos = len(iter.series)
|
|
}
|
|
|
|
// EncodedObjectSliceIter implements EncodedObjectIter. It iterates over a
|
|
// series of objects stored in a slice and yields each one in turn when Next()
|
|
// is called.
|
|
//
|
|
// The EncodedObjectSliceIter must be closed with a call to Close() when it is
|
|
// no longer needed.
|
|
type EncodedObjectSliceIter struct {
|
|
series []plumbing.EncodedObject
|
|
}
|
|
|
|
// NewEncodedObjectSliceIter returns an object iterator for the given slice of
|
|
// objects.
|
|
func NewEncodedObjectSliceIter(series []plumbing.EncodedObject) *EncodedObjectSliceIter {
|
|
return &EncodedObjectSliceIter{
|
|
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 *EncodedObjectSliceIter) Next() (plumbing.EncodedObject, 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 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 *EncodedObjectSliceIter) ForEach(cb func(plumbing.EncodedObject) error) error {
|
|
return ForEachIterator(iter, cb)
|
|
}
|
|
|
|
// Close releases any resources used by the iterator.
|
|
func (iter *EncodedObjectSliceIter) Close() {
|
|
iter.series = []plumbing.EncodedObject{}
|
|
}
|
|
|
|
// MultiEncodedObjectIter implements EncodedObjectIter. It iterates over several
|
|
// EncodedObjectIter,
|
|
//
|
|
// The MultiObjectIter must be closed with a call to Close() when it is no
|
|
// longer needed.
|
|
type MultiEncodedObjectIter struct {
|
|
iters []EncodedObjectIter
|
|
}
|
|
|
|
// NewMultiEncodedObjectIter returns an object iterator for the given slice of
|
|
// objects.
|
|
func NewMultiEncodedObjectIter(iters []EncodedObjectIter) EncodedObjectIter {
|
|
return &MultiEncodedObjectIter{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 *MultiEncodedObjectIter) Next() (plumbing.EncodedObject, 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 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 *MultiEncodedObjectIter) ForEach(cb func(plumbing.EncodedObject) error) error {
|
|
return ForEachIterator(iter, cb)
|
|
}
|
|
|
|
// Close releases any resources used by the iterator.
|
|
func (iter *MultiEncodedObjectIter) Close() {
|
|
for _, i := range iter.iters {
|
|
i.Close()
|
|
}
|
|
}
|
|
|
|
type bareIterator interface {
|
|
Next() (plumbing.EncodedObject, 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.EncodedObject) 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
|
|
}
|
|
}
|
|
}
|