@@ -52,17 +52,62 @@ def name(self):
52
52
def _get_path (self ):
53
53
return join_path_native (self .repo .path , self .path )
54
54
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
+
55
88
def _get_commit (self ):
56
89
"""
57
90
Returns:
58
91
Commit object we point to, works for detached and non-detached
59
92
SymbolicReferences
60
93
"""
61
94
# 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
66
111
67
112
# it is a detached reference
68
113
if self .repo .re_hexsha_only .match (tokens [0 ]):
@@ -282,26 +327,10 @@ def iter_items(cls, repo, common_path = None, **kwargs):
282
327
# END for each directory to walk
283
328
284
329
# 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
305
334
# END packed refs reading
306
335
307
336
# return paths in sorted order
0 commit comments