本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
9.6KB

  1. package storer
  2. import (
  3. "errors"
  4. "io"
  5. "time"
  6. "gopkg.in/src-d/go-git.v4/plumbing"
  7. )
  8. var (
  9. //ErrStop is used to stop a ForEach function in an Iter
  10. ErrStop = errors.New("stop iter")
  11. )
  12. // EncodedObjectStorer generic storage of objects
  13. type EncodedObjectStorer interface {
  14. // NewEncodedObject returns a new plumbing.EncodedObject, the real type
  15. // of the object can be a custom implementation or the default one,
  16. // plumbing.MemoryObject.
  17. NewEncodedObject() plumbing.EncodedObject
  18. // SetEncodedObject saves an object into the storage, the object should
  19. // be create with the NewEncodedObject, method, and file if the type is
  20. // not supported.
  21. SetEncodedObject(plumbing.EncodedObject) (plumbing.Hash, error)
  22. // EncodedObject gets an object by hash with the given
  23. // plumbing.ObjectType. Implementors should return
  24. // (nil, plumbing.ErrObjectNotFound) if an object doesn't exist with
  25. // both the given hash and object type.
  26. //
  27. // Valid plumbing.ObjectType values are CommitObject, BlobObject, TagObject,
  28. // TreeObject and AnyObject. If plumbing.AnyObject is given, the object must
  29. // be looked up regardless of its type.
  30. EncodedObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, error)
  31. // IterObjects returns a custom EncodedObjectStorer over all the object
  32. // on the storage.
  33. //
  34. // Valid plumbing.ObjectType values are CommitObject, BlobObject, TagObject,
  35. IterEncodedObjects(plumbing.ObjectType) (EncodedObjectIter, error)
  36. // HasEncodedObject returns ErrObjNotFound if the object doesn't
  37. // exist. If the object does exist, it returns nil.
  38. HasEncodedObject(plumbing.Hash) error
  39. // EncodedObjectSize returns the plaintext size of the encoded object.
  40. EncodedObjectSize(plumbing.Hash) (int64, error)
  41. }
  42. // DeltaObjectStorer is an EncodedObjectStorer that can return delta
  43. // objects.
  44. type DeltaObjectStorer interface {
  45. // DeltaObject is the same as EncodedObject but without resolving deltas.
  46. // Deltas will be returned as plumbing.DeltaObject instances.
  47. DeltaObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, error)
  48. }
  49. // Transactioner is a optional method for ObjectStorer, it enable transaction
  50. // base write and read operations in the storage
  51. type Transactioner interface {
  52. // Begin starts a transaction.
  53. Begin() Transaction
  54. }
  55. // LooseObjectStorer is an optional interface for managing "loose"
  56. // objects, i.e. those not in packfiles.
  57. type LooseObjectStorer interface {
  58. // ForEachObjectHash iterates over all the (loose) object hashes
  59. // in the repository without necessarily having to read those objects.
  60. // Objects only inside pack files may be omitted.
  61. // If ErrStop is sent the iteration is stop but no error is returned.
  62. ForEachObjectHash(func(plumbing.Hash) error) error
  63. // LooseObjectTime looks up the (m)time associated with the
  64. // loose object (that is not in a pack file). Some
  65. // implementations (e.g. without loose objects)
  66. // always return an error.
  67. LooseObjectTime(plumbing.Hash) (time.Time, error)
  68. // DeleteLooseObject deletes a loose object if it exists.
  69. DeleteLooseObject(plumbing.Hash) error
  70. }
  71. // PackedObjectStorer is an optional interface for managing objects in
  72. // packfiles.
  73. type PackedObjectStorer interface {
  74. // ObjectPacks returns hashes of object packs if the underlying
  75. // implementation has pack files.
  76. ObjectPacks() ([]plumbing.Hash, error)
  77. // DeleteOldObjectPackAndIndex deletes an object pack and the corresponding index file if they exist.
  78. // Deletion is only performed if the pack is older than the supplied time (or the time is zero).
  79. DeleteOldObjectPackAndIndex(plumbing.Hash, time.Time) error
  80. }
  81. // PackfileWriter is a optional method for ObjectStorer, it enable direct write
  82. // of packfile to the storage
  83. type PackfileWriter interface {
  84. // PackfileWriter returns a writer for writing a packfile to the storage
  85. //
  86. // If the Storer not implements PackfileWriter the objects should be written
  87. // using the Set method.
  88. PackfileWriter() (io.WriteCloser, error)
  89. }
  90. // EncodedObjectIter is a generic closable interface for iterating over objects.
  91. type EncodedObjectIter interface {
  92. Next() (plumbing.EncodedObject, error)
  93. ForEach(func(plumbing.EncodedObject) error) error
  94. Close()
  95. }
  96. // Transaction is an in-progress storage transaction. A transaction must end
  97. // with a call to Commit or Rollback.
  98. type Transaction interface {
  99. SetEncodedObject(plumbing.EncodedObject) (plumbing.Hash, error)
  100. EncodedObject(plumbing.ObjectType, plumbing.Hash) (plumbing.EncodedObject, error)
  101. Commit() error
  102. Rollback() error
  103. }
  104. // EncodedObjectLookupIter implements EncodedObjectIter. It iterates over a
  105. // series of object hashes and yields their associated objects by retrieving
  106. // each one from object storage. The retrievals are lazy and only occur when the
  107. // iterator moves forward with a call to Next().
  108. //
  109. // The EncodedObjectLookupIter must be closed with a call to Close() when it is
  110. // no longer needed.
  111. type EncodedObjectLookupIter struct {
  112. storage EncodedObjectStorer
  113. series []plumbing.Hash
  114. t plumbing.ObjectType
  115. pos int
  116. }
  117. // NewEncodedObjectLookupIter returns an object iterator given an object storage
  118. // and a slice of object hashes.
  119. func NewEncodedObjectLookupIter(
  120. storage EncodedObjectStorer, t plumbing.ObjectType, series []plumbing.Hash) *EncodedObjectLookupIter {
  121. return &EncodedObjectLookupIter{
  122. storage: storage,
  123. series: series,
  124. t: t,
  125. }
  126. }
  127. // Next returns the next object from the iterator. If the iterator has reached
  128. // the end it will return io.EOF as an error. If the object can't be found in
  129. // the object storage, it will return plumbing.ErrObjectNotFound as an error.
  130. // If the object is retreieved successfully error will be nil.
  131. func (iter *EncodedObjectLookupIter) Next() (plumbing.EncodedObject, error) {
  132. if iter.pos >= len(iter.series) {
  133. return nil, io.EOF
  134. }
  135. hash := iter.series[iter.pos]
  136. obj, err := iter.storage.EncodedObject(iter.t, hash)
  137. if err == nil {
  138. iter.pos++
  139. }
  140. return obj, err
  141. }
  142. // ForEach call the cb function for each object contained on this iter until
  143. // an error happens or the end of the iter is reached. If ErrStop is sent
  144. // the iteration is stop but no error is returned. The iterator is closed.
  145. func (iter *EncodedObjectLookupIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  146. return ForEachIterator(iter, cb)
  147. }
  148. // Close releases any resources used by the iterator.
  149. func (iter *EncodedObjectLookupIter) Close() {
  150. iter.pos = len(iter.series)
  151. }
  152. // EncodedObjectSliceIter implements EncodedObjectIter. It iterates over a
  153. // series of objects stored in a slice and yields each one in turn when Next()
  154. // is called.
  155. //
  156. // The EncodedObjectSliceIter must be closed with a call to Close() when it is
  157. // no longer needed.
  158. type EncodedObjectSliceIter struct {
  159. series []plumbing.EncodedObject
  160. }
  161. // NewEncodedObjectSliceIter returns an object iterator for the given slice of
  162. // objects.
  163. func NewEncodedObjectSliceIter(series []plumbing.EncodedObject) *EncodedObjectSliceIter {
  164. return &EncodedObjectSliceIter{
  165. series: series,
  166. }
  167. }
  168. // Next returns the next object from the iterator. If the iterator has reached
  169. // the end it will return io.EOF as an error. If the object is retreieved
  170. // successfully error will be nil.
  171. func (iter *EncodedObjectSliceIter) Next() (plumbing.EncodedObject, error) {
  172. if len(iter.series) == 0 {
  173. return nil, io.EOF
  174. }
  175. obj := iter.series[0]
  176. iter.series = iter.series[1:]
  177. return obj, nil
  178. }
  179. // ForEach call the cb function for each object contained on this iter until
  180. // an error happens or the end of the iter is reached. If ErrStop is sent
  181. // the iteration is stop but no error is returned. The iterator is closed.
  182. func (iter *EncodedObjectSliceIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  183. return ForEachIterator(iter, cb)
  184. }
  185. // Close releases any resources used by the iterator.
  186. func (iter *EncodedObjectSliceIter) Close() {
  187. iter.series = []plumbing.EncodedObject{}
  188. }
  189. // MultiEncodedObjectIter implements EncodedObjectIter. It iterates over several
  190. // EncodedObjectIter,
  191. //
  192. // The MultiObjectIter must be closed with a call to Close() when it is no
  193. // longer needed.
  194. type MultiEncodedObjectIter struct {
  195. iters []EncodedObjectIter
  196. }
  197. // NewMultiEncodedObjectIter returns an object iterator for the given slice of
  198. // EncodedObjectIters.
  199. func NewMultiEncodedObjectIter(iters []EncodedObjectIter) EncodedObjectIter {
  200. return &MultiEncodedObjectIter{iters: iters}
  201. }
  202. // Next returns the next object from the iterator, if one iterator reach io.EOF
  203. // is removed and the next one is used.
  204. func (iter *MultiEncodedObjectIter) Next() (plumbing.EncodedObject, error) {
  205. if len(iter.iters) == 0 {
  206. return nil, io.EOF
  207. }
  208. obj, err := iter.iters[0].Next()
  209. if err == io.EOF {
  210. iter.iters[0].Close()
  211. iter.iters = iter.iters[1:]
  212. return iter.Next()
  213. }
  214. return obj, err
  215. }
  216. // ForEach call the cb function for each object contained on this iter until
  217. // an error happens or the end of the iter is reached. If ErrStop is sent
  218. // the iteration is stop but no error is returned. The iterator is closed.
  219. func (iter *MultiEncodedObjectIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  220. return ForEachIterator(iter, cb)
  221. }
  222. // Close releases any resources used by the iterator.
  223. func (iter *MultiEncodedObjectIter) Close() {
  224. for _, i := range iter.iters {
  225. i.Close()
  226. }
  227. }
  228. type bareIterator interface {
  229. Next() (plumbing.EncodedObject, error)
  230. Close()
  231. }
  232. // ForEachIterator is a helper function to build iterators without need to
  233. // rewrite the same ForEach function each time.
  234. func ForEachIterator(iter bareIterator, cb func(plumbing.EncodedObject) error) error {
  235. defer iter.Close()
  236. for {
  237. obj, err := iter.Next()
  238. if err != nil {
  239. if err == io.EOF {
  240. return nil
  241. }
  242. return err
  243. }
  244. if err := cb(obj); err != nil {
  245. if err == ErrStop {
  246. return nil
  247. }
  248. return err
  249. }
  250. }
  251. }
上海开阖软件有限公司 沪ICP备12045867号-1