Mercurial > hg
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''' |