comparison mercurial/store.py @ 45942:89a2afe31e82

formating: upgrade to black 20.8b1 This required a couple of small tweaks to un-confuse black, but now it works. Big formatting changes come from: * Dramatically improved collection-splitting logic upstream * Black having a strong (correct IMO) opinion that """ is better than ''' Differential Revision: https://phab.mercurial-scm.org/D9430
author Augie Fackler <raf@durin42.com>
date Fri, 27 Nov 2020 17:03:29 -0500
parents d252f51ab032
children 59fa3890d40a
comparison
equal deleted inserted replaced
45941:346af7687c6f 45942:89a2afe31e82
50 50
51 51
52 # This avoids a collision between a file named foo and a dir named 52 # This avoids a collision between a file named foo and a dir named
53 # foo.i or foo.d 53 # foo.i or foo.d
54 def _encodedir(path): 54 def _encodedir(path):
55 ''' 55 """
56 >>> _encodedir(b'data/foo.i') 56 >>> _encodedir(b'data/foo.i')
57 'data/foo.i' 57 'data/foo.i'
58 >>> _encodedir(b'data/foo.i/bla.i') 58 >>> _encodedir(b'data/foo.i/bla.i')
59 'data/foo.i.hg/bla.i' 59 'data/foo.i.hg/bla.i'
60 >>> _encodedir(b'data/foo.i.hg/bla.i') 60 >>> _encodedir(b'data/foo.i.hg/bla.i')
61 'data/foo.i.hg.hg/bla.i' 61 'data/foo.i.hg.hg/bla.i'
62 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n') 62 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n')
63 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n' 63 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n'
64 ''' 64 """
65 return ( 65 return (
66 path.replace(b".hg/", b".hg.hg/") 66 path.replace(b".hg/", b".hg.hg/")
67 .replace(b".i/", b".i.hg/") 67 .replace(b".i/", b".i.hg/")
68 .replace(b".d/", b".d.hg/") 68 .replace(b".d/", b".d.hg/")
69 ) 69 )
71 71
72 encodedir = getattr(parsers, 'encodedir', _encodedir) 72 encodedir = getattr(parsers, 'encodedir', _encodedir)
73 73
74 74
75 def decodedir(path): 75 def decodedir(path):
76 ''' 76 """
77 >>> decodedir(b'data/foo.i') 77 >>> decodedir(b'data/foo.i')
78 'data/foo.i' 78 'data/foo.i'
79 >>> decodedir(b'data/foo.i.hg/bla.i') 79 >>> decodedir(b'data/foo.i.hg/bla.i')
80 'data/foo.i/bla.i' 80 'data/foo.i/bla.i'
81 >>> decodedir(b'data/foo.i.hg.hg/bla.i') 81 >>> decodedir(b'data/foo.i.hg.hg/bla.i')
82 'data/foo.i.hg/bla.i' 82 'data/foo.i.hg/bla.i'
83 ''' 83 """
84 if b".hg/" not in path: 84 if b".hg/" not in path:
85 return path 85 return path
86 return ( 86 return (
87 path.replace(b".d.hg/", b".d/") 87 path.replace(b".d.hg/", b".d/")
88 .replace(b".i.hg/", b".i/") 88 .replace(b".i.hg/", b".i/")
89 .replace(b".hg.hg/", b".hg/") 89 .replace(b".hg.hg/", b".hg/")
90 ) 90 )
91 91
92 92
93 def _reserved(): 93 def _reserved():
94 ''' characters that are problematic for filesystems 94 """characters that are problematic for filesystems
95 95
96 * ascii escapes (0..31) 96 * ascii escapes (0..31)
97 * ascii hi (126..255) 97 * ascii hi (126..255)
98 * windows specials 98 * windows specials
99 99
100 these characters will be escaped by encodefunctions 100 these characters will be escaped by encodefunctions
101 ''' 101 """
102 winreserved = [ord(x) for x in u'\\:*?"<>|'] 102 winreserved = [ord(x) for x in u'\\:*?"<>|']
103 for x in range(32): 103 for x in range(32):
104 yield x 104 yield x
105 for x in range(126, 256): 105 for x in range(126, 256):
106 yield x 106 yield x
107 for x in winreserved: 107 for x in winreserved:
108 yield x 108 yield x
109 109
110 110
111 def _buildencodefun(): 111 def _buildencodefun():
112 ''' 112 """
113 >>> enc, dec = _buildencodefun() 113 >>> enc, dec = _buildencodefun()
114 114
115 >>> enc(b'nothing/special.txt') 115 >>> enc(b'nothing/special.txt')
116 'nothing/special.txt' 116 'nothing/special.txt'
117 >>> dec(b'nothing/special.txt') 117 >>> dec(b'nothing/special.txt')
129 129
130 >>> enc(b'the\\x07quick\\xADshot') 130 >>> enc(b'the\\x07quick\\xADshot')
131 'the~07quick~adshot' 131 'the~07quick~adshot'
132 >>> dec(b'the~07quick~adshot') 132 >>> dec(b'the~07quick~adshot')
133 'the\\x07quick\\xadshot' 133 'the\\x07quick\\xadshot'
134 ''' 134 """
135 e = b'_' 135 e = b'_'
136 xchr = pycompat.bytechr 136 xchr = pycompat.bytechr
137 asciistr = list(map(xchr, range(127))) 137 asciistr = list(map(xchr, range(127)))
138 capitals = list(range(ord(b"A"), ord(b"Z") + 1)) 138 capitals = list(range(ord(b"A"), ord(b"Z") + 1))
139 139
170 170
171 _encodefname, _decodefname = _buildencodefun() 171 _encodefname, _decodefname = _buildencodefun()
172 172
173 173
174 def encodefilename(s): 174 def encodefilename(s):
175 ''' 175 """
176 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO') 176 >>> encodefilename(b'foo.i/bar.d/bla.hg/hi:world?/HELLO')
177 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o' 177 'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o'
178 ''' 178 """
179 return _encodefname(encodedir(s)) 179 return _encodefname(encodedir(s))
180 180
181 181
182 def decodefilename(s): 182 def decodefilename(s):
183 ''' 183 """
184 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o') 184 >>> decodefilename(b'foo.i.hg/bar.d.hg/bla.hg.hg/hi~3aworld~3f/_h_e_l_l_o')
185 'foo.i/bar.d/bla.hg/hi:world?/HELLO' 185 'foo.i/bar.d/bla.hg/hi:world?/HELLO'
186 ''' 186 """
187 return decodedir(_decodefname(s)) 187 return decodedir(_decodefname(s))
188 188
189 189
190 def _buildlowerencodefun(): 190 def _buildlowerencodefun():
191 ''' 191 """
192 >>> f = _buildlowerencodefun() 192 >>> f = _buildlowerencodefun()
193 >>> f(b'nothing/special.txt') 193 >>> f(b'nothing/special.txt')
194 'nothing/special.txt' 194 'nothing/special.txt'
195 >>> f(b'HELLO') 195 >>> f(b'HELLO')
196 'hello' 196 'hello'
197 >>> f(b'hello:world?') 197 >>> f(b'hello:world?')
198 'hello~3aworld~3f' 198 'hello~3aworld~3f'
199 >>> f(b'the\\x07quick\\xADshot') 199 >>> f(b'the\\x07quick\\xADshot')
200 'the~07quick~adshot' 200 'the~07quick~adshot'
201 ''' 201 """
202 xchr = pycompat.bytechr 202 xchr = pycompat.bytechr
203 cmap = {xchr(x): xchr(x) for x in pycompat.xrange(127)} 203 cmap = {xchr(x): xchr(x) for x in pycompat.xrange(127)}
204 for x in _reserved(): 204 for x in _reserved():
205 cmap[xchr(x)] = b"~%02x" % x 205 cmap[xchr(x)] = b"~%02x" % x
206 for x in range(ord(b"A"), ord(b"Z") + 1): 206 for x in range(ord(b"A"), ord(b"Z") + 1):
218 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3 218 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3
219 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9) 219 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9)
220 220
221 221
222 def _auxencode(path, dotencode): 222 def _auxencode(path, dotencode):
223 ''' 223 """
224 Encodes filenames containing names reserved by Windows or which end in 224 Encodes filenames containing names reserved by Windows or which end in
225 period or space. Does not touch other single reserved characters c. 225 period or space. Does not touch other single reserved characters c.
226 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here. 226 Specifically, c in '\\:*?"<>|' or ord(c) <= 31 are *not* encoded here.
227 Additionally encodes space or period at the beginning, if dotencode is 227 Additionally encodes space or period at the beginning, if dotencode is
228 True. Parameter path is assumed to be all lowercase. 228 True. Parameter path is assumed to be all lowercase.
238 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e'] 238 ['.com1com2', 'lp~749.lpt4.lpt1', 'conprn', 'com0', 'lpt0', 'foo~2e']
239 >>> _auxencode([b'foo. '], True) 239 >>> _auxencode([b'foo. '], True)
240 ['foo.~20'] 240 ['foo.~20']
241 >>> _auxencode([b' .foo'], True) 241 >>> _auxencode([b' .foo'], True)
242 ['~20.foo'] 242 ['~20.foo']
243 ''' 243 """
244 for i, n in enumerate(path): 244 for i, n in enumerate(path):
245 if not n: 245 if not n:
246 continue 246 continue
247 if dotencode and n[0] in b'. ': 247 if dotencode and n[0] in b'. ':
248 n = b"~%02x" % ord(n[0:1]) + n[1:] 248 n = b"~%02x" % ord(n[0:1]) + n[1:]
303 res = b'dh/' + dirs + filler + digest + ext 303 res = b'dh/' + dirs + filler + digest + ext
304 return res 304 return res
305 305
306 306
307 def _hybridencode(path, dotencode): 307 def _hybridencode(path, dotencode):
308 '''encodes path with a length limit 308 """encodes path with a length limit
309 309
310 Encodes all paths that begin with 'data/', according to the following. 310 Encodes all paths that begin with 'data/', according to the following.
311 311
312 Default encoding (reversible): 312 Default encoding (reversible):
313 313
332 basename have been taken). 332 basename have been taken).
333 The extension (e.g. '.i' or '.d') is preserved. 333 The extension (e.g. '.i' or '.d') is preserved.
334 334
335 The string 'data/' at the beginning is replaced with 'dh/', if the hashed 335 The string 'data/' at the beginning is replaced with 'dh/', if the hashed
336 encoding was used. 336 encoding was used.
337 ''' 337 """
338 path = encodedir(path) 338 path = encodedir(path)
339 ef = _encodefname(path).split(b'/') 339 ef = _encodefname(path).split(b'/')
340 res = b'/'.join(_auxencode(ef, dotencode)) 340 res = b'/'.join(_auxencode(ef, dotencode))
341 if len(res) > _maxstorepathlen: 341 if len(res) > _maxstorepathlen:
342 res = _hashencode(path, dotencode) 342 res = _hashencode(path, dotencode)
442 def topfiles(self): 442 def topfiles(self):
443 # yield manifest before changelog 443 # yield manifest before changelog
444 return reversed(self._walk(b'', False)) 444 return reversed(self._walk(b'', False))
445 445
446 def walk(self, matcher=None): 446 def walk(self, matcher=None):
447 '''yields (unencoded, encoded, size) 447 """yields (unencoded, encoded, size)
448 448
449 if a matcher is passed, storage files of only those tracked paths 449 if a matcher is passed, storage files of only those tracked paths
450 are passed with matches the matcher 450 are passed with matches the matcher
451 ''' 451 """
452 # yield data files first 452 # yield data files first
453 for x in self.datafiles(matcher): 453 for x in self.datafiles(matcher):
454 yield x 454 yield x
455 for x in self.topfiles(): 455 for x in self.topfiles():
456 yield x 456 yield x
515 self._dirty = False 515 self._dirty = False
516 # set of new additions to fncache 516 # set of new additions to fncache
517 self.addls = set() 517 self.addls = set()
518 518
519 def ensureloaded(self, warn=None): 519 def ensureloaded(self, warn=None):
520 '''read the fncache file if not already read. 520 """read the fncache file if not already read.
521 521
522 If the file on disk is corrupted, raise. If warn is provided, 522 If the file on disk is corrupted, raise. If warn is provided,
523 warn and keep going instead.''' 523 warn and keep going instead."""
524 if self.entries is None: 524 if self.entries is None:
525 self._load(warn) 525 self._load(warn)
526 526
527 def _load(self, warn=None): 527 def _load(self, warn=None):
528 '''fill the entries from the fncache file''' 528 '''fill the entries from the fncache file'''