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.

object.go 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  1. package filesystem
  2. import (
  3. "io"
  4. "os"
  5. "time"
  6. "github.com/go-git/go-git/v5/plumbing"
  7. "github.com/go-git/go-git/v5/plumbing/cache"
  8. "github.com/go-git/go-git/v5/plumbing/format/idxfile"
  9. "github.com/go-git/go-git/v5/plumbing/format/objfile"
  10. "github.com/go-git/go-git/v5/plumbing/format/packfile"
  11. "github.com/go-git/go-git/v5/plumbing/storer"
  12. "github.com/go-git/go-git/v5/storage/filesystem/dotgit"
  13. "github.com/go-git/go-git/v5/utils/ioutil"
  14. "github.com/go-git/go-billy/v5"
  15. )
  16. type ObjectStorage struct {
  17. options Options
  18. // objectCache is an object cache uses to cache delta's bases and also recently
  19. // loaded loose objects
  20. objectCache cache.Object
  21. dir *dotgit.DotGit
  22. index map[plumbing.Hash]idxfile.Index
  23. packList []plumbing.Hash
  24. packListIdx int
  25. packfiles map[plumbing.Hash]*packfile.Packfile
  26. }
  27. // NewObjectStorage creates a new ObjectStorage with the given .git directory and cache.
  28. func NewObjectStorage(dir *dotgit.DotGit, objectCache cache.Object) *ObjectStorage {
  29. return NewObjectStorageWithOptions(dir, objectCache, Options{})
  30. }
  31. // NewObjectStorageWithOptions creates a new ObjectStorage with the given .git directory, cache and extra options
  32. func NewObjectStorageWithOptions(dir *dotgit.DotGit, objectCache cache.Object, ops Options) *ObjectStorage {
  33. return &ObjectStorage{
  34. options: ops,
  35. objectCache: objectCache,
  36. dir: dir,
  37. }
  38. }
  39. func (s *ObjectStorage) requireIndex() error {
  40. if s.index != nil {
  41. return nil
  42. }
  43. s.index = make(map[plumbing.Hash]idxfile.Index)
  44. packs, err := s.dir.ObjectPacks()
  45. if err != nil {
  46. return err
  47. }
  48. for _, h := range packs {
  49. if err := s.loadIdxFile(h); err != nil {
  50. return err
  51. }
  52. }
  53. return nil
  54. }
  55. // Reindex indexes again all packfiles. Useful if git changed packfiles externally
  56. func (s *ObjectStorage) Reindex() {
  57. s.index = nil
  58. }
  59. func (s *ObjectStorage) loadIdxFile(h plumbing.Hash) (err error) {
  60. f, err := s.dir.ObjectPackIdx(h)
  61. if err != nil {
  62. return err
  63. }
  64. defer ioutil.CheckClose(f, &err)
  65. idxf := idxfile.NewMemoryIndex()
  66. d := idxfile.NewDecoder(f)
  67. if err = d.Decode(idxf); err != nil {
  68. return err
  69. }
  70. s.index[h] = idxf
  71. return err
  72. }
  73. func (s *ObjectStorage) NewEncodedObject() plumbing.EncodedObject {
  74. return &plumbing.MemoryObject{}
  75. }
  76. func (s *ObjectStorage) PackfileWriter() (io.WriteCloser, error) {
  77. if err := s.requireIndex(); err != nil {
  78. return nil, err
  79. }
  80. w, err := s.dir.NewObjectPack()
  81. if err != nil {
  82. return nil, err
  83. }
  84. w.Notify = func(h plumbing.Hash, writer *idxfile.Writer) {
  85. index, err := writer.Index()
  86. if err == nil {
  87. s.index[h] = index
  88. }
  89. }
  90. return w, nil
  91. }
  92. // SetEncodedObject adds a new object to the storage.
  93. func (s *ObjectStorage) SetEncodedObject(o plumbing.EncodedObject) (h plumbing.Hash, err error) {
  94. if o.Type() == plumbing.OFSDeltaObject || o.Type() == plumbing.REFDeltaObject {
  95. return plumbing.ZeroHash, plumbing.ErrInvalidType
  96. }
  97. ow, err := s.dir.NewObject()
  98. if err != nil {
  99. return plumbing.ZeroHash, err
  100. }
  101. defer ioutil.CheckClose(ow, &err)
  102. or, err := o.Reader()
  103. if err != nil {
  104. return plumbing.ZeroHash, err
  105. }
  106. defer ioutil.CheckClose(or, &err)
  107. if err = ow.WriteHeader(o.Type(), o.Size()); err != nil {
  108. return plumbing.ZeroHash, err
  109. }
  110. if _, err = io.Copy(ow, or); err != nil {
  111. return plumbing.ZeroHash, err
  112. }
  113. return o.Hash(), err
  114. }
  115. // HasEncodedObject returns nil if the object exists, without actually
  116. // reading the object data from storage.
  117. func (s *ObjectStorage) HasEncodedObject(h plumbing.Hash) (err error) {
  118. // Check unpacked objects
  119. f, err := s.dir.Object(h)
  120. if err != nil {
  121. if !os.IsNotExist(err) {
  122. return err
  123. }
  124. // Fall through to check packed objects.
  125. } else {
  126. defer ioutil.CheckClose(f, &err)
  127. return nil
  128. }
  129. // Check packed objects.
  130. if err := s.requireIndex(); err != nil {
  131. return err
  132. }
  133. _, _, offset := s.findObjectInPackfile(h)
  134. if offset == -1 {
  135. return plumbing.ErrObjectNotFound
  136. }
  137. return nil
  138. }
  139. func (s *ObjectStorage) encodedObjectSizeFromUnpacked(h plumbing.Hash) (
  140. size int64, err error) {
  141. f, err := s.dir.Object(h)
  142. if err != nil {
  143. if os.IsNotExist(err) {
  144. return 0, plumbing.ErrObjectNotFound
  145. }
  146. return 0, err
  147. }
  148. r, err := objfile.NewReader(f)
  149. if err != nil {
  150. return 0, err
  151. }
  152. defer ioutil.CheckClose(r, &err)
  153. _, size, err = r.Header()
  154. return size, err
  155. }
  156. func (s *ObjectStorage) packfile(idx idxfile.Index, pack plumbing.Hash) (*packfile.Packfile, error) {
  157. if p := s.packfileFromCache(pack); p != nil {
  158. return p, nil
  159. }
  160. f, err := s.dir.ObjectPack(pack)
  161. if err != nil {
  162. return nil, err
  163. }
  164. var p *packfile.Packfile
  165. if s.objectCache != nil {
  166. p = packfile.NewPackfileWithCache(idx, s.dir.Fs(), f, s.objectCache)
  167. } else {
  168. p = packfile.NewPackfile(idx, s.dir.Fs(), f)
  169. }
  170. return p, s.storePackfileInCache(pack, p)
  171. }
  172. func (s *ObjectStorage) packfileFromCache(hash plumbing.Hash) *packfile.Packfile {
  173. if s.packfiles == nil {
  174. if s.options.KeepDescriptors {
  175. s.packfiles = make(map[plumbing.Hash]*packfile.Packfile)
  176. } else if s.options.MaxOpenDescriptors > 0 {
  177. s.packList = make([]plumbing.Hash, s.options.MaxOpenDescriptors)
  178. s.packfiles = make(map[plumbing.Hash]*packfile.Packfile, s.options.MaxOpenDescriptors)
  179. }
  180. }
  181. return s.packfiles[hash]
  182. }
  183. func (s *ObjectStorage) storePackfileInCache(hash plumbing.Hash, p *packfile.Packfile) error {
  184. if s.options.KeepDescriptors {
  185. s.packfiles[hash] = p
  186. return nil
  187. }
  188. if s.options.MaxOpenDescriptors <= 0 {
  189. return nil
  190. }
  191. // start over as the limit of packList is hit
  192. if s.packListIdx >= len(s.packList) {
  193. s.packListIdx = 0
  194. }
  195. // close the existing packfile if open
  196. if next := s.packList[s.packListIdx]; !next.IsZero() {
  197. open := s.packfiles[next]
  198. delete(s.packfiles, next)
  199. if open != nil {
  200. if err := open.Close(); err != nil {
  201. return err
  202. }
  203. }
  204. }
  205. // cache newly open packfile
  206. s.packList[s.packListIdx] = hash
  207. s.packfiles[hash] = p
  208. s.packListIdx++
  209. return nil
  210. }
  211. func (s *ObjectStorage) encodedObjectSizeFromPackfile(h plumbing.Hash) (
  212. size int64, err error) {
  213. if err := s.requireIndex(); err != nil {
  214. return 0, err
  215. }
  216. pack, _, offset := s.findObjectInPackfile(h)
  217. if offset == -1 {
  218. return 0, plumbing.ErrObjectNotFound
  219. }
  220. idx := s.index[pack]
  221. hash, err := idx.FindHash(offset)
  222. if err == nil {
  223. obj, ok := s.objectCache.Get(hash)
  224. if ok {
  225. return obj.Size(), nil
  226. }
  227. } else if err != nil && err != plumbing.ErrObjectNotFound {
  228. return 0, err
  229. }
  230. p, err := s.packfile(idx, pack)
  231. if err != nil {
  232. return 0, err
  233. }
  234. if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 {
  235. defer ioutil.CheckClose(p, &err)
  236. }
  237. return p.GetSizeByOffset(offset)
  238. }
  239. // EncodedObjectSize returns the plaintext size of the given object,
  240. // without actually reading the full object data from storage.
  241. func (s *ObjectStorage) EncodedObjectSize(h plumbing.Hash) (
  242. size int64, err error) {
  243. size, err = s.encodedObjectSizeFromUnpacked(h)
  244. if err != nil && err != plumbing.ErrObjectNotFound {
  245. return 0, err
  246. } else if err == nil {
  247. return size, nil
  248. }
  249. return s.encodedObjectSizeFromPackfile(h)
  250. }
  251. // EncodedObject returns the object with the given hash, by searching for it in
  252. // the packfile and the git object directories.
  253. func (s *ObjectStorage) EncodedObject(t plumbing.ObjectType, h plumbing.Hash) (plumbing.EncodedObject, error) {
  254. var obj plumbing.EncodedObject
  255. var err error
  256. if s.index != nil {
  257. obj, err = s.getFromPackfile(h, false)
  258. if err == plumbing.ErrObjectNotFound {
  259. obj, err = s.getFromUnpacked(h)
  260. }
  261. } else {
  262. obj, err = s.getFromUnpacked(h)
  263. if err == plumbing.ErrObjectNotFound {
  264. obj, err = s.getFromPackfile(h, false)
  265. }
  266. }
  267. // If the error is still object not found, check if it's a shared object
  268. // repository.
  269. if err == plumbing.ErrObjectNotFound {
  270. dotgits, e := s.dir.Alternates()
  271. if e == nil {
  272. // Create a new object storage with the DotGit(s) and check for the
  273. // required hash object. Skip when not found.
  274. for _, dg := range dotgits {
  275. o := NewObjectStorage(dg, s.objectCache)
  276. enobj, enerr := o.EncodedObject(t, h)
  277. if enerr != nil {
  278. continue
  279. }
  280. return enobj, nil
  281. }
  282. }
  283. }
  284. if err != nil {
  285. return nil, err
  286. }
  287. if plumbing.AnyObject != t && obj.Type() != t {
  288. return nil, plumbing.ErrObjectNotFound
  289. }
  290. return obj, nil
  291. }
  292. // DeltaObject returns the object with the given hash, by searching for
  293. // it in the packfile and the git object directories.
  294. func (s *ObjectStorage) DeltaObject(t plumbing.ObjectType,
  295. h plumbing.Hash) (plumbing.EncodedObject, error) {
  296. obj, err := s.getFromUnpacked(h)
  297. if err == plumbing.ErrObjectNotFound {
  298. obj, err = s.getFromPackfile(h, true)
  299. }
  300. if err != nil {
  301. return nil, err
  302. }
  303. if plumbing.AnyObject != t && obj.Type() != t {
  304. return nil, plumbing.ErrObjectNotFound
  305. }
  306. return obj, nil
  307. }
  308. func (s *ObjectStorage) getFromUnpacked(h plumbing.Hash) (obj plumbing.EncodedObject, err error) {
  309. f, err := s.dir.Object(h)
  310. if err != nil {
  311. if os.IsNotExist(err) {
  312. return nil, plumbing.ErrObjectNotFound
  313. }
  314. return nil, err
  315. }
  316. defer ioutil.CheckClose(f, &err)
  317. if cacheObj, found := s.objectCache.Get(h); found {
  318. return cacheObj, nil
  319. }
  320. obj = s.NewEncodedObject()
  321. r, err := objfile.NewReader(f)
  322. if err != nil {
  323. return nil, err
  324. }
  325. defer ioutil.CheckClose(r, &err)
  326. t, size, err := r.Header()
  327. if err != nil {
  328. return nil, err
  329. }
  330. obj.SetType(t)
  331. obj.SetSize(size)
  332. w, err := obj.Writer()
  333. if err != nil {
  334. return nil, err
  335. }
  336. defer ioutil.CheckClose(w, &err)
  337. s.objectCache.Put(obj)
  338. _, err = io.Copy(w, r)
  339. return obj, err
  340. }
  341. // Get returns the object with the given hash, by searching for it in
  342. // the packfile.
  343. func (s *ObjectStorage) getFromPackfile(h plumbing.Hash, canBeDelta bool) (
  344. plumbing.EncodedObject, error) {
  345. if err := s.requireIndex(); err != nil {
  346. return nil, err
  347. }
  348. pack, hash, offset := s.findObjectInPackfile(h)
  349. if offset == -1 {
  350. return nil, plumbing.ErrObjectNotFound
  351. }
  352. idx := s.index[pack]
  353. p, err := s.packfile(idx, pack)
  354. if err != nil {
  355. return nil, err
  356. }
  357. if !s.options.KeepDescriptors && s.options.MaxOpenDescriptors == 0 {
  358. defer ioutil.CheckClose(p, &err)
  359. }
  360. if canBeDelta {
  361. return s.decodeDeltaObjectAt(p, offset, hash)
  362. }
  363. return s.decodeObjectAt(p, offset)
  364. }
  365. func (s *ObjectStorage) decodeObjectAt(
  366. p *packfile.Packfile,
  367. offset int64,
  368. ) (plumbing.EncodedObject, error) {
  369. hash, err := p.FindHash(offset)
  370. if err == nil {
  371. obj, ok := s.objectCache.Get(hash)
  372. if ok {
  373. return obj, nil
  374. }
  375. }
  376. if err != nil && err != plumbing.ErrObjectNotFound {
  377. return nil, err
  378. }
  379. return p.GetByOffset(offset)
  380. }
  381. func (s *ObjectStorage) decodeDeltaObjectAt(
  382. p *packfile.Packfile,
  383. offset int64,
  384. hash plumbing.Hash,
  385. ) (plumbing.EncodedObject, error) {
  386. scan := p.Scanner()
  387. header, err := scan.SeekObjectHeader(offset)
  388. if err != nil {
  389. return nil, err
  390. }
  391. var (
  392. base plumbing.Hash
  393. )
  394. switch header.Type {
  395. case plumbing.REFDeltaObject:
  396. base = header.Reference
  397. case plumbing.OFSDeltaObject:
  398. base, err = p.FindHash(header.OffsetReference)
  399. if err != nil {
  400. return nil, err
  401. }
  402. default:
  403. return s.decodeObjectAt(p, offset)
  404. }
  405. obj := &plumbing.MemoryObject{}
  406. obj.SetType(header.Type)
  407. w, err := obj.Writer()
  408. if err != nil {
  409. return nil, err
  410. }
  411. if _, _, err := scan.NextObject(w); err != nil {
  412. return nil, err
  413. }
  414. return newDeltaObject(obj, hash, base, header.Length), nil
  415. }
  416. func (s *ObjectStorage) findObjectInPackfile(h plumbing.Hash) (plumbing.Hash, plumbing.Hash, int64) {
  417. for packfile, index := range s.index {
  418. offset, err := index.FindOffset(h)
  419. if err == nil {
  420. return packfile, h, offset
  421. }
  422. }
  423. return plumbing.ZeroHash, plumbing.ZeroHash, -1
  424. }
  425. // IterEncodedObjects returns an iterator for all the objects in the packfile
  426. // with the given type.
  427. func (s *ObjectStorage) IterEncodedObjects(t plumbing.ObjectType) (storer.EncodedObjectIter, error) {
  428. objects, err := s.dir.Objects()
  429. if err != nil {
  430. return nil, err
  431. }
  432. seen := make(map[plumbing.Hash]struct{})
  433. var iters []storer.EncodedObjectIter
  434. if len(objects) != 0 {
  435. iters = append(iters, &objectsIter{s: s, t: t, h: objects})
  436. seen = hashListAsMap(objects)
  437. }
  438. packi, err := s.buildPackfileIters(t, seen)
  439. if err != nil {
  440. return nil, err
  441. }
  442. iters = append(iters, packi)
  443. return storer.NewMultiEncodedObjectIter(iters), nil
  444. }
  445. func (s *ObjectStorage) buildPackfileIters(
  446. t plumbing.ObjectType,
  447. seen map[plumbing.Hash]struct{},
  448. ) (storer.EncodedObjectIter, error) {
  449. if err := s.requireIndex(); err != nil {
  450. return nil, err
  451. }
  452. packs, err := s.dir.ObjectPacks()
  453. if err != nil {
  454. return nil, err
  455. }
  456. return &lazyPackfilesIter{
  457. hashes: packs,
  458. open: func(h plumbing.Hash) (storer.EncodedObjectIter, error) {
  459. pack, err := s.dir.ObjectPack(h)
  460. if err != nil {
  461. return nil, err
  462. }
  463. return newPackfileIter(
  464. s.dir.Fs(), pack, t, seen, s.index[h],
  465. s.objectCache, s.options.KeepDescriptors,
  466. )
  467. },
  468. }, nil
  469. }
  470. // Close closes all opened files.
  471. func (s *ObjectStorage) Close() error {
  472. var firstError error
  473. if s.options.KeepDescriptors || s.options.MaxOpenDescriptors > 0 {
  474. for _, packfile := range s.packfiles {
  475. err := packfile.Close()
  476. if firstError == nil && err != nil {
  477. firstError = err
  478. }
  479. }
  480. }
  481. s.packfiles = nil
  482. s.dir.Close()
  483. return firstError
  484. }
  485. type lazyPackfilesIter struct {
  486. hashes []plumbing.Hash
  487. open func(h plumbing.Hash) (storer.EncodedObjectIter, error)
  488. cur storer.EncodedObjectIter
  489. }
  490. func (it *lazyPackfilesIter) Next() (plumbing.EncodedObject, error) {
  491. for {
  492. if it.cur == nil {
  493. if len(it.hashes) == 0 {
  494. return nil, io.EOF
  495. }
  496. h := it.hashes[0]
  497. it.hashes = it.hashes[1:]
  498. sub, err := it.open(h)
  499. if err == io.EOF {
  500. continue
  501. } else if err != nil {
  502. return nil, err
  503. }
  504. it.cur = sub
  505. }
  506. ob, err := it.cur.Next()
  507. if err == io.EOF {
  508. it.cur.Close()
  509. it.cur = nil
  510. continue
  511. } else if err != nil {
  512. return nil, err
  513. }
  514. return ob, nil
  515. }
  516. }
  517. func (it *lazyPackfilesIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  518. return storer.ForEachIterator(it, cb)
  519. }
  520. func (it *lazyPackfilesIter) Close() {
  521. if it.cur != nil {
  522. it.cur.Close()
  523. it.cur = nil
  524. }
  525. it.hashes = nil
  526. }
  527. type packfileIter struct {
  528. pack billy.File
  529. iter storer.EncodedObjectIter
  530. seen map[plumbing.Hash]struct{}
  531. // tells whether the pack file should be left open after iteration or not
  532. keepPack bool
  533. }
  534. // NewPackfileIter returns a new EncodedObjectIter for the provided packfile
  535. // and object type. Packfile and index file will be closed after they're
  536. // used. If keepPack is true the packfile won't be closed after the iteration
  537. // finished.
  538. func NewPackfileIter(
  539. fs billy.Filesystem,
  540. f billy.File,
  541. idxFile billy.File,
  542. t plumbing.ObjectType,
  543. keepPack bool,
  544. ) (storer.EncodedObjectIter, error) {
  545. idx := idxfile.NewMemoryIndex()
  546. if err := idxfile.NewDecoder(idxFile).Decode(idx); err != nil {
  547. return nil, err
  548. }
  549. if err := idxFile.Close(); err != nil {
  550. return nil, err
  551. }
  552. seen := make(map[plumbing.Hash]struct{})
  553. return newPackfileIter(fs, f, t, seen, idx, nil, keepPack)
  554. }
  555. func newPackfileIter(
  556. fs billy.Filesystem,
  557. f billy.File,
  558. t plumbing.ObjectType,
  559. seen map[plumbing.Hash]struct{},
  560. index idxfile.Index,
  561. cache cache.Object,
  562. keepPack bool,
  563. ) (storer.EncodedObjectIter, error) {
  564. var p *packfile.Packfile
  565. if cache != nil {
  566. p = packfile.NewPackfileWithCache(index, fs, f, cache)
  567. } else {
  568. p = packfile.NewPackfile(index, fs, f)
  569. }
  570. iter, err := p.GetByType(t)
  571. if err != nil {
  572. return nil, err
  573. }
  574. return &packfileIter{
  575. pack: f,
  576. iter: iter,
  577. seen: seen,
  578. keepPack: keepPack,
  579. }, nil
  580. }
  581. func (iter *packfileIter) Next() (plumbing.EncodedObject, error) {
  582. for {
  583. obj, err := iter.iter.Next()
  584. if err != nil {
  585. return nil, err
  586. }
  587. if _, ok := iter.seen[obj.Hash()]; ok {
  588. continue
  589. }
  590. return obj, nil
  591. }
  592. }
  593. func (iter *packfileIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  594. for {
  595. o, err := iter.Next()
  596. if err != nil {
  597. if err == io.EOF {
  598. iter.Close()
  599. return nil
  600. }
  601. return err
  602. }
  603. if err := cb(o); err != nil {
  604. return err
  605. }
  606. }
  607. }
  608. func (iter *packfileIter) Close() {
  609. iter.iter.Close()
  610. if !iter.keepPack {
  611. _ = iter.pack.Close()
  612. }
  613. }
  614. type objectsIter struct {
  615. s *ObjectStorage
  616. t plumbing.ObjectType
  617. h []plumbing.Hash
  618. }
  619. func (iter *objectsIter) Next() (plumbing.EncodedObject, error) {
  620. if len(iter.h) == 0 {
  621. return nil, io.EOF
  622. }
  623. obj, err := iter.s.getFromUnpacked(iter.h[0])
  624. iter.h = iter.h[1:]
  625. if err != nil {
  626. return nil, err
  627. }
  628. if iter.t != plumbing.AnyObject && iter.t != obj.Type() {
  629. return iter.Next()
  630. }
  631. return obj, err
  632. }
  633. func (iter *objectsIter) ForEach(cb func(plumbing.EncodedObject) error) error {
  634. for {
  635. o, err := iter.Next()
  636. if err != nil {
  637. if err == io.EOF {
  638. return nil
  639. }
  640. return err
  641. }
  642. if err := cb(o); err != nil {
  643. return err
  644. }
  645. }
  646. }
  647. func (iter *objectsIter) Close() {
  648. iter.h = []plumbing.Hash{}
  649. }
  650. func hashListAsMap(l []plumbing.Hash) map[plumbing.Hash]struct{} {
  651. m := make(map[plumbing.Hash]struct{}, len(l))
  652. for _, h := range l {
  653. m[h] = struct{}{}
  654. }
  655. return m
  656. }
  657. func (s *ObjectStorage) ForEachObjectHash(fun func(plumbing.Hash) error) error {
  658. err := s.dir.ForEachObjectHash(fun)
  659. if err == storer.ErrStop {
  660. return nil
  661. }
  662. return err
  663. }
  664. func (s *ObjectStorage) LooseObjectTime(hash plumbing.Hash) (time.Time, error) {
  665. fi, err := s.dir.ObjectStat(hash)
  666. if err != nil {
  667. return time.Time{}, err
  668. }
  669. return fi.ModTime(), nil
  670. }
  671. func (s *ObjectStorage) DeleteLooseObject(hash plumbing.Hash) error {
  672. return s.dir.ObjectDelete(hash)
  673. }
  674. func (s *ObjectStorage) ObjectPacks() ([]plumbing.Hash, error) {
  675. return s.dir.ObjectPacks()
  676. }
  677. func (s *ObjectStorage) DeleteOldObjectPackAndIndex(h plumbing.Hash, t time.Time) error {
  678. return s.dir.DeleteOldObjectPackAndIndex(h, t)
  679. }