@@ -52,17 +52,62 @@ def name(self):
5252 def _get_path (self ):
5353 return join_path_native (self .repo .path , self .path )
5454
55+ @classmethod
56+ def _iter_packed_refs (cls , repo ):
57+ """Returns an iterator yielding pairs of sha1/path pairs for the corresponding
58+ refs.
59+ NOTE: The packed refs file will be kept open as long as we iterate"""
60+ try :
61+ fp = open (os .path .join (repo .path , 'packed-refs' ), 'r' )
62+ for line in fp :
63+ line = line .strip ()
64+ if not line :
65+ continue
66+ if line .startswith ('#' ):
67+ if line .startswith ('# pack-refs with:' ) and not line .endswith ('peeled' ):
68+ raise TypeError ("PackingType of packed-Refs not understood: %r" % line )
69+ # END abort if we do not understand the packing scheme
70+ continue
71+ # END parse comment
72+
73+ # skip dereferenced tag object entries - previous line was actual
74+ # tag reference for it
75+ if line [0 ] == '^' :
76+ continue
77+
78+ yield tuple (line .split (' ' , 1 ))
79+ # END for each line
80+ except (OSError ,IOError ):
81+ raise StopIteration
82+ # END no packed-refs file handling
83+ # NOTE: Had try-finally block around here to close the fp,
84+ # but some python version woudn't allow yields within that.
85+ # I believe files are closing themselves on destruction, so it is
86+ # alright.
87+
5588 def _get_commit (self ):
5689 """
5790 Returns:
5891 Commit object we point to, works for detached and non-detached
5992 SymbolicReferences
6093 """
6194 # we partially reimplement it to prevent unnecessary file access
62- fp = open (self ._get_path (), 'r' )
63- value = fp .read ().rstrip ()
64- fp .close ()
65- tokens = value .split (" " )
95+ tokens = None
96+ try :
97+ fp = open (self ._get_path (), 'r' )
98+ value = fp .read ().rstrip ()
99+ fp .close ()
100+ tokens = value .split (" " )
101+ except (OSError ,IOError ):
102+ # Probably we are just packed, find our entry in the packed refs file
103+ # NOTE: We are not a symbolic ref if we are in a packed file, as these
104+ # are excluded explictly
105+ for sha , path in self ._iter_packed_refs (self .repo ):
106+ if path != self .path : continue
107+ tokens = (sha , path )
108+ break
109+ # END for each packed ref
110+ # END handle packed refs
66111
67112 # it is a detached reference
68113 if self .repo .re_hexsha_only .match (tokens [0 ]):
@@ -282,26 +327,10 @@ def iter_items(cls, repo, common_path = None, **kwargs):
282327 # END for each directory to walk
283328
284329 # read packed refs
285- packed_refs_path = join_path_native (repo .path , 'packed-refs' )
286- if os .path .isfile (packed_refs_path ):
287- fp = open (packed_refs_path , 'r' )
288- try :
289- for line in fp .readlines ():
290- if line .startswith ('#' ):
291- continue
292- # 439689865b9c6e2a0dad61db22a0c9855bacf597 refs/heads/hello
293- line = line .rstrip ()
294- first_space = line .find (' ' )
295- if first_space == - 1 :
296- continue
297-
298- rela_path = line [first_space + 1 :]
299- if rela_path .startswith (common_path ):
300- rela_paths .add (rela_path )
301- # END relative path matches common path
302- # END for each line in packed-refs
303- finally :
304- fp .close ()
330+ for sha , rela_path in cls ._iter_packed_refs (repo ):
331+ if rela_path .startswith (common_path ):
332+ rela_paths .add (rela_path )
333+ # END relative path matches common path
305334 # END packed refs reading
306335
307336 # return paths in sorted order
0 commit comments