Mercurial > hg
comparison mercurial/store.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | c59eb1560c44 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
38 If matcher is None, returns True""" | 38 If matcher is None, returns True""" |
39 | 39 |
40 if matcher is None: | 40 if matcher is None: |
41 return True | 41 return True |
42 path = decodedir(path) | 42 path = decodedir(path) |
43 if path.startswith('data/'): | 43 if path.startswith(b'data/'): |
44 return matcher(path[len('data/') : -len('.i')]) | 44 return matcher(path[len(b'data/') : -len(b'.i')]) |
45 elif path.startswith('meta/'): | 45 elif path.startswith(b'meta/'): |
46 return matcher.visitdir(path[len('meta/') : -len('/00manifest.i')]) | 46 return matcher.visitdir(path[len(b'meta/') : -len(b'/00manifest.i')]) |
47 | 47 |
48 raise error.ProgrammingError("cannot decode path %s" % path) | 48 raise error.ProgrammingError(b"cannot decode path %s" % path) |
49 | 49 |
50 | 50 |
51 # This avoids a collision between a file named foo and a dir named | 51 # This avoids a collision between a file named foo and a dir named |
52 # foo.i or foo.d | 52 # foo.i or foo.d |
53 def _encodedir(path): | 53 def _encodedir(path): |
60 'data/foo.i.hg.hg/bla.i' | 60 'data/foo.i.hg.hg/bla.i' |
61 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n') | 61 >>> _encodedir(b'data/foo.i\\ndata/foo.i/bla.i\\ndata/foo.i.hg/bla.i\\n') |
62 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n' | 62 'data/foo.i\\ndata/foo.i.hg/bla.i\\ndata/foo.i.hg.hg/bla.i\\n' |
63 ''' | 63 ''' |
64 return ( | 64 return ( |
65 path.replace(".hg/", ".hg.hg/") | 65 path.replace(b".hg/", b".hg.hg/") |
66 .replace(".i/", ".i.hg/") | 66 .replace(b".i/", b".i.hg/") |
67 .replace(".d/", ".d.hg/") | 67 .replace(b".d/", b".d.hg/") |
68 ) | 68 ) |
69 | 69 |
70 | 70 |
71 encodedir = getattr(parsers, 'encodedir', _encodedir) | 71 encodedir = getattr(parsers, 'encodedir', _encodedir) |
72 | 72 |
78 >>> decodedir(b'data/foo.i.hg/bla.i') | 78 >>> decodedir(b'data/foo.i.hg/bla.i') |
79 'data/foo.i/bla.i' | 79 'data/foo.i/bla.i' |
80 >>> decodedir(b'data/foo.i.hg.hg/bla.i') | 80 >>> decodedir(b'data/foo.i.hg.hg/bla.i') |
81 'data/foo.i.hg/bla.i' | 81 'data/foo.i.hg/bla.i' |
82 ''' | 82 ''' |
83 if ".hg/" not in path: | 83 if b".hg/" not in path: |
84 return path | 84 return path |
85 return ( | 85 return ( |
86 path.replace(".d.hg/", ".d/") | 86 path.replace(b".d.hg/", b".d/") |
87 .replace(".i.hg/", ".i/") | 87 .replace(b".i.hg/", b".i/") |
88 .replace(".hg.hg/", ".hg/") | 88 .replace(b".hg.hg/", b".hg/") |
89 ) | 89 ) |
90 | 90 |
91 | 91 |
92 def _reserved(): | 92 def _reserved(): |
93 ''' characters that are problematic for filesystems | 93 ''' characters that are problematic for filesystems |
129 >>> enc(b'the\\x07quick\\xADshot') | 129 >>> enc(b'the\\x07quick\\xADshot') |
130 'the~07quick~adshot' | 130 'the~07quick~adshot' |
131 >>> dec(b'the~07quick~adshot') | 131 >>> dec(b'the~07quick~adshot') |
132 'the\\x07quick\\xadshot' | 132 'the\\x07quick\\xadshot' |
133 ''' | 133 ''' |
134 e = '_' | 134 e = b'_' |
135 xchr = pycompat.bytechr | 135 xchr = pycompat.bytechr |
136 asciistr = list(map(xchr, range(127))) | 136 asciistr = list(map(xchr, range(127))) |
137 capitals = list(range(ord("A"), ord("Z") + 1)) | 137 capitals = list(range(ord(b"A"), ord(b"Z") + 1)) |
138 | 138 |
139 cmap = dict((x, x) for x in asciistr) | 139 cmap = dict((x, x) for x in asciistr) |
140 for x in _reserved(): | 140 for x in _reserved(): |
141 cmap[xchr(x)] = "~%02x" % x | 141 cmap[xchr(x)] = b"~%02x" % x |
142 for x in capitals + [ord(e)]: | 142 for x in capitals + [ord(e)]: |
143 cmap[xchr(x)] = e + xchr(x).lower() | 143 cmap[xchr(x)] = e + xchr(x).lower() |
144 | 144 |
145 dmap = {} | 145 dmap = {} |
146 for k, v in cmap.iteritems(): | 146 for k, v in cmap.iteritems(): |
158 pass | 158 pass |
159 else: | 159 else: |
160 raise KeyError | 160 raise KeyError |
161 | 161 |
162 return ( | 162 return ( |
163 lambda s: ''.join( | 163 lambda s: b''.join( |
164 [cmap[s[c : c + 1]] for c in pycompat.xrange(len(s))] | 164 [cmap[s[c : c + 1]] for c in pycompat.xrange(len(s))] |
165 ), | 165 ), |
166 lambda s: ''.join(list(decode(s))), | 166 lambda s: b''.join(list(decode(s))), |
167 ) | 167 ) |
168 | 168 |
169 | 169 |
170 _encodefname, _decodefname = _buildencodefun() | 170 _encodefname, _decodefname = _buildencodefun() |
171 | 171 |
199 'the~07quick~adshot' | 199 'the~07quick~adshot' |
200 ''' | 200 ''' |
201 xchr = pycompat.bytechr | 201 xchr = pycompat.bytechr |
202 cmap = dict([(xchr(x), xchr(x)) for x in pycompat.xrange(127)]) | 202 cmap = dict([(xchr(x), xchr(x)) for x in pycompat.xrange(127)]) |
203 for x in _reserved(): | 203 for x in _reserved(): |
204 cmap[xchr(x)] = "~%02x" % x | 204 cmap[xchr(x)] = b"~%02x" % x |
205 for x in range(ord("A"), ord("Z") + 1): | 205 for x in range(ord(b"A"), ord(b"Z") + 1): |
206 cmap[xchr(x)] = xchr(x).lower() | 206 cmap[xchr(x)] = xchr(x).lower() |
207 | 207 |
208 def lowerencode(s): | 208 def lowerencode(s): |
209 return "".join([cmap[c] for c in pycompat.iterbytestr(s)]) | 209 return b"".join([cmap[c] for c in pycompat.iterbytestr(s)]) |
210 | 210 |
211 return lowerencode | 211 return lowerencode |
212 | 212 |
213 | 213 |
214 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun() | 214 lowerencode = getattr(parsers, 'lowerencode', None) or _buildlowerencodefun() |
215 | 215 |
216 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9 | 216 # Windows reserved names: con, prn, aux, nul, com1..com9, lpt1..lpt9 |
217 _winres3 = ('aux', 'con', 'prn', 'nul') # length 3 | 217 _winres3 = (b'aux', b'con', b'prn', b'nul') # length 3 |
218 _winres4 = ('com', 'lpt') # length 4 (with trailing 1..9) | 218 _winres4 = (b'com', b'lpt') # length 4 (with trailing 1..9) |
219 | 219 |
220 | 220 |
221 def _auxencode(path, dotencode): | 221 def _auxencode(path, dotencode): |
222 ''' | 222 ''' |
223 Encodes filenames containing names reserved by Windows or which end in | 223 Encodes filenames containing names reserved by Windows or which end in |
241 ['~20.foo'] | 241 ['~20.foo'] |
242 ''' | 242 ''' |
243 for i, n in enumerate(path): | 243 for i, n in enumerate(path): |
244 if not n: | 244 if not n: |
245 continue | 245 continue |
246 if dotencode and n[0] in '. ': | 246 if dotencode and n[0] in b'. ': |
247 n = "~%02x" % ord(n[0:1]) + n[1:] | 247 n = b"~%02x" % ord(n[0:1]) + n[1:] |
248 path[i] = n | 248 path[i] = n |
249 else: | 249 else: |
250 l = n.find('.') | 250 l = n.find(b'.') |
251 if l == -1: | 251 if l == -1: |
252 l = len(n) | 252 l = len(n) |
253 if (l == 3 and n[:3] in _winres3) or ( | 253 if (l == 3 and n[:3] in _winres3) or ( |
254 l == 4 and n[3:4] <= '9' and n[3:4] >= '1' and n[:3] in _winres4 | 254 l == 4 |
255 and n[3:4] <= b'9' | |
256 and n[3:4] >= b'1' | |
257 and n[:3] in _winres4 | |
255 ): | 258 ): |
256 # encode third letter ('aux' -> 'au~78') | 259 # encode third letter ('aux' -> 'au~78') |
257 ec = "~%02x" % ord(n[2:3]) | 260 ec = b"~%02x" % ord(n[2:3]) |
258 n = n[0:2] + ec + n[3:] | 261 n = n[0:2] + ec + n[3:] |
259 path[i] = n | 262 path[i] = n |
260 if n[-1] in '. ': | 263 if n[-1] in b'. ': |
261 # encode last period or space ('foo...' -> 'foo..~2e') | 264 # encode last period or space ('foo...' -> 'foo..~2e') |
262 path[i] = n[:-1] + "~%02x" % ord(n[-1:]) | 265 path[i] = n[:-1] + b"~%02x" % ord(n[-1:]) |
263 return path | 266 return path |
264 | 267 |
265 | 268 |
266 _maxstorepathlen = 120 | 269 _maxstorepathlen = 120 |
267 _dirprefixlen = 8 | 270 _dirprefixlen = 8 |
268 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4 | 271 _maxshortdirslen = 8 * (_dirprefixlen + 1) - 4 |
269 | 272 |
270 | 273 |
271 def _hashencode(path, dotencode): | 274 def _hashencode(path, dotencode): |
272 digest = node.hex(hashlib.sha1(path).digest()) | 275 digest = node.hex(hashlib.sha1(path).digest()) |
273 le = lowerencode(path[5:]).split('/') # skips prefix 'data/' or 'meta/' | 276 le = lowerencode(path[5:]).split(b'/') # skips prefix 'data/' or 'meta/' |
274 parts = _auxencode(le, dotencode) | 277 parts = _auxencode(le, dotencode) |
275 basename = parts[-1] | 278 basename = parts[-1] |
276 _root, ext = os.path.splitext(basename) | 279 _root, ext = os.path.splitext(basename) |
277 sdirs = [] | 280 sdirs = [] |
278 sdirslen = 0 | 281 sdirslen = 0 |
279 for p in parts[:-1]: | 282 for p in parts[:-1]: |
280 d = p[:_dirprefixlen] | 283 d = p[:_dirprefixlen] |
281 if d[-1] in '. ': | 284 if d[-1] in b'. ': |
282 # Windows can't access dirs ending in period or space | 285 # Windows can't access dirs ending in period or space |
283 d = d[:-1] + '_' | 286 d = d[:-1] + b'_' |
284 if sdirslen == 0: | 287 if sdirslen == 0: |
285 t = len(d) | 288 t = len(d) |
286 else: | 289 else: |
287 t = sdirslen + 1 + len(d) | 290 t = sdirslen + 1 + len(d) |
288 if t > _maxshortdirslen: | 291 if t > _maxshortdirslen: |
289 break | 292 break |
290 sdirs.append(d) | 293 sdirs.append(d) |
291 sdirslen = t | 294 sdirslen = t |
292 dirs = '/'.join(sdirs) | 295 dirs = b'/'.join(sdirs) |
293 if len(dirs) > 0: | 296 if len(dirs) > 0: |
294 dirs += '/' | 297 dirs += b'/' |
295 res = 'dh/' + dirs + digest + ext | 298 res = b'dh/' + dirs + digest + ext |
296 spaceleft = _maxstorepathlen - len(res) | 299 spaceleft = _maxstorepathlen - len(res) |
297 if spaceleft > 0: | 300 if spaceleft > 0: |
298 filler = basename[:spaceleft] | 301 filler = basename[:spaceleft] |
299 res = 'dh/' + dirs + filler + digest + ext | 302 res = b'dh/' + dirs + filler + digest + ext |
300 return res | 303 return res |
301 | 304 |
302 | 305 |
303 def _hybridencode(path, dotencode): | 306 def _hybridencode(path, dotencode): |
304 '''encodes path with a length limit | 307 '''encodes path with a length limit |
330 | 333 |
331 The string 'data/' at the beginning is replaced with 'dh/', if the hashed | 334 The string 'data/' at the beginning is replaced with 'dh/', if the hashed |
332 encoding was used. | 335 encoding was used. |
333 ''' | 336 ''' |
334 path = encodedir(path) | 337 path = encodedir(path) |
335 ef = _encodefname(path).split('/') | 338 ef = _encodefname(path).split(b'/') |
336 res = '/'.join(_auxencode(ef, dotencode)) | 339 res = b'/'.join(_auxencode(ef, dotencode)) |
337 if len(res) > _maxstorepathlen: | 340 if len(res) > _maxstorepathlen: |
338 res = _hashencode(path, dotencode) | 341 res = _hashencode(path, dotencode) |
339 return res | 342 return res |
340 | 343 |
341 | 344 |
342 def _pathencode(path): | 345 def _pathencode(path): |
343 de = encodedir(path) | 346 de = encodedir(path) |
344 if len(path) > _maxstorepathlen: | 347 if len(path) > _maxstorepathlen: |
345 return _hashencode(de, True) | 348 return _hashencode(de, True) |
346 ef = _encodefname(de).split('/') | 349 ef = _encodefname(de).split(b'/') |
347 res = '/'.join(_auxencode(ef, True)) | 350 res = b'/'.join(_auxencode(ef, True)) |
348 if len(res) > _maxstorepathlen: | 351 if len(res) > _maxstorepathlen: |
349 return _hashencode(de, True) | 352 return _hashencode(de, True) |
350 return res | 353 return res |
351 | 354 |
352 | 355 |
368 mode = None | 371 mode = None |
369 return mode | 372 return mode |
370 | 373 |
371 | 374 |
372 _data = ( | 375 _data = ( |
373 'bookmarks narrowspec data meta 00manifest.d 00manifest.i' | 376 b'bookmarks narrowspec data meta 00manifest.d 00manifest.i' |
374 ' 00changelog.d 00changelog.i phaseroots obsstore' | 377 b' 00changelog.d 00changelog.i phaseroots obsstore' |
375 ) | 378 ) |
376 | 379 |
377 | 380 |
378 def isrevlog(f, kind, st): | 381 def isrevlog(f, kind, st): |
379 return kind == stat.S_IFREG and f[-2:] in ('.i', '.d') | 382 return kind == stat.S_IFREG and f[-2:] in (b'.i', b'.d') |
380 | 383 |
381 | 384 |
382 class basicstore(object): | 385 class basicstore(object): |
383 '''base class for local repository stores''' | 386 '''base class for local repository stores''' |
384 | 387 |
390 self.rawvfs = vfs | 393 self.rawvfs = vfs |
391 self.vfs = vfsmod.filtervfs(vfs, encodedir) | 394 self.vfs = vfsmod.filtervfs(vfs, encodedir) |
392 self.opener = self.vfs | 395 self.opener = self.vfs |
393 | 396 |
394 def join(self, f): | 397 def join(self, f): |
395 return self.path + '/' + encodedir(f) | 398 return self.path + b'/' + encodedir(f) |
396 | 399 |
397 def _walk(self, relpath, recurse, filefilter=isrevlog): | 400 def _walk(self, relpath, recurse, filefilter=isrevlog): |
398 '''yields (unencoded, encoded, size)''' | 401 '''yields (unencoded, encoded, size)''' |
399 path = self.path | 402 path = self.path |
400 if relpath: | 403 if relpath: |
401 path += '/' + relpath | 404 path += b'/' + relpath |
402 striplen = len(self.path) + 1 | 405 striplen = len(self.path) + 1 |
403 l = [] | 406 l = [] |
404 if self.rawvfs.isdir(path): | 407 if self.rawvfs.isdir(path): |
405 visit = [path] | 408 visit = [path] |
406 readdir = self.rawvfs.readdir | 409 readdir = self.rawvfs.readdir |
407 while visit: | 410 while visit: |
408 p = visit.pop() | 411 p = visit.pop() |
409 for f, kind, st in readdir(p, stat=True): | 412 for f, kind, st in readdir(p, stat=True): |
410 fp = p + '/' + f | 413 fp = p + b'/' + f |
411 if filefilter(f, kind, st): | 414 if filefilter(f, kind, st): |
412 n = util.pconvert(fp[striplen:]) | 415 n = util.pconvert(fp[striplen:]) |
413 l.append((decodedir(n), n, st.st_size)) | 416 l.append((decodedir(n), n, st.st_size)) |
414 elif kind == stat.S_IFDIR and recurse: | 417 elif kind == stat.S_IFDIR and recurse: |
415 visit.append(fp) | 418 visit.append(fp) |
422 def manifestlog(self, repo, storenarrowmatch): | 425 def manifestlog(self, repo, storenarrowmatch): |
423 rootstore = manifest.manifestrevlog(self.vfs) | 426 rootstore = manifest.manifestrevlog(self.vfs) |
424 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch) | 427 return manifest.manifestlog(self.vfs, repo, rootstore, storenarrowmatch) |
425 | 428 |
426 def datafiles(self, matcher=None): | 429 def datafiles(self, matcher=None): |
427 return self._walk('data', True) + self._walk('meta', True) | 430 return self._walk(b'data', True) + self._walk(b'meta', True) |
428 | 431 |
429 def topfiles(self): | 432 def topfiles(self): |
430 # yield manifest before changelog | 433 # yield manifest before changelog |
431 return reversed(self._walk('', False)) | 434 return reversed(self._walk(b'', False)) |
432 | 435 |
433 def walk(self, matcher=None): | 436 def walk(self, matcher=None): |
434 '''yields (unencoded, encoded, size) | 437 '''yields (unencoded, encoded, size) |
435 | 438 |
436 if a matcher is passed, storage files of only those tracked paths | 439 if a matcher is passed, storage files of only those tracked paths |
441 yield x | 444 yield x |
442 for x in self.topfiles(): | 445 for x in self.topfiles(): |
443 yield x | 446 yield x |
444 | 447 |
445 def copylist(self): | 448 def copylist(self): |
446 return ['requires'] + _data.split() | 449 return [b'requires'] + _data.split() |
447 | 450 |
448 def write(self, tr): | 451 def write(self, tr): |
449 pass | 452 pass |
450 | 453 |
451 def invalidatecaches(self): | 454 def invalidatecaches(self): |
454 def markremoved(self, fn): | 457 def markremoved(self, fn): |
455 pass | 458 pass |
456 | 459 |
457 def __contains__(self, path): | 460 def __contains__(self, path): |
458 '''Checks if the store contains path''' | 461 '''Checks if the store contains path''' |
459 path = "/".join(("data", path)) | 462 path = b"/".join((b"data", path)) |
460 # file? | 463 # file? |
461 if self.vfs.exists(path + ".i"): | 464 if self.vfs.exists(path + b".i"): |
462 return True | 465 return True |
463 # dir? | 466 # dir? |
464 if not path.endswith("/"): | 467 if not path.endswith(b"/"): |
465 path = path + "/" | 468 path = path + b"/" |
466 return self.vfs.exists(path) | 469 return self.vfs.exists(path) |
467 | 470 |
468 | 471 |
469 class encodedstore(basicstore): | 472 class encodedstore(basicstore): |
470 def __init__(self, path, vfstype): | 473 def __init__(self, path, vfstype): |
471 vfs = vfstype(path + '/store') | 474 vfs = vfstype(path + b'/store') |
472 self.path = vfs.base | 475 self.path = vfs.base |
473 self.createmode = _calcmode(vfs) | 476 self.createmode = _calcmode(vfs) |
474 vfs.createmode = self.createmode | 477 vfs.createmode = self.createmode |
475 self.rawvfs = vfs | 478 self.rawvfs = vfs |
476 self.vfs = vfsmod.filtervfs(vfs, encodefilename) | 479 self.vfs = vfsmod.filtervfs(vfs, encodefilename) |
485 if a is not None and not _matchtrackedpath(a, matcher): | 488 if a is not None and not _matchtrackedpath(a, matcher): |
486 continue | 489 continue |
487 yield a, b, size | 490 yield a, b, size |
488 | 491 |
489 def join(self, f): | 492 def join(self, f): |
490 return self.path + '/' + encodefilename(f) | 493 return self.path + b'/' + encodefilename(f) |
491 | 494 |
492 def copylist(self): | 495 def copylist(self): |
493 return ['requires', '00changelog.i'] + [ | 496 return [b'requires', b'00changelog.i'] + [ |
494 'store/' + f for f in _data.split() | 497 b'store/' + f for f in _data.split() |
495 ] | 498 ] |
496 | 499 |
497 | 500 |
498 class fncache(object): | 501 class fncache(object): |
499 # the filename used to be partially encoded | 502 # the filename used to be partially encoded |
515 | 518 |
516 def _load(self, warn=None): | 519 def _load(self, warn=None): |
517 '''fill the entries from the fncache file''' | 520 '''fill the entries from the fncache file''' |
518 self._dirty = False | 521 self._dirty = False |
519 try: | 522 try: |
520 fp = self.vfs('fncache', mode='rb') | 523 fp = self.vfs(b'fncache', mode=b'rb') |
521 except IOError: | 524 except IOError: |
522 # skip nonexistent file | 525 # skip nonexistent file |
523 self.entries = set() | 526 self.entries = set() |
524 return | 527 return |
525 | 528 |
535 # substring '\n' not found, maybe the entry is bigger than the | 538 # substring '\n' not found, maybe the entry is bigger than the |
536 # chunksize, so let's keep iterating | 539 # chunksize, so let's keep iterating |
537 pass | 540 pass |
538 | 541 |
539 if chunk: | 542 if chunk: |
540 msg = _("fncache does not ends with a newline") | 543 msg = _(b"fncache does not ends with a newline") |
541 if warn: | 544 if warn: |
542 warn(msg + '\n') | 545 warn(msg + b'\n') |
543 else: | 546 else: |
544 raise error.Abort( | 547 raise error.Abort( |
545 msg, | 548 msg, |
546 hint=_( | 549 hint=_( |
547 "use 'hg debugrebuildfncache' to " "rebuild the fncache" | 550 b"use 'hg debugrebuildfncache' to " |
551 b"rebuild the fncache" | |
548 ), | 552 ), |
549 ) | 553 ) |
550 self._checkentries(fp, warn) | 554 self._checkentries(fp, warn) |
551 fp.close() | 555 fp.close() |
552 | 556 |
553 def _checkentries(self, fp, warn): | 557 def _checkentries(self, fp, warn): |
554 """ make sure there is no empty string in entries """ | 558 """ make sure there is no empty string in entries """ |
555 if '' in self.entries: | 559 if b'' in self.entries: |
556 fp.seek(0) | 560 fp.seek(0) |
557 for n, line in enumerate(util.iterfile(fp)): | 561 for n, line in enumerate(util.iterfile(fp)): |
558 if not line.rstrip('\n'): | 562 if not line.rstrip(b'\n'): |
559 t = _('invalid entry in fncache, line %d') % (n + 1) | 563 t = _(b'invalid entry in fncache, line %d') % (n + 1) |
560 if warn: | 564 if warn: |
561 warn(t + '\n') | 565 warn(t + b'\n') |
562 else: | 566 else: |
563 raise error.Abort(t) | 567 raise error.Abort(t) |
564 | 568 |
565 def write(self, tr): | 569 def write(self, tr): |
566 if self._dirty: | 570 if self._dirty: |
567 assert self.entries is not None | 571 assert self.entries is not None |
568 self.entries = self.entries | self.addls | 572 self.entries = self.entries | self.addls |
569 self.addls = set() | 573 self.addls = set() |
570 tr.addbackup('fncache') | 574 tr.addbackup(b'fncache') |
571 fp = self.vfs('fncache', mode='wb', atomictemp=True) | 575 fp = self.vfs(b'fncache', mode=b'wb', atomictemp=True) |
572 if self.entries: | 576 if self.entries: |
573 fp.write(encodedir('\n'.join(self.entries) + '\n')) | 577 fp.write(encodedir(b'\n'.join(self.entries) + b'\n')) |
574 fp.close() | 578 fp.close() |
575 self._dirty = False | 579 self._dirty = False |
576 if self.addls: | 580 if self.addls: |
577 # if we have just new entries, let's append them to the fncache | 581 # if we have just new entries, let's append them to the fncache |
578 tr.addbackup('fncache') | 582 tr.addbackup(b'fncache') |
579 fp = self.vfs('fncache', mode='ab', atomictemp=True) | 583 fp = self.vfs(b'fncache', mode=b'ab', atomictemp=True) |
580 if self.addls: | 584 if self.addls: |
581 fp.write(encodedir('\n'.join(self.addls) + '\n')) | 585 fp.write(encodedir(b'\n'.join(self.addls) + b'\n')) |
582 fp.close() | 586 fp.close() |
583 self.entries = None | 587 self.entries = None |
584 self.addls = set() | 588 self.addls = set() |
585 | 589 |
586 def add(self, fn): | 590 def add(self, fn): |
618 def __init__(self, vfs, fnc, encode): | 622 def __init__(self, vfs, fnc, encode): |
619 vfsmod.proxyvfs.__init__(self, vfs) | 623 vfsmod.proxyvfs.__init__(self, vfs) |
620 self.fncache = fnc | 624 self.fncache = fnc |
621 self.encode = encode | 625 self.encode = encode |
622 | 626 |
623 def __call__(self, path, mode='r', *args, **kw): | 627 def __call__(self, path, mode=b'r', *args, **kw): |
624 encoded = self.encode(path) | 628 encoded = self.encode(path) |
625 if mode not in ('r', 'rb') and ( | 629 if mode not in (b'r', b'rb') and ( |
626 path.startswith('data/') or path.startswith('meta/') | 630 path.startswith(b'data/') or path.startswith(b'meta/') |
627 ): | 631 ): |
628 # do not trigger a fncache load when adding a file that already is | 632 # do not trigger a fncache load when adding a file that already is |
629 # known to exist. | 633 # known to exist. |
630 notload = self.fncache.entries is None and self.vfs.exists(encoded) | 634 notload = self.fncache.entries is None and self.vfs.exists(encoded) |
631 if notload and 'a' in mode and not self.vfs.stat(encoded).st_size: | 635 if notload and b'a' in mode and not self.vfs.stat(encoded).st_size: |
632 # when appending to an existing file, if the file has size zero, | 636 # when appending to an existing file, if the file has size zero, |
633 # it should be considered as missing. Such zero-size files are | 637 # it should be considered as missing. Such zero-size files are |
634 # the result of truncation when a transaction is aborted. | 638 # the result of truncation when a transaction is aborted. |
635 notload = False | 639 notload = False |
636 if not notload: | 640 if not notload: |
649 if dotencode: | 653 if dotencode: |
650 encode = _pathencode | 654 encode = _pathencode |
651 else: | 655 else: |
652 encode = _plainhybridencode | 656 encode = _plainhybridencode |
653 self.encode = encode | 657 self.encode = encode |
654 vfs = vfstype(path + '/store') | 658 vfs = vfstype(path + b'/store') |
655 self.path = vfs.base | 659 self.path = vfs.base |
656 self.pathsep = self.path + '/' | 660 self.pathsep = self.path + b'/' |
657 self.createmode = _calcmode(vfs) | 661 self.createmode = _calcmode(vfs) |
658 vfs.createmode = self.createmode | 662 vfs.createmode = self.createmode |
659 self.rawvfs = vfs | 663 self.rawvfs = vfs |
660 fnc = fncache(vfs) | 664 fnc = fncache(vfs) |
661 self.fncache = fnc | 665 self.fncache = fnc |
679 if err.errno != errno.ENOENT: | 683 if err.errno != errno.ENOENT: |
680 raise | 684 raise |
681 | 685 |
682 def copylist(self): | 686 def copylist(self): |
683 d = ( | 687 d = ( |
684 'bookmarks narrowspec data meta dh fncache phaseroots obsstore' | 688 b'bookmarks narrowspec data meta dh fncache phaseroots obsstore' |
685 ' 00manifest.d 00manifest.i 00changelog.d 00changelog.i' | 689 b' 00manifest.d 00manifest.i 00changelog.d 00changelog.i' |
686 ) | 690 ) |
687 return ['requires', '00changelog.i'] + ['store/' + f for f in d.split()] | 691 return [b'requires', b'00changelog.i'] + [ |
692 b'store/' + f for f in d.split() | |
693 ] | |
688 | 694 |
689 def write(self, tr): | 695 def write(self, tr): |
690 self.fncache.write(tr) | 696 self.fncache.write(tr) |
691 | 697 |
692 def invalidatecaches(self): | 698 def invalidatecaches(self): |
707 # nonexistent entry | 713 # nonexistent entry |
708 return False | 714 return False |
709 | 715 |
710 def __contains__(self, path): | 716 def __contains__(self, path): |
711 '''Checks if the store contains path''' | 717 '''Checks if the store contains path''' |
712 path = "/".join(("data", path)) | 718 path = b"/".join((b"data", path)) |
713 # check for files (exact match) | 719 # check for files (exact match) |
714 e = path + '.i' | 720 e = path + b'.i' |
715 if e in self.fncache and self._exists(e): | 721 if e in self.fncache and self._exists(e): |
716 return True | 722 return True |
717 # now check for directories (prefix match) | 723 # now check for directories (prefix match) |
718 if not path.endswith('/'): | 724 if not path.endswith(b'/'): |
719 path += '/' | 725 path += b'/' |
720 for e in self.fncache: | 726 for e in self.fncache: |
721 if e.startswith(path) and self._exists(e): | 727 if e.startswith(path) and self._exists(e): |
722 return True | 728 return True |
723 return False | 729 return False |