@@ -247,7 +247,7 @@ def write(self, pack_sha, write):
247
247
return sha
248
248
249
249
250
- class PackIndexFile (object ):
250
+ class PackIndexFile (LazyMixin ):
251
251
252
252
"""A pack index provides offsets into the corresponding pack, allowing to find
253
253
locations for offsets faster."""
@@ -261,15 +261,19 @@ class PackIndexFile(object):
261
261
_sha_list_offset = 8 + 1024
262
262
index_v2_signature = b'\xff tOc'
263
263
index_version_default = 2
264
- _entered = 0
265
264
266
265
def __init__ (self , indexpath ):
267
266
self ._indexpath = indexpath
267
+ self ._entered = 0
268
+ self ._cursor = None
268
269
269
270
def __enter__ (self ):
270
- if not hasattr (self , '_cursor' ):
271
- assert self ._entered == 0 , (self , self ._indexpath )
272
- self ._prepare_enter ()
271
+ if self ._entered == 0 :
272
+ # Note: We don't lock the file when reading as we cannot be sure
273
+ # that we can actually write to the location - it could be a read-only
274
+ # alternate for instance
275
+ assert self ._cursor is None , self ._cursor
276
+ self ._cursor = self ._make_cursor ()
273
277
self ._entered += 1
274
278
275
279
return self
@@ -279,20 +283,19 @@ def __exit__(self, exc_type, exc_value, traceback):
279
283
assert self ._entered >= 0 , (self , self ._indexpath )
280
284
if self ._entered == 0 :
281
285
self ._cursor ._destroy ()
282
- del self ._cursor
283
- del self ._fanout_table
284
-
285
- def _prepare_enter (self ):
286
- # Note: We don't lock the file when reading as we cannot be sure
287
- # that we can actually write to the location - it could be a read-only
288
- # alternate for instance
289
- self ._cursor = mman .make_cursor (self ._indexpath ).use_region ()
286
+ self ._cursor = None
287
+
288
+ def _make_cursor (self ):
289
+ cursor = mman .make_cursor (self ._indexpath ).use_region ()
290
+
290
291
# We will assume that the index will always fully fit into memory !
291
- if mman .window_size () > 0 and self . _cursor .file_size () > mman .window_size ():
292
+ if mman .window_size () > 0 and cursor .file_size () > mman .window_size ():
292
293
raise AssertionError ("The index file at %s is too large to fit into a mapped window (%i > %i). This is a limitation of the implementation" % (
293
- self ._indexpath , self ._cursor .file_size (), mman .window_size ()))
294
- # END assert window size
294
+ self ._indexpath , cursor .file_size (), mman .window_size ()))
295
295
296
+ return cursor
297
+
298
+ def _set_cache_ (self , attr ):
296
299
# now its time to initialize everything - if we are here, someone wants
297
300
# to access the fanout table or related properties
298
301
@@ -312,7 +315,24 @@ def _prepare_enter(self):
312
315
313
316
# INITIALIZE DATA
314
317
# byte offset is 8 if version is 2, 0 otherwise
315
- self ._initialize ()
318
+ self ._fanout_table = self ._read_fanout ((self ._version == 2 ) * 8 )
319
+
320
+ if self ._version == 2 :
321
+ self ._crc_list_offset = self ._sha_list_offset + self .size () * 20
322
+ self ._pack_offset = self ._crc_list_offset + self .size () * 4
323
+ self ._pack_64_offset = self ._pack_offset + self .size () * 4
324
+ # END setup base
325
+
326
+ def _read_fanout (self , byte_offset ):
327
+ """Generate a fanout table from our data"""
328
+ d = self ._cursor .map ()
329
+ out = []
330
+ append = out .append
331
+ for i in xrange (256 ):
332
+ append (unpack_from ('>L' , d , byte_offset + i * 4 )[0 ])
333
+ # END for each entry
334
+ return out
335
+
316
336
# END handle attributes
317
337
318
338
#{ Access V1
@@ -366,30 +386,6 @@ def _crc_v2(self, i):
366
386
367
387
#} END access V2
368
388
369
- #{ Initialization
370
-
371
- def _initialize (self ):
372
- """initialize base data"""
373
- self ._fanout_table = self ._read_fanout ((self ._version == 2 ) * 8 )
374
-
375
- if self ._version == 2 :
376
- self ._crc_list_offset = self ._sha_list_offset + self .size () * 20
377
- self ._pack_offset = self ._crc_list_offset + self .size () * 4
378
- self ._pack_64_offset = self ._pack_offset + self .size () * 4
379
- # END setup base
380
-
381
- def _read_fanout (self , byte_offset ):
382
- """Generate a fanout table from our data"""
383
- d = self ._cursor .map ()
384
- out = []
385
- append = out .append
386
- for i in xrange (256 ):
387
- append (unpack_from ('>L' , d , byte_offset + i * 4 )[0 ])
388
- # END for each entry
389
- return out
390
-
391
- #} END initialization
392
-
393
389
#{ Properties
394
390
def version (self ):
395
391
return self ._version
@@ -434,7 +430,7 @@ def sha_to_index(self, sha):
434
430
:param sha: 20 byte sha to lookup"""
435
431
first_byte = byte_ord (sha [0 ])
436
432
get_sha = self .sha
437
- lo = 0
433
+ lo = 0 # lower index, the left bound of the bisection
438
434
if first_byte != 0 :
439
435
lo = self ._fanout_table [first_byte - 1 ]
440
436
hi = self ._fanout_table [first_byte ] # the upper, right bound of the bisection
@@ -514,7 +510,7 @@ def sha_to_index(self, sha):
514
510
#} END properties
515
511
516
512
517
- class PackFile (object ):
513
+ class PackFile (LazyMixin ):
518
514
519
515
"""A pack is a file written according to the Version 2 for git packs
520
516
@@ -543,32 +539,30 @@ class PackFile(object):
543
539
def __init__ (self , packpath ):
544
540
self ._packpath = packpath
545
541
self ._entered = 0
542
+ self ._cursor = None
546
543
547
544
def __enter__ (self ):
548
- if not hasattr ( self , '_cursor' ) :
549
- assert self ._entered == 0 , ( self , self . _packpath )
550
- self ._prepare_enter ()
545
+ if self . _entered == 0 :
546
+ assert self ._cursor is None , self . _cursor
547
+ self ._cursor = mman . make_cursor ( self . _packpath ). use_region ()
551
548
self ._entered += 1
552
549
553
550
return self
554
551
555
552
def __exit__ (self , exc_type , exc_value , traceback ):
556
553
self ._entered -= 1
557
- assert self ._entered >= 0 , (self , self ._indexpath )
554
+ assert self ._entered >= 0 , (self , self ._packpath )
558
555
if self ._entered == 0 :
559
556
self ._cursor ._destroy ()
560
- del self ._cursor
561
-
562
- def _prepare_enter (self ):
563
- # we fill the whole cache, whichever attribute gets queried first
564
- self ._cursor = mman .make_cursor (self ._packpath ).use_region ()
557
+ self ._cursor = None
565
558
566
- # read the header information
559
+ def _set_cache_ (self , attr ):
560
+ # Fill cache by reading the header information.
567
561
type_id , self ._version , self ._size = unpack_from (">LLL" , self ._cursor .map (), 0 )
568
562
569
563
# TODO: figure out whether we should better keep the lock, or maybe
570
564
# add a .keep file instead ?
571
- if type_id != self .pack_signature :
565
+ if type_id != PackFile .pack_signature :
572
566
raise ParseError ("Invalid pack signature: %i" % type_id )
573
567
574
568
def _iter_objects (self , start_offset , as_stream = True ):
@@ -681,12 +675,12 @@ def stream_iter(self, start_offset=0):
681
675
#} END Read-Database like Interface
682
676
683
677
684
- class PackEntity (object ):
678
+ class PackEntity (LazyMixin ):
685
679
686
680
"""Combines the PackIndexFile and the PackFile into one, allowing the
687
681
actual objects to be resolved and iterated"""
688
682
689
- __slots__ = ('_basename' ,
683
+ __slots__ = ('_basename' , # Could have been int, but better limit scurpulus nesting.
690
684
'_index' , # our index file
691
685
'_pack' , # our pack file
692
686
'_offset_map' , # on demand dict mapping one offset to the next consecutive one
@@ -713,41 +707,34 @@ def __enter__(self):
713
707
return self
714
708
715
709
def __exit__ (self , exc_type , exc_value , traceback ):
716
- if self ._index :
717
- self ._index .__exit__ (exc_type , exc_value , traceback )
718
- if self ._pack :
719
- self ._pack .__exit__ (exc_type , exc_value , traceback )
710
+ self ._index .__exit__ (exc_type , exc_value , traceback )
711
+ self ._pack .__exit__ (exc_type , exc_value , traceback )
720
712
self ._entered = False
721
713
722
- @property
723
- def offset_map (self ):
724
- if not hasattr (self , '_offset_map' ):
725
- # currently this can only be _offset_map
726
- # TODO: make this a simple sorted offset array which can be bisected
727
- # to find the respective entry, from which we can take a +1 easily
728
- # This might be slower, but should also be much lighter in memory !
729
- offsets_sorted = sorted (self ._index .offsets ())
730
- last_offset = len (self ._pack .data ()) - self ._pack .footer_size
731
- assert offsets_sorted , "Cannot handle empty indices"
732
-
733
- offset_map = None
734
- if len (offsets_sorted ) == 1 :
735
- offset_map = {offsets_sorted [0 ]: last_offset }
736
- else :
737
- iter_offsets = iter (offsets_sorted )
738
- iter_offsets_plus_one = iter (offsets_sorted )
739
- next (iter_offsets_plus_one )
740
- consecutive = izip (iter_offsets , iter_offsets_plus_one )
741
-
742
- offset_map = dict (consecutive )
743
-
744
- # the last offset is not yet set
745
- offset_map [offsets_sorted [- 1 ]] = last_offset
746
- # END handle offset amount
714
+ def _set_cache_ (self , attr ):
715
+ # currently this can only be _offset_map
716
+ # TODO: make this a simple sorted offset array which can be bisected
717
+ # to find the respective entry, from which we can take a +1 easily
718
+ # This might be slower, but should also be much lighter in memory !
719
+ offsets_sorted = sorted (self ._index .offsets ())
720
+ last_offset = len (self ._pack .data ()) - self ._pack .footer_size
721
+ assert offsets_sorted , "Cannot handle empty indices"
722
+
723
+ offset_map = None
724
+ if len (offsets_sorted ) == 1 :
725
+ offset_map = {offsets_sorted [0 ]: last_offset }
726
+ else :
727
+ iter_offsets = iter (offsets_sorted )
728
+ iter_offsets_plus_one = iter (offsets_sorted )
729
+ next (iter_offsets_plus_one )
730
+ consecutive = izip (iter_offsets , iter_offsets_plus_one )
747
731
748
- self . _offset_map = offset_map
732
+ offset_map = dict ( consecutive )
749
733
750
- return self ._offset_map
734
+ # the last offset is not yet set
735
+ offset_map [offsets_sorted [- 1 ]] = last_offset
736
+ # END handle offset amount
737
+ self ._offset_map = offset_map
751
738
752
739
def _sha_to_index (self , sha ):
753
740
""":return: index for the given sha, or raise"""
@@ -870,7 +857,7 @@ def is_valid_stream(self, sha, use_crc=False):
870
857
871
858
index = self ._sha_to_index (sha )
872
859
offset = self ._index .offset (index )
873
- next_offset = self .offset_map [offset ]
860
+ next_offset = self ._offset_map [offset ]
874
861
crc_value = self ._index .crc (index )
875
862
876
863
# create the current crc value, on the compressed object data
0 commit comments