Mercurial > hg
comparison mercurial/transaction.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 | d783f945a701 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
26 version = 2 | 26 version = 2 |
27 | 27 |
28 # These are the file generators that should only be executed after the | 28 # These are the file generators that should only be executed after the |
29 # finalizers are done, since they rely on the output of the finalizers (like | 29 # finalizers are done, since they rely on the output of the finalizers (like |
30 # the changelog having been written). | 30 # the changelog having been written). |
31 postfinalizegenerators = {'bookmarks', 'dirstate'} | 31 postfinalizegenerators = {b'bookmarks', b'dirstate'} |
32 | 32 |
33 gengroupall = 'all' | 33 gengroupall = b'all' |
34 gengroupprefinalize = 'prefinalize' | 34 gengroupprefinalize = b'prefinalize' |
35 gengrouppostfinalize = 'postfinalize' | 35 gengrouppostfinalize = b'postfinalize' |
36 | 36 |
37 | 37 |
38 def active(func): | 38 def active(func): |
39 def _active(self, *args, **kwds): | 39 def _active(self, *args, **kwds): |
40 if self._count == 0: | 40 if self._count == 0: |
41 raise error.Abort( | 41 raise error.Abort( |
42 _('cannot use transaction when it is already committed/aborted') | 42 _( |
43 b'cannot use transaction when it is already committed/aborted' | |
44 ) | |
43 ) | 45 ) |
44 return func(self, *args, **kwds) | 46 return func(self, *args, **kwds) |
45 | 47 |
46 return _active | 48 return _active |
47 | 49 |
56 unlink=True, | 58 unlink=True, |
57 checkambigfiles=None, | 59 checkambigfiles=None, |
58 ): | 60 ): |
59 for f, o, _ignore in entries: | 61 for f, o, _ignore in entries: |
60 if o or not unlink: | 62 if o or not unlink: |
61 checkambig = checkambigfiles and (f, '') in checkambigfiles | 63 checkambig = checkambigfiles and (f, b'') in checkambigfiles |
62 try: | 64 try: |
63 fp = opener(f, 'a', checkambig=checkambig) | 65 fp = opener(f, b'a', checkambig=checkambig) |
64 if fp.tell() < o: | 66 if fp.tell() < o: |
65 raise error.Abort( | 67 raise error.Abort( |
66 _( | 68 _( |
67 "attempted to truncate %s to %d bytes, but it was " | 69 b"attempted to truncate %s to %d bytes, but it was " |
68 "already %d bytes\n" | 70 b"already %d bytes\n" |
69 ) | 71 ) |
70 % (f, o, fp.tell()) | 72 % (f, o, fp.tell()) |
71 ) | 73 ) |
72 fp.truncate(o) | 74 fp.truncate(o) |
73 fp.close() | 75 fp.close() |
74 except IOError: | 76 except IOError: |
75 report(_("failed to truncate %s\n") % f) | 77 report(_(b"failed to truncate %s\n") % f) |
76 raise | 78 raise |
77 else: | 79 else: |
78 try: | 80 try: |
79 opener.unlink(f) | 81 opener.unlink(f) |
80 except (IOError, OSError) as inst: | 82 except (IOError, OSError) as inst: |
82 raise | 84 raise |
83 | 85 |
84 backupfiles = [] | 86 backupfiles = [] |
85 for l, f, b, c in backupentries: | 87 for l, f, b, c in backupentries: |
86 if l not in vfsmap and c: | 88 if l not in vfsmap and c: |
87 report("couldn't handle %s: unknown cache location %s\n" % (b, l)) | 89 report(b"couldn't handle %s: unknown cache location %s\n" % (b, l)) |
88 vfs = vfsmap[l] | 90 vfs = vfsmap[l] |
89 try: | 91 try: |
90 if f and b: | 92 if f and b: |
91 filepath = vfs.join(f) | 93 filepath = vfs.join(f) |
92 backuppath = vfs.join(b) | 94 backuppath = vfs.join(b) |
93 checkambig = checkambigfiles and (f, l) in checkambigfiles | 95 checkambig = checkambigfiles and (f, l) in checkambigfiles |
94 try: | 96 try: |
95 util.copyfile(backuppath, filepath, checkambig=checkambig) | 97 util.copyfile(backuppath, filepath, checkambig=checkambig) |
96 backupfiles.append(b) | 98 backupfiles.append(b) |
97 except IOError: | 99 except IOError: |
98 report(_("failed to recover %s\n") % f) | 100 report(_(b"failed to recover %s\n") % f) |
99 else: | 101 else: |
100 target = f or b | 102 target = f or b |
101 try: | 103 try: |
102 vfs.unlink(target) | 104 vfs.unlink(target) |
103 except (IOError, OSError) as inst: | 105 except (IOError, OSError) as inst: |
105 raise | 107 raise |
106 except (IOError, OSError, error.Abort): | 108 except (IOError, OSError, error.Abort): |
107 if not c: | 109 if not c: |
108 raise | 110 raise |
109 | 111 |
110 backuppath = "%s.backupfiles" % journal | 112 backuppath = b"%s.backupfiles" % journal |
111 if opener.exists(backuppath): | 113 if opener.exists(backuppath): |
112 opener.unlink(backuppath) | 114 opener.unlink(backuppath) |
113 opener.unlink(journal) | 115 opener.unlink(journal) |
114 try: | 116 try: |
115 for f in backupfiles: | 117 for f in backupfiles: |
153 self._report = report | 155 self._report = report |
154 # a vfs to the store content | 156 # a vfs to the store content |
155 self._opener = opener | 157 self._opener = opener |
156 # a map to access file in various {location -> vfs} | 158 # a map to access file in various {location -> vfs} |
157 vfsmap = vfsmap.copy() | 159 vfsmap = vfsmap.copy() |
158 vfsmap[''] = opener # set default value | 160 vfsmap[b''] = opener # set default value |
159 self._vfsmap = vfsmap | 161 self._vfsmap = vfsmap |
160 self._after = after | 162 self._after = after |
161 self._entries = [] | 163 self._entries = [] |
162 self._map = {} | 164 self._map = {} |
163 self._journal = journalname | 165 self._journal = journalname |
184 # transaction. | 186 # transaction. |
185 self.changes = {} | 187 self.changes = {} |
186 | 188 |
187 # a dict of arguments to be passed to hooks | 189 # a dict of arguments to be passed to hooks |
188 self.hookargs = {} | 190 self.hookargs = {} |
189 self._file = opener.open(self._journal, "w") | 191 self._file = opener.open(self._journal, b"w") |
190 | 192 |
191 # a list of ('location', 'path', 'backuppath', cache) entries. | 193 # a list of ('location', 'path', 'backuppath', cache) entries. |
192 # - if 'backuppath' is empty, no file existed at backup time | 194 # - if 'backuppath' is empty, no file existed at backup time |
193 # - if 'path' is empty, this is a temporary transaction file | 195 # - if 'path' is empty, this is a temporary transaction file |
194 # - if 'location' is not empty, the path is outside main opener reach. | 196 # - if 'location' is not empty, the path is outside main opener reach. |
195 # use 'location' value as a key in a vfsmap to find the right 'vfs' | 197 # use 'location' value as a key in a vfsmap to find the right 'vfs' |
196 # (cache is currently unused) | 198 # (cache is currently unused) |
197 self._backupentries = [] | 199 self._backupentries = [] |
198 self._backupmap = {} | 200 self._backupmap = {} |
199 self._backupjournal = "%s.backupfiles" % self._journal | 201 self._backupjournal = b"%s.backupfiles" % self._journal |
200 self._backupsfile = opener.open(self._backupjournal, 'w') | 202 self._backupsfile = opener.open(self._backupjournal, b'w') |
201 self._backupsfile.write('%d\n' % version) | 203 self._backupsfile.write(b'%d\n' % version) |
202 | 204 |
203 if createmode is not None: | 205 if createmode is not None: |
204 opener.chmod(self._journal, createmode & 0o666) | 206 opener.chmod(self._journal, createmode & 0o666) |
205 opener.chmod(self._backupjournal, createmode & 0o666) | 207 opener.chmod(self._backupjournal, createmode & 0o666) |
206 | 208 |
263 if file in self._map or file in self._backupmap: | 265 if file in self._map or file in self._backupmap: |
264 return | 266 return |
265 self._entries.append((file, offset, data)) | 267 self._entries.append((file, offset, data)) |
266 self._map[file] = len(self._entries) - 1 | 268 self._map[file] = len(self._entries) - 1 |
267 # add enough data to the journal to do the truncate | 269 # add enough data to the journal to do the truncate |
268 self._file.write("%s\0%d\n" % (file, offset)) | 270 self._file.write(b"%s\0%d\n" % (file, offset)) |
269 self._file.flush() | 271 self._file.flush() |
270 | 272 |
271 @active | 273 @active |
272 def addbackup(self, file, hardlink=True, location=''): | 274 def addbackup(self, file, hardlink=True, location=b''): |
273 """Adds a backup of the file to the transaction | 275 """Adds a backup of the file to the transaction |
274 | 276 |
275 Calling addbackup() creates a hardlink backup of the specified file | 277 Calling addbackup() creates a hardlink backup of the specified file |
276 that is used to recover the file in the event of the transaction | 278 that is used to recover the file in the event of the transaction |
277 aborting. | 279 aborting. |
278 | 280 |
279 * `file`: the file path, relative to .hg/store | 281 * `file`: the file path, relative to .hg/store |
280 * `hardlink`: use a hardlink to quickly create the backup | 282 * `hardlink`: use a hardlink to quickly create the backup |
281 """ | 283 """ |
282 if self._queue: | 284 if self._queue: |
283 msg = 'cannot use transaction.addbackup inside "group"' | 285 msg = b'cannot use transaction.addbackup inside "group"' |
284 raise error.ProgrammingError(msg) | 286 raise error.ProgrammingError(msg) |
285 | 287 |
286 if file in self._map or file in self._backupmap: | 288 if file in self._map or file in self._backupmap: |
287 return | 289 return |
288 vfs = self._vfsmap[location] | 290 vfs = self._vfsmap[location] |
289 dirname, filename = vfs.split(file) | 291 dirname, filename = vfs.split(file) |
290 backupfilename = "%s.backup.%s" % (self._journal, filename) | 292 backupfilename = b"%s.backup.%s" % (self._journal, filename) |
291 backupfile = vfs.reljoin(dirname, backupfilename) | 293 backupfile = vfs.reljoin(dirname, backupfilename) |
292 if vfs.exists(file): | 294 if vfs.exists(file): |
293 filepath = vfs.join(file) | 295 filepath = vfs.join(file) |
294 backuppath = vfs.join(backupfile) | 296 backuppath = vfs.join(backupfile) |
295 util.copyfile(filepath, backuppath, hardlink=hardlink) | 297 util.copyfile(filepath, backuppath, hardlink=hardlink) |
296 else: | 298 else: |
297 backupfile = '' | 299 backupfile = b'' |
298 | 300 |
299 self._addbackupentry((location, file, backupfile, False)) | 301 self._addbackupentry((location, file, backupfile, False)) |
300 | 302 |
301 def _addbackupentry(self, entry): | 303 def _addbackupentry(self, entry): |
302 """register a new backup entry and write it to disk""" | 304 """register a new backup entry and write it to disk""" |
303 self._backupentries.append(entry) | 305 self._backupentries.append(entry) |
304 self._backupmap[entry[1]] = len(self._backupentries) - 1 | 306 self._backupmap[entry[1]] = len(self._backupentries) - 1 |
305 self._backupsfile.write("%s\0%s\0%s\0%d\n" % entry) | 307 self._backupsfile.write(b"%s\0%s\0%s\0%d\n" % entry) |
306 self._backupsfile.flush() | 308 self._backupsfile.flush() |
307 | 309 |
308 @active | 310 @active |
309 def registertmp(self, tmpfile, location=''): | 311 def registertmp(self, tmpfile, location=b''): |
310 """register a temporary transaction file | 312 """register a temporary transaction file |
311 | 313 |
312 Such files will be deleted when the transaction exits (on both | 314 Such files will be deleted when the transaction exits (on both |
313 failure and success). | 315 failure and success). |
314 """ | 316 """ |
315 self._addbackupentry((location, '', tmpfile, False)) | 317 self._addbackupentry((location, b'', tmpfile, False)) |
316 | 318 |
317 @active | 319 @active |
318 def addfilegenerator(self, genid, filenames, genfunc, order=0, location=''): | 320 def addfilegenerator( |
321 self, genid, filenames, genfunc, order=0, location=b'' | |
322 ): | |
319 """add a function to generates some files at transaction commit | 323 """add a function to generates some files at transaction commit |
320 | 324 |
321 The `genfunc` argument is a function capable of generating proper | 325 The `genfunc` argument is a function capable of generating proper |
322 content of each entry in the `filename` tuple. | 326 content of each entry in the `filename` tuple. |
323 | 327 |
346 def removefilegenerator(self, genid): | 350 def removefilegenerator(self, genid): |
347 """reverse of addfilegenerator, remove a file generator function""" | 351 """reverse of addfilegenerator, remove a file generator function""" |
348 if genid in self._filegenerators: | 352 if genid in self._filegenerators: |
349 del self._filegenerators[genid] | 353 del self._filegenerators[genid] |
350 | 354 |
351 def _generatefiles(self, suffix='', group=gengroupall): | 355 def _generatefiles(self, suffix=b'', group=gengroupall): |
352 # write files registered for generation | 356 # write files registered for generation |
353 any = False | 357 any = False |
354 for id, entry in sorted(self._filegenerators.iteritems()): | 358 for id, entry in sorted(self._filegenerators.iteritems()): |
355 any = True | 359 any = True |
356 order, filenames, genfunc, location = entry | 360 order, filenames, genfunc, location = entry |
373 checkambig = False | 377 checkambig = False |
374 else: | 378 else: |
375 self.addbackup(name, location=location) | 379 self.addbackup(name, location=location) |
376 checkambig = (name, location) in self._checkambigfiles | 380 checkambig = (name, location) in self._checkambigfiles |
377 files.append( | 381 files.append( |
378 vfs(name, 'w', atomictemp=True, checkambig=checkambig) | 382 vfs(name, b'w', atomictemp=True, checkambig=checkambig) |
379 ) | 383 ) |
380 genfunc(*files) | 384 genfunc(*files) |
381 for f in files: | 385 for f in files: |
382 f.close() | 386 f.close() |
383 # skip discard() loop since we're sure no open file remains | 387 # skip discard() loop since we're sure no open file remains |
404 | 408 |
405 if file not in self._map: | 409 if file not in self._map: |
406 raise KeyError(file) | 410 raise KeyError(file) |
407 index = self._map[file] | 411 index = self._map[file] |
408 self._entries[index] = (file, offset, data) | 412 self._entries[index] = (file, offset, data) |
409 self._file.write("%s\0%d\n" % (file, offset)) | 413 self._file.write(b"%s\0%d\n" % (file, offset)) |
410 self._file.flush() | 414 self._file.flush() |
411 | 415 |
412 @active | 416 @active |
413 def nest(self, name=r'<unnamed>'): | 417 def nest(self, name=r'<unnamed>'): |
414 self._count += 1 | 418 self._count += 1 |
446 categories = sorted(self._pendingcallback) | 450 categories = sorted(self._pendingcallback) |
447 for cat in categories: | 451 for cat in categories: |
448 # remove callback since the data will have been flushed | 452 # remove callback since the data will have been flushed |
449 any = self._pendingcallback.pop(cat)(self) | 453 any = self._pendingcallback.pop(cat)(self) |
450 self._anypending = self._anypending or any | 454 self._anypending = self._anypending or any |
451 self._anypending |= self._generatefiles(suffix='.pending') | 455 self._anypending |= self._generatefiles(suffix=b'.pending') |
452 return self._anypending | 456 return self._anypending |
453 | 457 |
454 @active | 458 @active |
455 def addfinalize(self, category, callback): | 459 def addfinalize(self, category, callback): |
456 """add a callback to be called when the transaction is closed | 460 """add a callback to be called when the transaction is closed |
510 self._backupsfile.close() | 514 self._backupsfile.close() |
511 # cleanup temporary files | 515 # cleanup temporary files |
512 for l, f, b, c in self._backupentries: | 516 for l, f, b, c in self._backupentries: |
513 if l not in self._vfsmap and c: | 517 if l not in self._vfsmap and c: |
514 self._report( | 518 self._report( |
515 "couldn't remove %s: unknown cache location %s\n" % (b, l) | 519 b"couldn't remove %s: unknown cache location %s\n" % (b, l) |
516 ) | 520 ) |
517 continue | 521 continue |
518 vfs = self._vfsmap[l] | 522 vfs = self._vfsmap[l] |
519 if not f and b and vfs.exists(b): | 523 if not f and b and vfs.exists(b): |
520 try: | 524 try: |
522 except (IOError, OSError, error.Abort) as inst: | 526 except (IOError, OSError, error.Abort) as inst: |
523 if not c: | 527 if not c: |
524 raise | 528 raise |
525 # Abort may be raise by read only opener | 529 # Abort may be raise by read only opener |
526 self._report( | 530 self._report( |
527 "couldn't remove %s: %s\n" % (vfs.join(b), inst) | 531 b"couldn't remove %s: %s\n" % (vfs.join(b), inst) |
528 ) | 532 ) |
529 self._entries = [] | 533 self._entries = [] |
530 self._writeundo() | 534 self._writeundo() |
531 if self._after: | 535 if self._after: |
532 self._after() | 536 self._after() |
536 if self._opener.isfile(self._journal): | 540 if self._opener.isfile(self._journal): |
537 self._opener.unlink(self._journal) | 541 self._opener.unlink(self._journal) |
538 for l, _f, b, c in self._backupentries: | 542 for l, _f, b, c in self._backupentries: |
539 if l not in self._vfsmap and c: | 543 if l not in self._vfsmap and c: |
540 self._report( | 544 self._report( |
541 "couldn't remove %s: unknown cache location" "%s\n" % (b, l) | 545 b"couldn't remove %s: unknown cache location" |
546 b"%s\n" % (b, l) | |
542 ) | 547 ) |
543 continue | 548 continue |
544 vfs = self._vfsmap[l] | 549 vfs = self._vfsmap[l] |
545 if b and vfs.exists(b): | 550 if b and vfs.exists(b): |
546 try: | 551 try: |
548 except (IOError, OSError, error.Abort) as inst: | 553 except (IOError, OSError, error.Abort) as inst: |
549 if not c: | 554 if not c: |
550 raise | 555 raise |
551 # Abort may be raise by read only opener | 556 # Abort may be raise by read only opener |
552 self._report( | 557 self._report( |
553 "couldn't remove %s: %s\n" % (vfs.join(b), inst) | 558 b"couldn't remove %s: %s\n" % (vfs.join(b), inst) |
554 ) | 559 ) |
555 self._backupentries = [] | 560 self._backupentries = [] |
556 self._journal = None | 561 self._journal = None |
557 | 562 |
558 self._releasefn(self, True) # notify success of closing transaction | 563 self._releasefn(self, True) # notify success of closing transaction |
575 def _writeundo(self): | 580 def _writeundo(self): |
576 """write transaction data for possible future undo call""" | 581 """write transaction data for possible future undo call""" |
577 if self._undoname is None: | 582 if self._undoname is None: |
578 return | 583 return |
579 undobackupfile = self._opener.open( | 584 undobackupfile = self._opener.open( |
580 "%s.backupfiles" % self._undoname, 'w' | 585 b"%s.backupfiles" % self._undoname, b'w' |
581 ) | 586 ) |
582 undobackupfile.write('%d\n' % version) | 587 undobackupfile.write(b'%d\n' % version) |
583 for l, f, b, c in self._backupentries: | 588 for l, f, b, c in self._backupentries: |
584 if not f: # temporary file | 589 if not f: # temporary file |
585 continue | 590 continue |
586 if not b: | 591 if not b: |
587 u = '' | 592 u = b'' |
588 else: | 593 else: |
589 if l not in self._vfsmap and c: | 594 if l not in self._vfsmap and c: |
590 self._report( | 595 self._report( |
591 "couldn't remove %s: unknown cache location" | 596 b"couldn't remove %s: unknown cache location" |
592 "%s\n" % (b, l) | 597 b"%s\n" % (b, l) |
593 ) | 598 ) |
594 continue | 599 continue |
595 vfs = self._vfsmap[l] | 600 vfs = self._vfsmap[l] |
596 base, name = vfs.split(b) | 601 base, name = vfs.split(b) |
597 assert name.startswith(self._journal), name | 602 assert name.startswith(self._journal), name |
598 uname = name.replace(self._journal, self._undoname, 1) | 603 uname = name.replace(self._journal, self._undoname, 1) |
599 u = vfs.reljoin(base, uname) | 604 u = vfs.reljoin(base, uname) |
600 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True) | 605 util.copyfile(vfs.join(b), vfs.join(u), hardlink=True) |
601 undobackupfile.write("%s\0%s\0%s\0%d\n" % (l, f, u, c)) | 606 undobackupfile.write(b"%s\0%s\0%s\0%d\n" % (l, f, u, c)) |
602 undobackupfile.close() | 607 undobackupfile.close() |
603 | 608 |
604 def _abort(self): | 609 def _abort(self): |
605 self._count = 0 | 610 self._count = 0 |
606 self._usages = 0 | 611 self._usages = 0 |
613 self._opener.unlink(self._backupjournal) | 618 self._opener.unlink(self._backupjournal) |
614 if self._journal: | 619 if self._journal: |
615 self._opener.unlink(self._journal) | 620 self._opener.unlink(self._journal) |
616 return | 621 return |
617 | 622 |
618 self._report(_("transaction abort!\n")) | 623 self._report(_(b"transaction abort!\n")) |
619 | 624 |
620 try: | 625 try: |
621 for cat in sorted(self._abortcallback): | 626 for cat in sorted(self._abortcallback): |
622 self._abortcallback[cat](self) | 627 self._abortcallback[cat](self) |
623 # Prevent double usage and help clear cycles. | 628 # Prevent double usage and help clear cycles. |
630 self._entries, | 635 self._entries, |
631 self._backupentries, | 636 self._backupentries, |
632 False, | 637 False, |
633 checkambigfiles=self._checkambigfiles, | 638 checkambigfiles=self._checkambigfiles, |
634 ) | 639 ) |
635 self._report(_("rollback completed\n")) | 640 self._report(_(b"rollback completed\n")) |
636 except BaseException as exc: | 641 except BaseException as exc: |
637 self._report(_("rollback failed - please run hg recover\n")) | 642 self._report(_(b"rollback failed - please run hg recover\n")) |
638 self._report( | 643 self._report( |
639 _("(failure reason: %s)\n") % stringutil.forcebytestr(exc) | 644 _(b"(failure reason: %s)\n") % stringutil.forcebytestr(exc) |
640 ) | 645 ) |
641 finally: | 646 finally: |
642 self._journal = None | 647 self._journal = None |
643 self._releasefn(self, False) # notify failure of transaction | 648 self._releasefn(self, False) # notify failure of transaction |
644 self._releasefn = None # Help prevent cycles. | 649 self._releasefn = None # Help prevent cycles. |
666 fp = opener.open(file) | 671 fp = opener.open(file) |
667 lines = fp.readlines() | 672 lines = fp.readlines() |
668 fp.close() | 673 fp.close() |
669 for l in lines: | 674 for l in lines: |
670 try: | 675 try: |
671 f, o = l.split('\0') | 676 f, o = l.split(b'\0') |
672 entries.append((f, int(o), None)) | 677 entries.append((f, int(o), None)) |
673 except ValueError: | 678 except ValueError: |
674 report(_("couldn't read journal entry %r!\n") % pycompat.bytestr(l)) | 679 report( |
675 | 680 _(b"couldn't read journal entry %r!\n") % pycompat.bytestr(l) |
676 backupjournal = "%s.backupfiles" % file | 681 ) |
682 | |
683 backupjournal = b"%s.backupfiles" % file | |
677 if opener.exists(backupjournal): | 684 if opener.exists(backupjournal): |
678 fp = opener.open(backupjournal) | 685 fp = opener.open(backupjournal) |
679 lines = fp.readlines() | 686 lines = fp.readlines() |
680 if lines: | 687 if lines: |
681 ver = lines[0][:-1] | 688 ver = lines[0][:-1] |
682 if ver == (b'%d' % version): | 689 if ver == (b'%d' % version): |
683 for line in lines[1:]: | 690 for line in lines[1:]: |
684 if line: | 691 if line: |
685 # Shave off the trailing newline | 692 # Shave off the trailing newline |
686 line = line[:-1] | 693 line = line[:-1] |
687 l, f, b, c = line.split('\0') | 694 l, f, b, c = line.split(b'\0') |
688 backupentries.append((l, f, b, bool(c))) | 695 backupentries.append((l, f, b, bool(c))) |
689 else: | 696 else: |
690 report( | 697 report( |
691 _( | 698 _( |
692 "journal was created by a different version of " | 699 b"journal was created by a different version of " |
693 "Mercurial\n" | 700 b"Mercurial\n" |
694 ) | 701 ) |
695 ) | 702 ) |
696 | 703 |
697 _playback( | 704 _playback( |
698 file, | 705 file, |