@@ -38,15 +38,14 @@ type Observer interface {
3838// Parser decodes a packfile and calls any observer associated to it. Is used
3939// to generate indexes.
4040type Parser struct {
41- storage storer.EncodedObjectStorer
42- scanner * Scanner
43- count uint32
44- oi []* objectInfo
45- oiByHash map [plumbing.Hash ]* objectInfo
46- oiByOffset map [int64 ]* objectInfo
47- hashOffset map [plumbing.Hash ]int64
48- pendingRefDeltas map [plumbing.Hash ][]* objectInfo
49- checksum plumbing.Hash
41+ storage storer.EncodedObjectStorer
42+ scanner * Scanner
43+ count uint32
44+ oi []* objectInfo
45+ oiByHash map [plumbing.Hash ]* objectInfo
46+ oiByOffset map [int64 ]* objectInfo
47+ hashOffset map [plumbing.Hash ]int64
48+ checksum plumbing.Hash
5049
5150 cache * cache.BufferLRU
5251 // delta content by offset, only used if source is not seekable
@@ -78,13 +77,12 @@ func NewParserWithStorage(
7877 }
7978
8079 return & Parser {
81- storage : storage ,
82- scanner : scanner ,
83- ob : ob ,
84- count : 0 ,
85- cache : cache .NewBufferLRUDefault (),
86- pendingRefDeltas : make (map [plumbing.Hash ][]* objectInfo ),
87- deltas : deltas ,
80+ storage : storage ,
81+ scanner : scanner ,
82+ ob : ob ,
83+ count : 0 ,
84+ cache : cache .NewBufferLRUDefault (),
85+ deltas : deltas ,
8886 }, nil
8987}
9088
@@ -150,10 +148,6 @@ func (p *Parser) Parse() (plumbing.Hash, error) {
150148 return plumbing .ZeroHash , err
151149 }
152150
153- if len (p .pendingRefDeltas ) > 0 {
154- return plumbing .ZeroHash , ErrReferenceDeltaNotFound
155- }
156-
157151 if err := p .onFooter (p .checksum ); err != nil {
158152 return plumbing .ZeroHash , err
159153 }
@@ -205,18 +199,21 @@ func (p *Parser) indexObjects() error {
205199 parent .Children = append (parent .Children , ota )
206200 case plumbing .REFDeltaObject :
207201 delta = true
208-
209202 parent , ok := p .oiByHash [oh .Reference ]
210- if ok {
211- ota = newDeltaObject (oh .Offset , oh .Length , t , parent )
212- parent .Children = append (parent .Children , ota )
213- } else {
214- ota = newBaseObject (oh .Offset , oh .Length , t )
215- p .pendingRefDeltas [oh .Reference ] = append (
216- p .pendingRefDeltas [oh .Reference ],
217- ota ,
218- )
203+ if ! ok {
204+ // can't find referenced object in this pack file
205+ // this must be a "thin" pack.
206+ parent = & objectInfo { //Placeholder parent
207+ SHA1 : oh .Reference ,
208+ ExternalRef : true , // mark as an external reference that must be resolved
209+ Type : plumbing .AnyObject ,
210+ DiskType : plumbing .AnyObject ,
211+ }
212+ p .oiByHash [oh .Reference ] = parent
219213 }
214+ ota = newDeltaObject (oh .Offset , oh .Length , t , parent )
215+ parent .Children = append (parent .Children , ota )
216+
220217 default :
221218 ota = newBaseObject (oh .Offset , oh .Length , t )
222219 }
@@ -297,16 +294,20 @@ func (p *Parser) resolveDeltas() error {
297294 return nil
298295}
299296
300- func (p * Parser ) get (o * objectInfo ) ([]byte , error ) {
301- b , ok := p .cache .Get (o .Offset )
297+ func (p * Parser ) get (o * objectInfo ) (b []byte , err error ) {
298+ var ok bool
299+ if ! o .ExternalRef { // skip cache check for placeholder parents
300+ b , ok = p .cache .Get (o .Offset )
301+ }
302+
302303 // If it's not on the cache and is not a delta we can try to find it in the
303- // storage, if there's one.
304+ // storage, if there's one. External refs must enter here.
304305 if ! ok && p .storage != nil && ! o .Type .IsDelta () {
305- var err error
306306 e , err := p .storage .EncodedObject (plumbing .AnyObject , o .SHA1 )
307307 if err != nil {
308308 return nil , err
309309 }
310+ o .Type = e .Type ()
310311
311312 r , err := e .Reader ()
312313 if err != nil {
@@ -323,6 +324,11 @@ func (p *Parser) get(o *objectInfo) ([]byte, error) {
323324 return b , nil
324325 }
325326
327+ if o .ExternalRef {
328+ // we were not able to resolve a ref in a thin pack
329+ return nil , ErrReferenceDeltaNotFound
330+ }
331+
326332 var data []byte
327333 if o .DiskType .IsDelta () {
328334 base , err := p .get (o .Parent )
@@ -335,7 +341,6 @@ func (p *Parser) get(o *objectInfo) ([]byte, error) {
335341 return nil , err
336342 }
337343 } else {
338- var err error
339344 data , err = p .readData (o )
340345 if err != nil {
341346 return nil , err
@@ -367,14 +372,6 @@ func (p *Parser) resolveObject(
367372 return nil , err
368373 }
369374
370- if pending , ok := p .pendingRefDeltas [o .SHA1 ]; ok {
371- for _ , po := range pending {
372- po .Parent = o
373- o .Children = append (o .Children , po )
374- }
375- delete (p .pendingRefDeltas , o .SHA1 )
376- }
377-
378375 if p .storage != nil {
379376 obj := new (plumbing.MemoryObject )
380377 obj .SetSize (o .Size ())
@@ -447,10 +444,11 @@ func getSHA1(t plumbing.ObjectType, data []byte) (plumbing.Hash, error) {
447444}
448445
449446type objectInfo struct {
450- Offset int64
451- Length int64
452- Type plumbing.ObjectType
453- DiskType plumbing.ObjectType
447+ Offset int64
448+ Length int64
449+ Type plumbing.ObjectType
450+ DiskType plumbing.ObjectType
451+ ExternalRef bool // indicates this is an external reference in a thin pack file
454452
455453 Crc32 uint32
456454
0 commit comments