Show More
The requested changes are too big and content was truncated. Show full diff
@@ -59,7 +59,7 b' from mercurial.utils import stringutil' | |||
|
59 | 59 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
60 | 60 | # be specifying the version(s) of Mercurial they are tested with, or |
|
61 | 61 | # leave the attribute unspecified. |
|
62 | testedwith = 'ships-with-hg-core' | |
|
62 | testedwith = b'ships-with-hg-core' | |
|
63 | 63 | |
|
64 | 64 | cmdtable = {} |
|
65 | 65 | command = registrar.command(cmdtable) |
@@ -67,14 +67,14 b' command = registrar.command(cmdtable)' | |||
|
67 | 67 | configtable = {} |
|
68 | 68 | configitem = registrar.configitem(configtable) |
|
69 | 69 | |
|
70 | configitem('absorb', 'add-noise', default=True) | |
|
71 | configitem('absorb', 'amend-flag', default=None) | |
|
72 | configitem('absorb', 'max-stack-size', default=50) | |
|
70 | configitem(b'absorb', b'add-noise', default=True) | |
|
71 | configitem(b'absorb', b'amend-flag', default=None) | |
|
72 | configitem(b'absorb', b'max-stack-size', default=50) | |
|
73 | 73 | |
|
74 | 74 | colortable = { |
|
75 | 'absorb.description': 'yellow', | |
|
76 | 'absorb.node': 'blue bold', | |
|
77 | 'absorb.path': 'bold', | |
|
75 | b'absorb.description': b'yellow', | |
|
76 | b'absorb.node': b'blue bold', | |
|
77 | b'absorb.path': b'bold', | |
|
78 | 78 | } |
|
79 | 79 | |
|
80 | 80 | defaultdict = collections.defaultdict |
@@ -98,7 +98,7 b' class emptyfilecontext(object):' | |||
|
98 | 98 | """minimal filecontext representing an empty file""" |
|
99 | 99 | |
|
100 | 100 | def data(self): |
|
101 | return '' | |
|
101 | return b'' | |
|
102 | 102 | |
|
103 | 103 | def node(self): |
|
104 | 104 | return node.nullid |
@@ -364,11 +364,11 b' class filefixupstate(object):' | |||
|
364 | 364 | if self.ui.debugflag: |
|
365 | 365 | idx = (max(rev - 1, 0)) // 2 |
|
366 | 366 | self.ui.write( |
|
367 | _('%s: chunk %d:%d -> %d lines\n') | |
|
367 | _(b'%s: chunk %d:%d -> %d lines\n') | |
|
368 | 368 | % (node.short(self.fctxs[idx].node()), a1, a2, len(blines)) |
|
369 | 369 | ) |
|
370 | 370 | self.linelog.replacelines(rev, a1, a2, b1, b2) |
|
371 | if self.opts.get('edit_lines', False): | |
|
371 | if self.opts.get(b'edit_lines', False): | |
|
372 | 372 | self.finalcontents = self._checkoutlinelogwithedits() |
|
373 | 373 | else: |
|
374 | 374 | self.finalcontents = self._checkoutlinelog() |
@@ -434,7 +434,7 b' class filefixupstate(object):' | |||
|
434 | 434 | """like mdiff.allblocks, but only care about differences""" |
|
435 | 435 | blocks = mdiff.allblocks(a, b, lines1=alines, lines2=blines) |
|
436 | 436 | for chunk, btype in blocks: |
|
437 | if btype != '!': | |
|
437 | if btype != b'!': | |
|
438 | 438 | continue |
|
439 | 439 | yield chunk |
|
440 | 440 | |
@@ -443,7 +443,7 b' class filefixupstate(object):' | |||
|
443 | 443 | this is similar to running a partial "annotate". |
|
444 | 444 | """ |
|
445 | 445 | llog = linelog.linelog() |
|
446 | a, alines = '', [] | |
|
446 | a, alines = b'', [] | |
|
447 | 447 | for i in pycompat.xrange(len(self.contents)): |
|
448 | 448 | b, blines = self.contents[i], self.contentlines[i] |
|
449 | 449 | llrev = i * 2 + 1 |
@@ -459,7 +459,7 b' class filefixupstate(object):' | |||
|
459 | 459 | for i in pycompat.xrange(len(self.contents)): |
|
460 | 460 | rev = (i + 1) * 2 |
|
461 | 461 | self.linelog.annotate(rev) |
|
462 | content = ''.join(map(self._getline, self.linelog.annotateresult)) | |
|
462 | content = b''.join(map(self._getline, self.linelog.annotateresult)) | |
|
463 | 463 | contents.append(content) |
|
464 | 464 | return contents |
|
465 | 465 | |
@@ -469,8 +469,8 b' class filefixupstate(object):' | |||
|
469 | 469 | # header |
|
470 | 470 | editortext = ( |
|
471 | 471 | _( |
|
472 | 'HG: editing %s\nHG: "y" means the line to the right ' | |
|
473 | 'exists in the changeset to the top\nHG:\n' | |
|
472 | b'HG: editing %s\nHG: "y" means the line to the right ' | |
|
473 | b'exists in the changeset to the top\nHG:\n' | |
|
474 | 474 | ) |
|
475 | 475 | % self.fctxs[-1].path() |
|
476 | 476 | ) |
@@ -481,13 +481,13 b' class filefixupstate(object):' | |||
|
481 | 481 | if not isinstance(f, emptyfilecontext) |
|
482 | 482 | ] |
|
483 | 483 | for i, (j, f) in enumerate(visiblefctxs): |
|
484 | editortext += _('HG: %s/%s %s %s\n') % ( | |
|
485 | '|' * i, | |
|
486 | '-' * (len(visiblefctxs) - i + 1), | |
|
484 | editortext += _(b'HG: %s/%s %s %s\n') % ( | |
|
485 | b'|' * i, | |
|
486 | b'-' * (len(visiblefctxs) - i + 1), | |
|
487 | 487 | node.short(f.node()), |
|
488 | f.description().split('\n', 1)[0], | |
|
488 | f.description().split(b'\n', 1)[0], | |
|
489 | 489 | ) |
|
490 | editortext += _('HG: %s\n') % ('|' * len(visiblefctxs)) | |
|
490 | editortext += _(b'HG: %s\n') % (b'|' * len(visiblefctxs)) | |
|
491 | 491 | # figure out the lifetime of a line, this is relatively inefficient, |
|
492 | 492 | # but probably fine |
|
493 | 493 | lineset = defaultdict(lambda: set()) # {(llrev, linenum): {llrev}} |
@@ -497,33 +497,33 b' class filefixupstate(object):' | |||
|
497 | 497 | lineset[l].add(i) |
|
498 | 498 | # append lines |
|
499 | 499 | for l in alllines: |
|
500 | editortext += ' %s : %s' % ( | |
|
501 | ''.join( | |
|
500 | editortext += b' %s : %s' % ( | |
|
501 | b''.join( | |
|
502 | 502 | [ |
|
503 | ('y' if i in lineset[l] else ' ') | |
|
503 | (b'y' if i in lineset[l] else b' ') | |
|
504 | 504 | for i, _f in visiblefctxs |
|
505 | 505 | ] |
|
506 | 506 | ), |
|
507 | 507 | self._getline(l), |
|
508 | 508 | ) |
|
509 | 509 | # run editor |
|
510 | editedtext = self.ui.edit(editortext, '', action='absorb') | |
|
510 | editedtext = self.ui.edit(editortext, b'', action=b'absorb') | |
|
511 | 511 | if not editedtext: |
|
512 | raise error.Abort(_('empty editor text')) | |
|
512 | raise error.Abort(_(b'empty editor text')) | |
|
513 | 513 | # parse edited result |
|
514 | contents = ['' for i in self.fctxs] | |
|
514 | contents = [b'' for i in self.fctxs] | |
|
515 | 515 | leftpadpos = 4 |
|
516 | 516 | colonpos = leftpadpos + len(visiblefctxs) + 1 |
|
517 | 517 | for l in mdiff.splitnewlines(editedtext): |
|
518 | if l.startswith('HG:'): | |
|
518 | if l.startswith(b'HG:'): | |
|
519 | 519 | continue |
|
520 | if l[colonpos - 1 : colonpos + 2] != ' : ': | |
|
521 | raise error.Abort(_('malformed line: %s') % l) | |
|
520 | if l[colonpos - 1 : colonpos + 2] != b' : ': | |
|
521 | raise error.Abort(_(b'malformed line: %s') % l) | |
|
522 | 522 | linecontent = l[colonpos + 2 :] |
|
523 | 523 | for i, ch in enumerate( |
|
524 | 524 | pycompat.bytestr(l[leftpadpos : colonpos - 1]) |
|
525 | 525 | ): |
|
526 | if ch == 'y': | |
|
526 | if ch == b'y': | |
|
527 | 527 | contents[visiblefctxs[i][0]] += linecontent |
|
528 | 528 | # chunkstats is hard to calculate if anything changes, therefore |
|
529 | 529 | # set them to just a simple value (1, 1). |
@@ -589,7 +589,7 b' class filefixupstate(object):' | |||
|
589 | 589 | |
|
590 | 590 | def _showchanges(self, fm, alines, blines, chunk, fixups): |
|
591 | 591 | def trim(line): |
|
592 | if line.endswith('\n'): | |
|
592 | if line.endswith(b'\n'): | |
|
593 | 593 | line = line[:-1] |
|
594 | 594 | return line |
|
595 | 595 | |
@@ -605,25 +605,25 b' class filefixupstate(object):' | |||
|
605 | 605 | |
|
606 | 606 | fm.startitem() |
|
607 | 607 | fm.write( |
|
608 | 'hunk', | |
|
609 | ' %s\n', | |
|
610 | '@@ -%d,%d +%d,%d @@' % (a1, a2 - a1, b1, b2 - b1), | |
|
611 | label='diff.hunk', | |
|
608 | b'hunk', | |
|
609 | b' %s\n', | |
|
610 | b'@@ -%d,%d +%d,%d @@' % (a1, a2 - a1, b1, b2 - b1), | |
|
611 | label=b'diff.hunk', | |
|
612 | 612 | ) |
|
613 | fm.data(path=self.path, linetype='hunk') | |
|
613 | fm.data(path=self.path, linetype=b'hunk') | |
|
614 | 614 | |
|
615 | 615 | def writeline(idx, diffchar, line, linetype, linelabel): |
|
616 | 616 | fm.startitem() |
|
617 | node = '' | |
|
617 | node = b'' | |
|
618 | 618 | if idx: |
|
619 | 619 | ctx = self.fctxs[idx] |
|
620 | 620 | fm.context(fctx=ctx) |
|
621 | 621 | node = ctx.hex() |
|
622 | 622 | self.ctxaffected.add(ctx.changectx()) |
|
623 | fm.write('node', '%-7.7s ', node, label='absorb.node') | |
|
623 | fm.write(b'node', b'%-7.7s ', node, label=b'absorb.node') | |
|
624 | 624 | fm.write( |
|
625 | 'diffchar ' + linetype, | |
|
626 | '%s%s\n', | |
|
625 | b'diffchar ' + linetype, | |
|
626 | b'%s%s\n', | |
|
627 | 627 | diffchar, |
|
628 | 628 | line, |
|
629 | 629 | label=linelabel, |
@@ -632,11 +632,19 b' class filefixupstate(object):' | |||
|
632 | 632 | |
|
633 | 633 | for i in pycompat.xrange(a1, a2): |
|
634 | 634 | writeline( |
|
635 | aidxs[i - a1], '-', trim(alines[i]), 'deleted', 'diff.deleted' | |
|
635 | aidxs[i - a1], | |
|
636 | b'-', | |
|
637 | trim(alines[i]), | |
|
638 | b'deleted', | |
|
639 | b'diff.deleted', | |
|
636 | 640 | ) |
|
637 | 641 | for i in pycompat.xrange(b1, b2): |
|
638 | 642 | writeline( |
|
639 | bidxs[i - b1], '+', trim(blines[i]), 'inserted', 'diff.inserted' | |
|
643 | bidxs[i - b1], | |
|
644 | b'+', | |
|
645 | trim(blines[i]), | |
|
646 | b'inserted', | |
|
647 | b'diff.inserted', | |
|
640 | 648 | ) |
|
641 | 649 | |
|
642 | 650 | |
@@ -681,7 +689,7 b' class fixupstate(object):' | |||
|
681 | 689 | self.paths = [] |
|
682 | 690 | # but if --edit-lines is used, the user may want to edit files |
|
683 | 691 | # even if they are not modified |
|
684 | editopt = self.opts.get('edit_lines') | |
|
692 | editopt = self.opts.get(b'edit_lines') | |
|
685 | 693 | if not self.status.modified and editopt and match: |
|
686 | 694 | interestingpaths = match.files() |
|
687 | 695 | else: |
@@ -691,7 +699,7 b' class fixupstate(object):' | |||
|
691 | 699 | # sorting is necessary to eliminate ambiguity for the "double move" |
|
692 | 700 | # case: "hg cp A B; hg cp A C; hg rm A", then only "B" can affect "A". |
|
693 | 701 | for path in sorted(interestingpaths): |
|
694 | self.ui.debug('calculating fixups for %s\n' % path) | |
|
702 | self.ui.debug(b'calculating fixups for %s\n' % path) | |
|
695 | 703 | targetfctx = targetctx[path] |
|
696 | 704 | fctxs, ctx2fctx = getfilestack(self.stack, path, seenfctxs) |
|
697 | 705 | # ignore symbolic links or binary, or unchanged files |
@@ -708,9 +716,9 b' class fixupstate(object):' | |||
|
708 | 716 | fstate = filefixupstate(fctxs, path, ui=self.ui, opts=self.opts) |
|
709 | 717 | if fm is not None: |
|
710 | 718 | fm.startitem() |
|
711 | fm.plain('showing changes for ') | |
|
712 | fm.write('path', '%s\n', path, label='absorb.path') | |
|
713 | fm.data(linetype='path') | |
|
719 | fm.plain(b'showing changes for ') | |
|
720 | fm.write(b'path', b'%s\n', path, label=b'absorb.path') | |
|
721 | fm.data(linetype=b'path') | |
|
714 | 722 | fstate.diffwith(targetfctx, fm) |
|
715 | 723 | self.fixupmap[path] = fstate |
|
716 | 724 | self.paths.append(path) |
@@ -720,7 +728,7 b' class fixupstate(object):' | |||
|
720 | 728 | """apply fixups to individual filefixupstates""" |
|
721 | 729 | for path, state in self.fixupmap.iteritems(): |
|
722 | 730 | if self.ui.debugflag: |
|
723 | self.ui.write(_('applying fixups to %s\n') % path) | |
|
731 | self.ui.write(_(b'applying fixups to %s\n') % path) | |
|
724 | 732 | state.apply() |
|
725 | 733 | |
|
726 | 734 | @property |
@@ -733,10 +741,10 b' class fixupstate(object):' | |||
|
733 | 741 | |
|
734 | 742 | def commit(self): |
|
735 | 743 | """commit changes. update self.finalnode, self.replacemap""" |
|
736 | with self.repo.transaction('absorb') as tr: | |
|
744 | with self.repo.transaction(b'absorb') as tr: | |
|
737 | 745 | self._commitstack() |
|
738 | 746 | self._movebookmarks(tr) |
|
739 | if self.repo['.'].node() in self.replacemap: | |
|
747 | if self.repo[b'.'].node() in self.replacemap: | |
|
740 | 748 | self._moveworkingdirectoryparent() |
|
741 | 749 | self._cleanupoldcommits() |
|
742 | 750 | return self.finalnode |
@@ -750,14 +758,14 b' class fixupstate(object):' | |||
|
750 | 758 | for path, stat in chunkstats.iteritems(): |
|
751 | 759 | if stat[0]: |
|
752 | 760 | ui.write( |
|
753 | _('%s: %d of %d chunk(s) applied\n') | |
|
761 | _(b'%s: %d of %d chunk(s) applied\n') | |
|
754 | 762 | % (path, stat[0], stat[1]) |
|
755 | 763 | ) |
|
756 | 764 | elif not ui.quiet: |
|
757 | 765 | # a summary for all files |
|
758 | 766 | stats = chunkstats.values() |
|
759 | 767 | applied, total = (sum(s[i] for s in stats) for i in (0, 1)) |
|
760 | ui.write(_('%d of %d chunk(s) applied\n') % (applied, total)) | |
|
768 | ui.write(_(b'%d of %d chunk(s) applied\n') % (applied, total)) | |
|
761 | 769 | |
|
762 | 770 | def _commitstack(self): |
|
763 | 771 | """make new commits. update self.finalnode, self.replacemap. |
@@ -777,7 +785,7 b' class fixupstate(object):' | |||
|
777 | 785 | if self._willbecomenoop(memworkingcopy, ctx, nextp1): |
|
778 | 786 | # changeset is no longer necessary |
|
779 | 787 | self.replacemap[ctx.node()] = None |
|
780 | msg = _('became empty and was dropped') | |
|
788 | msg = _(b'became empty and was dropped') | |
|
781 | 789 | else: |
|
782 | 790 | # changeset needs re-commit |
|
783 | 791 | nodestr = self._commitsingle(memworkingcopy, ctx, p1=nextp1) |
@@ -785,21 +793,21 b' class fixupstate(object):' | |||
|
785 | 793 | nextp1 = lastcommitted |
|
786 | 794 | self.replacemap[ctx.node()] = lastcommitted.node() |
|
787 | 795 | if memworkingcopy: |
|
788 | msg = _('%d file(s) changed, became %s') % ( | |
|
796 | msg = _(b'%d file(s) changed, became %s') % ( | |
|
789 | 797 | len(memworkingcopy), |
|
790 | 798 | self._ctx2str(lastcommitted), |
|
791 | 799 | ) |
|
792 | 800 | else: |
|
793 | msg = _('became %s') % self._ctx2str(lastcommitted) | |
|
801 | msg = _(b'became %s') % self._ctx2str(lastcommitted) | |
|
794 | 802 | if self.ui.verbose and msg: |
|
795 | self.ui.write(_('%s: %s\n') % (self._ctx2str(ctx), msg)) | |
|
803 | self.ui.write(_(b'%s: %s\n') % (self._ctx2str(ctx), msg)) | |
|
796 | 804 | self.finalnode = lastcommitted and lastcommitted.node() |
|
797 | 805 | |
|
798 | 806 | def _ctx2str(self, ctx): |
|
799 | 807 | if self.ui.debugflag: |
|
800 | return '%d:%s' % (ctx.rev(), ctx.hex()) | |
|
808 | return b'%d:%s' % (ctx.rev(), ctx.hex()) | |
|
801 | 809 | else: |
|
802 | return '%d:%s' % (ctx.rev(), node.short(ctx.node())) | |
|
810 | return b'%d:%s' % (ctx.rev(), node.short(ctx.node())) | |
|
803 | 811 | |
|
804 | 812 | def _getnewfilecontents(self, ctx): |
|
805 | 813 | """(ctx) -> {path: str} |
@@ -832,18 +840,18 b' class fixupstate(object):' | |||
|
832 | 840 | changes.append((name, hsh)) |
|
833 | 841 | if self.ui.verbose: |
|
834 | 842 | self.ui.write( |
|
835 | _('moving bookmark %s to %s\n') % (name, node.hex(hsh)) | |
|
843 | _(b'moving bookmark %s to %s\n') % (name, node.hex(hsh)) | |
|
836 | 844 | ) |
|
837 | 845 | else: |
|
838 | 846 | changes.append((name, None)) |
|
839 | 847 | if self.ui.verbose: |
|
840 | self.ui.write(_('deleting bookmark %s\n') % name) | |
|
848 | self.ui.write(_(b'deleting bookmark %s\n') % name) | |
|
841 | 849 | repo._bookmarks.applychanges(repo, tr, changes) |
|
842 | 850 | |
|
843 | 851 | def _moveworkingdirectoryparent(self): |
|
844 | 852 | if not self.finalnode: |
|
845 | 853 | # Find the latest not-{obsoleted,stripped} parent. |
|
846 | revs = self.repo.revs('max(::. - %ln)', self.replacemap.keys()) | |
|
854 | revs = self.repo.revs(b'max(::. - %ln)', self.replacemap.keys()) | |
|
847 | 855 | ctx = self.repo[revs.first()] |
|
848 | 856 | self.finalnode = ctx.node() |
|
849 | 857 | else: |
@@ -854,7 +862,7 b' class fixupstate(object):' | |||
|
854 | 862 | # be slow. in absorb's case, no need to invalidate fsmonitorstate. |
|
855 | 863 | noop = lambda: 0 |
|
856 | 864 | restore = noop |
|
857 | if util.safehasattr(dirstate, '_fsmonitorstate'): | |
|
865 | if util.safehasattr(dirstate, b'_fsmonitorstate'): | |
|
858 | 866 | bak = dirstate._fsmonitorstate.invalidate |
|
859 | 867 | |
|
860 | 868 | def restore(): |
@@ -901,8 +909,8 b' class fixupstate(object):' | |||
|
901 | 909 | """ |
|
902 | 910 | parents = p1 and (p1, node.nullid) |
|
903 | 911 | extra = ctx.extra() |
|
904 | if self._useobsolete and self.ui.configbool('absorb', 'add-noise'): | |
|
905 | extra['absorb_source'] = ctx.hex() | |
|
912 | if self._useobsolete and self.ui.configbool(b'absorb', b'add-noise'): | |
|
913 | extra[b'absorb_source'] = ctx.hex() | |
|
906 | 914 | mctx = overlaycontext(memworkingcopy, ctx, parents, extra=extra) |
|
907 | 915 | return mctx.commit() |
|
908 | 916 | |
@@ -918,7 +926,7 b' class fixupstate(object):' | |||
|
918 | 926 | } |
|
919 | 927 | if replacements: |
|
920 | 928 | scmutil.cleanupnodes( |
|
921 | self.repo, replacements, operation='absorb', fixphase=True | |
|
929 | self.repo, replacements, operation=b'absorb', fixphase=True | |
|
922 | 930 | ) |
|
923 | 931 | |
|
924 | 932 | |
@@ -935,7 +943,7 b' def _parsechunk(hunk):' | |||
|
935 | 943 | patchlines = mdiff.splitnewlines(buf.getvalue()) |
|
936 | 944 | # hunk.prettystr() will update hunk.removed |
|
937 | 945 | a2 = a1 + hunk.removed |
|
938 | blines = [l[1:] for l in patchlines[1:] if not l.startswith('-')] | |
|
946 | blines = [l[1:] for l in patchlines[1:] if not l.startswith(b'-')] | |
|
939 | 947 | return path, (a1, a2, blines) |
|
940 | 948 | |
|
941 | 949 | |
@@ -967,7 +975,7 b' def overlaydiffcontext(ctx, chunks):' | |||
|
967 | 975 | lines = mdiff.splitnewlines(ctx[path].data()) |
|
968 | 976 | for a1, a2, blines in patches: |
|
969 | 977 | lines[a1:a2] = blines |
|
970 | memworkingcopy[path] = ''.join(lines) | |
|
978 | memworkingcopy[path] = b''.join(lines) | |
|
971 | 979 | return overlaycontext(memworkingcopy, ctx) |
|
972 | 980 | |
|
973 | 981 | |
@@ -979,18 +987,21 b' def absorb(ui, repo, stack=None, targetc' | |||
|
979 | 987 | return fixupstate. |
|
980 | 988 | """ |
|
981 | 989 | if stack is None: |
|
982 | limit = ui.configint('absorb', 'max-stack-size') | |
|
983 | headctx = repo['.'] | |
|
990 | limit = ui.configint(b'absorb', b'max-stack-size') | |
|
991 | headctx = repo[b'.'] | |
|
984 | 992 | if len(headctx.parents()) > 1: |
|
985 | raise error.Abort(_('cannot absorb into a merge')) | |
|
993 | raise error.Abort(_(b'cannot absorb into a merge')) | |
|
986 | 994 | stack = getdraftstack(headctx, limit) |
|
987 | 995 | if limit and len(stack) >= limit: |
|
988 | 996 | ui.warn( |
|
989 | _('absorb: only the recent %d changesets will ' 'be analysed\n') | |
|
997 | _( | |
|
998 | b'absorb: only the recent %d changesets will ' | |
|
999 | b'be analysed\n' | |
|
1000 | ) | |
|
990 | 1001 | % limit |
|
991 | 1002 | ) |
|
992 | 1003 | if not stack: |
|
993 | raise error.Abort(_('no mutable changeset to change')) | |
|
1004 | raise error.Abort(_(b'no mutable changeset to change')) | |
|
994 | 1005 | if targetctx is None: # default to working copy |
|
995 | 1006 | targetctx = repo[None] |
|
996 | 1007 | if pats is None: |
@@ -999,85 +1010,89 b' def absorb(ui, repo, stack=None, targetc' | |||
|
999 | 1010 | opts = {} |
|
1000 | 1011 | state = fixupstate(stack, ui=ui, opts=opts) |
|
1001 | 1012 | matcher = scmutil.match(targetctx, pats, opts) |
|
1002 | if opts.get('interactive'): | |
|
1013 | if opts.get(b'interactive'): | |
|
1003 | 1014 | diff = patch.diff(repo, stack[-1].node(), targetctx.node(), matcher) |
|
1004 | 1015 | origchunks = patch.parsepatch(diff) |
|
1005 | 1016 | chunks = cmdutil.recordfilter(ui, origchunks, matcher)[0] |
|
1006 | 1017 | targetctx = overlaydiffcontext(stack[-1], chunks) |
|
1007 | 1018 | fm = None |
|
1008 | if opts.get('print_changes') or not opts.get('apply_changes'): | |
|
1009 | fm = ui.formatter('absorb', opts) | |
|
1019 | if opts.get(b'print_changes') or not opts.get(b'apply_changes'): | |
|
1020 | fm = ui.formatter(b'absorb', opts) | |
|
1010 | 1021 | state.diffwith(targetctx, matcher, fm) |
|
1011 | 1022 | if fm is not None: |
|
1012 | 1023 | fm.startitem() |
|
1013 | fm.write("count", "\n%d changesets affected\n", len(state.ctxaffected)) | |
|
1014 | fm.data(linetype='summary') | |
|
1024 | fm.write( | |
|
1025 | b"count", b"\n%d changesets affected\n", len(state.ctxaffected) | |
|
1026 | ) | |
|
1027 | fm.data(linetype=b'summary') | |
|
1015 | 1028 | for ctx in reversed(stack): |
|
1016 | 1029 | if ctx not in state.ctxaffected: |
|
1017 | 1030 | continue |
|
1018 | 1031 | fm.startitem() |
|
1019 | 1032 | fm.context(ctx=ctx) |
|
1020 | fm.data(linetype='changeset') | |
|
1021 | fm.write('node', '%-7.7s ', ctx.hex(), label='absorb.node') | |
|
1033 | fm.data(linetype=b'changeset') | |
|
1034 | fm.write(b'node', b'%-7.7s ', ctx.hex(), label=b'absorb.node') | |
|
1022 | 1035 | descfirstline = ctx.description().splitlines()[0] |
|
1023 | 1036 | fm.write( |
|
1024 | 'descfirstline', | |
|
1025 | '%s\n', | |
|
1037 | b'descfirstline', | |
|
1038 | b'%s\n', | |
|
1026 | 1039 | descfirstline, |
|
1027 | label='absorb.description', | |
|
1040 | label=b'absorb.description', | |
|
1028 | 1041 | ) |
|
1029 | 1042 | fm.end() |
|
1030 | if not opts.get('dry_run'): | |
|
1043 | if not opts.get(b'dry_run'): | |
|
1031 | 1044 | if ( |
|
1032 | not opts.get('apply_changes') | |
|
1045 | not opts.get(b'apply_changes') | |
|
1033 | 1046 | and state.ctxaffected |
|
1034 | and ui.promptchoice("apply changes (yn)? $$ &Yes $$ &No", default=1) | |
|
1047 | and ui.promptchoice( | |
|
1048 | b"apply changes (yn)? $$ &Yes $$ &No", default=1 | |
|
1049 | ) | |
|
1035 | 1050 | ): |
|
1036 | raise error.Abort(_('absorb cancelled\n')) | |
|
1051 | raise error.Abort(_(b'absorb cancelled\n')) | |
|
1037 | 1052 | |
|
1038 | 1053 | state.apply() |
|
1039 | 1054 | if state.commit(): |
|
1040 | 1055 | state.printchunkstats() |
|
1041 | 1056 | elif not ui.quiet: |
|
1042 | ui.write(_('nothing applied\n')) | |
|
1057 | ui.write(_(b'nothing applied\n')) | |
|
1043 | 1058 | return state |
|
1044 | 1059 | |
|
1045 | 1060 | |
|
1046 | 1061 | @command( |
|
1047 | 'absorb', | |
|
1062 | b'absorb', | |
|
1048 | 1063 | [ |
|
1049 | 1064 | ( |
|
1050 | 'a', | |
|
1051 | 'apply-changes', | |
|
1065 | b'a', | |
|
1066 | b'apply-changes', | |
|
1052 | 1067 | None, |
|
1053 | _('apply changes without prompting for confirmation'), | |
|
1068 | _(b'apply changes without prompting for confirmation'), | |
|
1054 | 1069 | ), |
|
1055 | 1070 | ( |
|
1056 | 'p', | |
|
1057 | 'print-changes', | |
|
1071 | b'p', | |
|
1072 | b'print-changes', | |
|
1058 | 1073 | None, |
|
1059 | _('always print which changesets are modified by which changes'), | |
|
1074 | _(b'always print which changesets are modified by which changes'), | |
|
1060 | 1075 | ), |
|
1061 | 1076 | ( |
|
1062 | 'i', | |
|
1063 | 'interactive', | |
|
1077 | b'i', | |
|
1078 | b'interactive', | |
|
1064 | 1079 | None, |
|
1065 | _('interactively select which chunks to apply (EXPERIMENTAL)'), | |
|
1080 | _(b'interactively select which chunks to apply (EXPERIMENTAL)'), | |
|
1066 | 1081 | ), |
|
1067 | 1082 | ( |
|
1068 | 'e', | |
|
1069 | 'edit-lines', | |
|
1083 | b'e', | |
|
1084 | b'edit-lines', | |
|
1070 | 1085 | None, |
|
1071 | 1086 | _( |
|
1072 | 'edit what lines belong to which changesets before commit ' | |
|
1073 | '(EXPERIMENTAL)' | |
|
1087 | b'edit what lines belong to which changesets before commit ' | |
|
1088 | b'(EXPERIMENTAL)' | |
|
1074 | 1089 | ), |
|
1075 | 1090 | ), |
|
1076 | 1091 | ] |
|
1077 | 1092 | + commands.dryrunopts |
|
1078 | 1093 | + commands.templateopts |
|
1079 | 1094 | + commands.walkopts, |
|
1080 | _('hg absorb [OPTION] [FILE]...'), | |
|
1095 | _(b'hg absorb [OPTION] [FILE]...'), | |
|
1081 | 1096 | helpcategory=command.CATEGORY_COMMITTING, |
|
1082 | 1097 | helpbasic=True, |
|
1083 | 1098 | ) |
@@ -1108,7 +1123,7 b' def absorbcmd(ui, repo, *pats, **opts):' | |||
|
1108 | 1123 | opts = pycompat.byteskwargs(opts) |
|
1109 | 1124 | |
|
1110 | 1125 | with repo.wlock(), repo.lock(): |
|
1111 | if not opts['dry_run']: | |
|
1126 | if not opts[b'dry_run']: | |
|
1112 | 1127 | cmdutil.checkunfinished(repo) |
|
1113 | 1128 | |
|
1114 | 1129 | state = absorb(ui, repo, pats=pats, opts=opts) |
@@ -232,66 +232,66 b' urlreq = util.urlreq' | |||
|
232 | 232 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
233 | 233 | # be specifying the version(s) of Mercurial they are tested with, or |
|
234 | 234 | # leave the attribute unspecified. |
|
235 | testedwith = 'ships-with-hg-core' | |
|
235 | testedwith = b'ships-with-hg-core' | |
|
236 | 236 | |
|
237 | 237 | configtable = {} |
|
238 | 238 | configitem = registrar.configitem(configtable) |
|
239 | 239 | |
|
240 | 240 | # deprecated config: acl.config |
|
241 | 241 | configitem( |
|
242 | 'acl', 'config', default=None, | |
|
242 | b'acl', b'config', default=None, | |
|
243 | 243 | ) |
|
244 | 244 | configitem( |
|
245 | 'acl.groups', '.*', default=None, generic=True, | |
|
245 | b'acl.groups', b'.*', default=None, generic=True, | |
|
246 | 246 | ) |
|
247 | 247 | configitem( |
|
248 | 'acl.deny.branches', '.*', default=None, generic=True, | |
|
248 | b'acl.deny.branches', b'.*', default=None, generic=True, | |
|
249 | 249 | ) |
|
250 | 250 | configitem( |
|
251 | 'acl.allow.branches', '.*', default=None, generic=True, | |
|
251 | b'acl.allow.branches', b'.*', default=None, generic=True, | |
|
252 | 252 | ) |
|
253 | 253 | configitem( |
|
254 | 'acl.deny', '.*', default=None, generic=True, | |
|
254 | b'acl.deny', b'.*', default=None, generic=True, | |
|
255 | 255 | ) |
|
256 | 256 | configitem( |
|
257 | 'acl.allow', '.*', default=None, generic=True, | |
|
257 | b'acl.allow', b'.*', default=None, generic=True, | |
|
258 | 258 | ) |
|
259 | 259 | configitem( |
|
260 | 'acl', 'sources', default=lambda: ['serve'], | |
|
260 | b'acl', b'sources', default=lambda: [b'serve'], | |
|
261 | 261 | ) |
|
262 | 262 | |
|
263 | 263 | |
|
264 | 264 | def _getusers(ui, group): |
|
265 | 265 | |
|
266 | 266 | # First, try to use group definition from section [acl.groups] |
|
267 | hgrcusers = ui.configlist('acl.groups', group) | |
|
267 | hgrcusers = ui.configlist(b'acl.groups', group) | |
|
268 | 268 | if hgrcusers: |
|
269 | 269 | return hgrcusers |
|
270 | 270 | |
|
271 | ui.debug('acl: "%s" not defined in [acl.groups]\n' % group) | |
|
271 | ui.debug(b'acl: "%s" not defined in [acl.groups]\n' % group) | |
|
272 | 272 | # If no users found in group definition, get users from OS-level group |
|
273 | 273 | try: |
|
274 | 274 | return util.groupmembers(group) |
|
275 | 275 | except KeyError: |
|
276 | raise error.Abort(_("group '%s' is undefined") % group) | |
|
276 | raise error.Abort(_(b"group '%s' is undefined") % group) | |
|
277 | 277 | |
|
278 | 278 | |
|
279 | 279 | def _usermatch(ui, user, usersorgroups): |
|
280 | 280 | |
|
281 | if usersorgroups == '*': | |
|
281 | if usersorgroups == b'*': | |
|
282 | 282 | return True |
|
283 | 283 | |
|
284 | for ug in usersorgroups.replace(',', ' ').split(): | |
|
284 | for ug in usersorgroups.replace(b',', b' ').split(): | |
|
285 | 285 | |
|
286 | if ug.startswith('!'): | |
|
286 | if ug.startswith(b'!'): | |
|
287 | 287 | # Test for excluded user or group. Format: |
|
288 | 288 | # if ug is a user name: !username |
|
289 | 289 | # if ug is a group name: !@groupname |
|
290 | 290 | ug = ug[1:] |
|
291 | 291 | if ( |
|
292 | not ug.startswith('@') | |
|
292 | not ug.startswith(b'@') | |
|
293 | 293 | and user != ug |
|
294 | or ug.startswith('@') | |
|
294 | or ug.startswith(b'@') | |
|
295 | 295 | and user not in _getusers(ui, ug[1:]) |
|
296 | 296 | ): |
|
297 | 297 | return True |
@@ -299,7 +299,9 b' def _usermatch(ui, user, usersorgroups):' | |||
|
299 | 299 | # Test for user or group. Format: |
|
300 | 300 | # if ug is a user name: username |
|
301 | 301 | # if ug is a group name: @groupname |
|
302 | elif user == ug or ug.startswith('@') and user in _getusers(ui, ug[1:]): | |
|
302 | elif ( | |
|
303 | user == ug or ug.startswith(b'@') and user in _getusers(ui, ug[1:]) | |
|
304 | ): | |
|
303 | 305 | return True |
|
304 | 306 | |
|
305 | 307 | return False |
@@ -308,14 +310,14 b' def _usermatch(ui, user, usersorgroups):' | |||
|
308 | 310 | def buildmatch(ui, repo, user, key): |
|
309 | 311 | '''return tuple of (match function, list enabled).''' |
|
310 | 312 | if not ui.has_section(key): |
|
311 | ui.debug('acl: %s not enabled\n' % key) | |
|
313 | ui.debug(b'acl: %s not enabled\n' % key) | |
|
312 | 314 | return None |
|
313 | 315 | |
|
314 | 316 | pats = [ |
|
315 | 317 | pat for pat, users in ui.configitems(key) if _usermatch(ui, user, users) |
|
316 | 318 | ] |
|
317 | 319 | ui.debug( |
|
318 | 'acl: %s enabled, %d entries for user %s\n' % (key, len(pats), user) | |
|
320 | b'acl: %s enabled, %d entries for user %s\n' % (key, len(pats), user) | |
|
319 | 321 | ) |
|
320 | 322 | |
|
321 | 323 | # Branch-based ACL |
@@ -323,14 +325,14 b' def buildmatch(ui, repo, user, key):' | |||
|
323 | 325 | if pats: |
|
324 | 326 | # If there's an asterisk (meaning "any branch"), always return True; |
|
325 | 327 | # Otherwise, test if b is in pats |
|
326 | if '*' in pats: | |
|
328 | if b'*' in pats: | |
|
327 | 329 | return util.always |
|
328 | 330 | return lambda b: b in pats |
|
329 | 331 | return util.never |
|
330 | 332 | |
|
331 | 333 | # Path-based ACL |
|
332 | 334 | if pats: |
|
333 | return match.match(repo.root, '', pats) | |
|
335 | return match.match(repo.root, b'', pats) | |
|
334 | 336 | return util.never |
|
335 | 337 | |
|
336 | 338 | |
@@ -342,122 +344,128 b' def ensureenabled(ui):' | |||
|
342 | 344 | never loaded. This function ensure the extension is enabled when running |
|
343 | 345 | hooks. |
|
344 | 346 | """ |
|
345 | if 'acl' in ui._knownconfig: | |
|
347 | if b'acl' in ui._knownconfig: | |
|
346 | 348 | return |
|
347 | ui.setconfig('extensions', 'acl', '', source='internal') | |
|
348 | extensions.loadall(ui, ['acl']) | |
|
349 | ui.setconfig(b'extensions', b'acl', b'', source=b'internal') | |
|
350 | extensions.loadall(ui, [b'acl']) | |
|
349 | 351 | |
|
350 | 352 | |
|
351 | 353 | def hook(ui, repo, hooktype, node=None, source=None, **kwargs): |
|
352 | 354 | |
|
353 | 355 | ensureenabled(ui) |
|
354 | 356 | |
|
355 | if hooktype not in ['pretxnchangegroup', 'pretxncommit', 'prepushkey']: | |
|
357 | if hooktype not in [b'pretxnchangegroup', b'pretxncommit', b'prepushkey']: | |
|
356 | 358 | raise error.Abort( |
|
357 | 359 | _( |
|
358 | 'config error - hook type "%s" cannot stop ' | |
|
359 | 'incoming changesets, commits, nor bookmarks' | |
|
360 | b'config error - hook type "%s" cannot stop ' | |
|
361 | b'incoming changesets, commits, nor bookmarks' | |
|
360 | 362 | ) |
|
361 | 363 | % hooktype |
|
362 | 364 | ) |
|
363 | if hooktype == 'pretxnchangegroup' and source not in ui.configlist( | |
|
364 | 'acl', 'sources' | |
|
365 | if hooktype == b'pretxnchangegroup' and source not in ui.configlist( | |
|
366 | b'acl', b'sources' | |
|
365 | 367 | ): |
|
366 | ui.debug('acl: changes have source "%s" - skipping\n' % source) | |
|
368 | ui.debug(b'acl: changes have source "%s" - skipping\n' % source) | |
|
367 | 369 | return |
|
368 | 370 | |
|
369 | 371 | user = None |
|
370 | if source == 'serve' and r'url' in kwargs: | |
|
371 | url = kwargs[r'url'].split(':') | |
|
372 | if url[0] == 'remote' and url[1].startswith('http'): | |
|
372 | if source == b'serve' and r'url' in kwargs: | |
|
373 | url = kwargs[r'url'].split(b':') | |
|
374 | if url[0] == b'remote' and url[1].startswith(b'http'): | |
|
373 | 375 | user = urlreq.unquote(url[3]) |
|
374 | 376 | |
|
375 | 377 | if user is None: |
|
376 | 378 | user = procutil.getuser() |
|
377 | 379 | |
|
378 | ui.debug('acl: checking access for user "%s"\n' % user) | |
|
380 | ui.debug(b'acl: checking access for user "%s"\n' % user) | |
|
379 | 381 | |
|
380 | if hooktype == 'prepushkey': | |
|
382 | if hooktype == b'prepushkey': | |
|
381 | 383 | _pkhook(ui, repo, hooktype, node, source, user, **kwargs) |
|
382 | 384 | else: |
|
383 | 385 | _txnhook(ui, repo, hooktype, node, source, user, **kwargs) |
|
384 | 386 | |
|
385 | 387 | |
|
386 | 388 | def _pkhook(ui, repo, hooktype, node, source, user, **kwargs): |
|
387 | if kwargs[r'namespace'] == 'bookmarks': | |
|
389 | if kwargs[r'namespace'] == b'bookmarks': | |
|
388 | 390 | bookmark = kwargs[r'key'] |
|
389 | 391 | ctx = kwargs[r'new'] |
|
390 | allowbookmarks = buildmatch(ui, None, user, 'acl.allow.bookmarks') | |
|
391 | denybookmarks = buildmatch(ui, None, user, 'acl.deny.bookmarks') | |
|
392 | allowbookmarks = buildmatch(ui, None, user, b'acl.allow.bookmarks') | |
|
393 | denybookmarks = buildmatch(ui, None, user, b'acl.deny.bookmarks') | |
|
392 | 394 | |
|
393 | 395 | if denybookmarks and denybookmarks(bookmark): |
|
394 | 396 | raise error.Abort( |
|
395 | _('acl: user "%s" denied on bookmark "%s"' ' (changeset "%s")') | |
|
397 | _( | |
|
398 | b'acl: user "%s" denied on bookmark "%s"' | |
|
399 | b' (changeset "%s")' | |
|
400 | ) | |
|
396 | 401 | % (user, bookmark, ctx) |
|
397 | 402 | ) |
|
398 | 403 | if allowbookmarks and not allowbookmarks(bookmark): |
|
399 | 404 | raise error.Abort( |
|
400 | 405 | _( |
|
401 | 'acl: user "%s" not allowed on bookmark "%s"' | |
|
402 | ' (changeset "%s")' | |
|
406 | b'acl: user "%s" not allowed on bookmark "%s"' | |
|
407 | b' (changeset "%s")' | |
|
403 | 408 | ) |
|
404 | 409 | % (user, bookmark, ctx) |
|
405 | 410 | ) |
|
406 | 411 | ui.debug( |
|
407 | 'acl: bookmark access granted: "%s" on bookmark "%s"\n' | |
|
412 | b'acl: bookmark access granted: "%s" on bookmark "%s"\n' | |
|
408 | 413 | % (ctx, bookmark) |
|
409 | 414 | ) |
|
410 | 415 | |
|
411 | 416 | |
|
412 | 417 | def _txnhook(ui, repo, hooktype, node, source, user, **kwargs): |
|
413 | 418 | # deprecated config: acl.config |
|
414 | cfg = ui.config('acl', 'config') | |
|
419 | cfg = ui.config(b'acl', b'config') | |
|
415 | 420 | if cfg: |
|
416 | 421 | ui.readconfig( |
|
417 | 422 | cfg, |
|
418 | 423 | sections=[ |
|
419 | 'acl.groups', | |
|
420 | 'acl.allow.branches', | |
|
421 | 'acl.deny.branches', | |
|
422 | 'acl.allow', | |
|
423 | 'acl.deny', | |
|
424 | b'acl.groups', | |
|
425 | b'acl.allow.branches', | |
|
426 | b'acl.deny.branches', | |
|
427 | b'acl.allow', | |
|
428 | b'acl.deny', | |
|
424 | 429 | ], |
|
425 | 430 | ) |
|
426 | 431 | |
|
427 | allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') | |
|
428 | denybranches = buildmatch(ui, None, user, 'acl.deny.branches') | |
|
429 | allow = buildmatch(ui, repo, user, 'acl.allow') | |
|
430 | deny = buildmatch(ui, repo, user, 'acl.deny') | |
|
432 | allowbranches = buildmatch(ui, None, user, b'acl.allow.branches') | |
|
433 | denybranches = buildmatch(ui, None, user, b'acl.deny.branches') | |
|
434 | allow = buildmatch(ui, repo, user, b'acl.allow') | |
|
435 | deny = buildmatch(ui, repo, user, b'acl.deny') | |
|
431 | 436 | |
|
432 | 437 | for rev in pycompat.xrange(repo[node].rev(), len(repo)): |
|
433 | 438 | ctx = repo[rev] |
|
434 | 439 | branch = ctx.branch() |
|
435 | 440 | if denybranches and denybranches(branch): |
|
436 | 441 | raise error.Abort( |
|
437 | _('acl: user "%s" denied on branch "%s"' ' (changeset "%s")') | |
|
442 | _(b'acl: user "%s" denied on branch "%s"' b' (changeset "%s")') | |
|
438 | 443 | % (user, branch, ctx) |
|
439 | 444 | ) |
|
440 | 445 | if allowbranches and not allowbranches(branch): |
|
441 | 446 | raise error.Abort( |
|
442 | 447 | _( |
|
443 | 'acl: user "%s" not allowed on branch "%s"' | |
|
444 | ' (changeset "%s")' | |
|
448 | b'acl: user "%s" not allowed on branch "%s"' | |
|
449 | b' (changeset "%s")' | |
|
445 | 450 | ) |
|
446 | 451 | % (user, branch, ctx) |
|
447 | 452 | ) |
|
448 | 453 | ui.debug( |
|
449 | 'acl: branch access granted: "%s" on branch "%s"\n' % (ctx, branch) | |
|
454 | b'acl: branch access granted: "%s" on branch "%s"\n' % (ctx, branch) | |
|
450 | 455 | ) |
|
451 | 456 | |
|
452 | 457 | for f in ctx.files(): |
|
453 | 458 | if deny and deny(f): |
|
454 | 459 | raise error.Abort( |
|
455 | _('acl: user "%s" denied on "%s"' ' (changeset "%s")') | |
|
460 | _(b'acl: user "%s" denied on "%s"' b' (changeset "%s")') | |
|
456 | 461 | % (user, f, ctx) |
|
457 | 462 | ) |
|
458 | 463 | if allow and not allow(f): |
|
459 | 464 | raise error.Abort( |
|
460 | _('acl: user "%s" not allowed on "%s"' ' (changeset "%s")') | |
|
465 | _( | |
|
466 | b'acl: user "%s" not allowed on "%s"' | |
|
467 | b' (changeset "%s")' | |
|
468 | ) | |
|
461 | 469 | % (user, f, ctx) |
|
462 | 470 | ) |
|
463 | ui.debug('acl: path access granted: "%s"\n' % ctx) | |
|
471 | ui.debug(b'acl: path access granted: "%s"\n' % ctx) |
@@ -24,23 +24,23 b' from mercurial import (' | |||
|
24 | 24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
25 | 25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
26 | 26 | # leave the attribute unspecified. |
|
27 | testedwith = 'ships-with-hg-core' | |
|
27 | testedwith = b'ships-with-hg-core' | |
|
28 | 28 | |
|
29 | 29 | cmdtable = {} |
|
30 | 30 | command = registrar.command(cmdtable) |
|
31 | 31 | |
|
32 | 32 | |
|
33 | 33 | @command( |
|
34 | 'amend', | |
|
34 | b'amend', | |
|
35 | 35 | [ |
|
36 | 36 | ( |
|
37 | 'A', | |
|
38 | 'addremove', | |
|
37 | b'A', | |
|
38 | b'addremove', | |
|
39 | 39 | None, |
|
40 | _('mark new/missing files as added/removed before committing'), | |
|
40 | _(b'mark new/missing files as added/removed before committing'), | |
|
41 | 41 | ), |
|
42 | ('e', 'edit', None, _('invoke editor on commit messages')), | |
|
43 | ('i', 'interactive', None, _('use interactive mode')), | |
|
42 | (b'e', b'edit', None, _(b'invoke editor on commit messages')), | |
|
43 | (b'i', b'interactive', None, _(b'use interactive mode')), | |
|
44 | 44 | ( |
|
45 | 45 | b'', |
|
46 | 46 | b'close-branch', |
@@ -48,13 +48,13 b' command = registrar.command(cmdtable)' | |||
|
48 | 48 | _(b'mark a branch as closed, hiding it from the branch list'), |
|
49 | 49 | ), |
|
50 | 50 | (b's', b'secret', None, _(b'use the secret phase for committing')), |
|
51 | ('n', 'note', '', _('store a note on the amend')), | |
|
51 | (b'n', b'note', b'', _(b'store a note on the amend')), | |
|
52 | 52 | ] |
|
53 | 53 | + cmdutil.walkopts |
|
54 | 54 | + cmdutil.commitopts |
|
55 | 55 | + cmdutil.commitopts2 |
|
56 | 56 | + cmdutil.commitopts3, |
|
57 | _('[OPTION]... [FILE]...'), | |
|
57 | _(b'[OPTION]... [FILE]...'), | |
|
58 | 58 | helpcategory=command.CATEGORY_COMMITTING, |
|
59 | 59 | inferrepo=True, |
|
60 | 60 | ) |
@@ -70,7 +70,7 b' def amend(ui, repo, *pats, **opts):' | |||
|
70 | 70 | cmdutil.checknotesize(ui, opts) |
|
71 | 71 | |
|
72 | 72 | with repo.wlock(), repo.lock(): |
|
73 | if not opts.get('logfile'): | |
|
74 | opts['message'] = opts.get('message') or repo['.'].description() | |
|
75 | opts['amend'] = True | |
|
73 | if not opts.get(b'logfile'): | |
|
74 | opts[b'message'] = opts.get(b'message') or repo[b'.'].description() | |
|
75 | opts[b'amend'] = True | |
|
76 | 76 | return commands._docommit(ui, repo, *pats, **pycompat.strkwargs(opts)) |
@@ -42,14 +42,14 b' configtable = {}' | |||
|
42 | 42 | configitem = registrar.configitem(configtable) |
|
43 | 43 | |
|
44 | 44 | configitem( |
|
45 | 'automv', 'similarity', default=95, | |
|
45 | b'automv', b'similarity', default=95, | |
|
46 | 46 | ) |
|
47 | 47 | |
|
48 | 48 | |
|
49 | 49 | def extsetup(ui): |
|
50 | entry = extensions.wrapcommand(commands.table, 'commit', mvcheck) | |
|
50 | entry = extensions.wrapcommand(commands.table, b'commit', mvcheck) | |
|
51 | 51 | entry[1].append( |
|
52 | ('', 'no-automv', None, _('disable automatic file move detection')) | |
|
52 | (b'', b'no-automv', None, _(b'disable automatic file move detection')) | |
|
53 | 53 | ) |
|
54 | 54 | |
|
55 | 55 | |
@@ -57,11 +57,11 b' def mvcheck(orig, ui, repo, *pats, **opt' | |||
|
57 | 57 | """Hook to check for moves at commit time""" |
|
58 | 58 | opts = pycompat.byteskwargs(opts) |
|
59 | 59 | renames = None |
|
60 | disabled = opts.pop('no_automv', False) | |
|
60 | disabled = opts.pop(b'no_automv', False) | |
|
61 | 61 | if not disabled: |
|
62 | threshold = ui.configint('automv', 'similarity') | |
|
62 | threshold = ui.configint(b'automv', b'similarity') | |
|
63 | 63 | if not 0 <= threshold <= 100: |
|
64 | raise error.Abort(_('automv.similarity must be between 0 and 100')) | |
|
64 | raise error.Abort(_(b'automv.similarity must be between 0 and 100')) | |
|
65 | 65 | if threshold > 0: |
|
66 | 66 | match = scmutil.match(repo[None], pats, opts) |
|
67 | 67 | added, removed = _interestingfiles(repo, match) |
@@ -87,7 +87,7 b' def _interestingfiles(repo, matcher):' | |||
|
87 | 87 | added = stat.added |
|
88 | 88 | removed = stat.removed |
|
89 | 89 | |
|
90 | copy = copies.pathcopies(repo['.'], repo[None], matcher) | |
|
90 | copy = copies.pathcopies(repo[b'.'], repo[None], matcher) | |
|
91 | 91 | # remove the copy files for which we already have copy info |
|
92 | 92 | added = [f for f in added if f not in copy] |
|
93 | 93 | |
@@ -108,10 +108,10 b' def _findrenames(repo, uipathfn, added, ' | |||
|
108 | 108 | ): |
|
109 | 109 | if repo.ui.verbose: |
|
110 | 110 | repo.ui.status( |
|
111 | _('detected move of %s as %s (%d%% similar)\n') | |
|
111 | _(b'detected move of %s as %s (%d%% similar)\n') | |
|
112 | 112 | % (uipathfn(src), uipathfn(dst), score * 100) |
|
113 | 113 | ) |
|
114 | 114 | renames[dst] = src |
|
115 | 115 | if renames: |
|
116 | repo.ui.status(_('detected move of %d files\n') % len(renames)) | |
|
116 | repo.ui.status(_(b'detected move of %d files\n') % len(renames)) | |
|
117 | 117 | return renames |
@@ -26,33 +26,33 b' from mercurial import (' | |||
|
26 | 26 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
27 | 27 | # be specifying the version(s) of Mercurial they are tested with, or |
|
28 | 28 | # leave the attribute unspecified. |
|
29 | testedwith = 'ships-with-hg-core' | |
|
29 | testedwith = b'ships-with-hg-core' | |
|
30 | 30 | |
|
31 | 31 | |
|
32 | 32 | def prettyedge(before, edge, after): |
|
33 | if edge == '~': | |
|
34 | return '\xE2\x95\xA7' # U+2567 ╧ | |
|
35 | if edge == '/': | |
|
36 | return '\xE2\x95\xB1' # U+2571 ╱ | |
|
37 | if edge == '-': | |
|
38 | return '\xE2\x94\x80' # U+2500 ─ | |
|
39 | if edge == '|': | |
|
40 | return '\xE2\x94\x82' # U+2502 │ | |
|
41 | if edge == ':': | |
|
42 | return '\xE2\x94\x86' # U+2506 ┆ | |
|
43 | if edge == '\\': | |
|
44 | return '\xE2\x95\xB2' # U+2572 ╲ | |
|
45 | if edge == '+': | |
|
46 | if before == ' ' and not after == ' ': | |
|
47 | return '\xE2\x94\x9C' # U+251C ├ | |
|
48 | if after == ' ' and not before == ' ': | |
|
49 | return '\xE2\x94\xA4' # U+2524 ┤ | |
|
50 | return '\xE2\x94\xBC' # U+253C ┼ | |
|
33 | if edge == b'~': | |
|
34 | return b'\xE2\x95\xA7' # U+2567 ╧ | |
|
35 | if edge == b'/': | |
|
36 | return b'\xE2\x95\xB1' # U+2571 ╱ | |
|
37 | if edge == b'-': | |
|
38 | return b'\xE2\x94\x80' # U+2500 ─ | |
|
39 | if edge == b'|': | |
|
40 | return b'\xE2\x94\x82' # U+2502 │ | |
|
41 | if edge == b':': | |
|
42 | return b'\xE2\x94\x86' # U+2506 ┆ | |
|
43 | if edge == b'\\': | |
|
44 | return b'\xE2\x95\xB2' # U+2572 ╲ | |
|
45 | if edge == b'+': | |
|
46 | if before == b' ' and not after == b' ': | |
|
47 | return b'\xE2\x94\x9C' # U+251C ├ | |
|
48 | if after == b' ' and not before == b' ': | |
|
49 | return b'\xE2\x94\xA4' # U+2524 ┤ | |
|
50 | return b'\xE2\x94\xBC' # U+253C ┼ | |
|
51 | 51 | return edge |
|
52 | 52 | |
|
53 | 53 | |
|
54 | 54 | def convertedges(line): |
|
55 | line = ' %s ' % line | |
|
55 | line = b' %s ' % line | |
|
56 | 56 | pretty = [] |
|
57 | 57 | for idx in pycompat.xrange(len(line) - 2): |
|
58 | 58 | pretty.append( |
@@ -62,21 +62,21 b' def convertedges(line):' | |||
|
62 | 62 | line[idx + 2 : idx + 3], |
|
63 | 63 | ) |
|
64 | 64 | ) |
|
65 | return ''.join(pretty) | |
|
65 | return b''.join(pretty) | |
|
66 | 66 | |
|
67 | 67 | |
|
68 | 68 | def getprettygraphnode(orig, *args, **kwargs): |
|
69 | 69 | node = orig(*args, **kwargs) |
|
70 | if node == 'o': | |
|
71 | return '\xE2\x97\x8B' # U+25CB ○ | |
|
72 | if node == '@': | |
|
73 | return '\xE2\x97\x8D' # U+25CD ◍ | |
|
74 | if node == '*': | |
|
75 | return '\xE2\x88\x97' # U+2217 ∗ | |
|
76 | if node == 'x': | |
|
77 | return '\xE2\x97\x8C' # U+25CC ◌ | |
|
78 | if node == '_': | |
|
79 | return '\xE2\x95\xA4' # U+2564 ╤ | |
|
70 | if node == b'o': | |
|
71 | return b'\xE2\x97\x8B' # U+25CB ○ | |
|
72 | if node == b'@': | |
|
73 | return b'\xE2\x97\x8D' # U+25CD ◍ | |
|
74 | if node == b'*': | |
|
75 | return b'\xE2\x88\x97' # U+2217 ∗ | |
|
76 | if node == b'x': | |
|
77 | return b'\xE2\x97\x8C' # U+25CC ◌ | |
|
78 | if node == b'_': | |
|
79 | return b'\xE2\x95\xA4' # U+2564 ╤ | |
|
80 | 80 | return node |
|
81 | 81 | |
|
82 | 82 | |
@@ -87,21 +87,21 b' def outputprettygraph(orig, ui, graph, *' | |||
|
87 | 87 | |
|
88 | 88 | |
|
89 | 89 | def extsetup(ui): |
|
90 | if ui.plain('graph'): | |
|
90 | if ui.plain(b'graph'): | |
|
91 | 91 | return |
|
92 | 92 | |
|
93 | if encoding.encoding != 'UTF-8': | |
|
94 | ui.warn(_('beautifygraph: unsupported encoding, UTF-8 required\n')) | |
|
93 | if encoding.encoding != b'UTF-8': | |
|
94 | ui.warn(_(b'beautifygraph: unsupported encoding, UTF-8 required\n')) | |
|
95 | 95 | return |
|
96 | 96 | |
|
97 | 97 | if r'A' in encoding._wide: |
|
98 | 98 | ui.warn( |
|
99 | 99 | _( |
|
100 | 'beautifygraph: unsupported terminal settings, ' | |
|
101 | 'monospace narrow text required\n' | |
|
100 | b'beautifygraph: unsupported terminal settings, ' | |
|
101 | b'monospace narrow text required\n' | |
|
102 | 102 | ) |
|
103 | 103 | ) |
|
104 | 104 | return |
|
105 | 105 | |
|
106 | extensions.wrapfunction(graphmod, 'outputgraph', outputprettygraph) | |
|
107 | extensions.wrapfunction(templatekw, 'getgraphnode', getprettygraphnode) | |
|
106 | extensions.wrapfunction(graphmod, b'outputgraph', outputprettygraph) | |
|
107 | extensions.wrapfunction(templatekw, b'getgraphnode', getprettygraphnode) |
@@ -63,7 +63,7 b' from mercurial.utils import (' | |||
|
63 | 63 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
64 | 64 | # be specifying the version(s) of Mercurial they are tested with, or |
|
65 | 65 | # leave the attribute unspecified. |
|
66 | testedwith = 'ships-with-hg-core' | |
|
66 | testedwith = b'ships-with-hg-core' | |
|
67 | 67 | |
|
68 | 68 | cmdtable = {} |
|
69 | 69 | command = registrar.command(cmdtable) |
@@ -72,27 +72,27 b' configtable = {}' | |||
|
72 | 72 | configitem = registrar.configitem(configtable) |
|
73 | 73 | |
|
74 | 74 | configitem( |
|
75 | 'blackbox', 'dirty', default=False, | |
|
75 | b'blackbox', b'dirty', default=False, | |
|
76 | 76 | ) |
|
77 | 77 | configitem( |
|
78 | 'blackbox', 'maxsize', default='1 MB', | |
|
78 | b'blackbox', b'maxsize', default=b'1 MB', | |
|
79 | 79 | ) |
|
80 | 80 | configitem( |
|
81 | 'blackbox', 'logsource', default=False, | |
|
81 | b'blackbox', b'logsource', default=False, | |
|
82 | 82 | ) |
|
83 | 83 | configitem( |
|
84 | 'blackbox', 'maxfiles', default=7, | |
|
84 | b'blackbox', b'maxfiles', default=7, | |
|
85 | 85 | ) |
|
86 | 86 | configitem( |
|
87 | 'blackbox', 'track', default=lambda: ['*'], | |
|
87 | b'blackbox', b'track', default=lambda: [b'*'], | |
|
88 | 88 | ) |
|
89 | 89 | configitem( |
|
90 | 'blackbox', | |
|
91 | 'ignore', | |
|
92 | default=lambda: ['chgserver', 'cmdserver', 'extension'], | |
|
90 | b'blackbox', | |
|
91 | b'ignore', | |
|
92 | default=lambda: [b'chgserver', b'cmdserver', b'extension'], | |
|
93 | 93 | ) |
|
94 | 94 | configitem( |
|
95 | 'blackbox', 'date-format', default='%Y/%m/%d %H:%M:%S', | |
|
95 | b'blackbox', b'date-format', default=b'%Y/%m/%d %H:%M:%S', | |
|
96 | 96 | ) |
|
97 | 97 | |
|
98 | 98 | _lastlogger = loggingutil.proxylogger() |
@@ -101,10 +101,10 b' configitem(' | |||
|
101 | 101 | class blackboxlogger(object): |
|
102 | 102 | def __init__(self, ui, repo): |
|
103 | 103 | self._repo = repo |
|
104 | self._trackedevents = set(ui.configlist('blackbox', 'track')) | |
|
105 | self._ignoredevents = set(ui.configlist('blackbox', 'ignore')) | |
|
106 | self._maxfiles = ui.configint('blackbox', 'maxfiles') | |
|
107 | self._maxsize = ui.configbytes('blackbox', 'maxsize') | |
|
104 | self._trackedevents = set(ui.configlist(b'blackbox', b'track')) | |
|
105 | self._ignoredevents = set(ui.configlist(b'blackbox', b'ignore')) | |
|
106 | self._maxfiles = ui.configint(b'blackbox', b'maxfiles') | |
|
107 | self._maxsize = ui.configbytes(b'blackbox', b'maxsize') | |
|
108 | 108 | self._inlog = False |
|
109 | 109 | |
|
110 | 110 | def tracked(self, event): |
@@ -125,29 +125,29 b' class blackboxlogger(object):' | |||
|
125 | 125 | self._inlog = False |
|
126 | 126 | |
|
127 | 127 | def _log(self, ui, event, msg, opts): |
|
128 | default = ui.configdate('devel', 'default-date') | |
|
129 | date = dateutil.datestr(default, ui.config('blackbox', 'date-format')) | |
|
128 | default = ui.configdate(b'devel', b'default-date') | |
|
129 | date = dateutil.datestr(default, ui.config(b'blackbox', b'date-format')) | |
|
130 | 130 | user = procutil.getuser() |
|
131 | pid = '%d' % procutil.getpid() | |
|
132 | changed = '' | |
|
131 | pid = b'%d' % procutil.getpid() | |
|
132 | changed = b'' | |
|
133 | 133 | ctx = self._repo[None] |
|
134 | 134 | parents = ctx.parents() |
|
135 | rev = '+'.join([hex(p.node()) for p in parents]) | |
|
136 | if ui.configbool('blackbox', 'dirty') and ctx.dirty( | |
|
135 | rev = b'+'.join([hex(p.node()) for p in parents]) | |
|
136 | if ui.configbool(b'blackbox', b'dirty') and ctx.dirty( | |
|
137 | 137 | missing=True, merge=False, branch=False |
|
138 | 138 | ): |
|
139 | changed = '+' | |
|
140 | if ui.configbool('blackbox', 'logsource'): | |
|
141 | src = ' [%s]' % event | |
|
139 | changed = b'+' | |
|
140 | if ui.configbool(b'blackbox', b'logsource'): | |
|
141 | src = b' [%s]' % event | |
|
142 | 142 | else: |
|
143 | src = '' | |
|
143 | src = b'' | |
|
144 | 144 | try: |
|
145 | fmt = '%s %s @%s%s (%s)%s> %s' | |
|
145 | fmt = b'%s %s @%s%s (%s)%s> %s' | |
|
146 | 146 | args = (date, user, rev, changed, pid, src, msg) |
|
147 | 147 | with loggingutil.openlogfile( |
|
148 | 148 | ui, |
|
149 | 149 | self._repo.vfs, |
|
150 | name='blackbox.log', | |
|
150 | name=b'blackbox.log', | |
|
151 | 151 | maxfiles=self._maxfiles, |
|
152 | 152 | maxsize=self._maxsize, |
|
153 | 153 | ) as fp: |
@@ -156,7 +156,7 b' class blackboxlogger(object):' | |||
|
156 | 156 | # deactivate this to avoid failed logging again |
|
157 | 157 | self._trackedevents.clear() |
|
158 | 158 | ui.debug( |
|
159 | 'warning: cannot write to blackbox.log: %s\n' | |
|
159 | b'warning: cannot write to blackbox.log: %s\n' | |
|
160 | 160 | % encoding.strtolocal(err.strerror) |
|
161 | 161 | ) |
|
162 | 162 | return |
@@ -184,13 +184,13 b' def reposetup(ui, repo):' | |||
|
184 | 184 | if _lastlogger.logger is None: |
|
185 | 185 | _lastlogger.logger = logger |
|
186 | 186 | |
|
187 | repo._wlockfreeprefix.add('blackbox.log') | |
|
187 | repo._wlockfreeprefix.add(b'blackbox.log') | |
|
188 | 188 | |
|
189 | 189 | |
|
190 | 190 | @command( |
|
191 | 'blackbox', | |
|
192 | [('l', 'limit', 10, _('the number of events to show')),], | |
|
193 | _('hg blackbox [OPTION]...'), | |
|
191 | b'blackbox', | |
|
192 | [(b'l', b'limit', 10, _(b'the number of events to show')),], | |
|
193 | _(b'hg blackbox [OPTION]...'), | |
|
194 | 194 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
195 | 195 | helpbasic=True, |
|
196 | 196 | ) |
@@ -198,12 +198,12 b' def blackbox(ui, repo, *revs, **opts):' | |||
|
198 | 198 | '''view the recent repository events |
|
199 | 199 | ''' |
|
200 | 200 | |
|
201 | if not repo.vfs.exists('blackbox.log'): | |
|
201 | if not repo.vfs.exists(b'blackbox.log'): | |
|
202 | 202 | return |
|
203 | 203 | |
|
204 | 204 | limit = opts.get(r'limit') |
|
205 | fp = repo.vfs('blackbox.log', 'r') | |
|
206 | lines = fp.read().split('\n') | |
|
205 | fp = repo.vfs(b'blackbox.log', b'r') | |
|
206 | lines = fp.read().split(b'\n') | |
|
207 | 207 | |
|
208 | 208 | count = 0 |
|
209 | 209 | output = [] |
@@ -216,4 +216,4 b' def blackbox(ui, repo, *revs, **opts):' | |||
|
216 | 216 | count += 1 |
|
217 | 217 | output.append(line) |
|
218 | 218 | |
|
219 | ui.status('\n'.join(reversed(output))) | |
|
219 | ui.status(b'\n'.join(reversed(output))) |
@@ -24,14 +24,14 b' from mercurial import (' | |||
|
24 | 24 | registrar, |
|
25 | 25 | ) |
|
26 | 26 | |
|
27 | MY_NAME = 'bookflow' | |
|
27 | MY_NAME = b'bookflow' | |
|
28 | 28 | |
|
29 | 29 | configtable = {} |
|
30 | 30 | configitem = registrar.configitem(configtable) |
|
31 | 31 | |
|
32 | configitem(MY_NAME, 'protect', ['@']) | |
|
33 | configitem(MY_NAME, 'require-bookmark', True) | |
|
34 | configitem(MY_NAME, 'enable-branches', False) | |
|
32 | configitem(MY_NAME, b'protect', [b'@']) | |
|
33 | configitem(MY_NAME, b'require-bookmark', True) | |
|
34 | configitem(MY_NAME, b'enable-branches', False) | |
|
35 | 35 | |
|
36 | 36 | cmdtable = {} |
|
37 | 37 | command = registrar.command(cmdtable) |
@@ -40,19 +40,19 b' command = registrar.command(cmdtable)' | |||
|
40 | 40 | def commit_hook(ui, repo, **kwargs): |
|
41 | 41 | active = repo._bookmarks.active |
|
42 | 42 | if active: |
|
43 | if active in ui.configlist(MY_NAME, 'protect'): | |
|
43 | if active in ui.configlist(MY_NAME, b'protect'): | |
|
44 | 44 | raise error.Abort( |
|
45 | _('cannot commit, bookmark %s is protected') % active | |
|
45 | _(b'cannot commit, bookmark %s is protected') % active | |
|
46 | 46 | ) |
|
47 | 47 | if not cwd_at_bookmark(repo, active): |
|
48 | 48 | raise error.Abort( |
|
49 | 49 | _( |
|
50 | 'cannot commit, working directory out of sync with active bookmark' | |
|
50 | b'cannot commit, working directory out of sync with active bookmark' | |
|
51 | 51 | ), |
|
52 | hint=_("run 'hg up %s'") % active, | |
|
52 | hint=_(b"run 'hg up %s'") % active, | |
|
53 | 53 | ) |
|
54 | elif ui.configbool(MY_NAME, 'require-bookmark', True): | |
|
55 | raise error.Abort(_('cannot commit without an active bookmark')) | |
|
54 | elif ui.configbool(MY_NAME, b'require-bookmark', True): | |
|
55 | raise error.Abort(_(b'cannot commit without an active bookmark')) | |
|
56 | 56 | return 0 |
|
57 | 57 | |
|
58 | 58 | |
@@ -74,7 +74,7 b' def bookmarks_addbookmarks(' | |||
|
74 | 74 | if name in marks: |
|
75 | 75 | raise error.Abort( |
|
76 | 76 | _( |
|
77 | "bookmark %s already exists, to move use the --rev option" | |
|
77 | b"bookmark %s already exists, to move use the --rev option" | |
|
78 | 78 | ) |
|
79 | 79 | % name |
|
80 | 80 | ) |
@@ -92,8 +92,8 b' def commands_pull(orig, ui, repo, *args,' | |||
|
92 | 92 | if active and not cwd_at_bookmark(repo, active): |
|
93 | 93 | ui.warn( |
|
94 | 94 | _( |
|
95 | "working directory out of sync with active bookmark, run " | |
|
96 | "'hg up %s'" | |
|
95 | b"working directory out of sync with active bookmark, run " | |
|
96 | b"'hg up %s'" | |
|
97 | 97 | ) |
|
98 | 98 | % active |
|
99 | 99 | ) |
@@ -104,23 +104,23 b' def commands_branch(orig, ui, repo, labe' | |||
|
104 | 104 | if label and not opts.get(r'clean') and not opts.get(r'rev'): |
|
105 | 105 | raise error.Abort( |
|
106 | 106 | _( |
|
107 | "creating named branches is disabled and you should use bookmarks" | |
|
107 | b"creating named branches is disabled and you should use bookmarks" | |
|
108 | 108 | ), |
|
109 | hint="see 'hg help bookflow'", | |
|
109 | hint=b"see 'hg help bookflow'", | |
|
110 | 110 | ) |
|
111 | 111 | return orig(ui, repo, label, **opts) |
|
112 | 112 | |
|
113 | 113 | |
|
114 | 114 | def cwd_at_bookmark(repo, mark): |
|
115 | 115 | mark_id = repo._bookmarks[mark] |
|
116 | cur_id = repo.lookup('.') | |
|
116 | cur_id = repo.lookup(b'.') | |
|
117 | 117 | return cur_id == mark_id |
|
118 | 118 | |
|
119 | 119 | |
|
120 | 120 | def uisetup(ui): |
|
121 | extensions.wrapfunction(bookmarks, 'update', bookmarks_update) | |
|
122 | extensions.wrapfunction(bookmarks, 'addbookmarks', bookmarks_addbookmarks) | |
|
123 | extensions.wrapcommand(commands.table, 'commit', commands_commit) | |
|
124 | extensions.wrapcommand(commands.table, 'pull', commands_pull) | |
|
125 | if not ui.configbool(MY_NAME, 'enable-branches'): | |
|
126 | extensions.wrapcommand(commands.table, 'branch', commands_branch) | |
|
121 | extensions.wrapfunction(bookmarks, b'update', bookmarks_update) | |
|
122 | extensions.wrapfunction(bookmarks, b'addbookmarks', bookmarks_addbookmarks) | |
|
123 | extensions.wrapcommand(commands.table, b'commit', commands_commit) | |
|
124 | extensions.wrapcommand(commands.table, b'pull', commands_pull) | |
|
125 | if not ui.configbool(MY_NAME, b'enable-branches'): | |
|
126 | extensions.wrapcommand(commands.table, b'branch', commands_branch) |
@@ -319,32 +319,32 b' xmlrpclib = util.xmlrpclib' | |||
|
319 | 319 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
320 | 320 | # be specifying the version(s) of Mercurial they are tested with, or |
|
321 | 321 | # leave the attribute unspecified. |
|
322 | testedwith = 'ships-with-hg-core' | |
|
322 | testedwith = b'ships-with-hg-core' | |
|
323 | 323 | |
|
324 | 324 | configtable = {} |
|
325 | 325 | configitem = registrar.configitem(configtable) |
|
326 | 326 | |
|
327 | 327 | configitem( |
|
328 | 'bugzilla', 'apikey', default='', | |
|
328 | b'bugzilla', b'apikey', default=b'', | |
|
329 | 329 | ) |
|
330 | 330 | configitem( |
|
331 | 'bugzilla', 'bzdir', default='/var/www/html/bugzilla', | |
|
331 | b'bugzilla', b'bzdir', default=b'/var/www/html/bugzilla', | |
|
332 | 332 | ) |
|
333 | 333 | configitem( |
|
334 | 'bugzilla', 'bzemail', default=None, | |
|
334 | b'bugzilla', b'bzemail', default=None, | |
|
335 | 335 | ) |
|
336 | 336 | configitem( |
|
337 | 'bugzilla', 'bzurl', default='http://localhost/bugzilla/', | |
|
337 | b'bugzilla', b'bzurl', default=b'http://localhost/bugzilla/', | |
|
338 | 338 | ) |
|
339 | 339 | configitem( |
|
340 | 'bugzilla', 'bzuser', default=None, | |
|
340 | b'bugzilla', b'bzuser', default=None, | |
|
341 | 341 | ) |
|
342 | 342 | configitem( |
|
343 | 'bugzilla', 'db', default='bugs', | |
|
343 | b'bugzilla', b'db', default=b'bugs', | |
|
344 | 344 | ) |
|
345 | 345 | configitem( |
|
346 | 'bugzilla', | |
|
347 | 'fixregexp', | |
|
346 | b'bugzilla', | |
|
347 | b'fixregexp', | |
|
348 | 348 | default=( |
|
349 | 349 | br'fix(?:es)?\s*(?:bugs?\s*)?,?\s*' |
|
350 | 350 | br'(?:nos?\.?|num(?:ber)?s?)?\s*' |
@@ -353,23 +353,23 b' configitem(' | |||
|
353 | 353 | ), |
|
354 | 354 | ) |
|
355 | 355 | configitem( |
|
356 | 'bugzilla', 'fixresolution', default='FIXED', | |
|
356 | b'bugzilla', b'fixresolution', default=b'FIXED', | |
|
357 | 357 | ) |
|
358 | 358 | configitem( |
|
359 | 'bugzilla', 'fixstatus', default='RESOLVED', | |
|
359 | b'bugzilla', b'fixstatus', default=b'RESOLVED', | |
|
360 | 360 | ) |
|
361 | 361 | configitem( |
|
362 | 'bugzilla', 'host', default='localhost', | |
|
362 | b'bugzilla', b'host', default=b'localhost', | |
|
363 | 363 | ) |
|
364 | 364 | configitem( |
|
365 | 'bugzilla', 'notify', default=configitem.dynamicdefault, | |
|
365 | b'bugzilla', b'notify', default=configitem.dynamicdefault, | |
|
366 | 366 | ) |
|
367 | 367 | configitem( |
|
368 | 'bugzilla', 'password', default=None, | |
|
368 | b'bugzilla', b'password', default=None, | |
|
369 | 369 | ) |
|
370 | 370 | configitem( |
|
371 | 'bugzilla', | |
|
372 | 'regexp', | |
|
371 | b'bugzilla', | |
|
372 | b'regexp', | |
|
373 | 373 | default=( |
|
374 | 374 | br'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' |
|
375 | 375 | br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
@@ -377,25 +377,25 b' configitem(' | |||
|
377 | 377 | ), |
|
378 | 378 | ) |
|
379 | 379 | configitem( |
|
380 | 'bugzilla', 'strip', default=0, | |
|
380 | b'bugzilla', b'strip', default=0, | |
|
381 | 381 | ) |
|
382 | 382 | configitem( |
|
383 | 'bugzilla', 'style', default=None, | |
|
383 | b'bugzilla', b'style', default=None, | |
|
384 | 384 | ) |
|
385 | 385 | configitem( |
|
386 | 'bugzilla', 'template', default=None, | |
|
386 | b'bugzilla', b'template', default=None, | |
|
387 | 387 | ) |
|
388 | 388 | configitem( |
|
389 | 'bugzilla', 'timeout', default=5, | |
|
389 | b'bugzilla', b'timeout', default=5, | |
|
390 | 390 | ) |
|
391 | 391 | configitem( |
|
392 | 'bugzilla', 'user', default='bugs', | |
|
392 | b'bugzilla', b'user', default=b'bugs', | |
|
393 | 393 | ) |
|
394 | 394 | configitem( |
|
395 | 'bugzilla', 'usermap', default=None, | |
|
395 | b'bugzilla', b'usermap', default=None, | |
|
396 | 396 | ) |
|
397 | 397 | configitem( |
|
398 | 'bugzilla', 'version', default=None, | |
|
398 | b'bugzilla', b'version', default=None, | |
|
399 | 399 | ) |
|
400 | 400 | |
|
401 | 401 | |
@@ -404,13 +404,13 b' class bzaccess(object):' | |||
|
404 | 404 | |
|
405 | 405 | def __init__(self, ui): |
|
406 | 406 | self.ui = ui |
|
407 | usermap = self.ui.config('bugzilla', 'usermap') | |
|
407 | usermap = self.ui.config(b'bugzilla', b'usermap') | |
|
408 | 408 | if usermap: |
|
409 | self.ui.readconfig(usermap, sections=['usermap']) | |
|
409 | self.ui.readconfig(usermap, sections=[b'usermap']) | |
|
410 | 410 | |
|
411 | 411 | def map_committer(self, user): |
|
412 | 412 | '''map name of committer to Bugzilla user name.''' |
|
413 | for committer, bzuser in self.ui.configitems('usermap'): | |
|
413 | for committer, bzuser in self.ui.configitems(b'usermap'): | |
|
414 | 414 | if committer.lower() == user.lower(): |
|
415 | 415 | return bzuser |
|
416 | 416 | return user |
@@ -457,7 +457,7 b' class bzmysql(bzaccess):' | |||
|
457 | 457 | @staticmethod |
|
458 | 458 | def sql_buglist(ids): |
|
459 | 459 | '''return SQL-friendly list of bug ids''' |
|
460 | return '(' + ','.join(map(str, ids)) + ')' | |
|
460 | return b'(' + b','.join(map(str, ids)) + b')' | |
|
461 | 461 | |
|
462 | 462 | _MySQLdb = None |
|
463 | 463 | |
@@ -467,18 +467,20 b' class bzmysql(bzaccess):' | |||
|
467 | 467 | |
|
468 | 468 | bzmysql._MySQLdb = mysql |
|
469 | 469 | except ImportError as err: |
|
470 | raise error.Abort(_('python mysql support not available: %s') % err) | |
|
470 | raise error.Abort( | |
|
471 | _(b'python mysql support not available: %s') % err | |
|
472 | ) | |
|
471 | 473 | |
|
472 | 474 | bzaccess.__init__(self, ui) |
|
473 | 475 | |
|
474 | host = self.ui.config('bugzilla', 'host') | |
|
475 | user = self.ui.config('bugzilla', 'user') | |
|
476 | passwd = self.ui.config('bugzilla', 'password') | |
|
477 | db = self.ui.config('bugzilla', 'db') | |
|
478 | timeout = int(self.ui.config('bugzilla', 'timeout')) | |
|
476 | host = self.ui.config(b'bugzilla', b'host') | |
|
477 | user = self.ui.config(b'bugzilla', b'user') | |
|
478 | passwd = self.ui.config(b'bugzilla', b'password') | |
|
479 | db = self.ui.config(b'bugzilla', b'db') | |
|
480 | timeout = int(self.ui.config(b'bugzilla', b'timeout')) | |
|
479 | 481 | self.ui.note( |
|
480 | _('connecting to %s:%s as %s, password %s\n') | |
|
481 | % (host, db, user, '*' * len(passwd)) | |
|
482 | _(b'connecting to %s:%s as %s, password %s\n') | |
|
483 | % (host, db, user, b'*' * len(passwd)) | |
|
482 | 484 | ) |
|
483 | 485 | self.conn = bzmysql._MySQLdb.connect( |
|
484 | 486 | host=host, user=user, passwd=passwd, db=db, connect_timeout=timeout |
@@ -486,35 +488,35 b' class bzmysql(bzaccess):' | |||
|
486 | 488 | self.cursor = self.conn.cursor() |
|
487 | 489 | self.longdesc_id = self.get_longdesc_id() |
|
488 | 490 | self.user_ids = {} |
|
489 | self.default_notify = "cd %(bzdir)s && ./processmail %(id)s %(user)s" | |
|
491 | self.default_notify = b"cd %(bzdir)s && ./processmail %(id)s %(user)s" | |
|
490 | 492 | |
|
491 | 493 | def run(self, *args, **kwargs): |
|
492 | 494 | '''run a query.''' |
|
493 | self.ui.note(_('query: %s %s\n') % (args, kwargs)) | |
|
495 | self.ui.note(_(b'query: %s %s\n') % (args, kwargs)) | |
|
494 | 496 | try: |
|
495 | 497 | self.cursor.execute(*args, **kwargs) |
|
496 | 498 | except bzmysql._MySQLdb.MySQLError: |
|
497 | self.ui.note(_('failed query: %s %s\n') % (args, kwargs)) | |
|
499 | self.ui.note(_(b'failed query: %s %s\n') % (args, kwargs)) | |
|
498 | 500 | raise |
|
499 | 501 | |
|
500 | 502 | def get_longdesc_id(self): |
|
501 | 503 | '''get identity of longdesc field''' |
|
502 | self.run('select fieldid from fielddefs where name = "longdesc"') | |
|
504 | self.run(b'select fieldid from fielddefs where name = "longdesc"') | |
|
503 | 505 | ids = self.cursor.fetchall() |
|
504 | 506 | if len(ids) != 1: |
|
505 | raise error.Abort(_('unknown database schema')) | |
|
507 | raise error.Abort(_(b'unknown database schema')) | |
|
506 | 508 | return ids[0][0] |
|
507 | 509 | |
|
508 | 510 | def filter_real_bug_ids(self, bugs): |
|
509 | 511 | '''filter not-existing bugs from set.''' |
|
510 | 512 | self.run( |
|
511 | 'select bug_id from bugs where bug_id in %s' | |
|
513 | b'select bug_id from bugs where bug_id in %s' | |
|
512 | 514 | % bzmysql.sql_buglist(bugs.keys()) |
|
513 | 515 | ) |
|
514 | 516 | existing = [id for (id,) in self.cursor.fetchall()] |
|
515 | 517 | for id in bugs.keys(): |
|
516 | 518 | if id not in existing: |
|
517 | self.ui.status(_('bug %d does not exist\n') % id) | |
|
519 | self.ui.status(_(b'bug %d does not exist\n') % id) | |
|
518 | 520 | del bugs[id] |
|
519 | 521 | |
|
520 | 522 | def filter_cset_known_bug_ids(self, node, bugs): |
@@ -526,36 +528,36 b' class bzmysql(bzaccess):' | |||
|
526 | 528 | ) |
|
527 | 529 | for (id,) in self.cursor.fetchall(): |
|
528 | 530 | self.ui.status( |
|
529 | _('bug %d already knows about changeset %s\n') | |
|
531 | _(b'bug %d already knows about changeset %s\n') | |
|
530 | 532 | % (id, short(node)) |
|
531 | 533 | ) |
|
532 | 534 | del bugs[id] |
|
533 | 535 | |
|
534 | 536 | def notify(self, bugs, committer): |
|
535 | 537 | '''tell bugzilla to send mail.''' |
|
536 | self.ui.status(_('telling bugzilla to send mail:\n')) | |
|
538 | self.ui.status(_(b'telling bugzilla to send mail:\n')) | |
|
537 | 539 | (user, userid) = self.get_bugzilla_user(committer) |
|
538 | 540 | for id in bugs.keys(): |
|
539 | self.ui.status(_(' bug %s\n') % id) | |
|
540 | cmdfmt = self.ui.config('bugzilla', 'notify', self.default_notify) | |
|
541 | bzdir = self.ui.config('bugzilla', 'bzdir') | |
|
541 | self.ui.status(_(b' bug %s\n') % id) | |
|
542 | cmdfmt = self.ui.config(b'bugzilla', b'notify', self.default_notify) | |
|
543 | bzdir = self.ui.config(b'bugzilla', b'bzdir') | |
|
542 | 544 | try: |
|
543 | 545 | # Backwards-compatible with old notify string, which |
|
544 | 546 | # took one string. This will throw with a new format |
|
545 | 547 | # string. |
|
546 | 548 | cmd = cmdfmt % id |
|
547 | 549 | except TypeError: |
|
548 | cmd = cmdfmt % {'bzdir': bzdir, 'id': id, 'user': user} | |
|
549 | self.ui.note(_('running notify command %s\n') % cmd) | |
|
550 | fp = procutil.popen('(%s) 2>&1' % cmd, 'rb') | |
|
550 | cmd = cmdfmt % {b'bzdir': bzdir, b'id': id, b'user': user} | |
|
551 | self.ui.note(_(b'running notify command %s\n') % cmd) | |
|
552 | fp = procutil.popen(b'(%s) 2>&1' % cmd, b'rb') | |
|
551 | 553 | out = util.fromnativeeol(fp.read()) |
|
552 | 554 | ret = fp.close() |
|
553 | 555 | if ret: |
|
554 | 556 | self.ui.warn(out) |
|
555 | 557 | raise error.Abort( |
|
556 | _('bugzilla notify command %s') % procutil.explainexit(ret) | |
|
558 | _(b'bugzilla notify command %s') % procutil.explainexit(ret) | |
|
557 | 559 | ) |
|
558 | self.ui.status(_('done\n')) | |
|
560 | self.ui.status(_(b'done\n')) | |
|
559 | 561 | |
|
560 | 562 | def get_user_id(self, user): |
|
561 | 563 | '''look up numeric bugzilla user id.''' |
@@ -565,7 +567,7 b' class bzmysql(bzaccess):' | |||
|
565 | 567 | try: |
|
566 | 568 | userid = int(user) |
|
567 | 569 | except ValueError: |
|
568 | self.ui.note(_('looking up user %s\n') % user) | |
|
570 | self.ui.note(_(b'looking up user %s\n') % user) | |
|
569 | 571 | self.run( |
|
570 | 572 | '''select userid from profiles |
|
571 | 573 | where login_name like %s''', |
@@ -587,16 +589,16 b' class bzmysql(bzaccess):' | |||
|
587 | 589 | userid = self.get_user_id(user) |
|
588 | 590 | except KeyError: |
|
589 | 591 | try: |
|
590 | defaultuser = self.ui.config('bugzilla', 'bzuser') | |
|
592 | defaultuser = self.ui.config(b'bugzilla', b'bzuser') | |
|
591 | 593 | if not defaultuser: |
|
592 | 594 | raise error.Abort( |
|
593 | _('cannot find bugzilla user id for %s') % user | |
|
595 | _(b'cannot find bugzilla user id for %s') % user | |
|
594 | 596 | ) |
|
595 | 597 | userid = self.get_user_id(defaultuser) |
|
596 | 598 | user = defaultuser |
|
597 | 599 | except KeyError: |
|
598 | 600 | raise error.Abort( |
|
599 | _('cannot find bugzilla user id for %s or %s') | |
|
601 | _(b'cannot find bugzilla user id for %s or %s') | |
|
600 | 602 | % (user, defaultuser) |
|
601 | 603 | ) |
|
602 | 604 | return (user, userid) |
@@ -607,7 +609,7 b' class bzmysql(bzaccess):' | |||
|
607 | 609 | Try adding comment as committer of changeset, otherwise as |
|
608 | 610 | default bugzilla user.''' |
|
609 | 611 | if len(newstate) > 0: |
|
610 | self.ui.warn(_("Bugzilla/MySQL cannot update bug state\n")) | |
|
612 | self.ui.warn(_(b"Bugzilla/MySQL cannot update bug state\n")) | |
|
611 | 613 | |
|
612 | 614 | (user, userid) = self.get_bugzilla_user(committer) |
|
613 | 615 | now = time.strftime(r'%Y-%m-%d %H:%M:%S') |
@@ -631,7 +633,7 b' class bzmysql_2_18(bzmysql):' | |||
|
631 | 633 | def __init__(self, ui): |
|
632 | 634 | bzmysql.__init__(self, ui) |
|
633 | 635 | self.default_notify = ( |
|
634 | "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" | |
|
636 | b"cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" | |
|
635 | 637 | ) |
|
636 | 638 | |
|
637 | 639 | |
@@ -643,10 +645,10 b' class bzmysql_3_0(bzmysql_2_18):' | |||
|
643 | 645 | |
|
644 | 646 | def get_longdesc_id(self): |
|
645 | 647 | '''get identity of longdesc field''' |
|
646 | self.run('select id from fielddefs where name = "longdesc"') | |
|
648 | self.run(b'select id from fielddefs where name = "longdesc"') | |
|
647 | 649 | ids = self.cursor.fetchall() |
|
648 | 650 | if len(ids) != 1: |
|
649 | raise error.Abort(_('unknown database schema')) | |
|
651 | raise error.Abort(_(b'unknown database schema')) | |
|
650 | 652 | return ids[0][0] |
|
651 | 653 | |
|
652 | 654 | |
@@ -674,7 +676,7 b' class cookietransportrequest(object):' | |||
|
674 | 676 | def send_cookies(self, connection): |
|
675 | 677 | if self.cookies: |
|
676 | 678 | for cookie in self.cookies: |
|
677 | connection.putheader("Cookie", cookie) | |
|
679 | connection.putheader(b"Cookie", cookie) | |
|
678 | 680 | |
|
679 | 681 | def request(self, host, handler, request_body, verbose=0): |
|
680 | 682 | self.verbose = verbose |
@@ -702,9 +704,9 b' class cookietransportrequest(object):' | |||
|
702 | 704 | response = h._conn.getresponse() |
|
703 | 705 | |
|
704 | 706 | # Add any cookie definitions to our list. |
|
705 | for header in response.msg.getallmatchingheaders("Set-Cookie"): | |
|
706 | val = header.split(": ", 1)[1] | |
|
707 | cookie = val.split(";", 1)[0] | |
|
707 | for header in response.msg.getallmatchingheaders(b"Set-Cookie"): | |
|
708 | val = header.split(b": ", 1)[1] | |
|
709 | cookie = val.split(b";", 1)[0] | |
|
708 | 710 | self.cookies.append(cookie) |
|
709 | 711 | |
|
710 | 712 | if response.status != 200: |
@@ -729,13 +731,13 b' class cookietransportrequest(object):' | |||
|
729 | 731 | # inheritance with a new-style class. |
|
730 | 732 | class cookietransport(cookietransportrequest, xmlrpclib.Transport): |
|
731 | 733 | def __init__(self, use_datetime=0): |
|
732 | if util.safehasattr(xmlrpclib.Transport, "__init__"): | |
|
734 | if util.safehasattr(xmlrpclib.Transport, b"__init__"): | |
|
733 | 735 | xmlrpclib.Transport.__init__(self, use_datetime) |
|
734 | 736 | |
|
735 | 737 | |
|
736 | 738 | class cookiesafetransport(cookietransportrequest, xmlrpclib.SafeTransport): |
|
737 | 739 | def __init__(self, use_datetime=0): |
|
738 | if util.safehasattr(xmlrpclib.Transport, "__init__"): | |
|
740 | if util.safehasattr(xmlrpclib.Transport, b"__init__"): | |
|
739 | 741 | xmlrpclib.SafeTransport.__init__(self, use_datetime) |
|
740 | 742 | |
|
741 | 743 | |
@@ -748,26 +750,26 b' class bzxmlrpc(bzaccess):' | |||
|
748 | 750 | def __init__(self, ui): |
|
749 | 751 | bzaccess.__init__(self, ui) |
|
750 | 752 | |
|
751 | bzweb = self.ui.config('bugzilla', 'bzurl') | |
|
752 | bzweb = bzweb.rstrip("/") + "/xmlrpc.cgi" | |
|
753 | bzweb = self.ui.config(b'bugzilla', b'bzurl') | |
|
754 | bzweb = bzweb.rstrip(b"/") + b"/xmlrpc.cgi" | |
|
753 | 755 | |
|
754 | user = self.ui.config('bugzilla', 'user') | |
|
755 | passwd = self.ui.config('bugzilla', 'password') | |
|
756 | user = self.ui.config(b'bugzilla', b'user') | |
|
757 | passwd = self.ui.config(b'bugzilla', b'password') | |
|
756 | 758 | |
|
757 | self.fixstatus = self.ui.config('bugzilla', 'fixstatus') | |
|
758 | self.fixresolution = self.ui.config('bugzilla', 'fixresolution') | |
|
759 | self.fixstatus = self.ui.config(b'bugzilla', b'fixstatus') | |
|
760 | self.fixresolution = self.ui.config(b'bugzilla', b'fixresolution') | |
|
759 | 761 | |
|
760 | 762 | self.bzproxy = xmlrpclib.ServerProxy(bzweb, self.transport(bzweb)) |
|
761 | ver = self.bzproxy.Bugzilla.version()['version'].split('.') | |
|
763 | ver = self.bzproxy.Bugzilla.version()[b'version'].split(b'.') | |
|
762 | 764 | self.bzvermajor = int(ver[0]) |
|
763 | 765 | self.bzverminor = int(ver[1]) |
|
764 | 766 | login = self.bzproxy.User.login( |
|
765 | {'login': user, 'password': passwd, 'restrict_login': True} | |
|
767 | {b'login': user, b'password': passwd, b'restrict_login': True} | |
|
766 | 768 | ) |
|
767 | self.bztoken = login.get('token', '') | |
|
769 | self.bztoken = login.get(b'token', b'') | |
|
768 | 770 | |
|
769 | 771 | def transport(self, uri): |
|
770 | if util.urlreq.urlparse(uri, "http")[0] == "https": | |
|
772 | if util.urlreq.urlparse(uri, b"http")[0] == b"https": | |
|
771 | 773 | return cookiesafetransport() |
|
772 | 774 | else: |
|
773 | 775 | return cookietransport() |
@@ -775,56 +777,58 b' class bzxmlrpc(bzaccess):' | |||
|
775 | 777 | def get_bug_comments(self, id): |
|
776 | 778 | """Return a string with all comment text for a bug.""" |
|
777 | 779 | c = self.bzproxy.Bug.comments( |
|
778 | {'ids': [id], 'include_fields': ['text'], 'token': self.bztoken} | |
|
780 | {b'ids': [id], b'include_fields': [b'text'], b'token': self.bztoken} | |
|
779 | 781 | ) |
|
780 | return ''.join([t['text'] for t in c['bugs']['%d' % id]['comments']]) | |
|
782 | return b''.join( | |
|
783 | [t[b'text'] for t in c[b'bugs'][b'%d' % id][b'comments']] | |
|
784 | ) | |
|
781 | 785 | |
|
782 | 786 | def filter_real_bug_ids(self, bugs): |
|
783 | 787 | probe = self.bzproxy.Bug.get( |
|
784 | 788 | { |
|
785 | 'ids': sorted(bugs.keys()), | |
|
786 | 'include_fields': [], | |
|
787 | 'permissive': True, | |
|
788 | 'token': self.bztoken, | |
|
789 | b'ids': sorted(bugs.keys()), | |
|
790 | b'include_fields': [], | |
|
791 | b'permissive': True, | |
|
792 | b'token': self.bztoken, | |
|
789 | 793 | } |
|
790 | 794 | ) |
|
791 | for badbug in probe['faults']: | |
|
792 | id = badbug['id'] | |
|
793 | self.ui.status(_('bug %d does not exist\n') % id) | |
|
795 | for badbug in probe[b'faults']: | |
|
796 | id = badbug[b'id'] | |
|
797 | self.ui.status(_(b'bug %d does not exist\n') % id) | |
|
794 | 798 | del bugs[id] |
|
795 | 799 | |
|
796 | 800 | def filter_cset_known_bug_ids(self, node, bugs): |
|
797 | 801 | for id in sorted(bugs.keys()): |
|
798 | 802 | if self.get_bug_comments(id).find(short(node)) != -1: |
|
799 | 803 | self.ui.status( |
|
800 | _('bug %d already knows about changeset %s\n') | |
|
804 | _(b'bug %d already knows about changeset %s\n') | |
|
801 | 805 | % (id, short(node)) |
|
802 | 806 | ) |
|
803 | 807 | del bugs[id] |
|
804 | 808 | |
|
805 | 809 | def updatebug(self, bugid, newstate, text, committer): |
|
806 | 810 | args = {} |
|
807 | if 'hours' in newstate: | |
|
808 | args['work_time'] = newstate['hours'] | |
|
811 | if b'hours' in newstate: | |
|
812 | args[b'work_time'] = newstate[b'hours'] | |
|
809 | 813 | |
|
810 | 814 | if self.bzvermajor >= 4: |
|
811 | args['ids'] = [bugid] | |
|
812 | args['comment'] = {'body': text} | |
|
813 | if 'fix' in newstate: | |
|
814 | args['status'] = self.fixstatus | |
|
815 | args['resolution'] = self.fixresolution | |
|
816 | args['token'] = self.bztoken | |
|
815 | args[b'ids'] = [bugid] | |
|
816 | args[b'comment'] = {b'body': text} | |
|
817 | if b'fix' in newstate: | |
|
818 | args[b'status'] = self.fixstatus | |
|
819 | args[b'resolution'] = self.fixresolution | |
|
820 | args[b'token'] = self.bztoken | |
|
817 | 821 | self.bzproxy.Bug.update(args) |
|
818 | 822 | else: |
|
819 | if 'fix' in newstate: | |
|
823 | if b'fix' in newstate: | |
|
820 | 824 | self.ui.warn( |
|
821 | 825 | _( |
|
822 | "Bugzilla/XMLRPC needs Bugzilla 4.0 or later " | |
|
823 | "to mark bugs fixed\n" | |
|
826 | b"Bugzilla/XMLRPC needs Bugzilla 4.0 or later " | |
|
827 | b"to mark bugs fixed\n" | |
|
824 | 828 | ) |
|
825 | 829 | ) |
|
826 | args['id'] = bugid | |
|
827 | args['comment'] = text | |
|
830 | args[b'id'] = bugid | |
|
831 | args[b'comment'] = text | |
|
828 | 832 | self.bzproxy.Bug.add_comment(args) |
|
829 | 833 | |
|
830 | 834 | |
@@ -851,18 +855,18 b' class bzxmlrpcemail(bzxmlrpc):' | |||
|
851 | 855 | def __init__(self, ui): |
|
852 | 856 | bzxmlrpc.__init__(self, ui) |
|
853 | 857 | |
|
854 | self.bzemail = self.ui.config('bugzilla', 'bzemail') | |
|
858 | self.bzemail = self.ui.config(b'bugzilla', b'bzemail') | |
|
855 | 859 | if not self.bzemail: |
|
856 | raise error.Abort(_("configuration 'bzemail' missing")) | |
|
860 | raise error.Abort(_(b"configuration 'bzemail' missing")) | |
|
857 | 861 | mail.validateconfig(self.ui) |
|
858 | 862 | |
|
859 | 863 | def makecommandline(self, fieldname, value): |
|
860 | 864 | if self.bzvermajor >= 4: |
|
861 | return "@%s %s" % (fieldname, pycompat.bytestr(value)) | |
|
865 | return b"@%s %s" % (fieldname, pycompat.bytestr(value)) | |
|
862 | 866 | else: |
|
863 | if fieldname == "id": | |
|
864 | fieldname = "bug_id" | |
|
865 | return "@%s = %s" % (fieldname, pycompat.bytestr(value)) | |
|
867 | if fieldname == b"id": | |
|
868 | fieldname = b"bug_id" | |
|
869 | return b"@%s = %s" % (fieldname, pycompat.bytestr(value)) | |
|
866 | 870 | |
|
867 | 871 | def send_bug_modify_email(self, bugid, commands, comment, committer): |
|
868 | 872 | '''send modification message to Bugzilla bug via email. |
@@ -877,39 +881,41 b' class bzxmlrpcemail(bzxmlrpc):' | |||
|
877 | 881 | ''' |
|
878 | 882 | user = self.map_committer(committer) |
|
879 | 883 | matches = self.bzproxy.User.get( |
|
880 | {'match': [user], 'token': self.bztoken} | |
|
884 | {b'match': [user], b'token': self.bztoken} | |
|
881 | 885 | ) |
|
882 | if not matches['users']: | |
|
883 | user = self.ui.config('bugzilla', 'user') | |
|
886 | if not matches[b'users']: | |
|
887 | user = self.ui.config(b'bugzilla', b'user') | |
|
884 | 888 | matches = self.bzproxy.User.get( |
|
885 | {'match': [user], 'token': self.bztoken} | |
|
889 | {b'match': [user], b'token': self.bztoken} | |
|
886 | 890 | ) |
|
887 | if not matches['users']: | |
|
891 | if not matches[b'users']: | |
|
888 | 892 | raise error.Abort( |
|
889 | _("default bugzilla user %s email not found") % user | |
|
893 | _(b"default bugzilla user %s email not found") % user | |
|
890 | 894 | ) |
|
891 | user = matches['users'][0]['email'] | |
|
892 | commands.append(self.makecommandline("id", bugid)) | |
|
895 | user = matches[b'users'][0][b'email'] | |
|
896 | commands.append(self.makecommandline(b"id", bugid)) | |
|
893 | 897 | |
|
894 | text = "\n".join(commands) + "\n\n" + comment | |
|
898 | text = b"\n".join(commands) + b"\n\n" + comment | |
|
895 | 899 | |
|
896 | 900 | _charsets = mail._charsets(self.ui) |
|
897 | 901 | user = mail.addressencode(self.ui, user, _charsets) |
|
898 | 902 | bzemail = mail.addressencode(self.ui, self.bzemail, _charsets) |
|
899 | 903 | msg = mail.mimeencode(self.ui, text, _charsets) |
|
900 | msg['From'] = user | |
|
901 | msg['To'] = bzemail | |
|
902 |
msg['Subject'] = mail.headencode( |
|
|
904 | msg[b'From'] = user | |
|
905 | msg[b'To'] = bzemail | |
|
906 | msg[b'Subject'] = mail.headencode( | |
|
907 | self.ui, b"Bug modification", _charsets | |
|
908 | ) | |
|
903 | 909 | sendmail = mail.connect(self.ui) |
|
904 | 910 | sendmail(user, bzemail, msg.as_string()) |
|
905 | 911 | |
|
906 | 912 | def updatebug(self, bugid, newstate, text, committer): |
|
907 | 913 | cmds = [] |
|
908 | if 'hours' in newstate: | |
|
909 | cmds.append(self.makecommandline("work_time", newstate['hours'])) | |
|
910 | if 'fix' in newstate: | |
|
911 | cmds.append(self.makecommandline("bug_status", self.fixstatus)) | |
|
912 | cmds.append(self.makecommandline("resolution", self.fixresolution)) | |
|
914 | if b'hours' in newstate: | |
|
915 | cmds.append(self.makecommandline(b"work_time", newstate[b'hours'])) | |
|
916 | if b'fix' in newstate: | |
|
917 | cmds.append(self.makecommandline(b"bug_status", self.fixstatus)) | |
|
918 | cmds.append(self.makecommandline(b"resolution", self.fixresolution)) | |
|
913 | 919 | self.send_bug_modify_email(bugid, cmds, text, committer) |
|
914 | 920 | |
|
915 | 921 | |
@@ -924,26 +930,26 b' class bzrestapi(bzaccess):' | |||
|
924 | 930 | |
|
925 | 931 | def __init__(self, ui): |
|
926 | 932 | bzaccess.__init__(self, ui) |
|
927 | bz = self.ui.config('bugzilla', 'bzurl') | |
|
928 | self.bzroot = '/'.join([bz, 'rest']) | |
|
929 | self.apikey = self.ui.config('bugzilla', 'apikey') | |
|
930 | self.user = self.ui.config('bugzilla', 'user') | |
|
931 | self.passwd = self.ui.config('bugzilla', 'password') | |
|
932 | self.fixstatus = self.ui.config('bugzilla', 'fixstatus') | |
|
933 | self.fixresolution = self.ui.config('bugzilla', 'fixresolution') | |
|
933 | bz = self.ui.config(b'bugzilla', b'bzurl') | |
|
934 | self.bzroot = b'/'.join([bz, b'rest']) | |
|
935 | self.apikey = self.ui.config(b'bugzilla', b'apikey') | |
|
936 | self.user = self.ui.config(b'bugzilla', b'user') | |
|
937 | self.passwd = self.ui.config(b'bugzilla', b'password') | |
|
938 | self.fixstatus = self.ui.config(b'bugzilla', b'fixstatus') | |
|
939 | self.fixresolution = self.ui.config(b'bugzilla', b'fixresolution') | |
|
934 | 940 | |
|
935 | 941 | def apiurl(self, targets, include_fields=None): |
|
936 | url = '/'.join([self.bzroot] + [pycompat.bytestr(t) for t in targets]) | |
|
942 | url = b'/'.join([self.bzroot] + [pycompat.bytestr(t) for t in targets]) | |
|
937 | 943 | qv = {} |
|
938 | 944 | if self.apikey: |
|
939 | qv['api_key'] = self.apikey | |
|
945 | qv[b'api_key'] = self.apikey | |
|
940 | 946 | elif self.user and self.passwd: |
|
941 | qv['login'] = self.user | |
|
942 | qv['password'] = self.passwd | |
|
947 | qv[b'login'] = self.user | |
|
948 | qv[b'password'] = self.passwd | |
|
943 | 949 | if include_fields: |
|
944 | qv['include_fields'] = include_fields | |
|
950 | qv[b'include_fields'] = include_fields | |
|
945 | 951 | if qv: |
|
946 | url = '%s?%s' % (url, util.urlreq.urlencode(qv)) | |
|
952 | url = b'%s?%s' % (url, util.urlreq.urlencode(qv)) | |
|
947 | 953 | return url |
|
948 | 954 | |
|
949 | 955 | def _fetch(self, burl): |
@@ -952,30 +958,30 b' class bzrestapi(bzaccess):' | |||
|
952 | 958 | return json.loads(resp.read()) |
|
953 | 959 | except util.urlerr.httperror as inst: |
|
954 | 960 | if inst.code == 401: |
|
955 | raise error.Abort(_('authorization failed')) | |
|
961 | raise error.Abort(_(b'authorization failed')) | |
|
956 | 962 | if inst.code == 404: |
|
957 | 963 | raise NotFound() |
|
958 | 964 | else: |
|
959 | 965 | raise |
|
960 | 966 | |
|
961 | def _submit(self, burl, data, method='POST'): | |
|
967 | def _submit(self, burl, data, method=b'POST'): | |
|
962 | 968 | data = json.dumps(data) |
|
963 | if method == 'PUT': | |
|
969 | if method == b'PUT': | |
|
964 | 970 | |
|
965 | 971 | class putrequest(util.urlreq.request): |
|
966 | 972 | def get_method(self): |
|
967 | return 'PUT' | |
|
973 | return b'PUT' | |
|
968 | 974 | |
|
969 | 975 | request_type = putrequest |
|
970 | 976 | else: |
|
971 | 977 | request_type = util.urlreq.request |
|
972 | req = request_type(burl, data, {'Content-Type': 'application/json'}) | |
|
978 | req = request_type(burl, data, {b'Content-Type': b'application/json'}) | |
|
973 | 979 | try: |
|
974 | 980 | resp = url.opener(self.ui).open(req) |
|
975 | 981 | return json.loads(resp.read()) |
|
976 | 982 | except util.urlerr.httperror as inst: |
|
977 | 983 | if inst.code == 401: |
|
978 | raise error.Abort(_('authorization failed')) | |
|
984 | raise error.Abort(_(b'authorization failed')) | |
|
979 | 985 | if inst.code == 404: |
|
980 | 986 | raise NotFound() |
|
981 | 987 | else: |
@@ -985,7 +991,7 b' class bzrestapi(bzaccess):' | |||
|
985 | 991 | '''remove bug IDs that do not exist in Bugzilla from bugs.''' |
|
986 | 992 | badbugs = set() |
|
987 | 993 | for bugid in bugs: |
|
988 | burl = self.apiurl(('bug', bugid), include_fields='status') | |
|
994 | burl = self.apiurl((b'bug', bugid), include_fields=b'status') | |
|
989 | 995 | try: |
|
990 | 996 | self._fetch(burl) |
|
991 | 997 | except NotFound: |
@@ -997,12 +1003,15 b' class bzrestapi(bzaccess):' | |||
|
997 | 1003 | '''remove bug IDs where node occurs in comment text from bugs.''' |
|
998 | 1004 | sn = short(node) |
|
999 | 1005 | for bugid in bugs.keys(): |
|
1000 | burl = self.apiurl(('bug', bugid, 'comment'), include_fields='text') | |
|
1006 | burl = self.apiurl( | |
|
1007 | (b'bug', bugid, b'comment'), include_fields=b'text' | |
|
1008 | ) | |
|
1001 | 1009 | result = self._fetch(burl) |
|
1002 | comments = result['bugs'][pycompat.bytestr(bugid)]['comments'] | |
|
1003 | if any(sn in c['text'] for c in comments): | |
|
1010 | comments = result[b'bugs'][pycompat.bytestr(bugid)][b'comments'] | |
|
1011 | if any(sn in c[b'text'] for c in comments): | |
|
1004 | 1012 | self.ui.status( |
|
1005 |
_('bug %d already knows about changeset %s\n') |
|
|
1013 | _(b'bug %d already knows about changeset %s\n') | |
|
1014 | % (bugid, sn) | |
|
1006 | 1015 | ) |
|
1007 | 1016 | del bugs[bugid] |
|
1008 | 1017 | |
@@ -1013,28 +1022,32 b' class bzrestapi(bzaccess):' | |||
|
1013 | 1022 | the changeset. Otherwise use the default Bugzilla user. |
|
1014 | 1023 | ''' |
|
1015 | 1024 | bugmod = {} |
|
1016 | if 'hours' in newstate: | |
|
1017 | bugmod['work_time'] = newstate['hours'] | |
|
1018 | if 'fix' in newstate: | |
|
1019 | bugmod['status'] = self.fixstatus | |
|
1020 | bugmod['resolution'] = self.fixresolution | |
|
1025 | if b'hours' in newstate: | |
|
1026 | bugmod[b'work_time'] = newstate[b'hours'] | |
|
1027 | if b'fix' in newstate: | |
|
1028 | bugmod[b'status'] = self.fixstatus | |
|
1029 | bugmod[b'resolution'] = self.fixresolution | |
|
1021 | 1030 | if bugmod: |
|
1022 | 1031 | # if we have to change the bugs state do it here |
|
1023 | bugmod['comment'] = { | |
|
1024 | 'comment': text, | |
|
1025 | 'is_private': False, | |
|
1026 | 'is_markdown': False, | |
|
1032 | bugmod[b'comment'] = { | |
|
1033 | b'comment': text, | |
|
1034 | b'is_private': False, | |
|
1035 | b'is_markdown': False, | |
|
1027 | 1036 | } |
|
1028 | burl = self.apiurl(('bug', bugid)) | |
|
1029 | self._submit(burl, bugmod, method='PUT') | |
|
1030 | self.ui.debug('updated bug %s\n' % bugid) | |
|
1037 | burl = self.apiurl((b'bug', bugid)) | |
|
1038 | self._submit(burl, bugmod, method=b'PUT') | |
|
1039 | self.ui.debug(b'updated bug %s\n' % bugid) | |
|
1031 | 1040 | else: |
|
1032 | burl = self.apiurl(('bug', bugid, 'comment')) | |
|
1041 | burl = self.apiurl((b'bug', bugid, b'comment')) | |
|
1033 | 1042 | self._submit( |
|
1034 | 1043 | burl, |
|
1035 | {'comment': text, 'is_private': False, 'is_markdown': False,}, | |
|
1044 | { | |
|
1045 | b'comment': text, | |
|
1046 | b'is_private': False, | |
|
1047 | b'is_markdown': False, | |
|
1048 | }, | |
|
1036 | 1049 | ) |
|
1037 | self.ui.debug('added comment to bug %s\n' % bugid) | |
|
1050 | self.ui.debug(b'added comment to bug %s\n' % bugid) | |
|
1038 | 1051 | |
|
1039 | 1052 | def notify(self, bugs, committer): |
|
1040 | 1053 | '''Force sending of Bugzilla notification emails. |
@@ -1049,32 +1062,32 b' class bugzilla(object):' | |||
|
1049 | 1062 | # supported versions of bugzilla. different versions have |
|
1050 | 1063 | # different schemas. |
|
1051 | 1064 | _versions = { |
|
1052 | '2.16': bzmysql, | |
|
1053 | '2.18': bzmysql_2_18, | |
|
1054 | '3.0': bzmysql_3_0, | |
|
1055 | 'xmlrpc': bzxmlrpc, | |
|
1056 | 'xmlrpc+email': bzxmlrpcemail, | |
|
1057 | 'restapi': bzrestapi, | |
|
1065 | b'2.16': bzmysql, | |
|
1066 | b'2.18': bzmysql_2_18, | |
|
1067 | b'3.0': bzmysql_3_0, | |
|
1068 | b'xmlrpc': bzxmlrpc, | |
|
1069 | b'xmlrpc+email': bzxmlrpcemail, | |
|
1070 | b'restapi': bzrestapi, | |
|
1058 | 1071 | } |
|
1059 | 1072 | |
|
1060 | 1073 | def __init__(self, ui, repo): |
|
1061 | 1074 | self.ui = ui |
|
1062 | 1075 | self.repo = repo |
|
1063 | 1076 | |
|
1064 | bzversion = self.ui.config('bugzilla', 'version') | |
|
1077 | bzversion = self.ui.config(b'bugzilla', b'version') | |
|
1065 | 1078 | try: |
|
1066 | 1079 | bzclass = bugzilla._versions[bzversion] |
|
1067 | 1080 | except KeyError: |
|
1068 | 1081 | raise error.Abort( |
|
1069 | _('bugzilla version %s not supported') % bzversion | |
|
1082 | _(b'bugzilla version %s not supported') % bzversion | |
|
1070 | 1083 | ) |
|
1071 | 1084 | self.bzdriver = bzclass(self.ui) |
|
1072 | 1085 | |
|
1073 | 1086 | self.bug_re = re.compile( |
|
1074 | self.ui.config('bugzilla', 'regexp'), re.IGNORECASE | |
|
1087 | self.ui.config(b'bugzilla', b'regexp'), re.IGNORECASE | |
|
1075 | 1088 | ) |
|
1076 | 1089 | self.fix_re = re.compile( |
|
1077 | self.ui.config('bugzilla', 'fixregexp'), re.IGNORECASE | |
|
1090 | self.ui.config(b'bugzilla', b'fixregexp'), re.IGNORECASE | |
|
1078 | 1091 | ) |
|
1079 | 1092 | self.split_re = re.compile(br'\D+') |
|
1080 | 1093 | |
@@ -1106,25 +1119,25 b' class bugzilla(object):' | |||
|
1106 | 1119 | start = m.end() |
|
1107 | 1120 | if m is bugmatch: |
|
1108 | 1121 | bugmatch = self.bug_re.search(ctx.description(), start) |
|
1109 | if 'fix' in bugattribs: | |
|
1110 | del bugattribs['fix'] | |
|
1122 | if b'fix' in bugattribs: | |
|
1123 | del bugattribs[b'fix'] | |
|
1111 | 1124 | else: |
|
1112 | 1125 | fixmatch = self.fix_re.search(ctx.description(), start) |
|
1113 | bugattribs['fix'] = None | |
|
1126 | bugattribs[b'fix'] = None | |
|
1114 | 1127 | |
|
1115 | 1128 | try: |
|
1116 | ids = m.group('ids') | |
|
1129 | ids = m.group(b'ids') | |
|
1117 | 1130 | except IndexError: |
|
1118 | 1131 | ids = m.group(1) |
|
1119 | 1132 | try: |
|
1120 | hours = float(m.group('hours')) | |
|
1121 | bugattribs['hours'] = hours | |
|
1133 | hours = float(m.group(b'hours')) | |
|
1134 | bugattribs[b'hours'] = hours | |
|
1122 | 1135 | except IndexError: |
|
1123 | 1136 | pass |
|
1124 | 1137 | except TypeError: |
|
1125 | 1138 | pass |
|
1126 | 1139 | except ValueError: |
|
1127 | self.ui.status(_("%s: invalid hours\n") % m.group('hours')) | |
|
1140 | self.ui.status(_(b"%s: invalid hours\n") % m.group(b'hours')) | |
|
1128 | 1141 | |
|
1129 | 1142 | for id in self.split_re.split(ids): |
|
1130 | 1143 | if not id: |
@@ -1142,10 +1155,10 b' class bugzilla(object):' | |||
|
1142 | 1155 | def webroot(root): |
|
1143 | 1156 | '''strip leading prefix of repo root and turn into |
|
1144 | 1157 | url-safe path.''' |
|
1145 | count = int(self.ui.config('bugzilla', 'strip')) | |
|
1158 | count = int(self.ui.config(b'bugzilla', b'strip')) | |
|
1146 | 1159 | root = util.pconvert(root) |
|
1147 | 1160 | while count > 0: |
|
1148 | c = root.find('/') | |
|
1161 | c = root.find(b'/') | |
|
1149 | 1162 | if c == -1: |
|
1150 | 1163 | break |
|
1151 | 1164 | root = root[c + 1 :] |
@@ -1153,13 +1166,13 b' class bugzilla(object):' | |||
|
1153 | 1166 | return root |
|
1154 | 1167 | |
|
1155 | 1168 | mapfile = None |
|
1156 | tmpl = self.ui.config('bugzilla', 'template') | |
|
1169 | tmpl = self.ui.config(b'bugzilla', b'template') | |
|
1157 | 1170 | if not tmpl: |
|
1158 | mapfile = self.ui.config('bugzilla', 'style') | |
|
1171 | mapfile = self.ui.config(b'bugzilla', b'style') | |
|
1159 | 1172 | if not mapfile and not tmpl: |
|
1160 | 1173 | tmpl = _( |
|
1161 | 'changeset {node|short} in repo {root} refers ' | |
|
1162 | 'to bug {bug}.\ndetails:\n\t{desc|tabindent}' | |
|
1174 | b'changeset {node|short} in repo {root} refers ' | |
|
1175 | b'to bug {bug}.\ndetails:\n\t{desc|tabindent}' | |
|
1163 | 1176 | ) |
|
1164 | 1177 | spec = logcmdutil.templatespec(tmpl, mapfile) |
|
1165 | 1178 | t = logcmdutil.changesettemplater(self.ui, self.repo, spec) |
@@ -1168,7 +1181,7 b' class bugzilla(object):' | |||
|
1168 | 1181 | ctx, |
|
1169 | 1182 | changes=ctx.changeset(), |
|
1170 | 1183 | bug=pycompat.bytestr(bugid), |
|
1171 | hgweb=self.ui.config('web', 'baseurl'), | |
|
1184 | hgweb=self.ui.config(b'web', b'baseurl'), | |
|
1172 | 1185 | root=self.repo.root, |
|
1173 | 1186 | webroot=webroot(self.repo.root), |
|
1174 | 1187 | ) |
@@ -1188,7 +1201,7 b' def hook(ui, repo, hooktype, node=None, ' | |||
|
1188 | 1201 | seen multiple times does not fill bug with duplicate data.''' |
|
1189 | 1202 | if node is None: |
|
1190 | 1203 | raise error.Abort( |
|
1191 | _('hook type %s does not pass a changeset id') % hooktype | |
|
1204 | _(b'hook type %s does not pass a changeset id') % hooktype | |
|
1192 | 1205 | ) |
|
1193 | 1206 | try: |
|
1194 | 1207 | bz = bugzilla(ui, repo) |
@@ -1199,4 +1212,4 b' def hook(ui, repo, hooktype, node=None, ' | |||
|
1199 | 1212 | bz.update(bug, bugs[bug], ctx) |
|
1200 | 1213 | bz.notify(bugs, stringutil.email(ctx.user())) |
|
1201 | 1214 | except Exception as e: |
|
1202 | raise error.Abort(_('Bugzilla error: %s') % e) | |
|
1215 | raise error.Abort(_(b'Bugzilla error: %s') % e) |
@@ -42,49 +42,55 b' command = registrar.command(cmdtable)' | |||
|
42 | 42 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
43 | 43 | # be specifying the version(s) of Mercurial they are tested with, or |
|
44 | 44 | # leave the attribute unspecified. |
|
45 | testedwith = 'ships-with-hg-core' | |
|
45 | testedwith = b'ships-with-hg-core' | |
|
46 | 46 | |
|
47 | 47 | |
|
48 | 48 | @command( |
|
49 | 'censor', | |
|
49 | b'censor', | |
|
50 | 50 | [ |
|
51 | ('r', 'rev', '', _('censor file from specified revision'), _('REV')), | |
|
52 | ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT')), | |
|
51 | ( | |
|
52 | b'r', | |
|
53 | b'rev', | |
|
54 | b'', | |
|
55 | _(b'censor file from specified revision'), | |
|
56 | _(b'REV'), | |
|
57 | ), | |
|
58 | (b't', b'tombstone', b'', _(b'replacement tombstone data'), _(b'TEXT')), | |
|
53 | 59 | ], |
|
54 | _('-r REV [-t TEXT] [FILE]'), | |
|
60 | _(b'-r REV [-t TEXT] [FILE]'), | |
|
55 | 61 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
56 | 62 | ) |
|
57 | def censor(ui, repo, path, rev='', tombstone='', **opts): | |
|
63 | def censor(ui, repo, path, rev=b'', tombstone=b'', **opts): | |
|
58 | 64 | with repo.wlock(), repo.lock(): |
|
59 | 65 | return _docensor(ui, repo, path, rev, tombstone, **opts) |
|
60 | 66 | |
|
61 | 67 | |
|
62 | def _docensor(ui, repo, path, rev='', tombstone='', **opts): | |
|
68 | def _docensor(ui, repo, path, rev=b'', tombstone=b'', **opts): | |
|
63 | 69 | if not path: |
|
64 | raise error.Abort(_('must specify file path to censor')) | |
|
70 | raise error.Abort(_(b'must specify file path to censor')) | |
|
65 | 71 | if not rev: |
|
66 | raise error.Abort(_('must specify revision to censor')) | |
|
72 | raise error.Abort(_(b'must specify revision to censor')) | |
|
67 | 73 | |
|
68 | 74 | wctx = repo[None] |
|
69 | 75 | |
|
70 | 76 | m = scmutil.match(wctx, (path,)) |
|
71 | 77 | if m.anypats() or len(m.files()) != 1: |
|
72 | raise error.Abort(_('can only specify an explicit filename')) | |
|
78 | raise error.Abort(_(b'can only specify an explicit filename')) | |
|
73 | 79 | path = m.files()[0] |
|
74 | 80 | flog = repo.file(path) |
|
75 | 81 | if not len(flog): |
|
76 | raise error.Abort(_('cannot censor file with no history')) | |
|
82 | raise error.Abort(_(b'cannot censor file with no history')) | |
|
77 | 83 | |
|
78 | 84 | rev = scmutil.revsingle(repo, rev, rev).rev() |
|
79 | 85 | try: |
|
80 | 86 | ctx = repo[rev] |
|
81 | 87 | except KeyError: |
|
82 | raise error.Abort(_('invalid revision identifier %s') % rev) | |
|
88 | raise error.Abort(_(b'invalid revision identifier %s') % rev) | |
|
83 | 89 | |
|
84 | 90 | try: |
|
85 | 91 | fctx = ctx.filectx(path) |
|
86 | 92 | except error.LookupError: |
|
87 | raise error.Abort(_('file does not exist at revision %s') % rev) | |
|
93 | raise error.Abort(_(b'file does not exist at revision %s') % rev) | |
|
88 | 94 | |
|
89 | 95 | fnode = fctx.filenode() |
|
90 | 96 | heads = [] |
@@ -93,17 +99,17 b" def _docensor(ui, repo, path, rev='', to" | |||
|
93 | 99 | if path in hc and hc.filenode(path) == fnode: |
|
94 | 100 | heads.append(hc) |
|
95 | 101 | if heads: |
|
96 | headlist = ', '.join([short(c.node()) for c in heads]) | |
|
102 | headlist = b', '.join([short(c.node()) for c in heads]) | |
|
97 | 103 | raise error.Abort( |
|
98 | _('cannot censor file in heads (%s)') % headlist, | |
|
99 | hint=_('clean/delete and commit first'), | |
|
104 | _(b'cannot censor file in heads (%s)') % headlist, | |
|
105 | hint=_(b'clean/delete and commit first'), | |
|
100 | 106 | ) |
|
101 | 107 | |
|
102 | 108 | wp = wctx.parents() |
|
103 | 109 | if ctx.node() in [p.node() for p in wp]: |
|
104 | 110 | raise error.Abort( |
|
105 | _('cannot censor working directory'), | |
|
106 | hint=_('clean/delete/update first'), | |
|
111 | _(b'cannot censor working directory'), | |
|
112 | hint=_(b'clean/delete/update first'), | |
|
107 | 113 | ) |
|
108 | 114 | |
|
109 | 115 | with repo.transaction(b'censor') as tr: |
@@ -33,14 +33,22 b' command = registrar.command(cmdtable)' | |||
|
33 | 33 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
34 | 34 | # be specifying the version(s) of Mercurial they are tested with, or |
|
35 | 35 | # leave the attribute unspecified. |
|
36 | testedwith = 'ships-with-hg-core' | |
|
36 | testedwith = b'ships-with-hg-core' | |
|
37 | 37 | |
|
38 | 38 | |
|
39 | 39 | @command( |
|
40 | 'children', | |
|
41 | [('r', 'rev', '.', _('show children of the specified revision'), _('REV')),] | |
|
40 | b'children', | |
|
41 | [ | |
|
42 | ( | |
|
43 | b'r', | |
|
44 | b'rev', | |
|
45 | b'.', | |
|
46 | _(b'show children of the specified revision'), | |
|
47 | _(b'REV'), | |
|
48 | ), | |
|
49 | ] | |
|
42 | 50 | + templateopts, |
|
43 | _('hg children [-r REV] [FILE]'), | |
|
51 | _(b'hg children [-r REV] [FILE]'), | |
|
44 | 52 | helpcategory=command.CATEGORY_CHANGE_NAVIGATION, |
|
45 | 53 | inferrepo=True, |
|
46 | 54 | ) |
@@ -62,7 +70,7 b' def children(ui, repo, file_=None, **opt' | |||
|
62 | 70 | |
|
63 | 71 | """ |
|
64 | 72 | opts = pycompat.byteskwargs(opts) |
|
65 | rev = opts.get('rev') | |
|
73 | rev = opts.get(b'rev') | |
|
66 | 74 | ctx = scmutil.revsingle(repo, rev) |
|
67 | 75 | if file_: |
|
68 | 76 | fctx = repo.filectx(file_, changeid=ctx.rev()) |
@@ -32,17 +32,17 b' command = registrar.command(cmdtable)' | |||
|
32 | 32 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
33 | 33 | # be specifying the version(s) of Mercurial they are tested with, or |
|
34 | 34 | # leave the attribute unspecified. |
|
35 | testedwith = 'ships-with-hg-core' | |
|
35 | testedwith = b'ships-with-hg-core' | |
|
36 | 36 | |
|
37 | 37 | |
|
38 | 38 | def changedlines(ui, repo, ctx1, ctx2, fns): |
|
39 | 39 | added, removed = 0, 0 |
|
40 | 40 | fmatch = scmutil.matchfiles(repo, fns) |
|
41 | diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) | |
|
42 | for l in diff.split('\n'): | |
|
43 | if l.startswith("+") and not l.startswith("+++ "): | |
|
41 | diff = b''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) | |
|
42 | for l in diff.split(b'\n'): | |
|
43 | if l.startswith(b"+") and not l.startswith(b"+++ "): | |
|
44 | 44 | added += 1 |
|
45 | elif l.startswith("-") and not l.startswith("--- "): | |
|
45 | elif l.startswith(b"-") and not l.startswith(b"--- "): | |
|
46 | 46 | removed += 1 |
|
47 | 47 | return (added, removed) |
|
48 | 48 | |
@@ -50,17 +50,17 b' def changedlines(ui, repo, ctx1, ctx2, f' | |||
|
50 | 50 | def countrate(ui, repo, amap, *pats, **opts): |
|
51 | 51 | """Calculate stats""" |
|
52 | 52 | opts = pycompat.byteskwargs(opts) |
|
53 | if opts.get('dateformat'): | |
|
53 | if opts.get(b'dateformat'): | |
|
54 | 54 | |
|
55 | 55 | def getkey(ctx): |
|
56 | 56 | t, tz = ctx.date() |
|
57 | 57 | date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) |
|
58 | 58 | return encoding.strtolocal( |
|
59 | date.strftime(encoding.strfromlocal(opts['dateformat'])) | |
|
59 | date.strftime(encoding.strfromlocal(opts[b'dateformat'])) | |
|
60 | 60 | ) |
|
61 | 61 | |
|
62 | 62 | else: |
|
63 | tmpl = opts.get('oldtemplate') or opts.get('template') | |
|
63 | tmpl = opts.get(b'oldtemplate') or opts.get(b'template') | |
|
64 | 64 | tmpl = logcmdutil.maketemplater(ui, repo, tmpl) |
|
65 | 65 | |
|
66 | 66 | def getkey(ctx): |
@@ -69,12 +69,12 b' def countrate(ui, repo, amap, *pats, **o' | |||
|
69 | 69 | return ui.popbuffer() |
|
70 | 70 | |
|
71 | 71 | progress = ui.makeprogress( |
|
72 | _('analyzing'), unit=_('revisions'), total=len(repo) | |
|
72 | _(b'analyzing'), unit=_(b'revisions'), total=len(repo) | |
|
73 | 73 | ) |
|
74 | 74 | rate = {} |
|
75 | 75 | df = False |
|
76 | if opts.get('date'): | |
|
77 | df = dateutil.matchdate(opts['date']) | |
|
76 | if opts.get(b'date'): | |
|
77 | df = dateutil.matchdate(opts[b'date']) | |
|
78 | 78 | |
|
79 | 79 | m = scmutil.match(repo[None], pats, opts) |
|
80 | 80 | |
@@ -85,12 +85,12 b' def countrate(ui, repo, amap, *pats, **o' | |||
|
85 | 85 | |
|
86 | 86 | key = getkey(ctx).strip() |
|
87 | 87 | key = amap.get(key, key) # alias remap |
|
88 | if opts.get('changesets'): | |
|
88 | if opts.get(b'changesets'): | |
|
89 | 89 | rate[key] = (rate.get(key, (0,))[0] + 1, 0) |
|
90 | 90 | else: |
|
91 | 91 | parents = ctx.parents() |
|
92 | 92 | if len(parents) > 1: |
|
93 | ui.note(_('revision %d is a merge, ignoring...\n') % (rev,)) | |
|
93 | ui.note(_(b'revision %d is a merge, ignoring...\n') % (rev,)) | |
|
94 | 94 | return |
|
95 | 95 | |
|
96 | 96 | ctx1 = parents[0] |
@@ -108,50 +108,50 b' def countrate(ui, repo, amap, *pats, **o' | |||
|
108 | 108 | |
|
109 | 109 | |
|
110 | 110 | @command( |
|
111 | 'churn', | |
|
111 | b'churn', | |
|
112 | 112 | [ |
|
113 | 113 | ( |
|
114 | 'r', | |
|
115 | 'rev', | |
|
114 | b'r', | |
|
115 | b'rev', | |
|
116 | 116 | [], |
|
117 | _('count rate for the specified revision or revset'), | |
|
118 | _('REV'), | |
|
117 | _(b'count rate for the specified revision or revset'), | |
|
118 | _(b'REV'), | |
|
119 | 119 | ), |
|
120 | 120 | ( |
|
121 | 'd', | |
|
122 | 'date', | |
|
123 | '', | |
|
124 | _('count rate for revisions matching date spec'), | |
|
125 | _('DATE'), | |
|
121 | b'd', | |
|
122 | b'date', | |
|
123 | b'', | |
|
124 | _(b'count rate for revisions matching date spec'), | |
|
125 | _(b'DATE'), | |
|
126 | 126 | ), |
|
127 | 127 | ( |
|
128 | 't', | |
|
129 | 'oldtemplate', | |
|
130 | '', | |
|
131 | _('template to group changesets (DEPRECATED)'), | |
|
132 | _('TEMPLATE'), | |
|
128 | b't', | |
|
129 | b'oldtemplate', | |
|
130 | b'', | |
|
131 | _(b'template to group changesets (DEPRECATED)'), | |
|
132 | _(b'TEMPLATE'), | |
|
133 | 133 | ), |
|
134 | 134 | ( |
|
135 | 'T', | |
|
136 | 'template', | |
|
137 | '{author|email}', | |
|
138 | _('template to group changesets'), | |
|
139 | _('TEMPLATE'), | |
|
135 | b'T', | |
|
136 | b'template', | |
|
137 | b'{author|email}', | |
|
138 | _(b'template to group changesets'), | |
|
139 | _(b'TEMPLATE'), | |
|
140 | 140 | ), |
|
141 | 141 | ( |
|
142 | 'f', | |
|
143 | 'dateformat', | |
|
144 | '', | |
|
145 | _('strftime-compatible format for grouping by date'), | |
|
146 | _('FORMAT'), | |
|
142 | b'f', | |
|
143 | b'dateformat', | |
|
144 | b'', | |
|
145 | _(b'strftime-compatible format for grouping by date'), | |
|
146 | _(b'FORMAT'), | |
|
147 | 147 | ), |
|
148 | ('c', 'changesets', False, _('count rate by number of changesets')), | |
|
149 | ('s', 'sort', False, _('sort by key (default: sort by count)')), | |
|
150 | ('', 'diffstat', False, _('display added/removed lines separately')), | |
|
151 | ('', 'aliases', '', _('file with email aliases'), _('FILE')), | |
|
148 | (b'c', b'changesets', False, _(b'count rate by number of changesets')), | |
|
149 | (b's', b'sort', False, _(b'sort by key (default: sort by count)')), | |
|
150 | (b'', b'diffstat', False, _(b'display added/removed lines separately')), | |
|
151 | (b'', b'aliases', b'', _(b'file with email aliases'), _(b'FILE')), | |
|
152 | 152 | ] |
|
153 | 153 | + cmdutil.walkopts, |
|
154 | _("hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]"), | |
|
154 | _(b"hg churn [-d DATE] [-r REV] [--aliases FILE] [FILE]"), | |
|
155 | 155 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
156 | 156 | inferrepo=True, |
|
157 | 157 | ) |
@@ -193,21 +193,21 b' def churn(ui, repo, *pats, **opts):' | |||
|
193 | 193 | ''' |
|
194 | 194 | |
|
195 | 195 | def pad(s, l): |
|
196 | return s + " " * (l - encoding.colwidth(s)) | |
|
196 | return s + b" " * (l - encoding.colwidth(s)) | |
|
197 | 197 | |
|
198 | 198 | amap = {} |
|
199 | 199 | aliases = opts.get(r'aliases') |
|
200 | if not aliases and os.path.exists(repo.wjoin('.hgchurn')): | |
|
201 | aliases = repo.wjoin('.hgchurn') | |
|
200 | if not aliases and os.path.exists(repo.wjoin(b'.hgchurn')): | |
|
201 | aliases = repo.wjoin(b'.hgchurn') | |
|
202 | 202 | if aliases: |
|
203 | for l in open(aliases, "rb"): | |
|
203 | for l in open(aliases, b"rb"): | |
|
204 | 204 | try: |
|
205 | alias, actual = l.rsplit('=' in l and '=' or None, 1) | |
|
205 | alias, actual = l.rsplit(b'=' in l and b'=' or None, 1) | |
|
206 | 206 | amap[alias.strip()] = actual.strip() |
|
207 | 207 | except ValueError: |
|
208 | 208 | l = l.strip() |
|
209 | 209 | if l: |
|
210 | ui.warn(_("skipping malformed alias: %s\n") % l) | |
|
210 | ui.warn(_(b"skipping malformed alias: %s\n") % l) | |
|
211 | 211 | continue |
|
212 | 212 | |
|
213 | 213 | rate = list(countrate(ui, repo, amap, *pats, **opts).items()) |
@@ -224,7 +224,7 b' def churn(ui, repo, *pats, **opts):' | |||
|
224 | 224 | maxname = max(len(k) for k, v in rate) |
|
225 | 225 | |
|
226 | 226 | ttywidth = ui.termwidth() |
|
227 | ui.debug("assuming %i character terminal\n" % ttywidth) | |
|
227 | ui.debug(b"assuming %i character terminal\n" % ttywidth) | |
|
228 | 228 | width = ttywidth - maxname - 2 - 2 - 2 |
|
229 | 229 | |
|
230 | 230 | if opts.get(r'diffstat'): |
@@ -232,21 +232,21 b' def churn(ui, repo, *pats, **opts):' | |||
|
232 | 232 | |
|
233 | 233 | def format(name, diffstat): |
|
234 | 234 | added, removed = diffstat |
|
235 | return "%s %15s %s%s\n" % ( | |
|
235 | return b"%s %15s %s%s\n" % ( | |
|
236 | 236 | pad(name, maxname), |
|
237 | '+%d/-%d' % (added, removed), | |
|
238 | ui.label('+' * charnum(added), 'diffstat.inserted'), | |
|
239 | ui.label('-' * charnum(removed), 'diffstat.deleted'), | |
|
237 | b'+%d/-%d' % (added, removed), | |
|
238 | ui.label(b'+' * charnum(added), b'diffstat.inserted'), | |
|
239 | ui.label(b'-' * charnum(removed), b'diffstat.deleted'), | |
|
240 | 240 | ) |
|
241 | 241 | |
|
242 | 242 | else: |
|
243 | 243 | width -= 6 |
|
244 | 244 | |
|
245 | 245 | def format(name, count): |
|
246 | return "%s %6d %s\n" % ( | |
|
246 | return b"%s %6d %s\n" % ( | |
|
247 | 247 | pad(name, maxname), |
|
248 | 248 | sum(count), |
|
249 | '*' * charnum(sum(count)), | |
|
249 | b'*' * charnum(sum(count)), | |
|
250 | 250 | ) |
|
251 | 251 | |
|
252 | 252 | def charnum(count): |
@@ -201,7 +201,7 b' from mercurial import (' | |||
|
201 | 201 | wireprotov1server, |
|
202 | 202 | ) |
|
203 | 203 | |
|
204 | testedwith = 'ships-with-hg-core' | |
|
204 | testedwith = b'ships-with-hg-core' | |
|
205 | 205 | |
|
206 | 206 | |
|
207 | 207 | def capabilities(orig, repo, proto): |
@@ -210,11 +210,11 b' def capabilities(orig, repo, proto):' | |||
|
210 | 210 | # Only advertise if a manifest exists. This does add some I/O to requests. |
|
211 | 211 | # But this should be cheaper than a wasted network round trip due to |
|
212 | 212 | # missing file. |
|
213 | if repo.vfs.exists('clonebundles.manifest'): | |
|
214 | caps.append('clonebundles') | |
|
213 | if repo.vfs.exists(b'clonebundles.manifest'): | |
|
214 | caps.append(b'clonebundles') | |
|
215 | 215 | |
|
216 | 216 | return caps |
|
217 | 217 | |
|
218 | 218 | |
|
219 | 219 | def extsetup(ui): |
|
220 | extensions.wrapfunction(wireprotov1server, '_capabilities', capabilities) | |
|
220 | extensions.wrapfunction(wireprotov1server, b'_capabilities', capabilities) |
@@ -24,17 +24,17 b' command = registrar.command(cmdtable)' | |||
|
24 | 24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
25 | 25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
26 | 26 | # leave the attribute unspecified. |
|
27 | testedwith = 'ships-with-hg-core' | |
|
27 | testedwith = b'ships-with-hg-core' | |
|
28 | 28 | |
|
29 | 29 | commitopts = cmdutil.commitopts |
|
30 | 30 | commitopts2 = cmdutil.commitopts2 |
|
31 | commitopts3 = [('r', 'rev', [], _('revision to check'), _('REV'))] | |
|
31 | commitopts3 = [(b'r', b'rev', [], _(b'revision to check'), _(b'REV'))] | |
|
32 | 32 | |
|
33 | 33 | |
|
34 | 34 | @command( |
|
35 | 'close-head|close-heads', | |
|
35 | b'close-head|close-heads', | |
|
36 | 36 | commitopts + commitopts2 + commitopts3, |
|
37 | _('[OPTION]... [REV]...'), | |
|
37 | _(b'[OPTION]... [REV]...'), | |
|
38 | 38 | helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, |
|
39 | 39 | inferrepo=True, |
|
40 | 40 | ) |
@@ -55,11 +55,11 b' def close_branch(ui, repo, *revs, **opts' | |||
|
55 | 55 | text=message, |
|
56 | 56 | files=[], |
|
57 | 57 | filectxfn=None, |
|
58 | user=opts.get('user'), | |
|
59 | date=opts.get('date'), | |
|
58 | user=opts.get(b'user'), | |
|
59 | date=opts.get(b'date'), | |
|
60 | 60 | extra=extra, |
|
61 | 61 | ) |
|
62 | tr = repo.transaction('commit') | |
|
62 | tr = repo.transaction(b'commit') | |
|
63 | 63 | ret = repo.commitctx(cctx, True) |
|
64 | 64 | bookmarks.update(repo, [rev, None], ret) |
|
65 | 65 | cctx.markcommitted(ret) |
@@ -67,11 +67,11 b' def close_branch(ui, repo, *revs, **opts' | |||
|
67 | 67 | |
|
68 | 68 | opts = pycompat.byteskwargs(opts) |
|
69 | 69 | |
|
70 | revs += tuple(opts.get('rev', [])) | |
|
70 | revs += tuple(opts.get(b'rev', [])) | |
|
71 | 71 | revs = scmutil.revrange(repo, revs) |
|
72 | 72 | |
|
73 | 73 | if not revs: |
|
74 | raise error.Abort(_('no revisions specified')) | |
|
74 | raise error.Abort(_(b'no revisions specified')) | |
|
75 | 75 | |
|
76 | 76 | heads = [] |
|
77 | 77 | for branch in repo.branchmap(): |
@@ -79,17 +79,17 b' def close_branch(ui, repo, *revs, **opts' | |||
|
79 | 79 | heads = set(repo[h].rev() for h in heads) |
|
80 | 80 | for rev in revs: |
|
81 | 81 | if rev not in heads: |
|
82 | raise error.Abort(_('revision is not an open head: %d') % rev) | |
|
82 | raise error.Abort(_(b'revision is not an open head: %d') % rev) | |
|
83 | 83 | |
|
84 | 84 | message = cmdutil.logmessage(ui, opts) |
|
85 | 85 | if not message: |
|
86 | raise error.Abort(_("no commit message specified with -l or -m")) | |
|
87 | extra = {'close': '1'} | |
|
86 | raise error.Abort(_(b"no commit message specified with -l or -m")) | |
|
87 | extra = {b'close': b'1'} | |
|
88 | 88 | |
|
89 | 89 | with repo.wlock(), repo.lock(): |
|
90 | 90 | for rev in revs: |
|
91 | 91 | r = repo[rev] |
|
92 | 92 | branch = r.branch() |
|
93 | extra['branch'] = branch | |
|
93 | extra[b'branch'] = branch | |
|
94 | 94 | docommit(r) |
|
95 | 95 | return 0 |
@@ -22,57 +22,64 b' from mercurial import (' | |||
|
22 | 22 | |
|
23 | 23 | cmdtable = {} |
|
24 | 24 | command = registrar.command(cmdtable) |
|
25 | testedwith = 'ships-with-hg-core' | |
|
25 | testedwith = b'ships-with-hg-core' | |
|
26 | 26 | |
|
27 | 27 | usedinternally = { |
|
28 | 'amend_source', | |
|
29 | 'branch', | |
|
30 | 'close', | |
|
31 | 'histedit_source', | |
|
32 | 'topic', | |
|
33 | 'rebase_source', | |
|
34 | 'intermediate-source', | |
|
35 | '__touch-noise__', | |
|
36 | 'source', | |
|
37 | 'transplant_source', | |
|
28 | b'amend_source', | |
|
29 | b'branch', | |
|
30 | b'close', | |
|
31 | b'histedit_source', | |
|
32 | b'topic', | |
|
33 | b'rebase_source', | |
|
34 | b'intermediate-source', | |
|
35 | b'__touch-noise__', | |
|
36 | b'source', | |
|
37 | b'transplant_source', | |
|
38 | 38 | } |
|
39 | 39 | |
|
40 | 40 | |
|
41 | 41 | def extsetup(ui): |
|
42 | entry = extensions.wrapcommand(commands.table, 'commit', _commit) | |
|
42 | entry = extensions.wrapcommand(commands.table, b'commit', _commit) | |
|
43 | 43 | options = entry[1] |
|
44 | 44 | options.append( |
|
45 | ('', 'extra', [], _('set a changeset\'s extra values'), _("KEY=VALUE")) | |
|
45 | ( | |
|
46 | b'', | |
|
47 | b'extra', | |
|
48 | [], | |
|
49 | _(b'set a changeset\'s extra values'), | |
|
50 | _(b"KEY=VALUE"), | |
|
51 | ) | |
|
46 | 52 | ) |
|
47 | 53 | |
|
48 | 54 | |
|
49 | 55 | def _commit(orig, ui, repo, *pats, **opts): |
|
50 | if util.safehasattr(repo, 'unfiltered'): | |
|
56 | if util.safehasattr(repo, b'unfiltered'): | |
|
51 | 57 | repo = repo.unfiltered() |
|
52 | 58 | |
|
53 | 59 | class repoextra(repo.__class__): |
|
54 | 60 | def commit(self, *innerpats, **inneropts): |
|
55 | 61 | extras = opts.get(r'extra') |
|
56 | 62 | for raw in extras: |
|
57 | if '=' not in raw: | |
|
63 | if b'=' not in raw: | |
|
58 | 64 | msg = _( |
|
59 | "unable to parse '%s', should follow " | |
|
60 | "KEY=VALUE format" | |
|
65 | b"unable to parse '%s', should follow " | |
|
66 | b"KEY=VALUE format" | |
|
61 | 67 | ) |
|
62 | 68 | raise error.Abort(msg % raw) |
|
63 | k, v = raw.split('=', 1) | |
|
69 | k, v = raw.split(b'=', 1) | |
|
64 | 70 | if not k: |
|
65 | msg = _("unable to parse '%s', keys can't be empty") | |
|
71 | msg = _(b"unable to parse '%s', keys can't be empty") | |
|
66 | 72 | raise error.Abort(msg % raw) |
|
67 | 73 | if re.search(br'[^\w-]', k): |
|
68 | 74 | msg = _( |
|
69 | "keys can only contain ascii letters, digits," | |
|
70 | " '_' and '-'" | |
|
75 | b"keys can only contain ascii letters, digits," | |
|
76 | b" '_' and '-'" | |
|
71 | 77 | ) |
|
72 | 78 | raise error.Abort(msg) |
|
73 | 79 | if k in usedinternally: |
|
74 | 80 | msg = _( |
|
75 |
"key '%s' is used internally, can't be set " |
|
|
81 | b"key '%s' is used internally, can't be set " | |
|
82 | b"manually" | |
|
76 | 83 | ) |
|
77 | 84 | raise error.Abort(msg % k) |
|
78 | 85 | inneropts[r'extra'][k] = v |
@@ -24,60 +24,72 b' command = registrar.command(cmdtable)' | |||
|
24 | 24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
25 | 25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
26 | 26 | # leave the attribute unspecified. |
|
27 | testedwith = 'ships-with-hg-core' | |
|
27 | testedwith = b'ships-with-hg-core' | |
|
28 | 28 | |
|
29 | 29 | # Commands definition was moved elsewhere to ease demandload job. |
|
30 | 30 | |
|
31 | 31 | |
|
32 | 32 | @command( |
|
33 | 'convert', | |
|
33 | b'convert', | |
|
34 | 34 | [ |
|
35 | 35 | ( |
|
36 | '', | |
|
37 | 'authors', | |
|
38 | '', | |
|
36 | b'', | |
|
37 | b'authors', | |
|
38 | b'', | |
|
39 | 39 | _( |
|
40 | 'username mapping filename (DEPRECATED) (use --authormap instead)' | |
|
40 | b'username mapping filename (DEPRECATED) (use --authormap instead)' | |
|
41 | 41 | ), |
|
42 | _('FILE'), | |
|
42 | _(b'FILE'), | |
|
43 | 43 | ), |
|
44 | ('s', 'source-type', '', _('source repository type'), _('TYPE')), | |
|
45 | ('d', 'dest-type', '', _('destination repository type'), _('TYPE')), | |
|
46 | ('r', 'rev', [], _('import up to source revision REV'), _('REV')), | |
|
47 | ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')), | |
|
44 | (b's', b'source-type', b'', _(b'source repository type'), _(b'TYPE')), | |
|
48 | 45 | ( |
|
49 | '', | |
|
50 |
' |
|
|
51 | '', | |
|
52 | _('remap file names using contents of file'), | |
|
53 |
_(' |
|
|
46 | b'd', | |
|
47 | b'dest-type', | |
|
48 | b'', | |
|
49 | _(b'destination repository type'), | |
|
50 | _(b'TYPE'), | |
|
51 | ), | |
|
52 | (b'r', b'rev', [], _(b'import up to source revision REV'), _(b'REV')), | |
|
53 | ( | |
|
54 | b'A', | |
|
55 | b'authormap', | |
|
56 | b'', | |
|
57 | _(b'remap usernames using this file'), | |
|
58 | _(b'FILE'), | |
|
54 | 59 | ), |
|
55 | 60 | ( |
|
56 | '', | |
|
57 |
'f |
|
|
58 |
|
|
|
59 |
_(' |
|
|
61 | b'', | |
|
62 | b'filemap', | |
|
63 | b'', | |
|
64 | _(b'remap file names using contents of file'), | |
|
65 | _(b'FILE'), | |
|
60 | 66 | ), |
|
61 | 67 | ( |
|
62 | '', | |
|
63 |
' |
|
|
64 |
|
|
|
65 | _('splice synthesized history into place'), | |
|
66 | _('FILE'), | |
|
68 | b'', | |
|
69 | b'full', | |
|
70 | None, | |
|
71 | _(b'apply filemap changes by converting all files again'), | |
|
67 | 72 | ), |
|
68 | 73 | ( |
|
69 | '', | |
|
70 |
' |
|
|
71 | '', | |
|
72 | _('change branch names while converting'), | |
|
73 | _('FILE'), | |
|
74 | b'', | |
|
75 | b'splicemap', | |
|
76 | b'', | |
|
77 | _(b'splice synthesized history into place'), | |
|
78 | _(b'FILE'), | |
|
74 | 79 | ), |
|
75 | ('', 'branchsort', None, _('try to sort changesets by branches')), | |
|
76 | ('', 'datesort', None, _('try to sort changesets by date')), | |
|
77 | ('', 'sourcesort', None, _('preserve source changesets order')), | |
|
78 | ('', 'closesort', None, _('try to reorder closed revisions')), | |
|
80 | ( | |
|
81 | b'', | |
|
82 | b'branchmap', | |
|
83 | b'', | |
|
84 | _(b'change branch names while converting'), | |
|
85 | _(b'FILE'), | |
|
86 | ), | |
|
87 | (b'', b'branchsort', None, _(b'try to sort changesets by branches')), | |
|
88 | (b'', b'datesort', None, _(b'try to sort changesets by date')), | |
|
89 | (b'', b'sourcesort', None, _(b'preserve source changesets order')), | |
|
90 | (b'', b'closesort', None, _(b'try to reorder closed revisions')), | |
|
79 | 91 | ], |
|
80 | _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]'), | |
|
92 | _(b'hg convert [OPTION]... SOURCE [DEST [REVMAP]]'), | |
|
81 | 93 | norepo=True, |
|
82 | 94 | ) |
|
83 | 95 | def convert(ui, src, dest=None, revmapfile=None, **opts): |
@@ -483,34 +495,44 b' def convert(ui, src, dest=None, revmapfi' | |||
|
483 | 495 | return convcmd.convert(ui, src, dest, revmapfile, **opts) |
|
484 | 496 | |
|
485 | 497 | |
|
486 | @command('debugsvnlog', [], 'hg debugsvnlog', norepo=True) | |
|
498 | @command(b'debugsvnlog', [], b'hg debugsvnlog', norepo=True) | |
|
487 | 499 | def debugsvnlog(ui, **opts): |
|
488 | 500 | return subversion.debugsvnlog(ui, **opts) |
|
489 | 501 | |
|
490 | 502 | |
|
491 | 503 | @command( |
|
492 | 'debugcvsps', | |
|
504 | b'debugcvsps', | |
|
493 | 505 | [ |
|
494 | 506 | # Main options shared with cvsps-2.1 |
|
495 | ('b', 'branches', [], _('only return changes on specified branches')), | |
|
496 | ('p', 'prefix', '', _('prefix to remove from file names')), | |
|
497 | 507 | ( |
|
498 |
' |
|
|
499 |
're |
|
|
508 | b'b', | |
|
509 | b'branches', | |
|
500 | 510 | [], |
|
501 |
_('only return changes |
|
|
511 | _(b'only return changes on specified branches'), | |
|
512 | ), | |
|
513 | (b'p', b'prefix', b'', _(b'prefix to remove from file names')), | |
|
514 | ( | |
|
515 | b'r', | |
|
516 | b'revisions', | |
|
517 | [], | |
|
518 | _(b'only return changes after or between specified tags'), | |
|
502 | 519 | ), |
|
503 | ('u', 'update-cache', None, _("update cvs log cache")), | |
|
504 | ('x', 'new-cache', None, _("create new cvs log cache")), | |
|
505 | ('z', 'fuzz', 60, _('set commit time fuzz in seconds')), | |
|
506 | ('', 'root', '', _('specify cvsroot')), | |
|
520 | (b'u', b'update-cache', None, _(b"update cvs log cache")), | |
|
521 | (b'x', b'new-cache', None, _(b"create new cvs log cache")), | |
|
522 | (b'z', b'fuzz', 60, _(b'set commit time fuzz in seconds')), | |
|
523 | (b'', b'root', b'', _(b'specify cvsroot')), | |
|
507 | 524 | # Options specific to builtin cvsps |
|
508 | ('', 'parents', '', _('show parent changesets')), | |
|
509 | ('', 'ancestors', '', _('show current changeset in ancestor branches')), | |
|
525 | (b'', b'parents', b'', _(b'show parent changesets')), | |
|
526 | ( | |
|
527 | b'', | |
|
528 | b'ancestors', | |
|
529 | b'', | |
|
530 | _(b'show current changeset in ancestor branches'), | |
|
531 | ), | |
|
510 | 532 | # Options that are ignored for compatibility with cvsps-2.1 |
|
511 | ('A', 'cvs-direct', None, _('ignored for compatibility')), | |
|
533 | (b'A', b'cvs-direct', None, _(b'ignored for compatibility')), | |
|
512 | 534 | ], |
|
513 | _('hg debugcvsps [OPTION]... [PATH]...'), | |
|
535 | _(b'hg debugcvsps [OPTION]... [PATH]...'), | |
|
514 | 536 | norepo=True, |
|
515 | 537 | ) |
|
516 | 538 | def debugcvsps(ui, *args, **opts): |
@@ -528,14 +550,14 b' def debugcvsps(ui, *args, **opts):' | |||
|
528 | 550 | |
|
529 | 551 | |
|
530 | 552 | def kwconverted(context, mapping, name): |
|
531 | ctx = context.resource(mapping, 'ctx') | |
|
532 | rev = ctx.extra().get('convert_revision', '') | |
|
533 | if rev.startswith('svn:'): | |
|
534 | if name == 'svnrev': | |
|
553 | ctx = context.resource(mapping, b'ctx') | |
|
554 | rev = ctx.extra().get(b'convert_revision', b'') | |
|
555 | if rev.startswith(b'svn:'): | |
|
556 | if name == b'svnrev': | |
|
535 | 557 | return b"%d" % subversion.revsplit(rev)[2] |
|
536 | elif name == 'svnpath': | |
|
558 | elif name == b'svnpath': | |
|
537 | 559 | return subversion.revsplit(rev)[1] |
|
538 | elif name == 'svnuuid': | |
|
560 | elif name == b'svnuuid': | |
|
539 | 561 | return subversion.revsplit(rev)[0] |
|
540 | 562 | return rev |
|
541 | 563 | |
@@ -543,22 +565,22 b' def kwconverted(context, mapping, name):' | |||
|
543 | 565 | templatekeyword = registrar.templatekeyword() |
|
544 | 566 | |
|
545 | 567 | |
|
546 | @templatekeyword('svnrev', requires={'ctx'}) | |
|
568 | @templatekeyword(b'svnrev', requires={b'ctx'}) | |
|
547 | 569 | def kwsvnrev(context, mapping): |
|
548 | 570 | """String. Converted subversion revision number.""" |
|
549 | return kwconverted(context, mapping, 'svnrev') | |
|
571 | return kwconverted(context, mapping, b'svnrev') | |
|
550 | 572 | |
|
551 | 573 | |
|
552 | @templatekeyword('svnpath', requires={'ctx'}) | |
|
574 | @templatekeyword(b'svnpath', requires={b'ctx'}) | |
|
553 | 575 | def kwsvnpath(context, mapping): |
|
554 | 576 | """String. Converted subversion revision project path.""" |
|
555 | return kwconverted(context, mapping, 'svnpath') | |
|
577 | return kwconverted(context, mapping, b'svnpath') | |
|
556 | 578 | |
|
557 | 579 | |
|
558 | @templatekeyword('svnuuid', requires={'ctx'}) | |
|
580 | @templatekeyword(b'svnuuid', requires={b'ctx'}) | |
|
559 | 581 | def kwsvnuuid(context, mapping): |
|
560 | 582 | """String. Converted subversion revision repository identifier.""" |
|
561 | return kwconverted(context, mapping, 'svnuuid') | |
|
583 | return kwconverted(context, mapping, b'svnuuid') | |
|
562 | 584 | |
|
563 | 585 | |
|
564 | 586 | # tell hggettext to extract docstrings from these functions: |
@@ -17,7 +17,7 b' from . import common' | |||
|
17 | 17 | |
|
18 | 18 | # these do not work with demandimport, blacklist |
|
19 | 19 | demandimport.IGNORES.update( |
|
20 | ['bzrlib.transactions', 'bzrlib.urlutils', 'ElementPath',] | |
|
20 | [b'bzrlib.transactions', b'bzrlib.urlutils', b'ElementPath',] | |
|
21 | 21 | ) |
|
22 | 22 | |
|
23 | 23 | try: |
@@ -35,7 +35,7 b' try:' | |||
|
35 | 35 | except ImportError: |
|
36 | 36 | pass |
|
37 | 37 | |
|
38 | supportedkinds = ('file', 'symlink') | |
|
38 | supportedkinds = (b'file', b'symlink') | |
|
39 | 39 | |
|
40 | 40 | |
|
41 | 41 | class bzr_source(common.converter_source): |
@@ -44,16 +44,16 b' class bzr_source(common.converter_source' | |||
|
44 | 44 | def __init__(self, ui, repotype, path, revs=None): |
|
45 | 45 | super(bzr_source, self).__init__(ui, repotype, path, revs=revs) |
|
46 | 46 | |
|
47 | if not os.path.exists(os.path.join(path, '.bzr')): | |
|
47 | if not os.path.exists(os.path.join(path, b'.bzr')): | |
|
48 | 48 | raise common.NoRepo( |
|
49 | _('%s does not look like a Bazaar repository') % path | |
|
49 | _(b'%s does not look like a Bazaar repository') % path | |
|
50 | 50 | ) |
|
51 | 51 | |
|
52 | 52 | try: |
|
53 | 53 | # access bzrlib stuff |
|
54 | 54 | bzrdir |
|
55 | 55 | except NameError: |
|
56 | raise common.NoRepo(_('Bazaar modules could not be loaded')) | |
|
56 | raise common.NoRepo(_(b'Bazaar modules could not be loaded')) | |
|
57 | 57 | |
|
58 | 58 | path = os.path.abspath(path) |
|
59 | 59 | self._checkrepotype(path) |
@@ -61,10 +61,10 b' class bzr_source(common.converter_source' | |||
|
61 | 61 | self.sourcerepo = bzrdir.BzrDir.open(path).open_repository() |
|
62 | 62 | except errors.NoRepositoryPresent: |
|
63 | 63 | raise common.NoRepo( |
|
64 | _('%s does not look like a Bazaar repository') % path | |
|
64 | _(b'%s does not look like a Bazaar repository') % path | |
|
65 | 65 | ) |
|
66 | 66 | self._parentids = {} |
|
67 | self._saverev = ui.configbool('convert', 'bzr.saverev') | |
|
67 | self._saverev = ui.configbool(b'convert', b'bzr.saverev') | |
|
68 | 68 | |
|
69 | 69 | def _checkrepotype(self, path): |
|
70 | 70 | # Lightweight checkouts detection is informational but probably |
@@ -84,13 +84,13 b' class bzr_source(common.converter_source' | |||
|
84 | 84 | ): |
|
85 | 85 | self.ui.warn( |
|
86 | 86 | _( |
|
87 | 'warning: lightweight checkouts may cause ' | |
|
88 | 'conversion failures, try with a regular ' | |
|
89 | 'branch instead.\n' | |
|
87 | b'warning: lightweight checkouts may cause ' | |
|
88 | b'conversion failures, try with a regular ' | |
|
89 | b'branch instead.\n' | |
|
90 | 90 | ) |
|
91 | 91 | ) |
|
92 | 92 | except Exception: |
|
93 | self.ui.note(_('bzr source type could not be determined\n')) | |
|
93 | self.ui.note(_(b'bzr source type could not be determined\n')) | |
|
94 | 94 | |
|
95 | 95 | def before(self): |
|
96 | 96 | """Before the conversion begins, acquire a read lock |
@@ -126,16 +126,16 b' class bzr_source(common.converter_source' | |||
|
126 | 126 | revid = info.rev_id |
|
127 | 127 | if revid is None: |
|
128 | 128 | raise error.Abort( |
|
129 | _('%s is not a valid revision') % self.revs[0] | |
|
129 | _(b'%s is not a valid revision') % self.revs[0] | |
|
130 | 130 | ) |
|
131 | 131 | heads = [revid] |
|
132 | 132 | # Empty repositories return 'null:', which cannot be retrieved |
|
133 | heads = [h for h in heads if h != 'null:'] | |
|
133 | heads = [h for h in heads if h != b'null:'] | |
|
134 | 134 | return heads |
|
135 | 135 | |
|
136 | 136 | def getfile(self, name, rev): |
|
137 | 137 | revtree = self.sourcerepo.revision_tree(rev) |
|
138 | fileid = revtree.path2id(name.decode(self.encoding or 'utf-8')) | |
|
138 | fileid = revtree.path2id(name.decode(self.encoding or b'utf-8')) | |
|
139 | 139 | kind = None |
|
140 | 140 | if fileid is not None: |
|
141 | 141 | kind = revtree.kind(fileid) |
@@ -143,11 +143,11 b' class bzr_source(common.converter_source' | |||
|
143 | 143 | # the file is not available anymore - was deleted |
|
144 | 144 | return None, None |
|
145 | 145 | mode = self._modecache[(name, rev)] |
|
146 | if kind == 'symlink': | |
|
146 | if kind == b'symlink': | |
|
147 | 147 | target = revtree.get_symlink_target(fileid) |
|
148 | 148 | if target is None: |
|
149 | 149 | raise error.Abort( |
|
150 | _('%s.%s symlink has no target') % (name, rev) | |
|
150 | _(b'%s.%s symlink has no target') % (name, rev) | |
|
151 | 151 | ) |
|
152 | 152 | return target, mode |
|
153 | 153 | else: |
@@ -156,7 +156,7 b' class bzr_source(common.converter_source' | |||
|
156 | 156 | |
|
157 | 157 | def getchanges(self, version, full): |
|
158 | 158 | if full: |
|
159 | raise error.Abort(_("convert from cvs does not support --full")) | |
|
159 | raise error.Abort(_(b"convert from cvs does not support --full")) | |
|
160 | 160 | self._modecache = {} |
|
161 | 161 | self._revtree = self.sourcerepo.revision_tree(version) |
|
162 | 162 | # get the parentids from the cache |
@@ -176,12 +176,12 b' class bzr_source(common.converter_source' | |||
|
176 | 176 | parents = self._filterghosts(rev.parent_ids) |
|
177 | 177 | self._parentids[version] = parents |
|
178 | 178 | |
|
179 | branch = self.recode(rev.properties.get('branch-nick', u'default')) | |
|
180 | if branch == 'trunk': | |
|
181 | branch = 'default' | |
|
179 | branch = self.recode(rev.properties.get(b'branch-nick', u'default')) | |
|
180 | if branch == b'trunk': | |
|
181 | branch = b'default' | |
|
182 | 182 | return common.commit( |
|
183 | 183 | parents=parents, |
|
184 | date='%d %d' % (rev.timestamp, -rev.timezone), | |
|
184 | date=b'%d %d' % (rev.timestamp, -rev.timezone), | |
|
185 | 185 | author=self.recode(rev.committer), |
|
186 | 186 | desc=self.recode(rev.message), |
|
187 | 187 | branch=branch, |
@@ -248,13 +248,13 b' class bzr_source(common.converter_source' | |||
|
248 | 248 | |
|
249 | 249 | # bazaar tracks directories, mercurial does not, so |
|
250 | 250 | # we have to rename the directory contents |
|
251 | if kind[1] == 'directory': | |
|
252 | if kind[0] not in (None, 'directory'): | |
|
251 | if kind[1] == b'directory': | |
|
252 | if kind[0] not in (None, b'directory'): | |
|
253 | 253 | # Replacing 'something' with a directory, record it |
|
254 | 254 | # so it can be removed. |
|
255 | 255 | changes.append((self.recode(paths[0]), revid)) |
|
256 | 256 | |
|
257 | if kind[0] == 'directory' and None not in paths: | |
|
257 | if kind[0] == b'directory' and None not in paths: | |
|
258 | 258 | renaming = paths[0] != paths[1] |
|
259 | 259 | # neither an add nor an delete - a move |
|
260 | 260 | # rename all directory contents manually |
@@ -262,9 +262,9 b' class bzr_source(common.converter_source' | |||
|
262 | 262 | # get all child-entries of the directory |
|
263 | 263 | for name, entry in inventory.iter_entries(subdir): |
|
264 | 264 | # hg does not track directory renames |
|
265 | if entry.kind == 'directory': | |
|
265 | if entry.kind == b'directory': | |
|
266 | 266 | continue |
|
267 | frompath = self.recode(paths[0] + '/' + name) | |
|
267 | frompath = self.recode(paths[0] + b'/' + name) | |
|
268 | 268 | if frompath in seen: |
|
269 | 269 | # Already handled by a more specific change entry |
|
270 | 270 | # This is important when you have: |
@@ -275,15 +275,15 b' class bzr_source(common.converter_source' | |||
|
275 | 275 | seen.add(frompath) |
|
276 | 276 | if not renaming: |
|
277 | 277 | continue |
|
278 | topath = self.recode(paths[1] + '/' + name) | |
|
278 | topath = self.recode(paths[1] + b'/' + name) | |
|
279 | 279 | # register the files as changed |
|
280 | 280 | changes.append((frompath, revid)) |
|
281 | 281 | changes.append((topath, revid)) |
|
282 | 282 | # add to mode cache |
|
283 | 283 | mode = ( |
|
284 | (entry.executable and 'x') | |
|
285 | or (entry.kind == 'symlink' and 's') | |
|
286 | or '' | |
|
284 | (entry.executable and b'x') | |
|
285 | or (entry.kind == b'symlink' and b's') | |
|
286 | or b'' | |
|
287 | 287 | ) |
|
288 | 288 | self._modecache[(topath, revid)] = mode |
|
289 | 289 | # register the change as move |
@@ -312,7 +312,7 b' class bzr_source(common.converter_source' | |||
|
312 | 312 | |
|
313 | 313 | # populate the mode cache |
|
314 | 314 | kind, executable = [e[1] for e in (kind, executable)] |
|
315 | mode = (executable and 'x') or (kind == 'symlink' and 'l') or '' | |
|
315 | mode = (executable and b'x') or (kind == b'symlink' and b'l') or b'' | |
|
316 | 316 | self._modecache[(topath, revid)] = mode |
|
317 | 317 | changes.append((topath, revid)) |
|
318 | 318 |
@@ -46,7 +46,7 b' class _shlexpy3proxy(object):' | |||
|
46 | 46 | |
|
47 | 47 | @property |
|
48 | 48 | def infile(self): |
|
49 | return self._l.infile or '<unknown>' | |
|
49 | return self._l.infile or b'<unknown>' | |
|
50 | 50 | |
|
51 | 51 | @property |
|
52 | 52 | def lineno(self): |
@@ -56,13 +56,13 b' class _shlexpy3proxy(object):' | |||
|
56 | 56 | def shlexer(data=None, filepath=None, wordchars=None, whitespace=None): |
|
57 | 57 | if data is None: |
|
58 | 58 | if pycompat.ispy3: |
|
59 | data = open(filepath, 'r', encoding=r'latin1') | |
|
59 | data = open(filepath, b'r', encoding=r'latin1') | |
|
60 | 60 | else: |
|
61 | data = open(filepath, 'r') | |
|
61 | data = open(filepath, b'r') | |
|
62 | 62 | else: |
|
63 | 63 | if filepath is not None: |
|
64 | 64 | raise error.ProgrammingError( |
|
65 | 'shlexer only accepts data or filepath, not both' | |
|
65 | b'shlexer only accepts data or filepath, not both' | |
|
66 | 66 | ) |
|
67 | 67 | if pycompat.ispy3: |
|
68 | 68 | data = data.decode('latin1') |
@@ -87,7 +87,7 b' def encodeargs(args):' | |||
|
87 | 87 | def encodearg(s): |
|
88 | 88 | lines = base64.encodestring(s) |
|
89 | 89 | lines = [l.splitlines()[0] for l in lines] |
|
90 | return ''.join(lines) | |
|
90 | return b''.join(lines) | |
|
91 | 91 | |
|
92 | 92 | s = pickle.dumps(args) |
|
93 | 93 | return encodearg(s) |
@@ -109,14 +109,14 b' def checktool(exe, name=None, abort=True' | |||
|
109 | 109 | exc = error.Abort |
|
110 | 110 | else: |
|
111 | 111 | exc = MissingTool |
|
112 | raise exc(_('cannot find required "%s" tool') % name) | |
|
112 | raise exc(_(b'cannot find required "%s" tool') % name) | |
|
113 | 113 | |
|
114 | 114 | |
|
115 | 115 | class NoRepo(Exception): |
|
116 | 116 | pass |
|
117 | 117 | |
|
118 | 118 | |
|
119 | SKIPREV = 'SKIP' | |
|
119 | SKIPREV = b'SKIP' | |
|
120 | 120 | |
|
121 | 121 | |
|
122 | 122 | class commit(object): |
@@ -135,8 +135,8 b' class commit(object):' | |||
|
135 | 135 | optparents=None, |
|
136 | 136 | ctx=None, |
|
137 | 137 | ): |
|
138 | self.author = author or 'unknown' | |
|
139 | self.date = date or '0 0' | |
|
138 | self.author = author or b'unknown' | |
|
139 | self.date = date or b'0 0' | |
|
140 | 140 | self.desc = desc |
|
141 | 141 | self.parents = parents # will be converted and used as parents |
|
142 | 142 | self.optparents = optparents or [] # will be used if already converted |
@@ -160,15 +160,15 b' class converter_source(object):' | |||
|
160 | 160 | self.revs = revs |
|
161 | 161 | self.repotype = repotype |
|
162 | 162 | |
|
163 | self.encoding = 'utf-8' | |
|
163 | self.encoding = b'utf-8' | |
|
164 | 164 | |
|
165 | def checkhexformat(self, revstr, mapname='splicemap'): | |
|
165 | def checkhexformat(self, revstr, mapname=b'splicemap'): | |
|
166 | 166 | """ fails if revstr is not a 40 byte hex. mercurial and git both uses |
|
167 | 167 | such format for their revision numbering |
|
168 | 168 | """ |
|
169 | 169 | if not re.match(br'[0-9a-fA-F]{40,40}$', revstr): |
|
170 | 170 | raise error.Abort( |
|
171 | _('%s entry %s is not a valid revision' ' identifier') | |
|
171 | _(b'%s entry %s is not a valid revision' b' identifier') | |
|
172 | 172 | % (mapname, revstr) |
|
173 | 173 | ) |
|
174 | 174 | |
@@ -236,7 +236,7 b' class converter_source(object):' | |||
|
236 | 236 | |
|
237 | 237 | def recode(self, s, encoding=None): |
|
238 | 238 | if not encoding: |
|
239 | encoding = self.encoding or 'utf-8' | |
|
239 | encoding = self.encoding or b'utf-8' | |
|
240 | 240 | |
|
241 | 241 | if isinstance(s, pycompat.unicode): |
|
242 | 242 | return s.encode("utf-8") |
@@ -292,7 +292,7 b' class converter_source(object):' | |||
|
292 | 292 | """ |
|
293 | 293 | return {} |
|
294 | 294 | |
|
295 | def checkrevformat(self, revstr, mapname='splicemap'): | |
|
295 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
|
296 | 296 | """revstr is a string that describes a revision in the given |
|
297 | 297 | source control system. Return true if revstr has correct |
|
298 | 298 | format. |
@@ -412,20 +412,20 b' class commandline(object):' | |||
|
412 | 412 | cmdline = [self.command, cmd] + list(args) |
|
413 | 413 | for k, v in kwargs.iteritems(): |
|
414 | 414 | if len(k) == 1: |
|
415 | cmdline.append('-' + k) | |
|
415 | cmdline.append(b'-' + k) | |
|
416 | 416 | else: |
|
417 | cmdline.append('--' + k.replace('_', '-')) | |
|
417 | cmdline.append(b'--' + k.replace(b'_', b'-')) | |
|
418 | 418 | try: |
|
419 | 419 | if len(k) == 1: |
|
420 | cmdline.append('' + v) | |
|
420 | cmdline.append(b'' + v) | |
|
421 | 421 | else: |
|
422 | cmdline[-1] += '=' + v | |
|
422 | cmdline[-1] += b'=' + v | |
|
423 | 423 | except TypeError: |
|
424 | 424 | pass |
|
425 | 425 | cmdline = [procutil.shellquote(arg) for arg in cmdline] |
|
426 | 426 | if not self.ui.debugflag: |
|
427 | cmdline += ['2>', pycompat.bytestr(os.devnull)] | |
|
428 | cmdline = ' '.join(cmdline) | |
|
427 | cmdline += [b'2>', pycompat.bytestr(os.devnull)] | |
|
428 | cmdline = b' '.join(cmdline) | |
|
429 | 429 | return cmdline |
|
430 | 430 | |
|
431 | 431 | def _run(self, cmd, *args, **kwargs): |
@@ -449,7 +449,7 b' class commandline(object):' | |||
|
449 | 449 | |
|
450 | 450 | def _dorun(self, openfunc, cmd, *args, **kwargs): |
|
451 | 451 | cmdline = self._cmdline(cmd, *args, **kwargs) |
|
452 | self.ui.debug('running: %s\n' % (cmdline,)) | |
|
452 | self.ui.debug(b'running: %s\n' % (cmdline,)) | |
|
453 | 453 | self.prerun() |
|
454 | 454 | try: |
|
455 | 455 | return openfunc(cmdline) |
@@ -466,16 +466,16 b' class commandline(object):' | |||
|
466 | 466 | p = self._run(cmd, *args, **kwargs) |
|
467 | 467 | output = p.stdout.readlines() |
|
468 | 468 | p.wait() |
|
469 | self.ui.debug(''.join(output)) | |
|
469 | self.ui.debug(b''.join(output)) | |
|
470 | 470 | return output, p.returncode |
|
471 | 471 | |
|
472 | def checkexit(self, status, output=''): | |
|
472 | def checkexit(self, status, output=b''): | |
|
473 | 473 | if status: |
|
474 | 474 | if output: |
|
475 | self.ui.warn(_('%s error:\n') % self.command) | |
|
475 | self.ui.warn(_(b'%s error:\n') % self.command) | |
|
476 | 476 | self.ui.warn(output) |
|
477 | 477 | msg = procutil.explainexit(status) |
|
478 | raise error.Abort('%s %s' % (self.command, msg)) | |
|
478 | raise error.Abort(b'%s %s' % (self.command, msg)) | |
|
479 | 479 | |
|
480 | 480 | def run0(self, cmd, *args, **kwargs): |
|
481 | 481 | output, status = self.run(cmd, *args, **kwargs) |
@@ -484,7 +484,7 b' class commandline(object):' | |||
|
484 | 484 | |
|
485 | 485 | def runlines0(self, cmd, *args, **kwargs): |
|
486 | 486 | output, status = self.runlines(cmd, *args, **kwargs) |
|
487 | self.checkexit(status, ''.join(output)) | |
|
487 | self.checkexit(status, b''.join(output)) | |
|
488 | 488 | return output |
|
489 | 489 | |
|
490 | 490 | @propertycache |
@@ -540,7 +540,7 b' class mapfile(dict):' | |||
|
540 | 540 | if not self.path: |
|
541 | 541 | return |
|
542 | 542 | try: |
|
543 | fp = open(self.path, 'rb') | |
|
543 | fp = open(self.path, b'rb') | |
|
544 | 544 | except IOError as err: |
|
545 | 545 | if err.errno != errno.ENOENT: |
|
546 | 546 | raise |
@@ -551,10 +551,10 b' class mapfile(dict):' | |||
|
551 | 551 | # Ignore blank lines |
|
552 | 552 | continue |
|
553 | 553 | try: |
|
554 | key, value = line.rsplit(' ', 1) | |
|
554 | key, value = line.rsplit(b' ', 1) | |
|
555 | 555 | except ValueError: |
|
556 | 556 | raise error.Abort( |
|
557 | _('syntax error in %s(%d): key/value pair expected') | |
|
557 | _(b'syntax error in %s(%d): key/value pair expected') | |
|
558 | 558 | % (self.path, i + 1) |
|
559 | 559 | ) |
|
560 | 560 | if key not in self: |
@@ -565,13 +565,13 b' class mapfile(dict):' | |||
|
565 | 565 | def __setitem__(self, key, value): |
|
566 | 566 | if self.fp is None: |
|
567 | 567 | try: |
|
568 | self.fp = open(self.path, 'ab') | |
|
568 | self.fp = open(self.path, b'ab') | |
|
569 | 569 | except IOError as err: |
|
570 | 570 | raise error.Abort( |
|
571 | _('could not open map file %r: %s') | |
|
571 | _(b'could not open map file %r: %s') | |
|
572 | 572 | % (self.path, encoding.strtolocal(err.strerror)) |
|
573 | 573 | ) |
|
574 | self.fp.write(util.tonativeeol('%s %s\n' % (key, value))) | |
|
574 | self.fp.write(util.tonativeeol(b'%s %s\n' % (key, value))) | |
|
575 | 575 | self.fp.flush() |
|
576 | 576 | super(mapfile, self).__setitem__(key, value) |
|
577 | 577 |
@@ -52,7 +52,7 b' p4_source = p4.p4_source' | |||
|
52 | 52 | svn_sink = subversion.svn_sink |
|
53 | 53 | svn_source = subversion.svn_source |
|
54 | 54 | |
|
55 | orig_encoding = 'ascii' | |
|
55 | orig_encoding = b'ascii' | |
|
56 | 56 | |
|
57 | 57 | |
|
58 | 58 | def recode(s): |
@@ -90,36 +90,36 b' def mapbranch(branch, branchmap):' | |||
|
90 | 90 | # destination repository. For such commits, using a literal "default" |
|
91 | 91 | # in branchmap below allows the user to map "default" to an alternate |
|
92 | 92 | # default branch in the destination repository. |
|
93 | branch = branchmap.get(branch or 'default', branch) | |
|
93 | branch = branchmap.get(branch or b'default', branch) | |
|
94 | 94 | # At some point we used "None" literal to denote the default branch, |
|
95 | 95 | # attempt to use that for backward compatibility. |
|
96 | 96 | if not branch: |
|
97 | branch = branchmap.get('None', branch) | |
|
97 | branch = branchmap.get(b'None', branch) | |
|
98 | 98 | return branch |
|
99 | 99 | |
|
100 | 100 | |
|
101 | 101 | source_converters = [ |
|
102 | ('cvs', convert_cvs, 'branchsort'), | |
|
103 | ('git', convert_git, 'branchsort'), | |
|
104 | ('svn', svn_source, 'branchsort'), | |
|
105 | ('hg', mercurial_source, 'sourcesort'), | |
|
106 | ('darcs', darcs_source, 'branchsort'), | |
|
107 | ('mtn', monotone_source, 'branchsort'), | |
|
108 | ('gnuarch', gnuarch_source, 'branchsort'), | |
|
109 | ('bzr', bzr_source, 'branchsort'), | |
|
110 | ('p4', p4_source, 'branchsort'), | |
|
102 | (b'cvs', convert_cvs, b'branchsort'), | |
|
103 | (b'git', convert_git, b'branchsort'), | |
|
104 | (b'svn', svn_source, b'branchsort'), | |
|
105 | (b'hg', mercurial_source, b'sourcesort'), | |
|
106 | (b'darcs', darcs_source, b'branchsort'), | |
|
107 | (b'mtn', monotone_source, b'branchsort'), | |
|
108 | (b'gnuarch', gnuarch_source, b'branchsort'), | |
|
109 | (b'bzr', bzr_source, b'branchsort'), | |
|
110 | (b'p4', p4_source, b'branchsort'), | |
|
111 | 111 | ] |
|
112 | 112 | |
|
113 | 113 | sink_converters = [ |
|
114 | ('hg', mercurial_sink), | |
|
115 | ('svn', svn_sink), | |
|
114 | (b'hg', mercurial_sink), | |
|
115 | (b'svn', svn_sink), | |
|
116 | 116 | ] |
|
117 | 117 | |
|
118 | 118 | |
|
119 | 119 | def convertsource(ui, path, type, revs): |
|
120 | 120 | exceptions = [] |
|
121 | 121 | if type and type not in [s[0] for s in source_converters]: |
|
122 | raise error.Abort(_('%s: invalid source repository type') % type) | |
|
122 | raise error.Abort(_(b'%s: invalid source repository type') % type) | |
|
123 | 123 | for name, source, sortmode in source_converters: |
|
124 | 124 | try: |
|
125 | 125 | if not type or name == type: |
@@ -128,22 +128,22 b' def convertsource(ui, path, type, revs):' | |||
|
128 | 128 | exceptions.append(inst) |
|
129 | 129 | if not ui.quiet: |
|
130 | 130 | for inst in exceptions: |
|
131 | ui.write("%s\n" % pycompat.bytestr(inst.args[0])) | |
|
132 | raise error.Abort(_('%s: missing or unsupported repository') % path) | |
|
131 | ui.write(b"%s\n" % pycompat.bytestr(inst.args[0])) | |
|
132 | raise error.Abort(_(b'%s: missing or unsupported repository') % path) | |
|
133 | 133 | |
|
134 | 134 | |
|
135 | 135 | def convertsink(ui, path, type): |
|
136 | 136 | if type and type not in [s[0] for s in sink_converters]: |
|
137 | raise error.Abort(_('%s: invalid destination repository type') % type) | |
|
137 | raise error.Abort(_(b'%s: invalid destination repository type') % type) | |
|
138 | 138 | for name, sink in sink_converters: |
|
139 | 139 | try: |
|
140 | 140 | if not type or name == type: |
|
141 | 141 | return sink(ui, name, path) |
|
142 | 142 | except NoRepo as inst: |
|
143 | ui.note(_("convert: %s\n") % inst) | |
|
143 | ui.note(_(b"convert: %s\n") % inst) | |
|
144 | 144 | except MissingTool as inst: |
|
145 | raise error.Abort('%s\n' % inst) | |
|
146 | raise error.Abort(_('%s: unknown repository type') % path) | |
|
145 | raise error.Abort(b'%s\n' % inst) | |
|
146 | raise error.Abort(_(b'%s: unknown repository type') % path) | |
|
147 | 147 | |
|
148 | 148 | |
|
149 | 149 | class progresssource(object): |
@@ -151,7 +151,7 b' class progresssource(object):' | |||
|
151 | 151 | self.ui = ui |
|
152 | 152 | self.source = source |
|
153 | 153 | self.progress = ui.makeprogress( |
|
154 | _('getting files'), unit=_('files'), total=filecount | |
|
154 | _(b'getting files'), unit=_(b'files'), total=filecount | |
|
155 | 155 | ) |
|
156 | 156 | |
|
157 | 157 | def getfile(self, file, rev): |
@@ -189,12 +189,12 b' class converter(object):' | |||
|
189 | 189 | if authorfile and os.path.exists(authorfile): |
|
190 | 190 | self.readauthormap(authorfile) |
|
191 | 191 | # Extend/Override with new author map if necessary |
|
192 | if opts.get('authormap'): | |
|
193 | self.readauthormap(opts.get('authormap')) | |
|
192 | if opts.get(b'authormap'): | |
|
193 | self.readauthormap(opts.get(b'authormap')) | |
|
194 | 194 | self.authorfile = self.dest.authorfile() |
|
195 | 195 | |
|
196 | self.splicemap = self.parsesplicemap(opts.get('splicemap')) | |
|
197 | self.branchmap = mapfile(ui, opts.get('branchmap')) | |
|
196 | self.splicemap = self.parsesplicemap(opts.get(b'splicemap')) | |
|
197 | self.branchmap = mapfile(ui, opts.get(b'branchmap')) | |
|
198 | 198 | |
|
199 | 199 | def parsesplicemap(self, path): |
|
200 | 200 | """ check and validate the splicemap format and |
@@ -211,21 +211,21 b' class converter(object):' | |||
|
211 | 211 | return {} |
|
212 | 212 | m = {} |
|
213 | 213 | try: |
|
214 | fp = open(path, 'rb') | |
|
214 | fp = open(path, b'rb') | |
|
215 | 215 | for i, line in enumerate(util.iterfile(fp)): |
|
216 | 216 | line = line.splitlines()[0].rstrip() |
|
217 | 217 | if not line: |
|
218 | 218 | # Ignore blank lines |
|
219 | 219 | continue |
|
220 | 220 | # split line |
|
221 | lex = common.shlexer(data=line, whitespace=',') | |
|
221 | lex = common.shlexer(data=line, whitespace=b',') | |
|
222 | 222 | line = list(lex) |
|
223 | 223 | # check number of parents |
|
224 | 224 | if not (2 <= len(line) <= 3): |
|
225 | 225 | raise error.Abort( |
|
226 | 226 | _( |
|
227 | 'syntax error in %s(%d): child parent1' | |
|
228 | '[,parent2] expected' | |
|
227 | b'syntax error in %s(%d): child parent1' | |
|
228 | b'[,parent2] expected' | |
|
229 | 229 | ) |
|
230 | 230 | % (path, i + 1) |
|
231 | 231 | ) |
@@ -239,7 +239,7 b' class converter(object):' | |||
|
239 | 239 | # if file does not exist or error reading, exit |
|
240 | 240 | except IOError: |
|
241 | 241 | raise error.Abort( |
|
242 | _('splicemap file not found or error reading %s:') % path | |
|
242 | _(b'splicemap file not found or error reading %s:') % path | |
|
243 | 243 | ) |
|
244 | 244 | return m |
|
245 | 245 | |
@@ -251,7 +251,7 b' class converter(object):' | |||
|
251 | 251 | parents = {} |
|
252 | 252 | numcommits = self.source.numcommits() |
|
253 | 253 | progress = self.ui.makeprogress( |
|
254 | _('scanning'), unit=_('revisions'), total=numcommits | |
|
254 | _(b'scanning'), unit=_(b'revisions'), total=numcommits | |
|
255 | 255 | ) |
|
256 | 256 | while visit: |
|
257 | 257 | n = visit.pop(0) |
@@ -283,8 +283,8 b' class converter(object):' | |||
|
283 | 283 | # Could be in source but not converted during this run |
|
284 | 284 | self.ui.warn( |
|
285 | 285 | _( |
|
286 | 'splice map revision %s is not being ' | |
|
287 | 'converted, ignoring\n' | |
|
286 | b'splice map revision %s is not being ' | |
|
287 | b'converted, ignoring\n' | |
|
288 | 288 | ) |
|
289 | 289 | % c |
|
290 | 290 | ) |
@@ -296,7 +296,7 b' class converter(object):' | |||
|
296 | 296 | continue |
|
297 | 297 | # Parent is not in dest and not being converted, not good |
|
298 | 298 | if p not in parents: |
|
299 | raise error.Abort(_('unknown splice map parent: %s') % p) | |
|
299 | raise error.Abort(_(b'unknown splice map parent: %s') % p) | |
|
300 | 300 | pc.append(p) |
|
301 | 301 | parents[c] = pc |
|
302 | 302 | |
@@ -369,7 +369,7 b' class converter(object):' | |||
|
369 | 369 | def makeclosesorter(): |
|
370 | 370 | """Close order sort.""" |
|
371 | 371 | keyfn = lambda n: ( |
|
372 | 'close' not in self.commitcache[n].extra, | |
|
372 | b'close' not in self.commitcache[n].extra, | |
|
373 | 373 | self.commitcache[n].sortkey, |
|
374 | 374 | ) |
|
375 | 375 | |
@@ -392,16 +392,16 b' class converter(object):' | |||
|
392 | 392 | |
|
393 | 393 | return picknext |
|
394 | 394 | |
|
395 | if sortmode == 'branchsort': | |
|
395 | if sortmode == b'branchsort': | |
|
396 | 396 | picknext = makebranchsorter() |
|
397 | elif sortmode == 'datesort': | |
|
397 | elif sortmode == b'datesort': | |
|
398 | 398 | picknext = makedatesorter() |
|
399 | elif sortmode == 'sourcesort': | |
|
399 | elif sortmode == b'sourcesort': | |
|
400 | 400 | picknext = makesourcesorter() |
|
401 | elif sortmode == 'closesort': | |
|
401 | elif sortmode == b'closesort': | |
|
402 | 402 | picknext = makeclosesorter() |
|
403 | 403 | else: |
|
404 | raise error.Abort(_('unknown sort mode: %s') % sortmode) | |
|
404 | raise error.Abort(_(b'unknown sort mode: %s') % sortmode) | |
|
405 | 405 | |
|
406 | 406 | children, actives = mapchildren(parents) |
|
407 | 407 | |
@@ -420,7 +420,7 b' class converter(object):' | |||
|
420 | 420 | pendings[c].remove(n) |
|
421 | 421 | except ValueError: |
|
422 | 422 | raise error.Abort( |
|
423 | _('cycle detected between %s and %s') | |
|
423 | _(b'cycle detected between %s and %s') | |
|
424 | 424 | % (recode(c), recode(n)) |
|
425 | 425 | ) |
|
426 | 426 | if not pendings[c]: |
@@ -429,45 +429,47 b' class converter(object):' | |||
|
429 | 429 | pendings[c] = None |
|
430 | 430 | |
|
431 | 431 | if len(s) != len(parents): |
|
432 | raise error.Abort(_("not all revisions were sorted")) | |
|
432 | raise error.Abort(_(b"not all revisions were sorted")) | |
|
433 | 433 | |
|
434 | 434 | return s |
|
435 | 435 | |
|
436 | 436 | def writeauthormap(self): |
|
437 | 437 | authorfile = self.authorfile |
|
438 | 438 | if authorfile: |
|
439 | self.ui.status(_('writing author map file %s\n') % authorfile) | |
|
440 | ofile = open(authorfile, 'wb+') | |
|
439 | self.ui.status(_(b'writing author map file %s\n') % authorfile) | |
|
440 | ofile = open(authorfile, b'wb+') | |
|
441 | 441 | for author in self.authors: |
|
442 | 442 | ofile.write( |
|
443 |
util.tonativeeol( |
|
|
443 | util.tonativeeol( | |
|
444 | b"%s=%s\n" % (author, self.authors[author]) | |
|
445 | ) | |
|
444 | 446 | ) |
|
445 | 447 | ofile.close() |
|
446 | 448 | |
|
447 | 449 | def readauthormap(self, authorfile): |
|
448 | afile = open(authorfile, 'rb') | |
|
450 | afile = open(authorfile, b'rb') | |
|
449 | 451 | for line in afile: |
|
450 | 452 | |
|
451 | 453 | line = line.strip() |
|
452 | if not line or line.startswith('#'): | |
|
454 | if not line or line.startswith(b'#'): | |
|
453 | 455 | continue |
|
454 | 456 | |
|
455 | 457 | try: |
|
456 | srcauthor, dstauthor = line.split('=', 1) | |
|
458 | srcauthor, dstauthor = line.split(b'=', 1) | |
|
457 | 459 | except ValueError: |
|
458 | msg = _('ignoring bad line in author map file %s: %s\n') | |
|
460 | msg = _(b'ignoring bad line in author map file %s: %s\n') | |
|
459 | 461 | self.ui.warn(msg % (authorfile, line.rstrip())) |
|
460 | 462 | continue |
|
461 | 463 | |
|
462 | 464 | srcauthor = srcauthor.strip() |
|
463 | 465 | dstauthor = dstauthor.strip() |
|
464 | 466 | if self.authors.get(srcauthor) in (None, dstauthor): |
|
465 | msg = _('mapping author %s to %s\n') | |
|
467 | msg = _(b'mapping author %s to %s\n') | |
|
466 | 468 | self.ui.debug(msg % (srcauthor, dstauthor)) |
|
467 | 469 | self.authors[srcauthor] = dstauthor |
|
468 | 470 | continue |
|
469 | 471 | |
|
470 | m = _('overriding mapping for author %s, was %s, will be %s\n') | |
|
472 | m = _(b'overriding mapping for author %s, was %s, will be %s\n') | |
|
471 | 473 | self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor)) |
|
472 | 474 | |
|
473 | 475 | afile.close() |
@@ -481,7 +483,7 b' class converter(object):' | |||
|
481 | 483 | |
|
482 | 484 | def copy(self, rev): |
|
483 | 485 | commit = self.commitcache[rev] |
|
484 | full = self.opts.get('full') | |
|
486 | full = self.opts.get(b'full') | |
|
485 | 487 | changes = self.source.getchanges(rev, full) |
|
486 | 488 | if isinstance(changes, bytes): |
|
487 | 489 | if changes == SKIPREV: |
@@ -503,8 +505,8 b' class converter(object):' | |||
|
503 | 505 | try: |
|
504 | 506 | parents = self.splicemap[rev] |
|
505 | 507 | self.ui.status( |
|
506 | _('spliced in %s as parents of %s\n') | |
|
507 | % (_(' and ').join(parents), rev) | |
|
508 | _(b'spliced in %s as parents of %s\n') | |
|
509 | % (_(b' and ').join(parents), rev) | |
|
508 | 510 | ) |
|
509 | 511 | parents = [self.map.get(p, p) for p in parents] |
|
510 | 512 | except KeyError: |
@@ -536,34 +538,34 b' class converter(object):' | |||
|
536 | 538 | self.source.before() |
|
537 | 539 | self.dest.before() |
|
538 | 540 | self.source.setrevmap(self.map) |
|
539 | self.ui.status(_("scanning source...\n")) | |
|
541 | self.ui.status(_(b"scanning source...\n")) | |
|
540 | 542 | heads = self.source.getheads() |
|
541 | 543 | parents = self.walktree(heads) |
|
542 | 544 | self.mergesplicemap(parents, self.splicemap) |
|
543 | self.ui.status(_("sorting...\n")) | |
|
545 | self.ui.status(_(b"sorting...\n")) | |
|
544 | 546 | t = self.toposort(parents, sortmode) |
|
545 | 547 | num = len(t) |
|
546 | 548 | c = None |
|
547 | 549 | |
|
548 | self.ui.status(_("converting...\n")) | |
|
550 | self.ui.status(_(b"converting...\n")) | |
|
549 | 551 | progress = self.ui.makeprogress( |
|
550 | _('converting'), unit=_('revisions'), total=len(t) | |
|
552 | _(b'converting'), unit=_(b'revisions'), total=len(t) | |
|
551 | 553 | ) |
|
552 | 554 | for i, c in enumerate(t): |
|
553 | 555 | num -= 1 |
|
554 | 556 | desc = self.commitcache[c].desc |
|
555 | if "\n" in desc: | |
|
557 | if b"\n" in desc: | |
|
556 | 558 | desc = desc.splitlines()[0] |
|
557 | 559 | # convert log message to local encoding without using |
|
558 | 560 | # tolocal() because the encoding.encoding convert() |
|
559 | 561 | # uses is 'utf-8' |
|
560 | self.ui.status("%d %s\n" % (num, recode(desc))) | |
|
561 | self.ui.note(_("source: %s\n") % recode(c)) | |
|
562 | self.ui.status(b"%d %s\n" % (num, recode(desc))) | |
|
563 | self.ui.note(_(b"source: %s\n") % recode(c)) | |
|
562 | 564 | progress.update(i) |
|
563 | 565 | self.copy(c) |
|
564 | 566 | progress.complete() |
|
565 | 567 | |
|
566 | if not self.ui.configbool('convert', 'skiptags'): | |
|
568 | if not self.ui.configbool(b'convert', b'skiptags'): | |
|
567 | 569 | tags = self.source.gettags() |
|
568 | 570 | ctags = {} |
|
569 | 571 | for k in tags: |
@@ -610,45 +612,47 b' def convert(ui, src, dest=None, revmapfi' | |||
|
610 | 612 | opts = pycompat.byteskwargs(opts) |
|
611 | 613 | global orig_encoding |
|
612 | 614 | orig_encoding = encoding.encoding |
|
613 | encoding.encoding = 'UTF-8' | |
|
615 | encoding.encoding = b'UTF-8' | |
|
614 | 616 | |
|
615 | 617 | # support --authors as an alias for --authormap |
|
616 | if not opts.get('authormap'): | |
|
617 | opts['authormap'] = opts.get('authors') | |
|
618 | if not opts.get(b'authormap'): | |
|
619 | opts[b'authormap'] = opts.get(b'authors') | |
|
618 | 620 | |
|
619 | 621 | if not dest: |
|
620 | dest = hg.defaultdest(src) + "-hg" | |
|
621 | ui.status(_("assuming destination %s\n") % dest) | |
|
622 | dest = hg.defaultdest(src) + b"-hg" | |
|
623 | ui.status(_(b"assuming destination %s\n") % dest) | |
|
622 | 624 | |
|
623 | destc = convertsink(ui, dest, opts.get('dest_type')) | |
|
625 | destc = convertsink(ui, dest, opts.get(b'dest_type')) | |
|
624 | 626 | destc = scmutil.wrapconvertsink(destc) |
|
625 | 627 | |
|
626 | 628 | try: |
|
627 | 629 | srcc, defaultsort = convertsource( |
|
628 | ui, src, opts.get('source_type'), opts.get('rev') | |
|
630 | ui, src, opts.get(b'source_type'), opts.get(b'rev') | |
|
629 | 631 | ) |
|
630 | 632 | except Exception: |
|
631 | 633 | for path in destc.created: |
|
632 | 634 | shutil.rmtree(path, True) |
|
633 | 635 | raise |
|
634 | 636 | |
|
635 | sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort') | |
|
637 | sortmodes = (b'branchsort', b'datesort', b'sourcesort', b'closesort') | |
|
636 | 638 | sortmode = [m for m in sortmodes if opts.get(m)] |
|
637 | 639 | if len(sortmode) > 1: |
|
638 | raise error.Abort(_('more than one sort mode specified')) | |
|
640 | raise error.Abort(_(b'more than one sort mode specified')) | |
|
639 | 641 | if sortmode: |
|
640 | 642 | sortmode = sortmode[0] |
|
641 | 643 | else: |
|
642 | 644 | sortmode = defaultsort |
|
643 | 645 | |
|
644 | if sortmode == 'sourcesort' and not srcc.hasnativeorder(): | |
|
646 | if sortmode == b'sourcesort' and not srcc.hasnativeorder(): | |
|
645 | 647 | raise error.Abort( |
|
646 | _('--sourcesort is not supported by this data source') | |
|
648 | _(b'--sourcesort is not supported by this data source') | |
|
647 | 649 | ) |
|
648 | if sortmode == 'closesort' and not srcc.hasnativeclose(): | |
|
649 | raise error.Abort(_('--closesort is not supported by this data source')) | |
|
650 | if sortmode == b'closesort' and not srcc.hasnativeclose(): | |
|
651 | raise error.Abort( | |
|
652 | _(b'--closesort is not supported by this data source') | |
|
653 | ) | |
|
650 | 654 | |
|
651 | fmap = opts.get('filemap') | |
|
655 | fmap = opts.get(b'filemap') | |
|
652 | 656 | if fmap: |
|
653 | 657 | srcc = filemap.filemap_source(ui, srcc, fmap) |
|
654 | 658 | destc.setfilemapmode(True) |
@@ -39,19 +39,19 b' class convert_cvs(converter_source):' | |||
|
39 | 39 | def __init__(self, ui, repotype, path, revs=None): |
|
40 | 40 | super(convert_cvs, self).__init__(ui, repotype, path, revs=revs) |
|
41 | 41 | |
|
42 | cvs = os.path.join(path, "CVS") | |
|
42 | cvs = os.path.join(path, b"CVS") | |
|
43 | 43 | if not os.path.exists(cvs): |
|
44 | raise NoRepo(_("%s does not look like a CVS checkout") % path) | |
|
44 | raise NoRepo(_(b"%s does not look like a CVS checkout") % path) | |
|
45 | 45 | |
|
46 | checktool('cvs') | |
|
46 | checktool(b'cvs') | |
|
47 | 47 | |
|
48 | 48 | self.changeset = None |
|
49 | 49 | self.files = {} |
|
50 | 50 | self.tags = {} |
|
51 | 51 | self.lastbranch = {} |
|
52 | 52 | self.socket = None |
|
53 | self.cvsroot = open(os.path.join(cvs, "Root"), 'rb').read()[:-1] | |
|
54 | self.cvsrepo = open(os.path.join(cvs, "Repository"), 'rb').read()[:-1] | |
|
53 | self.cvsroot = open(os.path.join(cvs, b"Root"), b'rb').read()[:-1] | |
|
54 | self.cvsrepo = open(os.path.join(cvs, b"Repository"), b'rb').read()[:-1] | |
|
55 | 55 | self.encoding = encoding.encoding |
|
56 | 56 | |
|
57 | 57 | self._connect() |
@@ -65,7 +65,10 b' class convert_cvs(converter_source):' | |||
|
65 | 65 | if self.revs: |
|
66 | 66 | if len(self.revs) > 1: |
|
67 | 67 | raise error.Abort( |
|
68 | _('cvs source does not support specifying ' 'multiple revs') | |
|
68 | _( | |
|
69 | b'cvs source does not support specifying ' | |
|
70 | b'multiple revs' | |
|
71 | ) | |
|
69 | 72 | ) |
|
70 | 73 | # TODO: handle tags |
|
71 | 74 | try: |
@@ -73,23 +76,23 b' class convert_cvs(converter_source):' | |||
|
73 | 76 | maxrev = int(self.revs[0]) |
|
74 | 77 | except ValueError: |
|
75 | 78 | raise error.Abort( |
|
76 | _('revision %s is not a patchset number') % self.revs[0] | |
|
79 | _(b'revision %s is not a patchset number') % self.revs[0] | |
|
77 | 80 | ) |
|
78 | 81 | |
|
79 | 82 | d = encoding.getcwd() |
|
80 | 83 | try: |
|
81 | 84 | os.chdir(self.path) |
|
82 | 85 | |
|
83 | cache = 'update' | |
|
84 | if not self.ui.configbool('convert', 'cvsps.cache'): | |
|
86 | cache = b'update' | |
|
87 | if not self.ui.configbool(b'convert', b'cvsps.cache'): | |
|
85 | 88 | cache = None |
|
86 | 89 | db = cvsps.createlog(self.ui, cache=cache) |
|
87 | 90 | db = cvsps.createchangeset( |
|
88 | 91 | self.ui, |
|
89 | 92 | db, |
|
90 | fuzz=int(self.ui.config('convert', 'cvsps.fuzz')), | |
|
91 | mergeto=self.ui.config('convert', 'cvsps.mergeto'), | |
|
92 | mergefrom=self.ui.config('convert', 'cvsps.mergefrom'), | |
|
93 | fuzz=int(self.ui.config(b'convert', b'cvsps.fuzz')), | |
|
94 | mergeto=self.ui.config(b'convert', b'cvsps.mergeto'), | |
|
95 | mergefrom=self.ui.config(b'convert', b'cvsps.mergefrom'), | |
|
93 | 96 | ) |
|
94 | 97 | |
|
95 | 98 | for cs in db: |
@@ -99,16 +102,16 b' class convert_cvs(converter_source):' | |||
|
99 | 102 | cs.author = self.recode(cs.author) |
|
100 | 103 | self.lastbranch[cs.branch] = id |
|
101 | 104 | cs.comment = self.recode(cs.comment) |
|
102 | if self.ui.configbool('convert', 'localtimezone'): | |
|
105 | if self.ui.configbool(b'convert', b'localtimezone'): | |
|
103 | 106 | cs.date = makedatetimestamp(cs.date[0]) |
|
104 | date = dateutil.datestr(cs.date, '%Y-%m-%d %H:%M:%S %1%2') | |
|
107 | date = dateutil.datestr(cs.date, b'%Y-%m-%d %H:%M:%S %1%2') | |
|
105 | 108 | self.tags.update(dict.fromkeys(cs.tags, id)) |
|
106 | 109 | |
|
107 | 110 | files = {} |
|
108 | 111 | for f in cs.entries: |
|
109 | files[f.file] = "%s%s" % ( | |
|
110 | '.'.join([(b"%d" % x) for x in f.revision]), | |
|
111 | ['', '(DEAD)'][f.dead], | |
|
112 | files[f.file] = b"%s%s" % ( | |
|
113 | b'.'.join([(b"%d" % x) for x in f.revision]), | |
|
114 | [b'', b'(DEAD)'][f.dead], | |
|
112 | 115 | ) |
|
113 | 116 | |
|
114 | 117 | # add current commit to set |
@@ -117,7 +120,7 b' class convert_cvs(converter_source):' | |||
|
117 | 120 | date=date, |
|
118 | 121 | parents=[(b"%d" % p.id) for p in cs.parents], |
|
119 | 122 | desc=cs.comment, |
|
120 | branch=cs.branch or '', | |
|
123 | branch=cs.branch or b'', | |
|
121 | 124 | ) |
|
122 | 125 | self.changeset[id] = c |
|
123 | 126 | self.files[id] = files |
@@ -130,38 +133,38 b' class convert_cvs(converter_source):' | |||
|
130 | 133 | root = self.cvsroot |
|
131 | 134 | conntype = None |
|
132 | 135 | user, host = None, None |
|
133 | cmd = ['cvs', 'server'] | |
|
136 | cmd = [b'cvs', b'server'] | |
|
134 | 137 | |
|
135 | self.ui.status(_("connecting to %s\n") % root) | |
|
138 | self.ui.status(_(b"connecting to %s\n") % root) | |
|
136 | 139 | |
|
137 | if root.startswith(":pserver:"): | |
|
140 | if root.startswith(b":pserver:"): | |
|
138 | 141 | root = root[9:] |
|
139 | 142 | m = re.match( |
|
140 | 143 | r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)', root |
|
141 | 144 | ) |
|
142 | 145 | if m: |
|
143 | conntype = "pserver" | |
|
146 | conntype = b"pserver" | |
|
144 | 147 | user, passw, serv, port, root = m.groups() |
|
145 | 148 | if not user: |
|
146 | user = "anonymous" | |
|
149 | user = b"anonymous" | |
|
147 | 150 | if not port: |
|
148 | 151 | port = 2401 |
|
149 | 152 | else: |
|
150 | 153 | port = int(port) |
|
151 | format0 = ":pserver:%s@%s:%s" % (user, serv, root) | |
|
152 | format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root) | |
|
154 | format0 = b":pserver:%s@%s:%s" % (user, serv, root) | |
|
155 | format1 = b":pserver:%s@%s:%d%s" % (user, serv, port, root) | |
|
153 | 156 | |
|
154 | 157 | if not passw: |
|
155 | passw = "A" | |
|
156 | cvspass = os.path.expanduser("~/.cvspass") | |
|
158 | passw = b"A" | |
|
159 | cvspass = os.path.expanduser(b"~/.cvspass") | |
|
157 | 160 | try: |
|
158 | pf = open(cvspass, 'rb') | |
|
161 | pf = open(cvspass, b'rb') | |
|
159 | 162 | for line in pf.read().splitlines(): |
|
160 | part1, part2 = line.split(' ', 1) | |
|
163 | part1, part2 = line.split(b' ', 1) | |
|
161 | 164 | # /1 :pserver:user@example.com:2401/cvsroot/foo |
|
162 | 165 | # Ah<Z |
|
163 | if part1 == '/1': | |
|
164 | part1, part2 = part2.split(' ', 1) | |
|
166 | if part1 == b'/1': | |
|
167 | part1, part2 = part2.split(b' ', 1) | |
|
165 | 168 | format = format1 |
|
166 | 169 | # :pserver:user@example.com:/cvsroot/foo Ah<Z |
|
167 | 170 | else: |
@@ -179,72 +182,72 b' class convert_cvs(converter_source):' | |||
|
179 | 182 | sck = socket.socket() |
|
180 | 183 | sck.connect((serv, port)) |
|
181 | 184 | sck.send( |
|
182 | "\n".join( | |
|
185 | b"\n".join( | |
|
183 | 186 | [ |
|
184 | "BEGIN AUTH REQUEST", | |
|
187 | b"BEGIN AUTH REQUEST", | |
|
185 | 188 | root, |
|
186 | 189 | user, |
|
187 | 190 | passw, |
|
188 | "END AUTH REQUEST", | |
|
189 | "", | |
|
191 | b"END AUTH REQUEST", | |
|
192 | b"", | |
|
190 | 193 | ] |
|
191 | 194 | ) |
|
192 | 195 | ) |
|
193 | if sck.recv(128) != "I LOVE YOU\n": | |
|
194 | raise error.Abort(_("CVS pserver authentication failed")) | |
|
196 | if sck.recv(128) != b"I LOVE YOU\n": | |
|
197 | raise error.Abort(_(b"CVS pserver authentication failed")) | |
|
195 | 198 | |
|
196 | self.writep = self.readp = sck.makefile('r+') | |
|
199 | self.writep = self.readp = sck.makefile(b'r+') | |
|
197 | 200 | |
|
198 | if not conntype and root.startswith(":local:"): | |
|
199 | conntype = "local" | |
|
201 | if not conntype and root.startswith(b":local:"): | |
|
202 | conntype = b"local" | |
|
200 | 203 | root = root[7:] |
|
201 | 204 | |
|
202 | 205 | if not conntype: |
|
203 | 206 | # :ext:user@host/home/user/path/to/cvsroot |
|
204 | if root.startswith(":ext:"): | |
|
207 | if root.startswith(b":ext:"): | |
|
205 | 208 | root = root[5:] |
|
206 | 209 | m = re.match(br'(?:([^@:/]+)@)?([^:/]+):?(.*)', root) |
|
207 | 210 | # Do not take Windows path "c:\foo\bar" for a connection strings |
|
208 | 211 | if os.path.isdir(root) or not m: |
|
209 | conntype = "local" | |
|
212 | conntype = b"local" | |
|
210 | 213 | else: |
|
211 | conntype = "rsh" | |
|
214 | conntype = b"rsh" | |
|
212 | 215 | user, host, root = m.group(1), m.group(2), m.group(3) |
|
213 | 216 | |
|
214 | if conntype != "pserver": | |
|
215 | if conntype == "rsh": | |
|
216 | rsh = encoding.environ.get("CVS_RSH") or "ssh" | |
|
217 | if conntype != b"pserver": | |
|
218 | if conntype == b"rsh": | |
|
219 | rsh = encoding.environ.get(b"CVS_RSH") or b"ssh" | |
|
217 | 220 | if user: |
|
218 | cmd = [rsh, '-l', user, host] + cmd | |
|
221 | cmd = [rsh, b'-l', user, host] + cmd | |
|
219 | 222 | else: |
|
220 | 223 | cmd = [rsh, host] + cmd |
|
221 | 224 | |
|
222 | 225 | # popen2 does not support argument lists under Windows |
|
223 | 226 | cmd = [procutil.shellquote(arg) for arg in cmd] |
|
224 | cmd = procutil.quotecommand(' '.join(cmd)) | |
|
227 | cmd = procutil.quotecommand(b' '.join(cmd)) | |
|
225 | 228 | self.writep, self.readp = procutil.popen2(cmd) |
|
226 | 229 | |
|
227 | 230 | self.realroot = root |
|
228 | 231 | |
|
229 | self.writep.write("Root %s\n" % root) | |
|
232 | self.writep.write(b"Root %s\n" % root) | |
|
230 | 233 | self.writep.write( |
|
231 | "Valid-responses ok error Valid-requests Mode" | |
|
232 | " M Mbinary E Checked-in Created Updated" | |
|
233 | " Merged Removed\n" | |
|
234 | b"Valid-responses ok error Valid-requests Mode" | |
|
235 | b" M Mbinary E Checked-in Created Updated" | |
|
236 | b" Merged Removed\n" | |
|
234 | 237 | ) |
|
235 | self.writep.write("valid-requests\n") | |
|
238 | self.writep.write(b"valid-requests\n") | |
|
236 | 239 | self.writep.flush() |
|
237 | 240 | r = self.readp.readline() |
|
238 | if not r.startswith("Valid-requests"): | |
|
241 | if not r.startswith(b"Valid-requests"): | |
|
239 | 242 | raise error.Abort( |
|
240 | 243 | _( |
|
241 | 'unexpected response from CVS server ' | |
|
242 | '(expected "Valid-requests", but got %r)' | |
|
244 | b'unexpected response from CVS server ' | |
|
245 | b'(expected "Valid-requests", but got %r)' | |
|
243 | 246 | ) |
|
244 | 247 | % r |
|
245 | 248 | ) |
|
246 | if "UseUnchanged" in r: | |
|
247 | self.writep.write("UseUnchanged\n") | |
|
249 | if b"UseUnchanged" in r: | |
|
250 | self.writep.write(b"UseUnchanged\n") | |
|
248 | 251 | self.writep.flush() |
|
249 | 252 | self.readp.readline() |
|
250 | 253 | |
@@ -262,55 +265,55 b' class convert_cvs(converter_source):' | |||
|
262 | 265 | data = fp.read(min(count, chunksize)) |
|
263 | 266 | if not data: |
|
264 | 267 | raise error.Abort( |
|
265 | _("%d bytes missing from remote file") % count | |
|
268 | _(b"%d bytes missing from remote file") % count | |
|
266 | 269 | ) |
|
267 | 270 | count -= len(data) |
|
268 | 271 | output.write(data) |
|
269 | 272 | return output.getvalue() |
|
270 | 273 | |
|
271 | 274 | self._parse() |
|
272 | if rev.endswith("(DEAD)"): | |
|
275 | if rev.endswith(b"(DEAD)"): | |
|
273 | 276 | return None, None |
|
274 | 277 | |
|
275 | args = ("-N -P -kk -r %s --" % rev).split() | |
|
276 | args.append(self.cvsrepo + '/' + name) | |
|
278 | args = (b"-N -P -kk -r %s --" % rev).split() | |
|
279 | args.append(self.cvsrepo + b'/' + name) | |
|
277 | 280 | for x in args: |
|
278 | self.writep.write("Argument %s\n" % x) | |
|
279 | self.writep.write("Directory .\n%s\nco\n" % self.realroot) | |
|
281 | self.writep.write(b"Argument %s\n" % x) | |
|
282 | self.writep.write(b"Directory .\n%s\nco\n" % self.realroot) | |
|
280 | 283 | self.writep.flush() |
|
281 | 284 | |
|
282 | data = "" | |
|
285 | data = b"" | |
|
283 | 286 | mode = None |
|
284 | 287 | while True: |
|
285 | 288 | line = self.readp.readline() |
|
286 | if line.startswith("Created ") or line.startswith("Updated "): | |
|
289 | if line.startswith(b"Created ") or line.startswith(b"Updated "): | |
|
287 | 290 | self.readp.readline() # path |
|
288 | 291 | self.readp.readline() # entries |
|
289 | 292 | mode = self.readp.readline()[:-1] |
|
290 | 293 | count = int(self.readp.readline()[:-1]) |
|
291 | 294 | data = chunkedread(self.readp, count) |
|
292 | elif line.startswith(" "): | |
|
295 | elif line.startswith(b" "): | |
|
293 | 296 | data += line[1:] |
|
294 | elif line.startswith("M "): | |
|
297 | elif line.startswith(b"M "): | |
|
295 | 298 | pass |
|
296 | elif line.startswith("Mbinary "): | |
|
299 | elif line.startswith(b"Mbinary "): | |
|
297 | 300 | count = int(self.readp.readline()[:-1]) |
|
298 | 301 | data = chunkedread(self.readp, count) |
|
299 | 302 | else: |
|
300 | if line == "ok\n": | |
|
303 | if line == b"ok\n": | |
|
301 | 304 | if mode is None: |
|
302 | raise error.Abort(_('malformed response from CVS')) | |
|
303 | return (data, "x" in mode and "x" or "") | |
|
304 | elif line.startswith("E "): | |
|
305 | self.ui.warn(_("cvs server: %s\n") % line[2:]) | |
|
306 | elif line.startswith("Remove"): | |
|
305 | raise error.Abort(_(b'malformed response from CVS')) | |
|
306 | return (data, b"x" in mode and b"x" or b"") | |
|
307 | elif line.startswith(b"E "): | |
|
308 | self.ui.warn(_(b"cvs server: %s\n") % line[2:]) | |
|
309 | elif line.startswith(b"Remove"): | |
|
307 | 310 | self.readp.readline() |
|
308 | 311 | else: |
|
309 | raise error.Abort(_("unknown CVS response: %s") % line) | |
|
312 | raise error.Abort(_(b"unknown CVS response: %s") % line) | |
|
310 | 313 | |
|
311 | 314 | def getchanges(self, rev, full): |
|
312 | 315 | if full: |
|
313 | raise error.Abort(_("convert from cvs does not support --full")) | |
|
316 | raise error.Abort(_(b"convert from cvs does not support --full")) | |
|
314 | 317 | self._parse() |
|
315 | 318 | return sorted(self.files[rev].iteritems()), {}, set() |
|
316 | 319 |
@@ -92,18 +92,18 b' def getrepopath(cvspath):' | |||
|
92 | 92 | # of the '/' char after the '@' is located. The solution is the rest of the |
|
93 | 93 | # string after that '/' sign including it |
|
94 | 94 | |
|
95 | parts = cvspath.split(':') | |
|
96 | atposition = parts[-1].find('@') | |
|
95 | parts = cvspath.split(b':') | |
|
96 | atposition = parts[-1].find(b'@') | |
|
97 | 97 | start = 0 |
|
98 | 98 | |
|
99 | 99 | if atposition != -1: |
|
100 | 100 | start = atposition |
|
101 | 101 | |
|
102 | repopath = parts[-1][parts[-1].find('/', start) :] | |
|
102 | repopath = parts[-1][parts[-1].find(b'/', start) :] | |
|
103 | 103 | return repopath |
|
104 | 104 | |
|
105 | 105 | |
|
106 | def createlog(ui, directory=None, root="", rlog=True, cache=None): | |
|
106 | def createlog(ui, directory=None, root=b"", rlog=True, cache=None): | |
|
107 | 107 | '''Collect the CVS rlog''' |
|
108 | 108 | |
|
109 | 109 | # Because we store many duplicate commit log messages, reusing strings |
@@ -111,10 +111,10 b' def createlog(ui, directory=None, root="' | |||
|
111 | 111 | _scache = {} |
|
112 | 112 | |
|
113 | 113 | def scache(s): |
|
114 | "return a shared version of a string" | |
|
114 | b"return a shared version of a string" | |
|
115 | 115 | return _scache.setdefault(s, s) |
|
116 | 116 | |
|
117 | ui.status(_('collecting CVS rlog\n')) | |
|
117 | ui.status(_(b'collecting CVS rlog\n')) | |
|
118 | 118 | |
|
119 | 119 | log = [] # list of logentry objects containing the CVS state |
|
120 | 120 | |
@@ -144,39 +144,39 b' def createlog(ui, directory=None, root="' | |||
|
144 | 144 | |
|
145 | 145 | file_added_re = re.compile(br'file [^/]+ was (initially )?added on branch') |
|
146 | 146 | |
|
147 | prefix = '' # leading path to strip of what we get from CVS | |
|
147 | prefix = b'' # leading path to strip of what we get from CVS | |
|
148 | 148 | |
|
149 | 149 | if directory is None: |
|
150 | 150 | # Current working directory |
|
151 | 151 | |
|
152 | 152 | # Get the real directory in the repository |
|
153 | 153 | try: |
|
154 | with open(os.path.join(b'CVS', b'Repository'), 'rb') as f: | |
|
154 | with open(os.path.join(b'CVS', b'Repository'), b'rb') as f: | |
|
155 | 155 | prefix = f.read().strip() |
|
156 | 156 | directory = prefix |
|
157 | if prefix == ".": | |
|
158 | prefix = "" | |
|
157 | if prefix == b".": | |
|
158 | prefix = b"" | |
|
159 | 159 | except IOError: |
|
160 | raise logerror(_('not a CVS sandbox')) | |
|
160 | raise logerror(_(b'not a CVS sandbox')) | |
|
161 | 161 | |
|
162 | 162 | if prefix and not prefix.endswith(pycompat.ossep): |
|
163 | 163 | prefix += pycompat.ossep |
|
164 | 164 | |
|
165 | 165 | # Use the Root file in the sandbox, if it exists |
|
166 | 166 | try: |
|
167 | root = open(os.path.join('CVS', 'Root'), 'rb').read().strip() | |
|
167 | root = open(os.path.join(b'CVS', b'Root'), b'rb').read().strip() | |
|
168 | 168 | except IOError: |
|
169 | 169 | pass |
|
170 | 170 | |
|
171 | 171 | if not root: |
|
172 | root = encoding.environ.get('CVSROOT', '') | |
|
172 | root = encoding.environ.get(b'CVSROOT', b'') | |
|
173 | 173 | |
|
174 | 174 | # read log cache if one exists |
|
175 | 175 | oldlog = [] |
|
176 | 176 | date = None |
|
177 | 177 | |
|
178 | 178 | if cache: |
|
179 | cachedir = os.path.expanduser('~/.hg.cvsps') | |
|
179 | cachedir = os.path.expanduser(b'~/.hg.cvsps') | |
|
180 | 180 | if not os.path.exists(cachedir): |
|
181 | 181 | os.mkdir(cachedir) |
|
182 | 182 | |
@@ -189,50 +189,50 b' def createlog(ui, directory=None, root="' | |||
|
189 | 189 | # and |
|
190 | 190 | # /pserver/user/server/path |
|
191 | 191 | # are mapped to different cache file names. |
|
192 | cachefile = root.split(":") + [directory, "cache"] | |
|
193 | cachefile = ['-'.join(re.findall(br'\w+', s)) for s in cachefile if s] | |
|
192 | cachefile = root.split(b":") + [directory, b"cache"] | |
|
193 | cachefile = [b'-'.join(re.findall(br'\w+', s)) for s in cachefile if s] | |
|
194 | 194 | cachefile = os.path.join( |
|
195 | cachedir, '.'.join([s for s in cachefile if s]) | |
|
195 | cachedir, b'.'.join([s for s in cachefile if s]) | |
|
196 | 196 | ) |
|
197 | 197 | |
|
198 | if cache == 'update': | |
|
198 | if cache == b'update': | |
|
199 | 199 | try: |
|
200 | ui.note(_('reading cvs log cache %s\n') % cachefile) | |
|
201 | oldlog = pickle.load(open(cachefile, 'rb')) | |
|
200 | ui.note(_(b'reading cvs log cache %s\n') % cachefile) | |
|
201 | oldlog = pickle.load(open(cachefile, b'rb')) | |
|
202 | 202 | for e in oldlog: |
|
203 | 203 | if not ( |
|
204 | util.safehasattr(e, 'branchpoints') | |
|
205 | and util.safehasattr(e, 'commitid') | |
|
206 | and util.safehasattr(e, 'mergepoint') | |
|
204 | util.safehasattr(e, b'branchpoints') | |
|
205 | and util.safehasattr(e, b'commitid') | |
|
206 | and util.safehasattr(e, b'mergepoint') | |
|
207 | 207 | ): |
|
208 | ui.status(_('ignoring old cache\n')) | |
|
208 | ui.status(_(b'ignoring old cache\n')) | |
|
209 | 209 | oldlog = [] |
|
210 | 210 | break |
|
211 | 211 | |
|
212 | ui.note(_('cache has %d log entries\n') % len(oldlog)) | |
|
212 | ui.note(_(b'cache has %d log entries\n') % len(oldlog)) | |
|
213 | 213 | except Exception as e: |
|
214 | ui.note(_('error reading cache: %r\n') % e) | |
|
214 | ui.note(_(b'error reading cache: %r\n') % e) | |
|
215 | 215 | |
|
216 | 216 | if oldlog: |
|
217 | 217 | date = oldlog[-1].date # last commit date as a (time,tz) tuple |
|
218 | date = dateutil.datestr(date, '%Y/%m/%d %H:%M:%S %1%2') | |
|
218 | date = dateutil.datestr(date, b'%Y/%m/%d %H:%M:%S %1%2') | |
|
219 | 219 | |
|
220 | 220 | # build the CVS commandline |
|
221 | cmd = ['cvs', '-q'] | |
|
221 | cmd = [b'cvs', b'-q'] | |
|
222 | 222 | if root: |
|
223 | cmd.append('-d%s' % root) | |
|
223 | cmd.append(b'-d%s' % root) | |
|
224 | 224 | p = util.normpath(getrepopath(root)) |
|
225 | if not p.endswith('/'): | |
|
226 | p += '/' | |
|
225 | if not p.endswith(b'/'): | |
|
226 | p += b'/' | |
|
227 | 227 | if prefix: |
|
228 | 228 | # looks like normpath replaces "" by "." |
|
229 | 229 | prefix = p + util.normpath(prefix) |
|
230 | 230 | else: |
|
231 | 231 | prefix = p |
|
232 | cmd.append(['log', 'rlog'][rlog]) | |
|
232 | cmd.append([b'log', b'rlog'][rlog]) | |
|
233 | 233 | if date: |
|
234 | 234 | # no space between option and date string |
|
235 | cmd.append('-d>%s' % date) | |
|
235 | cmd.append(b'-d>%s' % date) | |
|
236 | 236 | cmd.append(directory) |
|
237 | 237 | |
|
238 | 238 | # state machine begins here |
@@ -243,17 +243,17 b' def createlog(ui, directory=None, root="' | |||
|
243 | 243 | store = False # set when a new record can be appended |
|
244 | 244 | |
|
245 | 245 | cmd = [procutil.shellquote(arg) for arg in cmd] |
|
246 | ui.note(_("running %s\n") % (' '.join(cmd))) | |
|
247 | ui.debug("prefix=%r directory=%r root=%r\n" % (prefix, directory, root)) | |
|
246 | ui.note(_(b"running %s\n") % (b' '.join(cmd))) | |
|
247 | ui.debug(b"prefix=%r directory=%r root=%r\n" % (prefix, directory, root)) | |
|
248 | 248 | |
|
249 | pfp = procutil.popen(' '.join(cmd), 'rb') | |
|
249 | pfp = procutil.popen(b' '.join(cmd), b'rb') | |
|
250 | 250 | peek = util.fromnativeeol(pfp.readline()) |
|
251 | 251 | while True: |
|
252 | 252 | line = peek |
|
253 | if line == '': | |
|
253 | if line == b'': | |
|
254 | 254 | break |
|
255 | 255 | peek = util.fromnativeeol(pfp.readline()) |
|
256 | if line.endswith('\n'): | |
|
256 | if line.endswith(b'\n'): | |
|
257 | 257 | line = line[:-1] |
|
258 | 258 | # ui.debug('state=%d line=%r\n' % (state, line)) |
|
259 | 259 | |
@@ -267,12 +267,12 b' def createlog(ui, directory=None, root="' | |||
|
267 | 267 | filename = util.normpath(rcs[:-2]) |
|
268 | 268 | if filename.startswith(prefix): |
|
269 | 269 | filename = filename[len(prefix) :] |
|
270 | if filename.startswith('/'): | |
|
270 | if filename.startswith(b'/'): | |
|
271 | 271 | filename = filename[1:] |
|
272 | if filename.startswith('Attic/'): | |
|
272 | if filename.startswith(b'Attic/'): | |
|
273 | 273 | filename = filename[6:] |
|
274 | 274 | else: |
|
275 | filename = filename.replace('/Attic/', '/') | |
|
275 | filename = filename.replace(b'/Attic/', b'/') | |
|
276 | 276 | state = 2 |
|
277 | 277 | continue |
|
278 | 278 | state = 1 |
@@ -289,7 +289,7 b' def createlog(ui, directory=None, root="' | |||
|
289 | 289 | elif state == 1: |
|
290 | 290 | # expect 'Working file' (only when using log instead of rlog) |
|
291 | 291 | match = re_10.match(line) |
|
292 | assert match, _('RCS file must be followed by working file') | |
|
292 | assert match, _(b'RCS file must be followed by working file') | |
|
293 | 293 | filename = util.normpath(match.group(1)) |
|
294 | 294 | state = 2 |
|
295 | 295 | |
@@ -303,7 +303,7 b' def createlog(ui, directory=None, root="' | |||
|
303 | 303 | # read the symbolic names and store as tags |
|
304 | 304 | match = re_30.match(line) |
|
305 | 305 | if match: |
|
306 | rev = [int(x) for x in match.group(2).split('.')] | |
|
306 | rev = [int(x) for x in match.group(2).split(b'.')] | |
|
307 | 307 | |
|
308 | 308 | # Convert magic branch number to an odd-numbered one |
|
309 | 309 | revn = len(rev) |
@@ -327,7 +327,7 b' def createlog(ui, directory=None, root="' | |||
|
327 | 327 | state = 5 |
|
328 | 328 | else: |
|
329 | 329 | assert not re_32.match(line), _( |
|
330 | 'must have at least ' 'some revisions' | |
|
330 | b'must have at least ' b'some revisions' | |
|
331 | 331 | ) |
|
332 | 332 | |
|
333 | 333 | elif state == 5: |
@@ -335,11 +335,11 b' def createlog(ui, directory=None, root="' | |||
|
335 | 335 | # we create the logentry here from values stored in states 0 to 4, |
|
336 | 336 | # as this state is re-entered for subsequent revisions of a file. |
|
337 | 337 | match = re_50.match(line) |
|
338 | assert match, _('expected revision number') | |
|
338 | assert match, _(b'expected revision number') | |
|
339 | 339 | e = logentry( |
|
340 | 340 | rcs=scache(rcs), |
|
341 | 341 | file=scache(filename), |
|
342 | revision=tuple([int(x) for x in match.group(1).split('.')]), | |
|
342 | revision=tuple([int(x) for x in match.group(1).split(b'.')]), | |
|
343 | 343 | branches=[], |
|
344 | 344 | parent=None, |
|
345 | 345 | commitid=None, |
@@ -352,21 +352,25 b' def createlog(ui, directory=None, root="' | |||
|
352 | 352 | elif state == 6: |
|
353 | 353 | # expecting date, author, state, lines changed |
|
354 | 354 | match = re_60.match(line) |
|
355 | assert match, _('revision must be followed by date line') | |
|
355 | assert match, _(b'revision must be followed by date line') | |
|
356 | 356 | d = match.group(1) |
|
357 | if d[2] == '/': | |
|
357 | if d[2] == b'/': | |
|
358 | 358 | # Y2K |
|
359 | d = '19' + d | |
|
359 | d = b'19' + d | |
|
360 | 360 | |
|
361 | 361 | if len(d.split()) != 3: |
|
362 | 362 | # cvs log dates always in GMT |
|
363 | d = d + ' UTC' | |
|
363 | d = d + b' UTC' | |
|
364 | 364 | e.date = dateutil.parsedate( |
|
365 | 365 | d, |
|
366 | ['%y/%m/%d %H:%M:%S', '%Y/%m/%d %H:%M:%S', '%Y-%m-%d %H:%M:%S'], | |
|
366 | [ | |
|
367 | b'%y/%m/%d %H:%M:%S', | |
|
368 | b'%Y/%m/%d %H:%M:%S', | |
|
369 | b'%Y-%m-%d %H:%M:%S', | |
|
370 | ], | |
|
367 | 371 | ) |
|
368 | 372 | e.author = scache(match.group(2)) |
|
369 | e.dead = match.group(3).lower() == 'dead' | |
|
373 | e.dead = match.group(3).lower() == b'dead' | |
|
370 | 374 | |
|
371 | 375 | if match.group(5): |
|
372 | 376 | if match.group(6): |
@@ -382,14 +386,14 b' def createlog(ui, directory=None, root="' | |||
|
382 | 386 | e.commitid = match.group(8) |
|
383 | 387 | |
|
384 | 388 | if match.group(9): # cvsnt mergepoint |
|
385 | myrev = match.group(10).split('.') | |
|
389 | myrev = match.group(10).split(b'.') | |
|
386 | 390 | if len(myrev) == 2: # head |
|
387 | e.mergepoint = 'HEAD' | |
|
391 | e.mergepoint = b'HEAD' | |
|
388 | 392 | else: |
|
389 | myrev = '.'.join(myrev[:-2] + ['0', myrev[-2]]) | |
|
393 | myrev = b'.'.join(myrev[:-2] + [b'0', myrev[-2]]) | |
|
390 | 394 | branches = [b for b in branchmap if branchmap[b] == myrev] |
|
391 | 395 | assert len(branches) == 1, ( |
|
392 | 'unknown branch: %s' % e.mergepoint | |
|
396 | b'unknown branch: %s' % e.mergepoint | |
|
393 | 397 | ) |
|
394 | 398 | e.mergepoint = branches[0] |
|
395 | 399 | |
@@ -402,8 +406,8 b' def createlog(ui, directory=None, root="' | |||
|
402 | 406 | m = re_70.match(line) |
|
403 | 407 | if m: |
|
404 | 408 | e.branches = [ |
|
405 | tuple([int(y) for y in x.strip().split('.')]) | |
|
406 | for x in m.group(1).split(';') | |
|
409 | tuple([int(y) for y in x.strip().split(b'.')]) | |
|
410 | for x in m.group(1).split(b';') | |
|
407 | 411 | ] |
|
408 | 412 | state = 8 |
|
409 | 413 | elif re_31.match(line) and re_50.match(peek): |
@@ -419,7 +423,7 b' def createlog(ui, directory=None, root="' | |||
|
419 | 423 | # store commit log message |
|
420 | 424 | if re_31.match(line): |
|
421 | 425 | cpeek = peek |
|
422 | if cpeek.endswith('\n'): | |
|
426 | if cpeek.endswith(b'\n'): | |
|
423 | 427 | cpeek = cpeek[:-1] |
|
424 | 428 | if re_50.match(cpeek): |
|
425 | 429 | state = 5 |
@@ -447,7 +451,7 b' def createlog(ui, directory=None, root="' | |||
|
447 | 451 | and file_added_re.match(e.comment[0]) |
|
448 | 452 | ): |
|
449 | 453 | ui.debug( |
|
450 | 'found synthetic revision in %s: %r\n' % (e.rcs, e.comment[0]) | |
|
454 | b'found synthetic revision in %s: %r\n' % (e.rcs, e.comment[0]) | |
|
451 | 455 | ) |
|
452 | 456 | e.synthetic = True |
|
453 | 457 | |
@@ -455,7 +459,7 b' def createlog(ui, directory=None, root="' | |||
|
455 | 459 | # clean up the results and save in the log. |
|
456 | 460 | store = False |
|
457 | 461 | e.tags = sorted([scache(x) for x in tags.get(e.revision, [])]) |
|
458 | e.comment = scache('\n'.join(e.comment)) | |
|
462 | e.comment = scache(b'\n'.join(e.comment)) | |
|
459 | 463 | |
|
460 | 464 | revn = len(e.revision) |
|
461 | 465 | if revn > 3 and (revn % 2) == 0: |
@@ -466,7 +470,7 b' def createlog(ui, directory=None, root="' | |||
|
466 | 470 | # find the branches starting from this revision |
|
467 | 471 | branchpoints = set() |
|
468 | 472 | for branch, revision in branchmap.iteritems(): |
|
469 | revparts = tuple([int(i) for i in revision.split('.')]) | |
|
473 | revparts = tuple([int(i) for i in revision.split(b'.')]) | |
|
470 | 474 | if len(revparts) < 2: # bad tags |
|
471 | 475 | continue |
|
472 | 476 | if revparts[-2] == 0 and revparts[-1] % 2 == 0: |
@@ -480,11 +484,12 b' def createlog(ui, directory=None, root="' | |||
|
480 | 484 | |
|
481 | 485 | log.append(e) |
|
482 | 486 | |
|
483 | rcsmap[e.rcs.replace('/Attic/', '/')] = e.rcs | |
|
487 | rcsmap[e.rcs.replace(b'/Attic/', b'/')] = e.rcs | |
|
484 | 488 | |
|
485 | 489 | if len(log) % 100 == 0: |
|
486 | 490 | ui.status( |
|
487 |
stringutil.ellipsis('%d %s' % (len(log), e.file), 80) |
|
|
491 | stringutil.ellipsis(b'%d %s' % (len(log), e.file), 80) | |
|
492 | + b'\n' | |
|
488 | 493 | ) |
|
489 | 494 | |
|
490 | 495 | log.sort(key=lambda x: (x.rcs, x.revision)) |
@@ -492,7 +497,7 b' def createlog(ui, directory=None, root="' | |||
|
492 | 497 | # find parent revisions of individual files |
|
493 | 498 | versions = {} |
|
494 | 499 | for e in sorted(oldlog, key=lambda x: (x.rcs, x.revision)): |
|
495 | rcs = e.rcs.replace('/Attic/', '/') | |
|
500 | rcs = e.rcs.replace(b'/Attic/', b'/') | |
|
496 | 501 | if rcs in rcsmap: |
|
497 | 502 | e.rcs = rcsmap[rcs] |
|
498 | 503 | branch = e.revision[:-1] |
@@ -515,28 +520,28 b' def createlog(ui, directory=None, root="' | |||
|
515 | 520 | if oldlog and oldlog[-1].date >= log[0].date: |
|
516 | 521 | raise logerror( |
|
517 | 522 | _( |
|
518 | 'log cache overlaps with new log entries,' | |
|
519 | ' re-run without cache.' | |
|
523 | b'log cache overlaps with new log entries,' | |
|
524 | b' re-run without cache.' | |
|
520 | 525 | ) |
|
521 | 526 | ) |
|
522 | 527 | |
|
523 | 528 | log = oldlog + log |
|
524 | 529 | |
|
525 | 530 | # write the new cachefile |
|
526 | ui.note(_('writing cvs log cache %s\n') % cachefile) | |
|
527 | pickle.dump(log, open(cachefile, 'wb')) | |
|
531 | ui.note(_(b'writing cvs log cache %s\n') % cachefile) | |
|
532 | pickle.dump(log, open(cachefile, b'wb')) | |
|
528 | 533 | else: |
|
529 | 534 | log = oldlog |
|
530 | 535 | |
|
531 | ui.status(_('%d log entries\n') % len(log)) | |
|
536 | ui.status(_(b'%d log entries\n') % len(log)) | |
|
532 | 537 | |
|
533 | encodings = ui.configlist('convert', 'cvsps.logencoding') | |
|
538 | encodings = ui.configlist(b'convert', b'cvsps.logencoding') | |
|
534 | 539 | if encodings: |
|
535 | 540 | |
|
536 | 541 | def revstr(r): |
|
537 | 542 | # this is needed, because logentry.revision is a tuple of "int" |
|
538 | 543 | # (e.g. (1, 2) for "1.2") |
|
539 | return '.'.join(pycompat.maplist(pycompat.bytestr, r)) | |
|
544 | return b'.'.join(pycompat.maplist(pycompat.bytestr, r)) | |
|
540 | 545 | |
|
541 | 546 | for entry in log: |
|
542 | 547 | comment = entry.comment |
@@ -547,7 +552,7 b' def createlog(ui, directory=None, root="' | |||
|
547 | 552 | ) |
|
548 | 553 | if ui.debugflag: |
|
549 | 554 | ui.debug( |
|
550 | "transcoding by %s: %s of %s\n" | |
|
555 | b"transcoding by %s: %s of %s\n" | |
|
551 | 556 | % (e, revstr(entry.revision), entry.file) |
|
552 | 557 | ) |
|
553 | 558 | break |
@@ -557,20 +562,22 b' def createlog(ui, directory=None, root="' | |||
|
557 | 562 | raise error.Abort( |
|
558 | 563 | inst, |
|
559 | 564 | hint=_( |
|
560 | 'check convert.cvsps.logencoding' ' configuration' | |
|
565 | b'check convert.cvsps.logencoding' b' configuration' | |
|
561 | 566 | ), |
|
562 | 567 | ) |
|
563 | 568 | else: |
|
564 | 569 | raise error.Abort( |
|
565 | 570 | _( |
|
566 | "no encoding can transcode" | |
|
567 | " CVS log message for %s of %s" | |
|
571 | b"no encoding can transcode" | |
|
572 | b" CVS log message for %s of %s" | |
|
568 | 573 | ) |
|
569 | 574 | % (revstr(entry.revision), entry.file), |
|
570 | hint=_('check convert.cvsps.logencoding' ' configuration'), | |
|
575 | hint=_( | |
|
576 | b'check convert.cvsps.logencoding' b' configuration' | |
|
577 | ), | |
|
571 | 578 | ) |
|
572 | 579 | |
|
573 | hook.hook(ui, None, "cvslog", True, log=log) | |
|
580 | hook.hook(ui, None, b"cvslog", True, log=log) | |
|
574 | 581 | |
|
575 | 582 | return log |
|
576 | 583 | |
@@ -597,14 +604,16 b' class changeset(object):' | |||
|
597 | 604 | self.__dict__.update(entries) |
|
598 | 605 | |
|
599 | 606 | def __repr__(self): |
|
600 | items = ("%s=%r" % (k, self.__dict__[k]) for k in sorted(self.__dict__)) | |
|
601 | return "%s(%s)" % (type(self).__name__, ", ".join(items)) | |
|
607 | items = ( | |
|
608 | b"%s=%r" % (k, self.__dict__[k]) for k in sorted(self.__dict__) | |
|
609 | ) | |
|
610 | return b"%s(%s)" % (type(self).__name__, b", ".join(items)) | |
|
602 | 611 | |
|
603 | 612 | |
|
604 | 613 | def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None): |
|
605 | 614 | '''Convert log into changesets.''' |
|
606 | 615 | |
|
607 | ui.status(_('creating changesets\n')) | |
|
616 | ui.status(_(b'creating changesets\n')) | |
|
608 | 617 | |
|
609 | 618 | # try to order commitids by date |
|
610 | 619 | mindate = {} |
@@ -619,10 +628,10 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
619 | 628 | log.sort( |
|
620 | 629 | key=lambda x: ( |
|
621 | 630 | mindate.get(x.commitid, (-1, 0)), |
|
622 | x.commitid or '', | |
|
631 | x.commitid or b'', | |
|
623 | 632 | x.comment, |
|
624 | 633 | x.author, |
|
625 | x.branch or '', | |
|
634 | x.branch or b'', | |
|
626 | 635 | x.date, |
|
627 | 636 | x.branchpoints, |
|
628 | 637 | ) |
@@ -682,8 +691,8 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
682 | 691 | |
|
683 | 692 | files = set() |
|
684 | 693 | if len(changesets) % 100 == 0: |
|
685 | t = '%d %s' % (len(changesets), repr(e.comment)[1:-1]) | |
|
686 | ui.status(stringutil.ellipsis(t, 80) + '\n') | |
|
694 | t = b'%d %s' % (len(changesets), repr(e.comment)[1:-1]) | |
|
695 | ui.status(stringutil.ellipsis(t, 80) + b'\n') | |
|
687 | 696 | |
|
688 | 697 | c.entries.append(e) |
|
689 | 698 | files.add(e.file) |
@@ -705,9 +714,9 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
705 | 714 | # Sort files in each changeset |
|
706 | 715 | |
|
707 | 716 | def entitycompare(l, r): |
|
708 | 'Mimic cvsps sorting order' | |
|
709 | l = l.file.split('/') | |
|
710 | r = r.file.split('/') | |
|
717 | b'Mimic cvsps sorting order' | |
|
718 | l = l.file.split(b'/') | |
|
719 | r = r.file.split(b'/') | |
|
711 | 720 | nl = len(l) |
|
712 | 721 | nr = len(r) |
|
713 | 722 | n = min(nl, nr) |
@@ -842,7 +851,7 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
842 | 851 | # Ensure no changeset has a synthetic changeset as a parent. |
|
843 | 852 | while p.synthetic: |
|
844 | 853 | assert len(p.parents) <= 1, _( |
|
845 | 'synthetic changeset cannot have multiple parents' | |
|
854 | b'synthetic changeset cannot have multiple parents' | |
|
846 | 855 | ) |
|
847 | 856 | if p.parents: |
|
848 | 857 | p = p.parents[0] |
@@ -854,7 +863,7 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
854 | 863 | c.parents.append(p) |
|
855 | 864 | |
|
856 | 865 | if c.mergepoint: |
|
857 | if c.mergepoint == 'HEAD': | |
|
866 | if c.mergepoint == b'HEAD': | |
|
858 | 867 | c.mergepoint = None |
|
859 | 868 | c.parents.append(changesets[branches[c.mergepoint]]) |
|
860 | 869 | |
@@ -862,15 +871,15 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
862 | 871 | m = mergefrom.search(c.comment) |
|
863 | 872 | if m: |
|
864 | 873 | m = m.group(1) |
|
865 | if m == 'HEAD': | |
|
874 | if m == b'HEAD': | |
|
866 | 875 | m = None |
|
867 | 876 | try: |
|
868 | 877 | candidate = changesets[branches[m]] |
|
869 | 878 | except KeyError: |
|
870 | 879 | ui.warn( |
|
871 | 880 | _( |
|
872 | "warning: CVS commit message references " | |
|
873 | "non-existent branch %r:\n%s\n" | |
|
881 | b"warning: CVS commit message references " | |
|
882 | b"non-existent branch %r:\n%s\n" | |
|
874 | 883 | ) |
|
875 | 884 | % (pycompat.bytestr(m), c.comment) |
|
876 | 885 | ) |
@@ -882,7 +891,7 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
882 | 891 | if m: |
|
883 | 892 | if m.groups(): |
|
884 | 893 | m = m.group(1) |
|
885 | if m == 'HEAD': | |
|
894 | if m == b'HEAD': | |
|
886 | 895 | m = None |
|
887 | 896 | else: |
|
888 | 897 | m = None # if no group found then merge to HEAD |
@@ -892,7 +901,7 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
892 | 901 | author=c.author, |
|
893 | 902 | branch=m, |
|
894 | 903 | date=c.date, |
|
895 | comment='convert-repo: CVS merge from branch %s' | |
|
904 | comment=b'convert-repo: CVS merge from branch %s' | |
|
896 | 905 | % c.branch, |
|
897 | 906 | entries=[], |
|
898 | 907 | tags=[], |
@@ -927,13 +936,13 b' def createchangeset(ui, log, fuzz=60, me' | |||
|
927 | 936 | for l, r in odd: |
|
928 | 937 | if l.id is not None and r.id is not None: |
|
929 | 938 | ui.warn( |
|
930 | _('changeset %d is both before and after %d\n') | |
|
939 | _(b'changeset %d is both before and after %d\n') | |
|
931 | 940 | % (l.id, r.id) |
|
932 | 941 | ) |
|
933 | 942 | |
|
934 | ui.status(_('%d changeset entries\n') % len(changesets)) | |
|
943 | ui.status(_(b'%d changeset entries\n') % len(changesets)) | |
|
935 | 944 | |
|
936 | hook.hook(ui, None, "cvschangesets", True, changesets=changesets) | |
|
945 | hook.hook(ui, None, b"cvschangesets", True, changesets=changesets) | |
|
937 | 946 | |
|
938 | 947 | return changesets |
|
939 | 948 | |
@@ -944,27 +953,27 b' def debugcvsps(ui, *args, **opts):' | |||
|
944 | 953 | commit log entries and dates. |
|
945 | 954 | ''' |
|
946 | 955 | opts = pycompat.byteskwargs(opts) |
|
947 | if opts["new_cache"]: | |
|
948 | cache = "write" | |
|
949 | elif opts["update_cache"]: | |
|
950 | cache = "update" | |
|
956 | if opts[b"new_cache"]: | |
|
957 | cache = b"write" | |
|
958 | elif opts[b"update_cache"]: | |
|
959 | cache = b"update" | |
|
951 | 960 | else: |
|
952 | 961 | cache = None |
|
953 | 962 | |
|
954 | revisions = opts["revisions"] | |
|
963 | revisions = opts[b"revisions"] | |
|
955 | 964 | |
|
956 | 965 | try: |
|
957 | 966 | if args: |
|
958 | 967 | log = [] |
|
959 | 968 | for d in args: |
|
960 | log += createlog(ui, d, root=opts["root"], cache=cache) | |
|
969 | log += createlog(ui, d, root=opts[b"root"], cache=cache) | |
|
961 | 970 | else: |
|
962 | log = createlog(ui, root=opts["root"], cache=cache) | |
|
971 | log = createlog(ui, root=opts[b"root"], cache=cache) | |
|
963 | 972 | except logerror as e: |
|
964 | ui.write("%r\n" % e) | |
|
973 | ui.write(b"%r\n" % e) | |
|
965 | 974 | return |
|
966 | 975 | |
|
967 | changesets = createchangeset(ui, log, opts["fuzz"]) | |
|
976 | changesets = createchangeset(ui, log, opts[b"fuzz"]) | |
|
968 | 977 | del log |
|
969 | 978 | |
|
970 | 979 | # Print changesets (optionally filtered) |
@@ -974,7 +983,7 b' def debugcvsps(ui, *args, **opts):' | |||
|
974 | 983 | ancestors = {} # parent branch |
|
975 | 984 | for cs in changesets: |
|
976 | 985 | |
|
977 | if opts["ancestors"]: | |
|
986 | if opts[b"ancestors"]: | |
|
978 | 987 | if cs.branch not in branches and cs.parents and cs.parents[0].id: |
|
979 | 988 | ancestors[cs.branch] = ( |
|
980 | 989 | changesets[cs.parents[0].id - 1].branch, |
@@ -983,72 +992,75 b' def debugcvsps(ui, *args, **opts):' | |||
|
983 | 992 | branches[cs.branch] = cs.id |
|
984 | 993 | |
|
985 | 994 | # limit by branches |
|
986 | if opts["branches"] and (cs.branch or 'HEAD') not in opts["branches"]: | |
|
995 | if ( | |
|
996 | opts[b"branches"] | |
|
997 | and (cs.branch or b'HEAD') not in opts[b"branches"] | |
|
998 | ): | |
|
987 | 999 | continue |
|
988 | 1000 | |
|
989 | 1001 | if not off: |
|
990 | 1002 | # Note: trailing spaces on several lines here are needed to have |
|
991 | 1003 | # bug-for-bug compatibility with cvsps. |
|
992 | ui.write('---------------------\n') | |
|
993 | ui.write(('PatchSet %d \n' % cs.id)) | |
|
1004 | ui.write(b'---------------------\n') | |
|
1005 | ui.write((b'PatchSet %d \n' % cs.id)) | |
|
994 | 1006 | ui.write( |
|
995 | 1007 | ( |
|
996 | 'Date: %s\n' | |
|
997 | % dateutil.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2') | |
|
1008 | b'Date: %s\n' | |
|
1009 | % dateutil.datestr(cs.date, b'%Y/%m/%d %H:%M:%S %1%2') | |
|
998 | 1010 | ) |
|
999 | 1011 | ) |
|
1000 | ui.write(('Author: %s\n' % cs.author)) | |
|
1001 | ui.write(('Branch: %s\n' % (cs.branch or 'HEAD'))) | |
|
1012 | ui.write((b'Author: %s\n' % cs.author)) | |
|
1013 | ui.write((b'Branch: %s\n' % (cs.branch or b'HEAD'))) | |
|
1002 | 1014 | ui.write( |
|
1003 | 1015 | ( |
|
1004 | 'Tag%s: %s \n' | |
|
1016 | b'Tag%s: %s \n' | |
|
1005 | 1017 | % ( |
|
1006 | ['', 's'][len(cs.tags) > 1], | |
|
1007 | ','.join(cs.tags) or '(none)', | |
|
1018 | [b'', b's'][len(cs.tags) > 1], | |
|
1019 | b','.join(cs.tags) or b'(none)', | |
|
1008 | 1020 | ) |
|
1009 | 1021 | ) |
|
1010 | 1022 | ) |
|
1011 | 1023 | if cs.branchpoints: |
|
1012 | 1024 | ui.write( |
|
1013 | 'Branchpoints: %s \n' % ', '.join(sorted(cs.branchpoints)) | |
|
1025 | b'Branchpoints: %s \n' % b', '.join(sorted(cs.branchpoints)) | |
|
1014 | 1026 | ) |
|
1015 | if opts["parents"] and cs.parents: | |
|
1027 | if opts[b"parents"] and cs.parents: | |
|
1016 | 1028 | if len(cs.parents) > 1: |
|
1017 | 1029 | ui.write( |
|
1018 | 1030 | ( |
|
1019 | 'Parents: %s\n' | |
|
1020 | % (','.join([(b"%d" % p.id) for p in cs.parents])) | |
|
1031 | b'Parents: %s\n' | |
|
1032 | % (b','.join([(b"%d" % p.id) for p in cs.parents])) | |
|
1021 | 1033 | ) |
|
1022 | 1034 | ) |
|
1023 | 1035 | else: |
|
1024 | ui.write(('Parent: %d\n' % cs.parents[0].id)) | |
|
1036 | ui.write((b'Parent: %d\n' % cs.parents[0].id)) | |
|
1025 | 1037 | |
|
1026 | if opts["ancestors"]: | |
|
1038 | if opts[b"ancestors"]: | |
|
1027 | 1039 | b = cs.branch |
|
1028 | 1040 | r = [] |
|
1029 | 1041 | while b: |
|
1030 | 1042 | b, c = ancestors[b] |
|
1031 | r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) | |
|
1043 | r.append(b'%s:%d:%d' % (b or b"HEAD", c, branches[b])) | |
|
1032 | 1044 | if r: |
|
1033 | ui.write(('Ancestors: %s\n' % (','.join(r)))) | |
|
1045 | ui.write((b'Ancestors: %s\n' % (b','.join(r)))) | |
|
1034 | 1046 | |
|
1035 | ui.write('Log:\n') | |
|
1036 | ui.write('%s\n\n' % cs.comment) | |
|
1037 | ui.write('Members: \n') | |
|
1047 | ui.write(b'Log:\n') | |
|
1048 | ui.write(b'%s\n\n' % cs.comment) | |
|
1049 | ui.write(b'Members: \n') | |
|
1038 | 1050 | for f in cs.entries: |
|
1039 | 1051 | fn = f.file |
|
1040 | if fn.startswith(opts["prefix"]): | |
|
1041 | fn = fn[len(opts["prefix"]) :] | |
|
1052 | if fn.startswith(opts[b"prefix"]): | |
|
1053 | fn = fn[len(opts[b"prefix"]) :] | |
|
1042 | 1054 | ui.write( |
|
1043 | '\t%s:%s->%s%s \n' | |
|
1055 | b'\t%s:%s->%s%s \n' | |
|
1044 | 1056 | % ( |
|
1045 | 1057 | fn, |
|
1046 | '.'.join([b"%d" % x for x in f.parent]) or 'INITIAL', | |
|
1047 | '.'.join([(b"%d" % x) for x in f.revision]), | |
|
1048 | ['', '(DEAD)'][f.dead], | |
|
1058 | b'.'.join([b"%d" % x for x in f.parent]) or b'INITIAL', | |
|
1059 | b'.'.join([(b"%d" % x) for x in f.revision]), | |
|
1060 | [b'', b'(DEAD)'][f.dead], | |
|
1049 | 1061 | ) |
|
1050 | 1062 | ) |
|
1051 | ui.write('\n') | |
|
1063 | ui.write(b'\n') | |
|
1052 | 1064 | |
|
1053 | 1065 | # have we seen the start tag? |
|
1054 | 1066 | if revisions and off: |
@@ -46,22 +46,22 b' except ImportError:' | |||
|
46 | 46 | class darcs_source(common.converter_source, common.commandline): |
|
47 | 47 | def __init__(self, ui, repotype, path, revs=None): |
|
48 | 48 | common.converter_source.__init__(self, ui, repotype, path, revs=revs) |
|
49 | common.commandline.__init__(self, ui, 'darcs') | |
|
49 | common.commandline.__init__(self, ui, b'darcs') | |
|
50 | 50 | |
|
51 | 51 | # check for _darcs, ElementTree so that we can easily skip |
|
52 | 52 | # test-convert-darcs if ElementTree is not around |
|
53 | if not os.path.exists(os.path.join(path, '_darcs')): | |
|
54 | raise NoRepo(_("%s does not look like a darcs repository") % path) | |
|
53 | if not os.path.exists(os.path.join(path, b'_darcs')): | |
|
54 | raise NoRepo(_(b"%s does not look like a darcs repository") % path) | |
|
55 | 55 | |
|
56 | common.checktool('darcs') | |
|
57 | version = self.run0('--version').splitlines()[0].strip() | |
|
58 | if version < '2.1': | |
|
56 | common.checktool(b'darcs') | |
|
57 | version = self.run0(b'--version').splitlines()[0].strip() | |
|
58 | if version < b'2.1': | |
|
59 | 59 | raise error.Abort( |
|
60 | _('darcs version 2.1 or newer needed (found %r)') % version | |
|
60 | _(b'darcs version 2.1 or newer needed (found %r)') % version | |
|
61 | 61 | ) |
|
62 | 62 | |
|
63 | if "ElementTree" not in globals(): | |
|
64 | raise error.Abort(_("Python ElementTree module is not available")) | |
|
63 | if b"ElementTree" not in globals(): | |
|
64 | raise error.Abort(_(b"Python ElementTree module is not available")) | |
|
65 | 65 | |
|
66 | 66 | self.path = os.path.realpath(path) |
|
67 | 67 | |
@@ -73,30 +73,33 b' class darcs_source(common.converter_sour' | |||
|
73 | 73 | # Check darcs repository format |
|
74 | 74 | format = self.format() |
|
75 | 75 | if format: |
|
76 | if format in ('darcs-1.0', 'hashed'): | |
|
76 | if format in (b'darcs-1.0', b'hashed'): | |
|
77 | 77 | raise NoRepo( |
|
78 | _("%s repository format is unsupported, " "please upgrade") | |
|
78 | _( | |
|
79 | b"%s repository format is unsupported, " | |
|
80 | b"please upgrade" | |
|
81 | ) | |
|
79 | 82 | % format |
|
80 | 83 | ) |
|
81 | 84 | else: |
|
82 | self.ui.warn(_('failed to detect repository format!')) | |
|
85 | self.ui.warn(_(b'failed to detect repository format!')) | |
|
83 | 86 | |
|
84 | 87 | def before(self): |
|
85 | 88 | self.tmppath = pycompat.mkdtemp( |
|
86 | prefix='convert-' + os.path.basename(self.path) + '-' | |
|
89 | prefix=b'convert-' + os.path.basename(self.path) + b'-' | |
|
87 | 90 | ) |
|
88 | output, status = self.run('init', repodir=self.tmppath) | |
|
91 | output, status = self.run(b'init', repodir=self.tmppath) | |
|
89 | 92 | self.checkexit(status) |
|
90 | 93 | |
|
91 | 94 | tree = self.xml( |
|
92 | 'changes', xml_output=True, summary=True, repodir=self.path | |
|
95 | b'changes', xml_output=True, summary=True, repodir=self.path | |
|
93 | 96 | ) |
|
94 | 97 | tagname = None |
|
95 | 98 | child = None |
|
96 | for elt in tree.findall('patch'): | |
|
97 | node = elt.get('hash') | |
|
98 | name = elt.findtext('name', '') | |
|
99 | if name.startswith('TAG '): | |
|
99 | for elt in tree.findall(b'patch'): | |
|
100 | node = elt.get(b'hash') | |
|
101 | name = elt.findtext(b'name', b'') | |
|
102 | if name.startswith(b'TAG '): | |
|
100 | 103 | tagname = name[4:].strip() |
|
101 | 104 | elif tagname is not None: |
|
102 | 105 | self.tags[tagname] = node |
@@ -107,7 +110,7 b' class darcs_source(common.converter_sour' | |||
|
107 | 110 | self.parents[child] = [] |
|
108 | 111 | |
|
109 | 112 | def after(self): |
|
110 | self.ui.debug('cleaning up %s\n' % self.tmppath) | |
|
113 | self.ui.debug(b'cleaning up %s\n' % self.tmppath) | |
|
111 | 114 | shutil.rmtree(self.tmppath, ignore_errors=True) |
|
112 | 115 | |
|
113 | 116 | def recode(self, s, encoding=None): |
@@ -125,7 +128,7 b' class darcs_source(common.converter_sour' | |||
|
125 | 128 | # While we are decoding the XML as latin-1 to be as liberal as |
|
126 | 129 | # possible, etree will still raise an exception if any |
|
127 | 130 | # non-printable characters are in the XML changelog. |
|
128 | parser = XMLParser(encoding='latin-1') | |
|
131 | parser = XMLParser(encoding=b'latin-1') | |
|
129 | 132 | p = self._run(cmd, **kwargs) |
|
130 | 133 | etree.parse(p.stdout, parser=parser) |
|
131 | 134 | p.wait() |
@@ -133,20 +136,20 b' class darcs_source(common.converter_sour' | |||
|
133 | 136 | return etree.getroot() |
|
134 | 137 | |
|
135 | 138 | def format(self): |
|
136 | output, status = self.run('show', 'repo', repodir=self.path) | |
|
139 | output, status = self.run(b'show', b'repo', repodir=self.path) | |
|
137 | 140 | self.checkexit(status) |
|
138 | 141 | m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE) |
|
139 | 142 | if not m: |
|
140 | 143 | return None |
|
141 | return ','.join(sorted(f.strip() for f in m.group(1).split(','))) | |
|
144 | return b','.join(sorted(f.strip() for f in m.group(1).split(b','))) | |
|
142 | 145 | |
|
143 | 146 | def manifest(self): |
|
144 | 147 | man = [] |
|
145 | 148 | output, status = self.run( |
|
146 | 'show', 'files', no_directories=True, repodir=self.tmppath | |
|
149 | b'show', b'files', no_directories=True, repodir=self.tmppath | |
|
147 | 150 | ) |
|
148 | 151 | self.checkexit(status) |
|
149 | for line in output.split('\n'): | |
|
152 | for line in output.split(b'\n'): | |
|
150 | 153 | path = line[2:] |
|
151 | 154 | if path: |
|
152 | 155 | man.append(path) |
@@ -157,14 +160,14 b' class darcs_source(common.converter_sour' | |||
|
157 | 160 | |
|
158 | 161 | def getcommit(self, rev): |
|
159 | 162 | elt = self.changes[rev] |
|
160 | dateformat = '%a %b %d %H:%M:%S %Z %Y' | |
|
161 | date = dateutil.strdate(elt.get('local_date'), dateformat) | |
|
162 | desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') | |
|
163 | dateformat = b'%a %b %d %H:%M:%S %Z %Y' | |
|
164 | date = dateutil.strdate(elt.get(b'local_date'), dateformat) | |
|
165 | desc = elt.findtext(b'name') + b'\n' + elt.findtext(b'comment', b'') | |
|
163 | 166 | # etree can return unicode objects for name, comment, and author, |
|
164 | 167 | # so recode() is used to ensure str objects are emitted. |
|
165 | newdateformat = '%Y-%m-%d %H:%M:%S %1%2' | |
|
168 | newdateformat = b'%Y-%m-%d %H:%M:%S %1%2' | |
|
166 | 169 | return common.commit( |
|
167 | author=self.recode(elt.get('author')), | |
|
170 | author=self.recode(elt.get(b'author')), | |
|
168 | 171 | date=dateutil.datestr(date, newdateformat), |
|
169 | 172 | desc=self.recode(desc).strip(), |
|
170 | 173 | parents=self.parents[rev], |
@@ -172,34 +175,34 b' class darcs_source(common.converter_sour' | |||
|
172 | 175 | |
|
173 | 176 | def pull(self, rev): |
|
174 | 177 | output, status = self.run( |
|
175 | 'pull', | |
|
178 | b'pull', | |
|
176 | 179 | self.path, |
|
177 | 180 | all=True, |
|
178 | match='hash %s' % rev, | |
|
181 | match=b'hash %s' % rev, | |
|
179 | 182 | no_test=True, |
|
180 | 183 | no_posthook=True, |
|
181 | external_merge='/bin/false', | |
|
184 | external_merge=b'/bin/false', | |
|
182 | 185 | repodir=self.tmppath, |
|
183 | 186 | ) |
|
184 | 187 | if status: |
|
185 | if output.find('We have conflicts in') == -1: | |
|
188 | if output.find(b'We have conflicts in') == -1: | |
|
186 | 189 | self.checkexit(status, output) |
|
187 | output, status = self.run('revert', all=True, repodir=self.tmppath) | |
|
190 | output, status = self.run(b'revert', all=True, repodir=self.tmppath) | |
|
188 | 191 | self.checkexit(status, output) |
|
189 | 192 | |
|
190 | 193 | def getchanges(self, rev, full): |
|
191 | 194 | if full: |
|
192 | raise error.Abort(_("convert from darcs does not support --full")) | |
|
195 | raise error.Abort(_(b"convert from darcs does not support --full")) | |
|
193 | 196 | copies = {} |
|
194 | 197 | changes = [] |
|
195 | 198 | man = None |
|
196 | for elt in self.changes[rev].find('summary').getchildren(): | |
|
197 | if elt.tag in ('add_directory', 'remove_directory'): | |
|
199 | for elt in self.changes[rev].find(b'summary').getchildren(): | |
|
200 | if elt.tag in (b'add_directory', b'remove_directory'): | |
|
198 | 201 | continue |
|
199 | if elt.tag == 'move': | |
|
202 | if elt.tag == b'move': | |
|
200 | 203 | if man is None: |
|
201 | 204 | man = self.manifest() |
|
202 | source, dest = elt.get('from'), elt.get('to') | |
|
205 | source, dest = elt.get(b'from'), elt.get(b'to') | |
|
203 | 206 | if source in man: |
|
204 | 207 | # File move |
|
205 | 208 | changes.append((source, rev)) |
@@ -207,11 +210,11 b' class darcs_source(common.converter_sour' | |||
|
207 | 210 | copies[dest] = source |
|
208 | 211 | else: |
|
209 | 212 | # Directory move, deduce file moves from manifest |
|
210 | source = source + '/' | |
|
213 | source = source + b'/' | |
|
211 | 214 | for f in man: |
|
212 | 215 | if not f.startswith(source): |
|
213 | 216 | continue |
|
214 | fdest = dest + '/' + f[len(source) :] | |
|
217 | fdest = dest + b'/' + f[len(source) :] | |
|
215 | 218 | changes.append((f, rev)) |
|
216 | 219 | changes.append((fdest, rev)) |
|
217 | 220 | copies[fdest] = f |
@@ -223,7 +226,7 b' class darcs_source(common.converter_sour' | |||
|
223 | 226 | |
|
224 | 227 | def getfile(self, name, rev): |
|
225 | 228 | if rev != self.lastrev: |
|
226 | raise error.Abort(_('internal calling inconsistency')) | |
|
229 | raise error.Abort(_(b'internal calling inconsistency')) | |
|
227 | 230 | path = os.path.join(self.tmppath, name) |
|
228 | 231 | try: |
|
229 | 232 | data = util.readfile(path) |
@@ -232,7 +235,7 b' class darcs_source(common.converter_sour' | |||
|
232 | 235 | if inst.errno == errno.ENOENT: |
|
233 | 236 | return None, None |
|
234 | 237 | raise |
|
235 | mode = (mode & 0o111) and 'x' or '' | |
|
238 | mode = (mode & 0o111) and b'x' or b'' | |
|
236 | 239 | return data, mode |
|
237 | 240 | |
|
238 | 241 | def gettags(self): |
@@ -30,8 +30,8 b' def rpairs(path):' | |||
|
30 | 30 | i = len(path) |
|
31 | 31 | while i != -1: |
|
32 | 32 | yield path[:i], path[i + 1 :] |
|
33 | i = path.rfind('/', 0, i) | |
|
34 | yield '.', path | |
|
33 | i = path.rfind(b'/', 0, i) | |
|
34 | yield b'.', path | |
|
35 | 35 | |
|
36 | 36 | |
|
37 | 37 | def normalize(path): |
@@ -55,7 +55,7 b' class filemapper(object):' | |||
|
55 | 55 | self.targetprefixes = None |
|
56 | 56 | if path: |
|
57 | 57 | if self.parse(path): |
|
58 | raise error.Abort(_('errors in filemap')) | |
|
58 | raise error.Abort(_(b'errors in filemap')) | |
|
59 | 59 | |
|
60 | 60 | def parse(self, path): |
|
61 | 61 | errs = 0 |
@@ -63,48 +63,48 b' class filemapper(object):' | |||
|
63 | 63 | def check(name, mapping, listname): |
|
64 | 64 | if not name: |
|
65 | 65 | self.ui.warn( |
|
66 | _('%s:%d: path to %s is missing\n') | |
|
66 | _(b'%s:%d: path to %s is missing\n') | |
|
67 | 67 | % (lex.infile, lex.lineno, listname) |
|
68 | 68 | ) |
|
69 | 69 | return 1 |
|
70 | 70 | if name in mapping: |
|
71 | 71 | self.ui.warn( |
|
72 | _('%s:%d: %r already in %s list\n') | |
|
72 | _(b'%s:%d: %r already in %s list\n') | |
|
73 | 73 | % (lex.infile, lex.lineno, name, listname) |
|
74 | 74 | ) |
|
75 | 75 | return 1 |
|
76 | if name.startswith('/') or name.endswith('/') or '//' in name: | |
|
76 | if name.startswith(b'/') or name.endswith(b'/') or b'//' in name: | |
|
77 | 77 | self.ui.warn( |
|
78 | _('%s:%d: superfluous / in %s %r\n') | |
|
78 | _(b'%s:%d: superfluous / in %s %r\n') | |
|
79 | 79 | % (lex.infile, lex.lineno, listname, pycompat.bytestr(name)) |
|
80 | 80 | ) |
|
81 | 81 | return 1 |
|
82 | 82 | return 0 |
|
83 | 83 | |
|
84 | 84 | lex = common.shlexer( |
|
85 | filepath=path, wordchars='!@#$%^&*()-=+[]{}|;:,./<>?' | |
|
85 | filepath=path, wordchars=b'!@#$%^&*()-=+[]{}|;:,./<>?' | |
|
86 | 86 | ) |
|
87 | 87 | cmd = lex.get_token() |
|
88 | 88 | while cmd: |
|
89 | if cmd == 'include': | |
|
89 | if cmd == b'include': | |
|
90 | 90 | name = normalize(lex.get_token()) |
|
91 | errs += check(name, self.exclude, 'exclude') | |
|
91 | errs += check(name, self.exclude, b'exclude') | |
|
92 | 92 | self.include[name] = name |
|
93 | elif cmd == 'exclude': | |
|
93 | elif cmd == b'exclude': | |
|
94 | 94 | name = normalize(lex.get_token()) |
|
95 | errs += check(name, self.include, 'include') | |
|
96 | errs += check(name, self.rename, 'rename') | |
|
95 | errs += check(name, self.include, b'include') | |
|
96 | errs += check(name, self.rename, b'rename') | |
|
97 | 97 | self.exclude[name] = name |
|
98 | elif cmd == 'rename': | |
|
98 | elif cmd == b'rename': | |
|
99 | 99 | src = normalize(lex.get_token()) |
|
100 | 100 | dest = normalize(lex.get_token()) |
|
101 | errs += check(src, self.exclude, 'exclude') | |
|
101 | errs += check(src, self.exclude, b'exclude') | |
|
102 | 102 | self.rename[src] = dest |
|
103 | elif cmd == 'source': | |
|
103 | elif cmd == b'source': | |
|
104 | 104 | errs += self.parse(normalize(lex.get_token())) |
|
105 | 105 | else: |
|
106 | 106 | self.ui.warn( |
|
107 | _('%s:%d: unknown directive %r\n') | |
|
107 | _(b'%s:%d: unknown directive %r\n') | |
|
108 | 108 | % (lex.infile, lex.lineno, pycompat.bytestr(cmd)) |
|
109 | 109 | ) |
|
110 | 110 | errs += 1 |
@@ -118,7 +118,7 b' class filemapper(object):' | |||
|
118 | 118 | return mapping[pre], pre, suf |
|
119 | 119 | except KeyError: |
|
120 | 120 | pass |
|
121 | return '', name, '' | |
|
121 | return b'', name, b'' | |
|
122 | 122 | |
|
123 | 123 | def istargetfile(self, filename): |
|
124 | 124 | """Return true if the given target filename is covered as a destination |
@@ -131,7 +131,7 b' class filemapper(object):' | |||
|
131 | 131 | |
|
132 | 132 | # If "." is a target, then all target files are considered from the |
|
133 | 133 | # source. |
|
134 | if not self.targetprefixes or '.' in self.targetprefixes: | |
|
134 | if not self.targetprefixes or b'.' in self.targetprefixes: | |
|
135 | 135 | return True |
|
136 | 136 | |
|
137 | 137 | filename = normalize(filename) |
@@ -152,17 +152,17 b' class filemapper(object):' | |||
|
152 | 152 | if self.exclude: |
|
153 | 153 | exc = self.lookup(name, self.exclude)[0] |
|
154 | 154 | else: |
|
155 | exc = '' | |
|
155 | exc = b'' | |
|
156 | 156 | if (not self.include and exc) or (len(inc) <= len(exc)): |
|
157 | 157 | return None |
|
158 | 158 | newpre, pre, suf = self.lookup(name, self.rename) |
|
159 | 159 | if newpre: |
|
160 | if newpre == '.': | |
|
160 | if newpre == b'.': | |
|
161 | 161 | return suf |
|
162 | 162 | if suf: |
|
163 | if newpre.endswith('/'): | |
|
163 | if newpre.endswith(b'/'): | |
|
164 | 164 | return newpre + suf |
|
165 | return newpre + '/' + suf | |
|
165 | return newpre + b'/' + suf | |
|
166 | 166 | return newpre |
|
167 | 167 | return name |
|
168 | 168 | |
@@ -204,7 +204,7 b' class filemap_source(common.converter_so' | |||
|
204 | 204 | self.seenchildren = {} |
|
205 | 205 | # experimental config: convert.ignoreancestorcheck |
|
206 | 206 | self.ignoreancestorcheck = self.ui.configbool( |
|
207 | 'convert', 'ignoreancestorcheck' | |
|
207 | b'convert', b'ignoreancestorcheck' | |
|
208 | 208 | ) |
|
209 | 209 | |
|
210 | 210 | def before(self): |
@@ -256,7 +256,7 b' class filemap_source(common.converter_so' | |||
|
256 | 256 | try: |
|
257 | 257 | self.origparents[rev] = self.getcommit(rev).parents |
|
258 | 258 | except error.RepoLookupError: |
|
259 | self.ui.debug("unknown revmap source: %s\n" % rev) | |
|
259 | self.ui.debug(b"unknown revmap source: %s\n" % rev) | |
|
260 | 260 | continue |
|
261 | 261 | if arg is not None: |
|
262 | 262 | self.children[arg] = self.children.get(arg, 0) + 1 |
@@ -316,7 +316,7 b' class filemap_source(common.converter_so' | |||
|
316 | 316 | try: |
|
317 | 317 | files = self.base.getchangedfiles(rev, i) |
|
318 | 318 | except NotImplementedError: |
|
319 | raise error.Abort(_("source repository doesn't support --filemap")) | |
|
319 | raise error.Abort(_(b"source repository doesn't support --filemap")) | |
|
320 | 320 | for f in files: |
|
321 | 321 | if self.filemapper(f): |
|
322 | 322 | return True |
@@ -331,7 +331,7 b' class filemap_source(common.converter_so' | |||
|
331 | 331 | # close marker is significant (i.e. all of the branch ancestors weren't |
|
332 | 332 | # eliminated). Therefore if there *is* a close marker, getchanges() |
|
333 | 333 | # doesn't consider it significant, and this revision should be dropped. |
|
334 | return not files and 'close' not in self.commits[rev].extra | |
|
334 | return not files and b'close' not in self.commits[rev].extra | |
|
335 | 335 | |
|
336 | 336 | def mark_not_wanted(self, rev, p): |
|
337 | 337 | # Mark rev as not interesting and update data structures. |
@@ -363,7 +363,9 b' class filemap_source(common.converter_so' | |||
|
363 | 363 | if p in self.wantedancestors: |
|
364 | 364 | wrev.update(self.wantedancestors[p]) |
|
365 | 365 | else: |
|
366 | self.ui.warn(_('warning: %s parent %s is missing\n') % (rev, p)) | |
|
366 | self.ui.warn( | |
|
367 | _(b'warning: %s parent %s is missing\n') % (rev, p) | |
|
368 | ) | |
|
367 | 369 | wrev.add(rev) |
|
368 | 370 | self.wantedancestors[rev] = wrev |
|
369 | 371 | |
@@ -423,7 +425,7 b' class filemap_source(common.converter_so' | |||
|
423 | 425 | self.origparents[rev] = parents |
|
424 | 426 | |
|
425 | 427 | closed = False |
|
426 | if 'close' in self.commits[rev].extra: | |
|
428 | if b'close' in self.commits[rev].extra: | |
|
427 | 429 | # A branch closing revision is only useful if one of its |
|
428 | 430 | # parents belong to the branch being closed |
|
429 | 431 | pbranches = [self._cachedcommit(p).branch for p in mparents] |
@@ -26,22 +26,22 b' class submodule(object):' | |||
|
26 | 26 | self.url = url |
|
27 | 27 | |
|
28 | 28 | def hgsub(self): |
|
29 | return "%s = [git]%s" % (self.path, self.url) | |
|
29 | return b"%s = [git]%s" % (self.path, self.url) | |
|
30 | 30 | |
|
31 | 31 | def hgsubstate(self): |
|
32 | return "%s %s" % (self.node, self.path) | |
|
32 | return b"%s %s" % (self.node, self.path) | |
|
33 | 33 | |
|
34 | 34 | |
|
35 | 35 | # Keys in extra fields that should not be copied if the user requests. |
|
36 | 36 | bannedextrakeys = { |
|
37 | 37 | # Git commit object built-ins. |
|
38 | 'tree', | |
|
39 | 'parent', | |
|
40 | 'author', | |
|
41 | 'committer', | |
|
38 | b'tree', | |
|
39 | b'parent', | |
|
40 | b'author', | |
|
41 | b'committer', | |
|
42 | 42 | # Mercurial built-ins. |
|
43 | 'branch', | |
|
44 | 'close', | |
|
43 | b'branch', | |
|
44 | b'close', | |
|
45 | 45 | } |
|
46 | 46 | |
|
47 | 47 | |
@@ -51,7 +51,7 b' class convert_git(common.converter_sourc' | |||
|
51 | 51 | # both issues. |
|
52 | 52 | |
|
53 | 53 | def _gitcmd(self, cmd, *args, **kwargs): |
|
54 | return cmd('--git-dir=%s' % self.path, *args, **kwargs) | |
|
54 | return cmd(b'--git-dir=%s' % self.path, *args, **kwargs) | |
|
55 | 55 | |
|
56 | 56 | def gitrun0(self, *args, **kwargs): |
|
57 | 57 | return self._gitcmd(self.run0, *args, **kwargs) |
@@ -70,100 +70,104 b' class convert_git(common.converter_sourc' | |||
|
70 | 70 | |
|
71 | 71 | def __init__(self, ui, repotype, path, revs=None): |
|
72 | 72 | super(convert_git, self).__init__(ui, repotype, path, revs=revs) |
|
73 | common.commandline.__init__(self, ui, 'git') | |
|
73 | common.commandline.__init__(self, ui, b'git') | |
|
74 | 74 | |
|
75 | 75 | # Pass an absolute path to git to prevent from ever being interpreted |
|
76 | 76 | # as a URL |
|
77 | 77 | path = os.path.abspath(path) |
|
78 | 78 | |
|
79 | if os.path.isdir(path + "/.git"): | |
|
80 | path += "/.git" | |
|
81 | if not os.path.exists(path + "/objects"): | |
|
79 | if os.path.isdir(path + b"/.git"): | |
|
80 | path += b"/.git" | |
|
81 | if not os.path.exists(path + b"/objects"): | |
|
82 | 82 | raise common.NoRepo( |
|
83 | _("%s does not look like a Git repository") % path | |
|
83 | _(b"%s does not look like a Git repository") % path | |
|
84 | 84 | ) |
|
85 | 85 | |
|
86 | 86 | # The default value (50) is based on the default for 'git diff'. |
|
87 | similarity = ui.configint('convert', 'git.similarity') | |
|
87 | similarity = ui.configint(b'convert', b'git.similarity') | |
|
88 | 88 | if similarity < 0 or similarity > 100: |
|
89 | raise error.Abort(_('similarity must be between 0 and 100')) | |
|
89 | raise error.Abort(_(b'similarity must be between 0 and 100')) | |
|
90 | 90 | if similarity > 0: |
|
91 | self.simopt = ['-C%d%%' % similarity] | |
|
92 |
findcopiesharder = ui.configbool( |
|
|
91 | self.simopt = [b'-C%d%%' % similarity] | |
|
92 | findcopiesharder = ui.configbool( | |
|
93 | b'convert', b'git.findcopiesharder' | |
|
94 | ) | |
|
93 | 95 | if findcopiesharder: |
|
94 | self.simopt.append('--find-copies-harder') | |
|
96 | self.simopt.append(b'--find-copies-harder') | |
|
95 | 97 | |
|
96 | renamelimit = ui.configint('convert', 'git.renamelimit') | |
|
97 | self.simopt.append('-l%d' % renamelimit) | |
|
98 | renamelimit = ui.configint(b'convert', b'git.renamelimit') | |
|
99 | self.simopt.append(b'-l%d' % renamelimit) | |
|
98 | 100 | else: |
|
99 | 101 | self.simopt = [] |
|
100 | 102 | |
|
101 | common.checktool('git', 'git') | |
|
103 | common.checktool(b'git', b'git') | |
|
102 | 104 | |
|
103 | 105 | self.path = path |
|
104 | 106 | self.submodules = [] |
|
105 | 107 | |
|
106 | self.catfilepipe = self.gitpipe('cat-file', '--batch') | |
|
108 | self.catfilepipe = self.gitpipe(b'cat-file', b'--batch') | |
|
107 | 109 | |
|
108 | self.copyextrakeys = self.ui.configlist('convert', 'git.extrakeys') | |
|
110 | self.copyextrakeys = self.ui.configlist(b'convert', b'git.extrakeys') | |
|
109 | 111 | banned = set(self.copyextrakeys) & bannedextrakeys |
|
110 | 112 | if banned: |
|
111 | 113 | raise error.Abort( |
|
112 | _('copying of extra key is forbidden: %s') | |
|
113 | % _(', ').join(sorted(banned)) | |
|
114 | _(b'copying of extra key is forbidden: %s') | |
|
115 | % _(b', ').join(sorted(banned)) | |
|
114 | 116 | ) |
|
115 | 117 | |
|
116 |
committeractions = self.ui.configlist( |
|
|
118 | committeractions = self.ui.configlist( | |
|
119 | b'convert', b'git.committeractions' | |
|
120 | ) | |
|
117 | 121 | |
|
118 | 122 | messagedifferent = None |
|
119 | 123 | messagealways = None |
|
120 | 124 | for a in committeractions: |
|
121 | if a.startswith(('messagedifferent', 'messagealways')): | |
|
125 | if a.startswith((b'messagedifferent', b'messagealways')): | |
|
122 | 126 | k = a |
|
123 | 127 | v = None |
|
124 | if '=' in a: | |
|
125 | k, v = a.split('=', 1) | |
|
128 | if b'=' in a: | |
|
129 | k, v = a.split(b'=', 1) | |
|
126 | 130 | |
|
127 | if k == 'messagedifferent': | |
|
128 | messagedifferent = v or 'committer:' | |
|
129 | elif k == 'messagealways': | |
|
130 | messagealways = v or 'committer:' | |
|
131 | if k == b'messagedifferent': | |
|
132 | messagedifferent = v or b'committer:' | |
|
133 | elif k == b'messagealways': | |
|
134 | messagealways = v or b'committer:' | |
|
131 | 135 | |
|
132 | 136 | if messagedifferent and messagealways: |
|
133 | 137 | raise error.Abort( |
|
134 | 138 | _( |
|
135 | 'committeractions cannot define both ' | |
|
136 | 'messagedifferent and messagealways' | |
|
139 | b'committeractions cannot define both ' | |
|
140 | b'messagedifferent and messagealways' | |
|
137 | 141 | ) |
|
138 | 142 | ) |
|
139 | 143 | |
|
140 | dropcommitter = 'dropcommitter' in committeractions | |
|
141 | replaceauthor = 'replaceauthor' in committeractions | |
|
144 | dropcommitter = b'dropcommitter' in committeractions | |
|
145 | replaceauthor = b'replaceauthor' in committeractions | |
|
142 | 146 | |
|
143 | 147 | if dropcommitter and replaceauthor: |
|
144 | 148 | raise error.Abort( |
|
145 | 149 | _( |
|
146 | 'committeractions cannot define both ' | |
|
147 | 'dropcommitter and replaceauthor' | |
|
150 | b'committeractions cannot define both ' | |
|
151 | b'dropcommitter and replaceauthor' | |
|
148 | 152 | ) |
|
149 | 153 | ) |
|
150 | 154 | |
|
151 | 155 | if dropcommitter and messagealways: |
|
152 | 156 | raise error.Abort( |
|
153 | 157 | _( |
|
154 | 'committeractions cannot define both ' | |
|
155 | 'dropcommitter and messagealways' | |
|
158 | b'committeractions cannot define both ' | |
|
159 | b'dropcommitter and messagealways' | |
|
156 | 160 | ) |
|
157 | 161 | ) |
|
158 | 162 | |
|
159 | 163 | if not messagedifferent and not messagealways: |
|
160 | messagedifferent = 'committer:' | |
|
164 | messagedifferent = b'committer:' | |
|
161 | 165 | |
|
162 | 166 | self.committeractions = { |
|
163 | 'dropcommitter': dropcommitter, | |
|
164 | 'replaceauthor': replaceauthor, | |
|
165 | 'messagedifferent': messagedifferent, | |
|
166 | 'messagealways': messagealways, | |
|
167 | b'dropcommitter': dropcommitter, | |
|
168 | b'replaceauthor': replaceauthor, | |
|
169 | b'messagedifferent': messagedifferent, | |
|
170 | b'messagealways': messagealways, | |
|
167 | 171 | } |
|
168 | 172 | |
|
169 | 173 | def after(self): |
@@ -172,35 +176,38 b' class convert_git(common.converter_sourc' | |||
|
172 | 176 | |
|
173 | 177 | def getheads(self): |
|
174 | 178 | if not self.revs: |
|
175 |
output, status = self.gitrun( |
|
|
179 | output, status = self.gitrun( | |
|
180 | b'rev-parse', b'--branches', b'--remotes' | |
|
181 | ) | |
|
176 | 182 | heads = output.splitlines() |
|
177 | 183 | if status: |
|
178 | raise error.Abort(_('cannot retrieve git heads')) | |
|
184 | raise error.Abort(_(b'cannot retrieve git heads')) | |
|
179 | 185 | else: |
|
180 | 186 | heads = [] |
|
181 | 187 | for rev in self.revs: |
|
182 | rawhead, ret = self.gitrun('rev-parse', '--verify', rev) | |
|
188 | rawhead, ret = self.gitrun(b'rev-parse', b'--verify', rev) | |
|
183 | 189 | heads.append(rawhead[:-1]) |
|
184 | 190 | if ret: |
|
185 | raise error.Abort(_('cannot retrieve git head "%s"') % rev) | |
|
191 | raise error.Abort(_(b'cannot retrieve git head "%s"') % rev) | |
|
186 | 192 | return heads |
|
187 | 193 | |
|
188 | 194 | def catfile(self, rev, ftype): |
|
189 | 195 | if rev == nodemod.nullhex: |
|
190 | 196 | raise IOError |
|
191 | self.catfilepipe[0].write(rev + '\n') | |
|
197 | self.catfilepipe[0].write(rev + b'\n') | |
|
192 | 198 | self.catfilepipe[0].flush() |
|
193 | 199 | info = self.catfilepipe[1].readline().split() |
|
194 | 200 | if info[1] != ftype: |
|
195 | 201 | raise error.Abort( |
|
196 | _('cannot read %r object at %s') | |
|
202 | _(b'cannot read %r object at %s') | |
|
197 | 203 | % (pycompat.bytestr(ftype), rev) |
|
198 | 204 | ) |
|
199 | 205 | size = int(info[2]) |
|
200 | 206 | data = self.catfilepipe[1].read(size) |
|
201 | 207 | if len(data) < size: |
|
202 | 208 | raise error.Abort( |
|
203 |
_('cannot read %r object at %s: unexpected size') |
|
|
209 | _(b'cannot read %r object at %s: unexpected size') | |
|
210 | % (ftype, rev) | |
|
204 | 211 | ) |
|
205 | 212 | # read the trailing newline |
|
206 | 213 | self.catfilepipe[1].read(1) |
@@ -209,14 +216,14 b' class convert_git(common.converter_sourc' | |||
|
209 | 216 | def getfile(self, name, rev): |
|
210 | 217 | if rev == nodemod.nullhex: |
|
211 | 218 | return None, None |
|
212 | if name == '.hgsub': | |
|
213 | data = '\n'.join([m.hgsub() for m in self.submoditer()]) | |
|
214 | mode = '' | |
|
215 | elif name == '.hgsubstate': | |
|
216 | data = '\n'.join([m.hgsubstate() for m in self.submoditer()]) | |
|
217 | mode = '' | |
|
219 | if name == b'.hgsub': | |
|
220 | data = b'\n'.join([m.hgsub() for m in self.submoditer()]) | |
|
221 | mode = b'' | |
|
222 | elif name == b'.hgsubstate': | |
|
223 | data = b'\n'.join([m.hgsubstate() for m in self.submoditer()]) | |
|
224 | mode = b'' | |
|
218 | 225 | else: |
|
219 | data = self.catfile(rev, "blob") | |
|
226 | data = self.catfile(rev, b"blob") | |
|
220 | 227 | mode = self.modecache[(name, rev)] |
|
221 | 228 | return data, mode |
|
222 | 229 | |
@@ -236,21 +243,23 b' class convert_git(common.converter_sourc' | |||
|
236 | 243 | c = config.config() |
|
237 | 244 | # Each item in .gitmodules starts with whitespace that cant be parsed |
|
238 | 245 | c.parse( |
|
239 | '.gitmodules', | |
|
240 | '\n'.join(line.strip() for line in content.split('\n')), | |
|
246 | b'.gitmodules', | |
|
247 | b'\n'.join(line.strip() for line in content.split(b'\n')), | |
|
241 | 248 | ) |
|
242 | 249 | for sec in c.sections(): |
|
243 | 250 | s = c[sec] |
|
244 | if 'url' in s and 'path' in s: | |
|
245 | self.submodules.append(submodule(s['path'], '', s['url'])) | |
|
251 | if b'url' in s and b'path' in s: | |
|
252 | self.submodules.append(submodule(s[b'path'], b'', s[b'url'])) | |
|
246 | 253 | |
|
247 | 254 | def retrievegitmodules(self, version): |
|
248 |
modules, ret = self.gitrun( |
|
|
255 | modules, ret = self.gitrun( | |
|
256 | b'show', b'%s:%s' % (version, b'.gitmodules') | |
|
257 | ) | |
|
249 | 258 | if ret: |
|
250 | 259 | # This can happen if a file is in the repo that has permissions |
|
251 | 260 | # 160000, but there is no .gitmodules file. |
|
252 | 261 | self.ui.warn( |
|
253 | _("warning: cannot read submodules config file in " "%s\n") | |
|
262 | _(b"warning: cannot read submodules config file in " b"%s\n") | |
|
254 | 263 | % version |
|
255 | 264 | ) |
|
256 | 265 | return |
@@ -259,74 +268,76 b' class convert_git(common.converter_sourc' | |||
|
259 | 268 | self.parsegitmodules(modules) |
|
260 | 269 | except error.ParseError: |
|
261 | 270 | self.ui.warn( |
|
262 | _("warning: unable to parse .gitmodules in %s\n") % version | |
|
271 | _(b"warning: unable to parse .gitmodules in %s\n") % version | |
|
263 | 272 | ) |
|
264 | 273 | return |
|
265 | 274 | |
|
266 | 275 | for m in self.submodules: |
|
267 | node, ret = self.gitrun('rev-parse', '%s:%s' % (version, m.path)) | |
|
276 | node, ret = self.gitrun(b'rev-parse', b'%s:%s' % (version, m.path)) | |
|
268 | 277 | if ret: |
|
269 | 278 | continue |
|
270 | 279 | m.node = node.strip() |
|
271 | 280 | |
|
272 | 281 | def getchanges(self, version, full): |
|
273 | 282 | if full: |
|
274 | raise error.Abort(_("convert from git does not support --full")) | |
|
283 | raise error.Abort(_(b"convert from git does not support --full")) | |
|
275 | 284 | self.modecache = {} |
|
276 | 285 | cmd = ( |
|
277 |
['diff-tree', '-z', '--root', '-m', '-r'] |
|
|
286 | [b'diff-tree', b'-z', b'--root', b'-m', b'-r'] | |
|
287 | + self.simopt | |
|
288 | + [version] | |
|
278 | 289 | ) |
|
279 | 290 | output, status = self.gitrun(*cmd) |
|
280 | 291 | if status: |
|
281 | raise error.Abort(_('cannot read changes in %s') % version) | |
|
292 | raise error.Abort(_(b'cannot read changes in %s') % version) | |
|
282 | 293 | changes = [] |
|
283 | 294 | copies = {} |
|
284 | 295 | seen = set() |
|
285 | 296 | entry = None |
|
286 | 297 | subexists = [False] |
|
287 | 298 | subdeleted = [False] |
|
288 | difftree = output.split('\x00') | |
|
299 | difftree = output.split(b'\x00') | |
|
289 | 300 | lcount = len(difftree) |
|
290 | 301 | i = 0 |
|
291 | 302 | |
|
292 | skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules') | |
|
303 | skipsubmodules = self.ui.configbool(b'convert', b'git.skipsubmodules') | |
|
293 | 304 | |
|
294 | 305 | def add(entry, f, isdest): |
|
295 | 306 | seen.add(f) |
|
296 | 307 | h = entry[3] |
|
297 | p = entry[1] == "100755" | |
|
298 | s = entry[1] == "120000" | |
|
299 | renamesource = not isdest and entry[4][0] == 'R' | |
|
308 | p = entry[1] == b"100755" | |
|
309 | s = entry[1] == b"120000" | |
|
310 | renamesource = not isdest and entry[4][0] == b'R' | |
|
300 | 311 | |
|
301 | if f == '.gitmodules': | |
|
312 | if f == b'.gitmodules': | |
|
302 | 313 | if skipsubmodules: |
|
303 | 314 | return |
|
304 | 315 | |
|
305 | 316 | subexists[0] = True |
|
306 | if entry[4] == 'D' or renamesource: | |
|
317 | if entry[4] == b'D' or renamesource: | |
|
307 | 318 | subdeleted[0] = True |
|
308 | changes.append(('.hgsub', nodemod.nullhex)) | |
|
319 | changes.append((b'.hgsub', nodemod.nullhex)) | |
|
309 | 320 | else: |
|
310 | changes.append(('.hgsub', '')) | |
|
311 | elif entry[1] == '160000' or entry[0] == ':160000': | |
|
321 | changes.append((b'.hgsub', b'')) | |
|
322 | elif entry[1] == b'160000' or entry[0] == b':160000': | |
|
312 | 323 | if not skipsubmodules: |
|
313 | 324 | subexists[0] = True |
|
314 | 325 | else: |
|
315 | 326 | if renamesource: |
|
316 | 327 | h = nodemod.nullhex |
|
317 | self.modecache[(f, h)] = (p and "x") or (s and "l") or "" | |
|
328 | self.modecache[(f, h)] = (p and b"x") or (s and b"l") or b"" | |
|
318 | 329 | changes.append((f, h)) |
|
319 | 330 | |
|
320 | 331 | while i < lcount: |
|
321 | 332 | l = difftree[i] |
|
322 | 333 | i += 1 |
|
323 | 334 | if not entry: |
|
324 | if not l.startswith(':'): | |
|
335 | if not l.startswith(b':'): | |
|
325 | 336 | continue |
|
326 | 337 | entry = tuple(pycompat.bytestr(p) for p in l.split()) |
|
327 | 338 | continue |
|
328 | 339 | f = l |
|
329 | if entry[4][0] == 'C': | |
|
340 | if entry[4][0] == b'C': | |
|
330 | 341 | copysrc = f |
|
331 | 342 | copydest = difftree[i] |
|
332 | 343 | i += 1 |
@@ -336,7 +347,7 b' class convert_git(common.converter_sourc' | |||
|
336 | 347 | add(entry, f, False) |
|
337 | 348 | # A file can be copied multiple times, or modified and copied |
|
338 | 349 | # simultaneously. So f can be repeated even if fdest isn't. |
|
339 | if entry[4][0] == 'R': | |
|
350 | if entry[4][0] == b'R': | |
|
340 | 351 | # rename: next line is the destination |
|
341 | 352 | fdest = difftree[i] |
|
342 | 353 | i += 1 |
@@ -344,21 +355,21 b' class convert_git(common.converter_sourc' | |||
|
344 | 355 | add(entry, fdest, True) |
|
345 | 356 | # .gitmodules isn't imported at all, so it being copied to |
|
346 | 357 | # and fro doesn't really make sense |
|
347 | if f != '.gitmodules' and fdest != '.gitmodules': | |
|
358 | if f != b'.gitmodules' and fdest != b'.gitmodules': | |
|
348 | 359 | copies[fdest] = f |
|
349 | 360 | entry = None |
|
350 | 361 | |
|
351 | 362 | if subexists[0]: |
|
352 | 363 | if subdeleted[0]: |
|
353 | changes.append(('.hgsubstate', nodemod.nullhex)) | |
|
364 | changes.append((b'.hgsubstate', nodemod.nullhex)) | |
|
354 | 365 | else: |
|
355 | 366 | self.retrievegitmodules(version) |
|
356 | changes.append(('.hgsubstate', '')) | |
|
367 | changes.append((b'.hgsubstate', b'')) | |
|
357 | 368 | return (changes, copies, set()) |
|
358 | 369 | |
|
359 | 370 | def getcommit(self, version): |
|
360 | c = self.catfile(version, "commit") # read the commit hash | |
|
361 | end = c.find("\n\n") | |
|
371 | c = self.catfile(version, b"commit") # read the commit hash | |
|
372 | end = c.find(b"\n\n") | |
|
362 | 373 | message = c[end + 2 :] |
|
363 | 374 | message = self.recode(message) |
|
364 | 375 | l = c[:end].splitlines() |
@@ -366,43 +377,43 b' class convert_git(common.converter_sourc' | |||
|
366 | 377 | author = committer = None |
|
367 | 378 | extra = {} |
|
368 | 379 | for e in l[1:]: |
|
369 | n, v = e.split(" ", 1) | |
|
370 | if n == "author": | |
|
380 | n, v = e.split(b" ", 1) | |
|
381 | if n == b"author": | |
|
371 | 382 | p = v.split() |
|
372 | 383 | tm, tz = p[-2:] |
|
373 | author = " ".join(p[:-2]) | |
|
374 | if author[0] == "<": | |
|
384 | author = b" ".join(p[:-2]) | |
|
385 | if author[0] == b"<": | |
|
375 | 386 | author = author[1:-1] |
|
376 | 387 | author = self.recode(author) |
|
377 | if n == "committer": | |
|
388 | if n == b"committer": | |
|
378 | 389 | p = v.split() |
|
379 | 390 | tm, tz = p[-2:] |
|
380 | committer = " ".join(p[:-2]) | |
|
381 | if committer[0] == "<": | |
|
391 | committer = b" ".join(p[:-2]) | |
|
392 | if committer[0] == b"<": | |
|
382 | 393 | committer = committer[1:-1] |
|
383 | 394 | committer = self.recode(committer) |
|
384 | if n == "parent": | |
|
395 | if n == b"parent": | |
|
385 | 396 | parents.append(v) |
|
386 | 397 | if n in self.copyextrakeys: |
|
387 | 398 | extra[n] = v |
|
388 | 399 | |
|
389 | if self.committeractions['dropcommitter']: | |
|
400 | if self.committeractions[b'dropcommitter']: | |
|
390 | 401 | committer = None |
|
391 | elif self.committeractions['replaceauthor']: | |
|
402 | elif self.committeractions[b'replaceauthor']: | |
|
392 | 403 | author = committer |
|
393 | 404 | |
|
394 | 405 | if committer: |
|
395 | messagealways = self.committeractions['messagealways'] | |
|
396 | messagedifferent = self.committeractions['messagedifferent'] | |
|
406 | messagealways = self.committeractions[b'messagealways'] | |
|
407 | messagedifferent = self.committeractions[b'messagedifferent'] | |
|
397 | 408 | if messagealways: |
|
398 | message += '\n%s %s\n' % (messagealways, committer) | |
|
409 | message += b'\n%s %s\n' % (messagealways, committer) | |
|
399 | 410 | elif messagedifferent and author != committer: |
|
400 | message += '\n%s %s\n' % (messagedifferent, committer) | |
|
411 | message += b'\n%s %s\n' % (messagedifferent, committer) | |
|
401 | 412 | |
|
402 | tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] | |
|
413 | tzs, tzh, tzm = tz[-5:-4] + b"1", tz[-4:-2], tz[-2:] | |
|
403 | 414 | tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) |
|
404 | date = tm + " " + (b"%d" % tz) | |
|
405 | saverev = self.ui.configbool('convert', 'git.saverev') | |
|
415 | date = tm + b" " + (b"%d" % tz) | |
|
416 | saverev = self.ui.configbool(b'convert', b'git.saverev') | |
|
406 | 417 | |
|
407 | 418 | c = common.commit( |
|
408 | 419 | parents=parents, |
@@ -416,27 +427,27 b' class convert_git(common.converter_sourc' | |||
|
416 | 427 | return c |
|
417 | 428 | |
|
418 | 429 | def numcommits(self): |
|
419 | output, ret = self.gitrunlines('rev-list', '--all') | |
|
430 | output, ret = self.gitrunlines(b'rev-list', b'--all') | |
|
420 | 431 | if ret: |
|
421 | 432 | raise error.Abort( |
|
422 | _('cannot retrieve number of commits in %s') % self.path | |
|
433 | _(b'cannot retrieve number of commits in %s') % self.path | |
|
423 | 434 | ) |
|
424 | 435 | return len(output) |
|
425 | 436 | |
|
426 | 437 | def gettags(self): |
|
427 | 438 | tags = {} |
|
428 | 439 | alltags = {} |
|
429 | output, status = self.gitrunlines('ls-remote', '--tags', self.path) | |
|
440 | output, status = self.gitrunlines(b'ls-remote', b'--tags', self.path) | |
|
430 | 441 | |
|
431 | 442 | if status: |
|
432 | raise error.Abort(_('cannot read tags from %s') % self.path) | |
|
433 | prefix = 'refs/tags/' | |
|
443 | raise error.Abort(_(b'cannot read tags from %s') % self.path) | |
|
444 | prefix = b'refs/tags/' | |
|
434 | 445 | |
|
435 | 446 | # Build complete list of tags, both annotated and bare ones |
|
436 | 447 | for line in output: |
|
437 | 448 | line = line.strip() |
|
438 | if line.startswith("error:") or line.startswith("fatal:"): | |
|
439 | raise error.Abort(_('cannot read tags from %s') % self.path) | |
|
449 | if line.startswith(b"error:") or line.startswith(b"fatal:"): | |
|
450 | raise error.Abort(_(b'cannot read tags from %s') % self.path) | |
|
440 | 451 | node, tag = line.split(None, 1) |
|
441 | 452 | if not tag.startswith(prefix): |
|
442 | 453 | continue |
@@ -444,10 +455,10 b' class convert_git(common.converter_sourc' | |||
|
444 | 455 | |
|
445 | 456 | # Filter out tag objects for annotated tag refs |
|
446 | 457 | for tag in alltags: |
|
447 | if tag.endswith('^{}'): | |
|
458 | if tag.endswith(b'^{}'): | |
|
448 | 459 | tags[tag[:-3]] = alltags[tag] |
|
449 | 460 | else: |
|
450 | if tag + '^{}' in alltags: | |
|
461 | if tag + b'^{}' in alltags: | |
|
451 | 462 | continue |
|
452 | 463 | else: |
|
453 | 464 | tags[tag] = alltags[tag] |
@@ -458,28 +469,28 b' class convert_git(common.converter_sourc' | |||
|
458 | 469 | changes = [] |
|
459 | 470 | if i is None: |
|
460 | 471 | output, status = self.gitrunlines( |
|
461 | 'diff-tree', '--root', '-m', '-r', version | |
|
472 | b'diff-tree', b'--root', b'-m', b'-r', version | |
|
462 | 473 | ) |
|
463 | 474 | if status: |
|
464 | raise error.Abort(_('cannot read changes in %s') % version) | |
|
475 | raise error.Abort(_(b'cannot read changes in %s') % version) | |
|
465 | 476 | for l in output: |
|
466 | if "\t" not in l: | |
|
477 | if b"\t" not in l: | |
|
467 | 478 | continue |
|
468 | m, f = l[:-1].split("\t") | |
|
479 | m, f = l[:-1].split(b"\t") | |
|
469 | 480 | changes.append(f) |
|
470 | 481 | else: |
|
471 | 482 | output, status = self.gitrunlines( |
|
472 | 'diff-tree', | |
|
473 | '--name-only', | |
|
474 | '--root', | |
|
475 | '-r', | |
|
483 | b'diff-tree', | |
|
484 | b'--name-only', | |
|
485 | b'--root', | |
|
486 | b'-r', | |
|
476 | 487 | version, |
|
477 | '%s^%d' % (version, i + 1), | |
|
478 | '--', | |
|
488 | b'%s^%d' % (version, i + 1), | |
|
489 | b'--', | |
|
479 | 490 | ) |
|
480 | 491 | if status: |
|
481 | raise error.Abort(_('cannot read changes in %s') % version) | |
|
482 | changes = [f.rstrip('\n') for f in output] | |
|
492 | raise error.Abort(_(b'cannot read changes in %s') % version) | |
|
493 | changes = [f.rstrip(b'\n') for f in output] | |
|
483 | 494 | |
|
484 | 495 | return changes |
|
485 | 496 | |
@@ -487,19 +498,19 b' class convert_git(common.converter_sourc' | |||
|
487 | 498 | bookmarks = {} |
|
488 | 499 | |
|
489 | 500 | # Handle local and remote branches |
|
490 | remoteprefix = self.ui.config('convert', 'git.remoteprefix') | |
|
501 | remoteprefix = self.ui.config(b'convert', b'git.remoteprefix') | |
|
491 | 502 | reftypes = [ |
|
492 | 503 | # (git prefix, hg prefix) |
|
493 | ('refs/remotes/origin/', remoteprefix + '/'), | |
|
494 | ('refs/heads/', ''), | |
|
504 | (b'refs/remotes/origin/', remoteprefix + b'/'), | |
|
505 | (b'refs/heads/', b''), | |
|
495 | 506 | ] |
|
496 | 507 | |
|
497 | 508 | exclude = { |
|
498 | 'refs/remotes/origin/HEAD', | |
|
509 | b'refs/remotes/origin/HEAD', | |
|
499 | 510 | } |
|
500 | 511 | |
|
501 | 512 | try: |
|
502 | output, status = self.gitrunlines('show-ref') | |
|
513 | output, status = self.gitrunlines(b'show-ref') | |
|
503 | 514 | for line in output: |
|
504 | 515 | line = line.strip() |
|
505 | 516 | rev, name = line.split(None, 1) |
@@ -507,13 +518,13 b' class convert_git(common.converter_sourc' | |||
|
507 | 518 | for gitprefix, hgprefix in reftypes: |
|
508 | 519 | if not name.startswith(gitprefix) or name in exclude: |
|
509 | 520 | continue |
|
510 | name = '%s%s' % (hgprefix, name[len(gitprefix) :]) | |
|
521 | name = b'%s%s' % (hgprefix, name[len(gitprefix) :]) | |
|
511 | 522 | bookmarks[name] = rev |
|
512 | 523 | except Exception: |
|
513 | 524 | pass |
|
514 | 525 | |
|
515 | 526 | return bookmarks |
|
516 | 527 | |
|
517 | def checkrevformat(self, revstr, mapname='splicemap'): | |
|
528 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
|
518 | 529 | """ git revision string is a 40 byte hex """ |
|
519 | 530 | self.checkhexformat(revstr, mapname) |
@@ -31,9 +31,9 b' class gnuarch_source(common.converter_so' | |||
|
31 | 31 | class gnuarch_rev(object): |
|
32 | 32 | def __init__(self, rev): |
|
33 | 33 | self.rev = rev |
|
34 | self.summary = '' | |
|
34 | self.summary = b'' | |
|
35 | 35 | self.date = None |
|
36 | self.author = '' | |
|
36 | self.author = b'' | |
|
37 | 37 | self.continuationof = None |
|
38 | 38 | self.add_files = [] |
|
39 | 39 | self.mod_files = [] |
@@ -44,20 +44,20 b' class gnuarch_source(common.converter_so' | |||
|
44 | 44 | def __init__(self, ui, repotype, path, revs=None): |
|
45 | 45 | super(gnuarch_source, self).__init__(ui, repotype, path, revs=revs) |
|
46 | 46 | |
|
47 | if not os.path.exists(os.path.join(path, '{arch}')): | |
|
47 | if not os.path.exists(os.path.join(path, b'{arch}')): | |
|
48 | 48 | raise common.NoRepo( |
|
49 | _("%s does not look like a GNU Arch repository") % path | |
|
49 | _(b"%s does not look like a GNU Arch repository") % path | |
|
50 | 50 | ) |
|
51 | 51 | |
|
52 | 52 | # Could use checktool, but we want to check for baz or tla. |
|
53 | 53 | self.execmd = None |
|
54 | if procutil.findexe('baz'): | |
|
55 | self.execmd = 'baz' | |
|
54 | if procutil.findexe(b'baz'): | |
|
55 | self.execmd = b'baz' | |
|
56 | 56 | else: |
|
57 | if procutil.findexe('tla'): | |
|
58 | self.execmd = 'tla' | |
|
57 | if procutil.findexe(b'tla'): | |
|
58 | self.execmd = b'tla' | |
|
59 | 59 | else: |
|
60 | raise error.Abort(_('cannot find a GNU Arch tool')) | |
|
60 | raise error.Abort(_(b'cannot find a GNU Arch tool')) | |
|
61 | 61 | |
|
62 | 62 | common.commandline.__init__(self, ui, self.execmd) |
|
63 | 63 | |
@@ -76,19 +76,19 b' class gnuarch_source(common.converter_so' | |||
|
76 | 76 | def before(self): |
|
77 | 77 | # Get registered archives |
|
78 | 78 | self.archives = [ |
|
79 | i.rstrip('\n') for i in self.runlines0('archives', '-n') | |
|
79 | i.rstrip(b'\n') for i in self.runlines0(b'archives', b'-n') | |
|
80 | 80 | ] |
|
81 | 81 | |
|
82 | if self.execmd == 'tla': | |
|
83 | output = self.run0('tree-version', self.path) | |
|
82 | if self.execmd == b'tla': | |
|
83 | output = self.run0(b'tree-version', self.path) | |
|
84 | 84 | else: |
|
85 | output = self.run0('tree-version', '-d', self.path) | |
|
85 | output = self.run0(b'tree-version', b'-d', self.path) | |
|
86 | 86 | self.treeversion = output.strip() |
|
87 | 87 | |
|
88 | 88 | # Get name of temporary directory |
|
89 | version = self.treeversion.split('/') | |
|
89 | version = self.treeversion.split(b'/') | |
|
90 | 90 | self.tmppath = os.path.join( |
|
91 | pycompat.fsencode(tempfile.gettempdir()), 'hg-%s' % version[1] | |
|
91 | pycompat.fsencode(tempfile.gettempdir()), b'hg-%s' % version[1] | |
|
92 | 92 | ) |
|
93 | 93 | |
|
94 | 94 | # Generate parents dictionary |
@@ -96,23 +96,25 b' class gnuarch_source(common.converter_so' | |||
|
96 | 96 | treeversion = self.treeversion |
|
97 | 97 | child = None |
|
98 | 98 | while treeversion: |
|
99 | self.ui.status(_('analyzing tree version %s...\n') % treeversion) | |
|
99 | self.ui.status(_(b'analyzing tree version %s...\n') % treeversion) | |
|
100 | 100 | |
|
101 | archive = treeversion.split('/')[0] | |
|
101 | archive = treeversion.split(b'/')[0] | |
|
102 | 102 | if archive not in self.archives: |
|
103 | 103 | self.ui.status( |
|
104 | 104 | _( |
|
105 | 'tree analysis stopped because it points to ' | |
|
106 | 'an unregistered archive %s...\n' | |
|
105 | b'tree analysis stopped because it points to ' | |
|
106 | b'an unregistered archive %s...\n' | |
|
107 | 107 | ) |
|
108 | 108 | % archive |
|
109 | 109 | ) |
|
110 | 110 | break |
|
111 | 111 | |
|
112 | 112 | # Get the complete list of revisions for that tree version |
|
113 |
output, status = self.runlines( |
|
|
113 | output, status = self.runlines( | |
|
114 | b'revisions', b'-r', b'-f', treeversion | |
|
115 | ) | |
|
114 | 116 | self.checkexit( |
|
115 | status, 'failed retrieving revisions for %s' % treeversion | |
|
117 | status, b'failed retrieving revisions for %s' % treeversion | |
|
116 | 118 | ) |
|
117 | 119 | |
|
118 | 120 | # No new iteration unless a revision has a continuation-of header |
@@ -124,9 +126,9 b' class gnuarch_source(common.converter_so' | |||
|
124 | 126 | self.parents[rev] = [] |
|
125 | 127 | |
|
126 | 128 | # Read author, date and summary |
|
127 | catlog, status = self.run('cat-log', '-d', self.path, rev) | |
|
129 | catlog, status = self.run(b'cat-log', b'-d', self.path, rev) | |
|
128 | 130 | if status: |
|
129 | catlog = self.run0('cat-archive-log', rev) | |
|
131 | catlog = self.run0(b'cat-archive-log', rev) | |
|
130 | 132 | self._parsecatlog(catlog, rev) |
|
131 | 133 | |
|
132 | 134 | # Populate the parents map |
@@ -140,18 +142,18 b' class gnuarch_source(common.converter_so' | |||
|
140 | 142 | # or if we have to 'jump' to a different treeversion given |
|
141 | 143 | # by the continuation-of header. |
|
142 | 144 | if self.changes[rev].continuationof: |
|
143 | treeversion = '--'.join( | |
|
144 | self.changes[rev].continuationof.split('--')[:-1] | |
|
145 | treeversion = b'--'.join( | |
|
146 | self.changes[rev].continuationof.split(b'--')[:-1] | |
|
145 | 147 | ) |
|
146 | 148 | break |
|
147 | 149 | |
|
148 | 150 | # If we reached a base-0 revision w/o any continuation-of |
|
149 | 151 | # header, it means the tree history ends here. |
|
150 | if rev[-6:] == 'base-0': | |
|
152 | if rev[-6:] == b'base-0': | |
|
151 | 153 | break |
|
152 | 154 | |
|
153 | 155 | def after(self): |
|
154 | self.ui.debug('cleaning up %s\n' % self.tmppath) | |
|
156 | self.ui.debug(b'cleaning up %s\n' % self.tmppath) | |
|
155 | 157 | shutil.rmtree(self.tmppath, ignore_errors=True) |
|
156 | 158 | |
|
157 | 159 | def getheads(self): |
@@ -159,7 +161,7 b' class gnuarch_source(common.converter_so' | |||
|
159 | 161 | |
|
160 | 162 | def getfile(self, name, rev): |
|
161 | 163 | if rev != self.lastrev: |
|
162 | raise error.Abort(_('internal calling inconsistency')) | |
|
164 | raise error.Abort(_(b'internal calling inconsistency')) | |
|
163 | 165 | |
|
164 | 166 | if not os.path.lexists(os.path.join(self.tmppath, name)): |
|
165 | 167 | return None, None |
@@ -168,7 +170,7 b' class gnuarch_source(common.converter_so' | |||
|
168 | 170 | |
|
169 | 171 | def getchanges(self, rev, full): |
|
170 | 172 | if full: |
|
171 | raise error.Abort(_("convert from arch does not support --full")) | |
|
173 | raise error.Abort(_(b"convert from arch does not support --full")) | |
|
172 | 174 | self._update(rev) |
|
173 | 175 | changes = [] |
|
174 | 176 | copies = {} |
@@ -214,14 +216,14 b' class gnuarch_source(common.converter_so' | |||
|
214 | 216 | cmdline = [self.execmd, cmd] |
|
215 | 217 | cmdline += args |
|
216 | 218 | cmdline = [procutil.shellquote(arg) for arg in cmdline] |
|
217 | cmdline += ['>', os.devnull, '2>', os.devnull] | |
|
218 | cmdline = procutil.quotecommand(' '.join(cmdline)) | |
|
219 | self.ui.debug(cmdline, '\n') | |
|
219 | cmdline += [b'>', os.devnull, b'2>', os.devnull] | |
|
220 | cmdline = procutil.quotecommand(b' '.join(cmdline)) | |
|
221 | self.ui.debug(cmdline, b'\n') | |
|
220 | 222 | return os.system(pycompat.rapply(procutil.tonativestr, cmdline)) |
|
221 | 223 | |
|
222 | 224 | def _update(self, rev): |
|
223 | self.ui.debug('applying revision %s...\n' % rev) | |
|
224 | changeset, status = self.runlines('replay', '-d', self.tmppath, rev) | |
|
225 | self.ui.debug(b'applying revision %s...\n' % rev) | |
|
226 | changeset, status = self.runlines(b'replay', b'-d', self.tmppath, rev) | |
|
225 | 227 | if status: |
|
226 | 228 | # Something went wrong while merging (baz or tla |
|
227 | 229 | # issue?), get latest revision and try from there |
@@ -230,7 +232,7 b' class gnuarch_source(common.converter_so' | |||
|
230 | 232 | else: |
|
231 | 233 | old_rev = self.parents[rev][0] |
|
232 | 234 | self.ui.debug( |
|
233 | 'computing changeset between %s and %s...\n' % (old_rev, rev) | |
|
235 | b'computing changeset between %s and %s...\n' % (old_rev, rev) | |
|
234 | 236 | ) |
|
235 | 237 | self._parsechangeset(changeset, rev) |
|
236 | 238 | |
@@ -239,16 +241,16 b' class gnuarch_source(common.converter_so' | |||
|
239 | 241 | if stat.S_ISLNK(mode): |
|
240 | 242 | data = util.readlink(os.path.join(self.tmppath, name)) |
|
241 | 243 | if mode: |
|
242 | mode = 'l' | |
|
244 | mode = b'l' | |
|
243 | 245 | else: |
|
244 | mode = '' | |
|
246 | mode = b'' | |
|
245 | 247 | else: |
|
246 | 248 | data = util.readfile(os.path.join(self.tmppath, name)) |
|
247 | mode = (mode & 0o111) and 'x' or '' | |
|
249 | mode = (mode & 0o111) and b'x' or b'' | |
|
248 | 250 | return data, mode |
|
249 | 251 | |
|
250 | 252 | def _exclude(self, name): |
|
251 | exclude = ['{arch}', '.arch-ids', '.arch-inventory'] | |
|
253 | exclude = [b'{arch}', b'.arch-ids', b'.arch-inventory'] | |
|
252 | 254 | for exc in exclude: |
|
253 | 255 | if name.find(exc) != -1: |
|
254 | 256 | return True |
@@ -282,15 +284,15 b' class gnuarch_source(common.converter_so' | |||
|
282 | 284 | return changes, copies |
|
283 | 285 | |
|
284 | 286 | def _obtainrevision(self, rev): |
|
285 | self.ui.debug('obtaining revision %s...\n' % rev) | |
|
286 | output = self._execute('get', rev, self.tmppath) | |
|
287 | self.ui.debug(b'obtaining revision %s...\n' % rev) | |
|
288 | output = self._execute(b'get', rev, self.tmppath) | |
|
287 | 289 | self.checkexit(output) |
|
288 | self.ui.debug('analyzing revision %s...\n' % rev) | |
|
290 | self.ui.debug(b'analyzing revision %s...\n' % rev) | |
|
289 | 291 | files = self._readcontents(self.tmppath) |
|
290 | 292 | self.changes[rev].add_files += files |
|
291 | 293 | |
|
292 | 294 | def _stripbasepath(self, path): |
|
293 | if path.startswith('./'): | |
|
295 | if path.startswith(b'./'): | |
|
294 | 296 | return path[2:] |
|
295 | 297 | return path |
|
296 | 298 | |
@@ -300,73 +302,73 b' class gnuarch_source(common.converter_so' | |||
|
300 | 302 | |
|
301 | 303 | # Commit date |
|
302 | 304 | self.changes[rev].date = dateutil.datestr( |
|
303 | dateutil.strdate(catlog['Standard-date'], '%Y-%m-%d %H:%M:%S') | |
|
305 | dateutil.strdate(catlog[b'Standard-date'], b'%Y-%m-%d %H:%M:%S') | |
|
304 | 306 | ) |
|
305 | 307 | |
|
306 | 308 | # Commit author |
|
307 | self.changes[rev].author = self.recode(catlog['Creator']) | |
|
309 | self.changes[rev].author = self.recode(catlog[b'Creator']) | |
|
308 | 310 | |
|
309 | 311 | # Commit description |
|
310 | self.changes[rev].summary = '\n\n'.join( | |
|
311 | (catlog['Summary'], catlog.get_payload()) | |
|
312 | self.changes[rev].summary = b'\n\n'.join( | |
|
313 | (catlog[b'Summary'], catlog.get_payload()) | |
|
312 | 314 | ) |
|
313 | 315 | self.changes[rev].summary = self.recode(self.changes[rev].summary) |
|
314 | 316 | |
|
315 | 317 | # Commit revision origin when dealing with a branch or tag |
|
316 | if 'Continuation-of' in catlog: | |
|
318 | if b'Continuation-of' in catlog: | |
|
317 | 319 | self.changes[rev].continuationof = self.recode( |
|
318 | catlog['Continuation-of'] | |
|
320 | catlog[b'Continuation-of'] | |
|
319 | 321 | ) |
|
320 | 322 | except Exception: |
|
321 | raise error.Abort(_('could not parse cat-log of %s') % rev) | |
|
323 | raise error.Abort(_(b'could not parse cat-log of %s') % rev) | |
|
322 | 324 | |
|
323 | 325 | def _parsechangeset(self, data, rev): |
|
324 | 326 | for l in data: |
|
325 | 327 | l = l.strip() |
|
326 | 328 | # Added file (ignore added directory) |
|
327 | if l.startswith('A') and not l.startswith('A/'): | |
|
329 | if l.startswith(b'A') and not l.startswith(b'A/'): | |
|
328 | 330 | file = self._stripbasepath(l[1:].strip()) |
|
329 | 331 | if not self._exclude(file): |
|
330 | 332 | self.changes[rev].add_files.append(file) |
|
331 | 333 | # Deleted file (ignore deleted directory) |
|
332 | elif l.startswith('D') and not l.startswith('D/'): | |
|
334 | elif l.startswith(b'D') and not l.startswith(b'D/'): | |
|
333 | 335 | file = self._stripbasepath(l[1:].strip()) |
|
334 | 336 | if not self._exclude(file): |
|
335 | 337 | self.changes[rev].del_files.append(file) |
|
336 | 338 | # Modified binary file |
|
337 | elif l.startswith('Mb'): | |
|
339 | elif l.startswith(b'Mb'): | |
|
338 | 340 | file = self._stripbasepath(l[2:].strip()) |
|
339 | 341 | if not self._exclude(file): |
|
340 | 342 | self.changes[rev].mod_files.append(file) |
|
341 | 343 | # Modified link |
|
342 | elif l.startswith('M->'): | |
|
344 | elif l.startswith(b'M->'): | |
|
343 | 345 | file = self._stripbasepath(l[3:].strip()) |
|
344 | 346 | if not self._exclude(file): |
|
345 | 347 | self.changes[rev].mod_files.append(file) |
|
346 | 348 | # Modified file |
|
347 | elif l.startswith('M'): | |
|
349 | elif l.startswith(b'M'): | |
|
348 | 350 | file = self._stripbasepath(l[1:].strip()) |
|
349 | 351 | if not self._exclude(file): |
|
350 | 352 | self.changes[rev].mod_files.append(file) |
|
351 | 353 | # Renamed file (or link) |
|
352 | elif l.startswith('=>'): | |
|
353 | files = l[2:].strip().split(' ') | |
|
354 | elif l.startswith(b'=>'): | |
|
355 | files = l[2:].strip().split(b' ') | |
|
354 | 356 | if len(files) == 1: |
|
355 | files = l[2:].strip().split('\t') | |
|
357 | files = l[2:].strip().split(b'\t') | |
|
356 | 358 | src = self._stripbasepath(files[0]) |
|
357 | 359 | dst = self._stripbasepath(files[1]) |
|
358 | 360 | if not self._exclude(src) and not self._exclude(dst): |
|
359 | 361 | self.changes[rev].ren_files[src] = dst |
|
360 | 362 | # Conversion from file to link or from link to file (modified) |
|
361 | elif l.startswith('ch'): | |
|
363 | elif l.startswith(b'ch'): | |
|
362 | 364 | file = self._stripbasepath(l[2:].strip()) |
|
363 | 365 | if not self._exclude(file): |
|
364 | 366 | self.changes[rev].mod_files.append(file) |
|
365 | 367 | # Renamed directory |
|
366 | elif l.startswith('/>'): | |
|
367 | dirs = l[2:].strip().split(' ') | |
|
368 | elif l.startswith(b'/>'): | |
|
369 | dirs = l[2:].strip().split(b' ') | |
|
368 | 370 | if len(dirs) == 1: |
|
369 | dirs = l[2:].strip().split('\t') | |
|
371 | dirs = l[2:].strip().split(b'\t') | |
|
370 | 372 | src = self._stripbasepath(dirs[0]) |
|
371 | 373 | dst = self._stripbasepath(dirs[1]) |
|
372 | 374 | if not self._exclude(src) and not self._exclude(dst): |
@@ -51,33 +51,33 b" sha1re = re.compile(br'\\b[0-9a-f]{12,40}" | |||
|
51 | 51 | class mercurial_sink(common.converter_sink): |
|
52 | 52 | def __init__(self, ui, repotype, path): |
|
53 | 53 | common.converter_sink.__init__(self, ui, repotype, path) |
|
54 | self.branchnames = ui.configbool('convert', 'hg.usebranchnames') | |
|
55 | self.clonebranches = ui.configbool('convert', 'hg.clonebranches') | |
|
56 | self.tagsbranch = ui.config('convert', 'hg.tagsbranch') | |
|
54 | self.branchnames = ui.configbool(b'convert', b'hg.usebranchnames') | |
|
55 | self.clonebranches = ui.configbool(b'convert', b'hg.clonebranches') | |
|
56 | self.tagsbranch = ui.config(b'convert', b'hg.tagsbranch') | |
|
57 | 57 | self.lastbranch = None |
|
58 | 58 | if os.path.isdir(path) and len(os.listdir(path)) > 0: |
|
59 | 59 | try: |
|
60 | 60 | self.repo = hg.repository(self.ui, path) |
|
61 | 61 | if not self.repo.local(): |
|
62 | 62 | raise NoRepo( |
|
63 | _('%s is not a local Mercurial repository') % path | |
|
63 | _(b'%s is not a local Mercurial repository') % path | |
|
64 | 64 | ) |
|
65 | 65 | except error.RepoError as err: |
|
66 | 66 | ui.traceback() |
|
67 | 67 | raise NoRepo(err.args[0]) |
|
68 | 68 | else: |
|
69 | 69 | try: |
|
70 | ui.status(_('initializing destination %s repository\n') % path) | |
|
70 | ui.status(_(b'initializing destination %s repository\n') % path) | |
|
71 | 71 | self.repo = hg.repository(self.ui, path, create=True) |
|
72 | 72 | if not self.repo.local(): |
|
73 | 73 | raise NoRepo( |
|
74 | _('%s is not a local Mercurial repository') % path | |
|
74 | _(b'%s is not a local Mercurial repository') % path | |
|
75 | 75 | ) |
|
76 | 76 | self.created.append(path) |
|
77 | 77 | except error.RepoError: |
|
78 | 78 | ui.traceback() |
|
79 | 79 | raise NoRepo( |
|
80 | _("could not create hg repository %s as sink") % path | |
|
80 | _(b"could not create hg repository %s as sink") % path | |
|
81 | 81 | ) |
|
82 | 82 | self.lock = None |
|
83 | 83 | self.wlock = None |
@@ -85,22 +85,22 b' class mercurial_sink(common.converter_si' | |||
|
85 | 85 | self.subrevmaps = {} |
|
86 | 86 | |
|
87 | 87 | def before(self): |
|
88 | self.ui.debug('run hg sink pre-conversion action\n') | |
|
88 | self.ui.debug(b'run hg sink pre-conversion action\n') | |
|
89 | 89 | self.wlock = self.repo.wlock() |
|
90 | 90 | self.lock = self.repo.lock() |
|
91 | 91 | |
|
92 | 92 | def after(self): |
|
93 | self.ui.debug('run hg sink post-conversion action\n') | |
|
93 | self.ui.debug(b'run hg sink post-conversion action\n') | |
|
94 | 94 | if self.lock: |
|
95 | 95 | self.lock.release() |
|
96 | 96 | if self.wlock: |
|
97 | 97 | self.wlock.release() |
|
98 | 98 | |
|
99 | 99 | def revmapfile(self): |
|
100 | return self.repo.vfs.join("shamap") | |
|
100 | return self.repo.vfs.join(b"shamap") | |
|
101 | 101 | |
|
102 | 102 | def authorfile(self): |
|
103 | return self.repo.vfs.join("authormap") | |
|
103 | return self.repo.vfs.join(b"authormap") | |
|
104 | 104 | |
|
105 | 105 | def setbranch(self, branch, pbranches): |
|
106 | 106 | if not self.clonebranches: |
@@ -109,8 +109,8 b' class mercurial_sink(common.converter_si' | |||
|
109 | 109 | setbranch = branch != self.lastbranch |
|
110 | 110 | self.lastbranch = branch |
|
111 | 111 | if not branch: |
|
112 | branch = 'default' | |
|
113 | pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches] | |
|
112 | branch = b'default' | |
|
113 | pbranches = [(b[0], b[1] and b[1] or b'default') for b in pbranches] | |
|
114 | 114 | |
|
115 | 115 | branchpath = os.path.join(self.path, branch) |
|
116 | 116 | if setbranch: |
@@ -135,7 +135,9 b' class mercurial_sink(common.converter_si' | |||
|
135 | 135 | for pbranch, heads in sorted(missings.iteritems()): |
|
136 | 136 | pbranchpath = os.path.join(self.path, pbranch) |
|
137 | 137 | prepo = hg.peer(self.ui, {}, pbranchpath) |
|
138 | self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch)) | |
|
138 | self.ui.note( | |
|
139 | _(b'pulling from %s into %s\n') % (pbranch, branch) | |
|
140 | ) | |
|
139 | 141 | exchange.pull( |
|
140 | 142 | self.repo, prepo, [prepo.lookup(h) for h in heads] |
|
141 | 143 | ) |
@@ -144,10 +146,10 b' class mercurial_sink(common.converter_si' | |||
|
144 | 146 | def _rewritetags(self, source, revmap, data): |
|
145 | 147 | fp = stringio() |
|
146 | 148 | for line in data.splitlines(): |
|
147 | s = line.split(' ', 1) | |
|
149 | s = line.split(b' ', 1) | |
|
148 | 150 | if len(s) != 2: |
|
149 | self.ui.warn(_('invalid tag entry: "%s"\n') % line) | |
|
150 | fp.write('%s\n' % line) # Bogus, but keep for hash stability | |
|
151 | self.ui.warn(_(b'invalid tag entry: "%s"\n') % line) | |
|
152 | fp.write(b'%s\n' % line) # Bogus, but keep for hash stability | |
|
151 | 153 | continue |
|
152 | 154 | revid = revmap.get(source.lookuprev(s[0])) |
|
153 | 155 | if not revid: |
@@ -155,16 +157,16 b' class mercurial_sink(common.converter_si' | |||
|
155 | 157 | revid = s[0] |
|
156 | 158 | else: |
|
157 | 159 | # missing, but keep for hash stability |
|
158 | self.ui.warn(_('missing tag entry: "%s"\n') % line) | |
|
159 | fp.write('%s\n' % line) | |
|
160 | self.ui.warn(_(b'missing tag entry: "%s"\n') % line) | |
|
161 | fp.write(b'%s\n' % line) | |
|
160 | 162 | continue |
|
161 | fp.write('%s %s\n' % (revid, s[1])) | |
|
163 | fp.write(b'%s %s\n' % (revid, s[1])) | |
|
162 | 164 | return fp.getvalue() |
|
163 | 165 | |
|
164 | 166 | def _rewritesubstate(self, source, data): |
|
165 | 167 | fp = stringio() |
|
166 | 168 | for line in data.splitlines(): |
|
167 | s = line.split(' ', 1) | |
|
169 | s = line.split(b' ', 1) | |
|
168 | 170 | if len(s) != 2: |
|
169 | 171 | continue |
|
170 | 172 | |
@@ -174,7 +176,7 b' class mercurial_sink(common.converter_si' | |||
|
174 | 176 | revmap = self.subrevmaps.get(subpath) |
|
175 | 177 | if revmap is None: |
|
176 | 178 | revmap = mapfile( |
|
177 | self.ui, self.repo.wjoin(subpath, '.hg/shamap') | |
|
179 | self.ui, self.repo.wjoin(subpath, b'.hg/shamap') | |
|
178 | 180 | ) |
|
179 | 181 | self.subrevmaps[subpath] = revmap |
|
180 | 182 | |
@@ -182,9 +184,9 b' class mercurial_sink(common.converter_si' | |||
|
182 | 184 | # need to be converted, in which case they can be cloned |
|
183 | 185 | # into place instead of converted. Therefore, only warn |
|
184 | 186 | # once. |
|
185 | msg = _('no ".hgsubstate" updates will be made for "%s"\n') | |
|
187 | msg = _(b'no ".hgsubstate" updates will be made for "%s"\n') | |
|
186 | 188 | if len(revmap) == 0: |
|
187 | sub = self.repo.wvfs.reljoin(subpath, '.hg') | |
|
189 | sub = self.repo.wvfs.reljoin(subpath, b'.hg') | |
|
188 | 190 | |
|
189 | 191 | if self.repo.wvfs.exists(sub): |
|
190 | 192 | self.ui.warn(msg % subpath) |
@@ -193,13 +195,13 b' class mercurial_sink(common.converter_si' | |||
|
193 | 195 | if not newid: |
|
194 | 196 | if len(revmap) > 0: |
|
195 | 197 | self.ui.warn( |
|
196 | _("%s is missing from %s/.hg/shamap\n") | |
|
198 | _(b"%s is missing from %s/.hg/shamap\n") | |
|
197 | 199 | % (revid, subpath) |
|
198 | 200 | ) |
|
199 | 201 | else: |
|
200 | 202 | revid = newid |
|
201 | 203 | |
|
202 | fp.write('%s %s\n' % (revid, subpath)) | |
|
204 | fp.write(b'%s %s\n' % (revid, subpath)) | |
|
203 | 205 | |
|
204 | 206 | return fp.getvalue() |
|
205 | 207 | |
@@ -232,16 +234,16 b' class mercurial_sink(common.converter_si' | |||
|
232 | 234 | |
|
233 | 235 | # If the file requires actual merging, abort. We don't have enough |
|
234 | 236 | # context to resolve merges correctly. |
|
235 | if action in ['m', 'dm', 'cd', 'dc']: | |
|
237 | if action in [b'm', b'dm', b'cd', b'dc']: | |
|
236 | 238 | raise error.Abort( |
|
237 | 239 | _( |
|
238 | "unable to convert merge commit " | |
|
239 | "since target parents do not merge cleanly (file " | |
|
240 | "%s, parents %s and %s)" | |
|
240 | b"unable to convert merge commit " | |
|
241 | b"since target parents do not merge cleanly (file " | |
|
242 | b"%s, parents %s and %s)" | |
|
241 | 243 | ) |
|
242 | 244 | % (file, p1ctx, p2ctx) |
|
243 | 245 | ) |
|
244 | elif action == 'k': | |
|
246 | elif action == b'k': | |
|
245 | 247 | # 'keep' means nothing changed from p1 |
|
246 | 248 | continue |
|
247 | 249 | else: |
@@ -255,7 +257,7 b' class mercurial_sink(common.converter_si' | |||
|
255 | 257 | |
|
256 | 258 | def getfilectx(repo, memctx, f): |
|
257 | 259 | if p2ctx and f in p2files and f not in copies: |
|
258 | self.ui.debug('reusing %s from p2\n' % f) | |
|
260 | self.ui.debug(b'reusing %s from p2\n' % f) | |
|
259 | 261 | try: |
|
260 | 262 | return p2ctx[f] |
|
261 | 263 | except error.ManifestLookupError: |
@@ -269,17 +271,17 b' class mercurial_sink(common.converter_si' | |||
|
269 | 271 | data, mode = source.getfile(f, v) |
|
270 | 272 | if data is None: |
|
271 | 273 | return None |
|
272 | if f == '.hgtags': | |
|
274 | if f == b'.hgtags': | |
|
273 | 275 | data = self._rewritetags(source, revmap, data) |
|
274 | if f == '.hgsubstate': | |
|
276 | if f == b'.hgsubstate': | |
|
275 | 277 | data = self._rewritesubstate(source, data) |
|
276 | 278 | return context.memfilectx( |
|
277 | 279 | self.repo, |
|
278 | 280 | memctx, |
|
279 | 281 | f, |
|
280 | 282 | data, |
|
281 | 'l' in mode, | |
|
282 | 'x' in mode, | |
|
283 | b'l' in mode, | |
|
284 | b'x' in mode, | |
|
283 | 285 | copies.get(f), |
|
284 | 286 | ) |
|
285 | 287 | |
@@ -310,15 +312,15 b' class mercurial_sink(common.converter_si' | |||
|
310 | 312 | |
|
311 | 313 | extra = commit.extra.copy() |
|
312 | 314 | |
|
313 | sourcename = self.repo.ui.config('convert', 'hg.sourcename') | |
|
315 | sourcename = self.repo.ui.config(b'convert', b'hg.sourcename') | |
|
314 | 316 | if sourcename: |
|
315 | extra['convert_source'] = sourcename | |
|
317 | extra[b'convert_source'] = sourcename | |
|
316 | 318 | |
|
317 | 319 | for label in ( |
|
318 | 'source', | |
|
319 | 'transplant_source', | |
|
320 | 'rebase_source', | |
|
321 | 'intermediate-source', | |
|
320 | b'source', | |
|
321 | b'transplant_source', | |
|
322 | b'rebase_source', | |
|
323 | b'intermediate-source', | |
|
322 | 324 | ): |
|
323 | 325 | node = extra.get(label) |
|
324 | 326 | |
@@ -326,20 +328,20 b' class mercurial_sink(common.converter_si' | |||
|
326 | 328 | continue |
|
327 | 329 | |
|
328 | 330 | # Only transplant stores its reference in binary |
|
329 | if label == 'transplant_source': | |
|
331 | if label == b'transplant_source': | |
|
330 | 332 | node = nodemod.hex(node) |
|
331 | 333 | |
|
332 | 334 | newrev = revmap.get(node) |
|
333 | 335 | if newrev is not None: |
|
334 | if label == 'transplant_source': | |
|
336 | if label == b'transplant_source': | |
|
335 | 337 | newrev = nodemod.bin(newrev) |
|
336 | 338 | |
|
337 | 339 | extra[label] = newrev |
|
338 | 340 | |
|
339 | 341 | if self.branchnames and commit.branch: |
|
340 | extra['branch'] = commit.branch | |
|
342 | extra[b'branch'] = commit.branch | |
|
341 | 343 | if commit.rev and commit.saverev: |
|
342 | extra['convert_revision'] = commit.rev | |
|
344 | extra[b'convert_revision'] = commit.rev | |
|
343 | 345 | |
|
344 | 346 | while parents: |
|
345 | 347 | p1 = p2 |
@@ -373,14 +375,14 b' class mercurial_sink(common.converter_si' | |||
|
373 | 375 | # We won't know if the conversion changes the node until after the |
|
374 | 376 | # commit, so copy the source's phase for now. |
|
375 | 377 | self.repo.ui.setconfig( |
|
376 | 'phases', | |
|
377 | 'new-commit', | |
|
378 | b'phases', | |
|
379 | b'new-commit', | |
|
378 | 380 | phases.phasenames[commit.phase], |
|
379 | 'convert', | |
|
381 | b'convert', | |
|
380 | 382 | ) |
|
381 | 383 | |
|
382 | with self.repo.transaction("convert") as tr: | |
|
383 | if self.repo.ui.config('convert', 'hg.preserve-hash'): | |
|
384 | with self.repo.transaction(b"convert") as tr: | |
|
385 | if self.repo.ui.config(b'convert', b'hg.preserve-hash'): | |
|
384 | 386 | origctx = commit.ctx |
|
385 | 387 | else: |
|
386 | 388 | origctx = None |
@@ -396,15 +398,15 b' class mercurial_sink(common.converter_si' | |||
|
396 | 398 | self.repo, tr, phases.draft, [ctx.node()] |
|
397 | 399 | ) |
|
398 | 400 | |
|
399 | text = "(octopus merge fixup)\n" | |
|
401 | text = b"(octopus merge fixup)\n" | |
|
400 | 402 | p2 = node |
|
401 | 403 | |
|
402 | 404 | if self.filemapmode and nparents == 1: |
|
403 | 405 | man = self.repo.manifestlog.getstorage(b'') |
|
404 | 406 | mnode = self.repo.changelog.read(nodemod.bin(p2))[0] |
|
405 | closed = 'close' in commit.extra | |
|
407 | closed = b'close' in commit.extra | |
|
406 | 408 | if not closed and not man.cmp(m1node, man.revision(mnode)): |
|
407 | self.ui.status(_("filtering out empty revision\n")) | |
|
409 | self.ui.status(_(b"filtering out empty revision\n")) | |
|
408 | 410 | self.repo.rollback(force=True) |
|
409 | 411 | return parent |
|
410 | 412 | return p2 |
@@ -416,13 +418,13 b' class mercurial_sink(common.converter_si' | |||
|
416 | 418 | oldlines = set() |
|
417 | 419 | for branch, heads in self.repo.branchmap().iteritems(): |
|
418 | 420 | for h in heads: |
|
419 | if '.hgtags' in self.repo[h]: | |
|
421 | if b'.hgtags' in self.repo[h]: | |
|
420 | 422 | oldlines.update( |
|
421 | set(self.repo[h]['.hgtags'].data().splitlines(True)) | |
|
423 | set(self.repo[h][b'.hgtags'].data().splitlines(True)) | |
|
422 | 424 | ) |
|
423 | 425 | oldlines = sorted(list(oldlines)) |
|
424 | 426 | |
|
425 | newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags]) | |
|
427 | newlines = sorted([(b"%s %s\n" % (tags[tag], tag)) for tag in tags]) | |
|
426 | 428 | if newlines == oldlines: |
|
427 | 429 | return None, None |
|
428 | 430 | |
@@ -430,12 +432,12 b' class mercurial_sink(common.converter_si' | |||
|
430 | 432 | oldtags = set() |
|
431 | 433 | newtags = set() |
|
432 | 434 | for line in oldlines: |
|
433 | s = line.strip().split(' ', 1) | |
|
435 | s = line.strip().split(b' ', 1) | |
|
434 | 436 | if len(s) != 2: |
|
435 | 437 | continue |
|
436 | 438 | oldtags.add(s[1]) |
|
437 | 439 | for line in newlines: |
|
438 | s = line.strip().split(' ', 1) | |
|
440 | s = line.strip().split(b' ', 1) | |
|
439 | 441 | if len(s) != 2: |
|
440 | 442 | continue |
|
441 | 443 | if s[1] not in oldtags: |
@@ -444,21 +446,21 b' class mercurial_sink(common.converter_si' | |||
|
444 | 446 | if not newtags: |
|
445 | 447 | return None, None |
|
446 | 448 | |
|
447 | data = "".join(newlines) | |
|
449 | data = b"".join(newlines) | |
|
448 | 450 | |
|
449 | 451 | def getfilectx(repo, memctx, f): |
|
450 | 452 | return context.memfilectx(repo, memctx, f, data, False, False, None) |
|
451 | 453 | |
|
452 | self.ui.status(_("updating tags\n")) | |
|
453 | date = "%d 0" % int(time.mktime(time.gmtime())) | |
|
454 | extra = {'branch': self.tagsbranch} | |
|
454 | self.ui.status(_(b"updating tags\n")) | |
|
455 | date = b"%d 0" % int(time.mktime(time.gmtime())) | |
|
456 | extra = {b'branch': self.tagsbranch} | |
|
455 | 457 | ctx = context.memctx( |
|
456 | 458 | self.repo, |
|
457 | 459 | (tagparent, None), |
|
458 | "update tags", | |
|
459 | [".hgtags"], | |
|
460 | b"update tags", | |
|
461 | [b".hgtags"], | |
|
460 | 462 | getfilectx, |
|
461 | "convert-repo", | |
|
463 | b"convert-repo", | |
|
462 | 464 | date, |
|
463 | 465 | extra, |
|
464 | 466 | ) |
@@ -475,8 +477,8 b' class mercurial_sink(common.converter_si' | |||
|
475 | 477 | try: |
|
476 | 478 | wlock = self.repo.wlock() |
|
477 | 479 | lock = self.repo.lock() |
|
478 | tr = self.repo.transaction('bookmark') | |
|
479 | self.ui.status(_("updating bookmarks\n")) | |
|
480 | tr = self.repo.transaction(b'bookmark') | |
|
481 | self.ui.status(_(b"updating bookmarks\n")) | |
|
480 | 482 | destmarks = self.repo._bookmarks |
|
481 | 483 | changes = [ |
|
482 | 484 | (bookmark, nodemod.bin(updatedbookmark[bookmark])) |
@@ -495,9 +497,9 b' class mercurial_sink(common.converter_si' | |||
|
495 | 497 | if rev not in self.repo and self.clonebranches: |
|
496 | 498 | raise error.Abort( |
|
497 | 499 | _( |
|
498 | 'revision %s not found in destination ' | |
|
499 | 'repository (lookups with clonebranches=true ' | |
|
500 | 'are not implemented)' | |
|
500 | b'revision %s not found in destination ' | |
|
501 | b'repository (lookups with clonebranches=true ' | |
|
502 | b'are not implemented)' | |
|
501 | 503 | ) |
|
502 | 504 | % rev |
|
503 | 505 | ) |
@@ -507,9 +509,9 b' class mercurial_sink(common.converter_si' | |||
|
507 | 509 | class mercurial_source(common.converter_source): |
|
508 | 510 | def __init__(self, ui, repotype, path, revs=None): |
|
509 | 511 | common.converter_source.__init__(self, ui, repotype, path, revs) |
|
510 | self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors') | |
|
512 | self.ignoreerrors = ui.configbool(b'convert', b'hg.ignoreerrors') | |
|
511 | 513 | self.ignored = set() |
|
512 | self.saverev = ui.configbool('convert', 'hg.saverev') | |
|
514 | self.saverev = ui.configbool(b'convert', b'hg.saverev') | |
|
513 | 515 | try: |
|
514 | 516 | self.repo = hg.repository(self.ui, path) |
|
515 | 517 | # try to provoke an exception if this isn't really a hg |
@@ -518,21 +520,21 b' class mercurial_source(common.converter_' | |||
|
518 | 520 | raise error.RepoError |
|
519 | 521 | except error.RepoError: |
|
520 | 522 | ui.traceback() |
|
521 | raise NoRepo(_("%s is not a local Mercurial repository") % path) | |
|
523 | raise NoRepo(_(b"%s is not a local Mercurial repository") % path) | |
|
522 | 524 | self.lastrev = None |
|
523 | 525 | self.lastctx = None |
|
524 | 526 | self._changescache = None, None |
|
525 | 527 | self.convertfp = None |
|
526 | 528 | # Restrict converted revisions to startrev descendants |
|
527 | startnode = ui.config('convert', 'hg.startrev') | |
|
528 | hgrevs = ui.config('convert', 'hg.revs') | |
|
529 | startnode = ui.config(b'convert', b'hg.startrev') | |
|
530 | hgrevs = ui.config(b'convert', b'hg.revs') | |
|
529 | 531 | if hgrevs is None: |
|
530 | 532 | if startnode is not None: |
|
531 | 533 | try: |
|
532 | 534 | startnode = self.repo.lookup(startnode) |
|
533 | 535 | except error.RepoError: |
|
534 | 536 | raise error.Abort( |
|
535 | _('%s is not a valid start revision') % startnode | |
|
537 | _(b'%s is not a valid start revision') % startnode | |
|
536 | 538 | ) |
|
537 | 539 | startrev = self.repo.changelog.rev(startnode) |
|
538 | 540 | children = {startnode: 1} |
@@ -548,7 +550,10 b' class mercurial_source(common.converter_' | |||
|
548 | 550 | else: |
|
549 | 551 | if revs or startnode is not None: |
|
550 | 552 | raise error.Abort( |
|
551 | _('hg.revs cannot be combined with ' 'hg.startrev or --rev') | |
|
553 | _( | |
|
554 | b'hg.revs cannot be combined with ' | |
|
555 | b'hg.startrev or --rev' | |
|
556 | ) | |
|
552 | 557 | ) |
|
553 | 558 | nodes = set() |
|
554 | 559 | parents = set() |
@@ -635,7 +640,7 b' class mercurial_source(common.converter_' | |||
|
635 | 640 | if not self.ignoreerrors: |
|
636 | 641 | raise |
|
637 | 642 | self.ignored.add(name) |
|
638 | self.ui.warn(_('ignoring: %s\n') % e) | |
|
643 | self.ui.warn(_(b'ignoring: %s\n') % e) | |
|
639 | 644 | return copies |
|
640 | 645 | |
|
641 | 646 | def getcommit(self, rev): |
@@ -647,7 +652,7 b' class mercurial_source(common.converter_' | |||
|
647 | 652 | |
|
648 | 653 | return common.commit( |
|
649 | 654 | author=ctx.user(), |
|
650 | date=dateutil.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'), | |
|
655 | date=dateutil.datestr(ctx.date(), b'%Y-%m-%d %H:%M:%S %1%2'), | |
|
651 | 656 | desc=ctx.description(), |
|
652 | 657 | rev=crev, |
|
653 | 658 | parents=parents, |
@@ -668,7 +673,7 b' class mercurial_source(common.converter_' | |||
|
668 | 673 | tags = [ |
|
669 | 674 | t |
|
670 | 675 | for t in self.repo.tagslist() |
|
671 | if self.repo.tagtype(t[0]) == 'global' | |
|
676 | if self.repo.tagtype(t[0]) == b'global' | |
|
672 | 677 | ] |
|
673 | 678 | return dict( |
|
674 | 679 | [ |
@@ -696,15 +701,15 b' class mercurial_source(common.converter_' | |||
|
696 | 701 | |
|
697 | 702 | def converted(self, rev, destrev): |
|
698 | 703 | if self.convertfp is None: |
|
699 | self.convertfp = open(self.repo.vfs.join('shamap'), 'ab') | |
|
700 | self.convertfp.write(util.tonativeeol('%s %s\n' % (destrev, rev))) | |
|
704 | self.convertfp = open(self.repo.vfs.join(b'shamap'), b'ab') | |
|
705 | self.convertfp.write(util.tonativeeol(b'%s %s\n' % (destrev, rev))) | |
|
701 | 706 | self.convertfp.flush() |
|
702 | 707 | |
|
703 | 708 | def before(self): |
|
704 | self.ui.debug('run hg source pre-conversion action\n') | |
|
709 | self.ui.debug(b'run hg source pre-conversion action\n') | |
|
705 | 710 | |
|
706 | 711 | def after(self): |
|
707 | self.ui.debug('run hg source post-conversion action\n') | |
|
712 | self.ui.debug(b'run hg source post-conversion action\n') | |
|
708 | 713 | |
|
709 | 714 | def hasnativeorder(self): |
|
710 | 715 | return True |
@@ -721,6 +726,6 b' class mercurial_source(common.converter_' | |||
|
721 | 726 | def getbookmarks(self): |
|
722 | 727 | return bookmarks.listbookmarks(self.repo) |
|
723 | 728 | |
|
724 | def checkrevformat(self, revstr, mapname='splicemap'): | |
|
729 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
|
725 | 730 | """ Mercurial, revision string is a 40 byte hex """ |
|
726 | 731 | self.checkhexformat(revstr, mapname) |
@@ -26,11 +26,11 b' class monotone_source(common.converter_s' | |||
|
26 | 26 | if revs and len(revs) > 1: |
|
27 | 27 | raise error.Abort( |
|
28 | 28 | _( |
|
29 | 'monotone source does not support specifying ' | |
|
30 | 'multiple revs' | |
|
29 | b'monotone source does not support specifying ' | |
|
30 | b'multiple revs' | |
|
31 | 31 | ) |
|
32 | 32 | ) |
|
33 | common.commandline.__init__(self, ui, 'mtn') | |
|
33 | common.commandline.__init__(self, ui, b'mtn') | |
|
34 | 34 | |
|
35 | 35 | self.ui = ui |
|
36 | 36 | self.path = path |
@@ -38,17 +38,17 b' class monotone_source(common.converter_s' | |||
|
38 | 38 | self.revs = revs |
|
39 | 39 | |
|
40 | 40 | norepo = common.NoRepo( |
|
41 | _("%s does not look like a monotone repository") % path | |
|
41 | _(b"%s does not look like a monotone repository") % path | |
|
42 | 42 | ) |
|
43 | if not os.path.exists(os.path.join(path, '_MTN')): | |
|
43 | if not os.path.exists(os.path.join(path, b'_MTN')): | |
|
44 | 44 | # Could be a monotone repository (SQLite db file) |
|
45 | 45 | try: |
|
46 | f = open(path, 'rb') | |
|
46 | f = open(path, b'rb') | |
|
47 | 47 | header = f.read(16) |
|
48 | 48 | f.close() |
|
49 | 49 | except IOError: |
|
50 | header = '' | |
|
51 | if header != 'SQLite format 3\x00': | |
|
50 | header = b'' | |
|
51 | if header != b'SQLite format 3\x00': | |
|
52 | 52 | raise norepo |
|
53 | 53 | |
|
54 | 54 | # regular expressions for parsing monotone output |
@@ -58,24 +58,26 b' class monotone_source(common.converter_s' | |||
|
58 | 58 | revision = br'\s+\[(\w+)\]\s*' |
|
59 | 59 | lines = br'(?:.|\n)+' |
|
60 | 60 | |
|
61 | self.dir_re = re.compile(space + "dir" + name) | |
|
62 |
self.file_re = re.compile( |
|
|
61 | self.dir_re = re.compile(space + b"dir" + name) | |
|
62 | self.file_re = re.compile( | |
|
63 | space + b"file" + name + b"content" + revision | |
|
64 | ) | |
|
63 | 65 | self.add_file_re = re.compile( |
|
64 | space + "add_file" + name + "content" + revision | |
|
66 | space + b"add_file" + name + b"content" + revision | |
|
65 | 67 | ) |
|
66 | 68 | self.patch_re = re.compile( |
|
67 | space + "patch" + name + "from" + revision + "to" + revision | |
|
69 | space + b"patch" + name + b"from" + revision + b"to" + revision | |
|
68 | 70 | ) |
|
69 | self.rename_re = re.compile(space + "rename" + name + "to" + name) | |
|
70 | self.delete_re = re.compile(space + "delete" + name) | |
|
71 | self.tag_re = re.compile(space + "tag" + name + "revision" + revision) | |
|
71 | self.rename_re = re.compile(space + b"rename" + name + b"to" + name) | |
|
72 | self.delete_re = re.compile(space + b"delete" + name) | |
|
73 | self.tag_re = re.compile(space + b"tag" + name + b"revision" + revision) | |
|
72 | 74 | self.cert_re = re.compile( |
|
73 | lines + space + "name" + name + "value" + value | |
|
75 | lines + space + b"name" + name + b"value" + value | |
|
74 | 76 | ) |
|
75 | 77 | |
|
76 | attr = space + "file" + lines + space + "attr" + space | |
|
78 | attr = space + b"file" + lines + space + b"attr" + space | |
|
77 | 79 | self.attr_execute_re = re.compile( |
|
78 | attr + '"mtn:execute"' + space + '"true"' | |
|
80 | attr + b'"mtn:execute"' + space + b'"true"' | |
|
79 | 81 | ) |
|
80 | 82 | |
|
81 | 83 | # cached data |
@@ -84,7 +86,7 b' class monotone_source(common.converter_s' | |||
|
84 | 86 | self.files = None |
|
85 | 87 | self.dirs = None |
|
86 | 88 | |
|
87 | common.checktool('mtn', abort=False) | |
|
89 | common.checktool(b'mtn', abort=False) | |
|
88 | 90 | |
|
89 | 91 | def mtnrun(self, *args, **kwargs): |
|
90 | 92 | if self.automatestdio: |
@@ -94,27 +96,27 b' class monotone_source(common.converter_s' | |||
|
94 | 96 | |
|
95 | 97 | def mtnrunsingle(self, *args, **kwargs): |
|
96 | 98 | kwargs[r'd'] = self.path |
|
97 | return self.run0('automate', *args, **kwargs) | |
|
99 | return self.run0(b'automate', *args, **kwargs) | |
|
98 | 100 | |
|
99 | 101 | def mtnrunstdio(self, *args, **kwargs): |
|
100 | 102 | # Prepare the command in automate stdio format |
|
101 | 103 | kwargs = pycompat.byteskwargs(kwargs) |
|
102 | 104 | command = [] |
|
103 | 105 | for k, v in kwargs.iteritems(): |
|
104 | command.append("%d:%s" % (len(k), k)) | |
|
106 | command.append(b"%d:%s" % (len(k), k)) | |
|
105 | 107 | if v: |
|
106 | command.append("%d:%s" % (len(v), v)) | |
|
108 | command.append(b"%d:%s" % (len(v), v)) | |
|
107 | 109 | if command: |
|
108 | command.insert(0, 'o') | |
|
109 | command.append('e') | |
|
110 | command.insert(0, b'o') | |
|
111 | command.append(b'e') | |
|
110 | 112 | |
|
111 | command.append('l') | |
|
113 | command.append(b'l') | |
|
112 | 114 | for arg in args: |
|
113 | command.append("%d:%s" % (len(arg), arg)) | |
|
114 | command.append('e') | |
|
115 | command = ''.join(command) | |
|
115 | command.append(b"%d:%s" % (len(arg), arg)) | |
|
116 | command.append(b'e') | |
|
117 | command = b''.join(command) | |
|
116 | 118 | |
|
117 | self.ui.debug("mtn: sending '%s'\n" % command) | |
|
119 | self.ui.debug(b"mtn: sending '%s'\n" % command) | |
|
118 | 120 | self.mtnwritefp.write(command) |
|
119 | 121 | self.mtnwritefp.flush() |
|
120 | 122 | |
@@ -122,42 +124,44 b' class monotone_source(common.converter_s' | |||
|
122 | 124 | |
|
123 | 125 | def mtnstdioreadpacket(self): |
|
124 | 126 | read = None |
|
125 | commandnbr = '' | |
|
126 | while read != ':': | |
|
127 | commandnbr = b'' | |
|
128 | while read != b':': | |
|
127 | 129 | read = self.mtnreadfp.read(1) |
|
128 | 130 | if not read: |
|
129 | raise error.Abort(_('bad mtn packet - no end of commandnbr')) | |
|
131 | raise error.Abort(_(b'bad mtn packet - no end of commandnbr')) | |
|
130 | 132 | commandnbr += read |
|
131 | 133 | commandnbr = commandnbr[:-1] |
|
132 | 134 | |
|
133 | 135 | stream = self.mtnreadfp.read(1) |
|
134 | if stream not in 'mewptl': | |
|
135 | raise error.Abort(_('bad mtn packet - bad stream type %s') % stream) | |
|
136 | if stream not in b'mewptl': | |
|
137 | raise error.Abort( | |
|
138 | _(b'bad mtn packet - bad stream type %s') % stream | |
|
139 | ) | |
|
136 | 140 | |
|
137 | 141 | read = self.mtnreadfp.read(1) |
|
138 | if read != ':': | |
|
139 | raise error.Abort(_('bad mtn packet - no divider before size')) | |
|
142 | if read != b':': | |
|
143 | raise error.Abort(_(b'bad mtn packet - no divider before size')) | |
|
140 | 144 | |
|
141 | 145 | read = None |
|
142 | lengthstr = '' | |
|
143 | while read != ':': | |
|
146 | lengthstr = b'' | |
|
147 | while read != b':': | |
|
144 | 148 | read = self.mtnreadfp.read(1) |
|
145 | 149 | if not read: |
|
146 | raise error.Abort(_('bad mtn packet - no end of packet size')) | |
|
150 | raise error.Abort(_(b'bad mtn packet - no end of packet size')) | |
|
147 | 151 | lengthstr += read |
|
148 | 152 | try: |
|
149 | 153 | length = pycompat.long(lengthstr[:-1]) |
|
150 | 154 | except TypeError: |
|
151 | 155 | raise error.Abort( |
|
152 | _('bad mtn packet - bad packet size %s') % lengthstr | |
|
156 | _(b'bad mtn packet - bad packet size %s') % lengthstr | |
|
153 | 157 | ) |
|
154 | 158 | |
|
155 | 159 | read = self.mtnreadfp.read(length) |
|
156 | 160 | if len(read) != length: |
|
157 | 161 | raise error.Abort( |
|
158 | 162 | _( |
|
159 | "bad mtn packet - unable to read full packet " | |
|
160 | "read %s of %s" | |
|
163 | b"bad mtn packet - unable to read full packet " | |
|
164 | b"read %s of %s" | |
|
161 | 165 | ) |
|
162 | 166 | % (len(read), length) |
|
163 | 167 | ) |
@@ -169,33 +173,33 b' class monotone_source(common.converter_s' | |||
|
169 | 173 | while True: |
|
170 | 174 | commandnbr, stream, length, output = self.mtnstdioreadpacket() |
|
171 | 175 | self.ui.debug( |
|
172 | 'mtn: read packet %s:%s:%d\n' % (commandnbr, stream, length) | |
|
176 | b'mtn: read packet %s:%s:%d\n' % (commandnbr, stream, length) | |
|
173 | 177 | ) |
|
174 | 178 | |
|
175 | if stream == 'l': | |
|
179 | if stream == b'l': | |
|
176 | 180 | # End of command |
|
177 | if output != '0': | |
|
181 | if output != b'0': | |
|
178 | 182 | raise error.Abort( |
|
179 | _("mtn command '%s' returned %s") % (command, output) | |
|
183 | _(b"mtn command '%s' returned %s") % (command, output) | |
|
180 | 184 | ) |
|
181 | 185 | break |
|
182 | elif stream in 'ew': | |
|
186 | elif stream in b'ew': | |
|
183 | 187 | # Error, warning output |
|
184 | self.ui.warn(_('%s error:\n') % self.command) | |
|
188 | self.ui.warn(_(b'%s error:\n') % self.command) | |
|
185 | 189 | self.ui.warn(output) |
|
186 | elif stream == 'p': | |
|
190 | elif stream == b'p': | |
|
187 | 191 | # Progress messages |
|
188 | self.ui.debug('mtn: ' + output) | |
|
189 | elif stream == 'm': | |
|
192 | self.ui.debug(b'mtn: ' + output) | |
|
193 | elif stream == b'm': | |
|
190 | 194 | # Main stream - command output |
|
191 | 195 | retval.append(output) |
|
192 | 196 | |
|
193 | return ''.join(retval) | |
|
197 | return b''.join(retval) | |
|
194 | 198 | |
|
195 | 199 | def mtnloadmanifest(self, rev): |
|
196 | 200 | if self.manifest_rev == rev: |
|
197 | 201 | return |
|
198 | self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n") | |
|
202 | self.manifest = self.mtnrun(b"get_manifest_of", rev).split(b"\n\n") | |
|
199 | 203 | self.manifest_rev = rev |
|
200 | 204 | self.files = {} |
|
201 | 205 | self.dirs = {} |
@@ -203,11 +207,11 b' class monotone_source(common.converter_s' | |||
|
203 | 207 | for e in self.manifest: |
|
204 | 208 | m = self.file_re.match(e) |
|
205 | 209 | if m: |
|
206 | attr = "" | |
|
210 | attr = b"" | |
|
207 | 211 | name = m.group(1) |
|
208 | 212 | node = m.group(2) |
|
209 | 213 | if self.attr_execute_re.match(e): |
|
210 | attr += "x" | |
|
214 | attr += b"x" | |
|
211 | 215 | self.files[name] = (node, attr) |
|
212 | 216 | m = self.dir_re.match(e) |
|
213 | 217 | if m: |
@@ -224,12 +228,12 b' class monotone_source(common.converter_s' | |||
|
224 | 228 | |
|
225 | 229 | def mtngetcerts(self, rev): |
|
226 | 230 | certs = { |
|
227 | "author": "<missing>", | |
|
228 | "date": "<missing>", | |
|
229 | "changelog": "<missing>", | |
|
230 | "branch": "<missing>", | |
|
231 | b"author": b"<missing>", | |
|
232 | b"date": b"<missing>", | |
|
233 | b"changelog": b"<missing>", | |
|
234 | b"branch": b"<missing>", | |
|
231 | 235 | } |
|
232 | certlist = self.mtnrun("certs", rev) | |
|
236 | certlist = self.mtnrun(b"certs", rev) | |
|
233 | 237 | # mtn < 0.45: |
|
234 | 238 | # key "test@selenic.com" |
|
235 | 239 | # mtn >= 0.45: |
@@ -239,28 +243,28 b' class monotone_source(common.converter_s' | |||
|
239 | 243 | m = self.cert_re.match(e) |
|
240 | 244 | if m: |
|
241 | 245 | name, value = m.groups() |
|
242 | value = value.replace(br'\"', '"') | |
|
243 | value = value.replace(br'\\', '\\') | |
|
246 | value = value.replace(br'\"', b'"') | |
|
247 | value = value.replace(br'\\', b'\\') | |
|
244 | 248 | certs[name] = value |
|
245 | 249 | # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306 |
|
246 | 250 | # and all times are stored in UTC |
|
247 | certs["date"] = certs["date"].split('.')[0] + " UTC" | |
|
251 | certs[b"date"] = certs[b"date"].split(b'.')[0] + b" UTC" | |
|
248 | 252 | return certs |
|
249 | 253 | |
|
250 | 254 | # implement the converter_source interface: |
|
251 | 255 | |
|
252 | 256 | def getheads(self): |
|
253 | 257 | if not self.revs: |
|
254 | return self.mtnrun("leaves").splitlines() | |
|
258 | return self.mtnrun(b"leaves").splitlines() | |
|
255 | 259 | else: |
|
256 | 260 | return self.revs |
|
257 | 261 | |
|
258 | 262 | def getchanges(self, rev, full): |
|
259 | 263 | if full: |
|
260 | 264 | raise error.Abort( |
|
261 | _("convert from monotone does not support " "--full") | |
|
265 | _(b"convert from monotone does not support " b"--full") | |
|
262 | 266 | ) |
|
263 | revision = self.mtnrun("get_revision", rev).split("\n\n") | |
|
267 | revision = self.mtnrun(b"get_revision", rev).split(b"\n\n") | |
|
264 | 268 | files = {} |
|
265 | 269 | ignoremove = {} |
|
266 | 270 | renameddirs = [] |
@@ -298,7 +302,7 b' class monotone_source(common.converter_s' | |||
|
298 | 302 | for tofile in self.files: |
|
299 | 303 | if tofile in ignoremove: |
|
300 | 304 | continue |
|
301 | if tofile.startswith(todir + '/'): | |
|
305 | if tofile.startswith(todir + b'/'): | |
|
302 | 306 | renamed[tofile] = fromdir + tofile[len(todir) :] |
|
303 | 307 | # Avoid chained moves like: |
|
304 | 308 | # d1(/a) => d3/d1(/a) |
@@ -306,9 +310,9 b' class monotone_source(common.converter_s' | |||
|
306 | 310 | ignoremove[tofile] = 1 |
|
307 | 311 | for tofile, fromfile in renamed.items(): |
|
308 | 312 | self.ui.debug( |
|
309 | "copying file in renamed directory from '%s' to '%s'" | |
|
313 | b"copying file in renamed directory from '%s' to '%s'" | |
|
310 | 314 | % (fromfile, tofile), |
|
311 | '\n', | |
|
315 | b'\n', | |
|
312 | 316 | ) |
|
313 | 317 | files[tofile] = rev |
|
314 | 318 | copies[tofile] = fromfile |
@@ -321,32 +325,32 b' class monotone_source(common.converter_s' | |||
|
321 | 325 | if not self.mtnisfile(name, rev): |
|
322 | 326 | return None, None |
|
323 | 327 | try: |
|
324 | data = self.mtnrun("get_file_of", name, r=rev) | |
|
328 | data = self.mtnrun(b"get_file_of", name, r=rev) | |
|
325 | 329 | except Exception: |
|
326 | 330 | return None, None |
|
327 | 331 | self.mtnloadmanifest(rev) |
|
328 | node, attr = self.files.get(name, (None, "")) | |
|
332 | node, attr = self.files.get(name, (None, b"")) | |
|
329 | 333 | return data, attr |
|
330 | 334 | |
|
331 | 335 | def getcommit(self, rev): |
|
332 | 336 | extra = {} |
|
333 | 337 | certs = self.mtngetcerts(rev) |
|
334 | if certs.get('suspend') == certs["branch"]: | |
|
335 | extra['close'] = 1 | |
|
336 | dateformat = "%Y-%m-%dT%H:%M:%S" | |
|
338 | if certs.get(b'suspend') == certs[b"branch"]: | |
|
339 | extra[b'close'] = 1 | |
|
340 | dateformat = b"%Y-%m-%dT%H:%M:%S" | |
|
337 | 341 | return common.commit( |
|
338 | author=certs["author"], | |
|
339 | date=dateutil.datestr(dateutil.strdate(certs["date"], dateformat)), | |
|
340 | desc=certs["changelog"], | |
|
342 | author=certs[b"author"], | |
|
343 | date=dateutil.datestr(dateutil.strdate(certs[b"date"], dateformat)), | |
|
344 | desc=certs[b"changelog"], | |
|
341 | 345 | rev=rev, |
|
342 | parents=self.mtnrun("parents", rev).splitlines(), | |
|
343 | branch=certs["branch"], | |
|
346 | parents=self.mtnrun(b"parents", rev).splitlines(), | |
|
347 | branch=certs[b"branch"], | |
|
344 | 348 | extra=extra, |
|
345 | 349 | ) |
|
346 | 350 | |
|
347 | 351 | def gettags(self): |
|
348 | 352 | tags = {} |
|
349 | for e in self.mtnrun("tags").split("\n\n"): | |
|
353 | for e in self.mtnrun(b"tags").split(b"\n\n"): | |
|
350 | 354 | m = self.tag_re.match(e) |
|
351 | 355 | if m: |
|
352 | 356 | tags[m.group(1)] = m.group(2) |
@@ -360,42 +364,42 b' class monotone_source(common.converter_s' | |||
|
360 | 364 | def before(self): |
|
361 | 365 | # Check if we have a new enough version to use automate stdio |
|
362 | 366 | try: |
|
363 | versionstr = self.mtnrunsingle("interface_version") | |
|
367 | versionstr = self.mtnrunsingle(b"interface_version") | |
|
364 | 368 | version = float(versionstr) |
|
365 | 369 | except Exception: |
|
366 | 370 | raise error.Abort( |
|
367 | _("unable to determine mtn automate interface " "version") | |
|
371 | _(b"unable to determine mtn automate interface " b"version") | |
|
368 | 372 | ) |
|
369 | 373 | |
|
370 | 374 | if version >= 12.0: |
|
371 | 375 | self.automatestdio = True |
|
372 | 376 | self.ui.debug( |
|
373 | "mtn automate version %f - using automate stdio\n" % version | |
|
377 | b"mtn automate version %f - using automate stdio\n" % version | |
|
374 | 378 | ) |
|
375 | 379 | |
|
376 | 380 | # launch the long-running automate stdio process |
|
377 | 381 | self.mtnwritefp, self.mtnreadfp = self._run2( |
|
378 | 'automate', 'stdio', '-d', self.path | |
|
382 | b'automate', b'stdio', b'-d', self.path | |
|
379 | 383 | ) |
|
380 | 384 | # read the headers |
|
381 | 385 | read = self.mtnreadfp.readline() |
|
382 | if read != 'format-version: 2\n': | |
|
386 | if read != b'format-version: 2\n': | |
|
383 | 387 | raise error.Abort( |
|
384 | _('mtn automate stdio header unexpected: %s') % read | |
|
388 | _(b'mtn automate stdio header unexpected: %s') % read | |
|
385 | 389 | ) |
|
386 | while read != '\n': | |
|
390 | while read != b'\n': | |
|
387 | 391 | read = self.mtnreadfp.readline() |
|
388 | 392 | if not read: |
|
389 | 393 | raise error.Abort( |
|
390 | 394 | _( |
|
391 | "failed to reach end of mtn automate " | |
|
392 | "stdio headers" | |
|
395 | b"failed to reach end of mtn automate " | |
|
396 | b"stdio headers" | |
|
393 | 397 | ) |
|
394 | 398 | ) |
|
395 | 399 | else: |
|
396 | 400 | self.ui.debug( |
|
397 | "mtn automate version %s - not using automate stdio " | |
|
398 | "(automate >= 12.0 - mtn >= 0.46 is needed)\n" % version | |
|
401 | b"mtn automate version %s - not using automate stdio " | |
|
402 | b"(automate >= 12.0 - mtn >= 0.46 is needed)\n" % version | |
|
399 | 403 | ) |
|
400 | 404 | |
|
401 | 405 | def after(self): |
@@ -24,7 +24,7 b' from . import common' | |||
|
24 | 24 | |
|
25 | 25 | |
|
26 | 26 | def loaditer(f): |
|
27 | "Yield the dictionary objects generated by p4" | |
|
27 | b"Yield the dictionary objects generated by p4" | |
|
28 | 28 | try: |
|
29 | 29 | while True: |
|
30 | 30 | d = marshal.load(f) |
@@ -44,7 +44,12 b' def decodefilename(filename):' | |||
|
44 | 44 | >>> decodefilename(b'//Depot/Directory/%2525/%2523/%23%40.%2A') |
|
45 | 45 | '//Depot/Directory/%25/%23/#@.*' |
|
46 | 46 | """ |
|
47 | replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')] | |
|
47 | replacements = [ | |
|
48 | (b'%2A', b'*'), | |
|
49 | (b'%23', b'#'), | |
|
50 | (b'%40', b'@'), | |
|
51 | (b'%25', b'%'), | |
|
52 | ] | |
|
48 | 53 | for k, v in replacements: |
|
49 | 54 | filename = filename.replace(k, v) |
|
50 | 55 | return filename |
@@ -57,16 +62,16 b' class p4_source(common.converter_source)' | |||
|
57 | 62 | |
|
58 | 63 | super(p4_source, self).__init__(ui, repotype, path, revs=revs) |
|
59 | 64 | |
|
60 | if "/" in path and not path.startswith('//'): | |
|
65 | if b"/" in path and not path.startswith(b'//'): | |
|
61 | 66 | raise common.NoRepo( |
|
62 | _('%s does not look like a P4 repository') % path | |
|
67 | _(b'%s does not look like a P4 repository') % path | |
|
63 | 68 | ) |
|
64 | 69 | |
|
65 | common.checktool('p4', abort=False) | |
|
70 | common.checktool(b'p4', abort=False) | |
|
66 | 71 | |
|
67 | 72 | self.revmap = {} |
|
68 | 73 | self.encoding = self.ui.config( |
|
69 | 'convert', 'p4.encoding', convcmd.orig_encoding | |
|
74 | b'convert', b'p4.encoding', convcmd.orig_encoding | |
|
70 | 75 | ) |
|
71 | 76 | self.re_type = re.compile( |
|
72 | 77 | br"([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)" |
@@ -80,7 +85,10 b' class p4_source(common.converter_source)' | |||
|
80 | 85 | |
|
81 | 86 | if revs and len(revs) > 1: |
|
82 | 87 | raise error.Abort( |
|
83 | _("p4 source does not support specifying " "multiple revisions") | |
|
88 | _( | |
|
89 | b"p4 source does not support specifying " | |
|
90 | b"multiple revisions" | |
|
91 | ) | |
|
84 | 92 | ) |
|
85 | 93 | |
|
86 | 94 | def setrevmap(self, revmap): |
@@ -97,18 +105,18 b' class p4_source(common.converter_source)' | |||
|
97 | 105 | self.revmap = revmap |
|
98 | 106 | |
|
99 | 107 | def _parse_view(self, path): |
|
100 | "Read changes affecting the path" | |
|
101 | cmd = 'p4 -G changes -s submitted %s' % procutil.shellquote(path) | |
|
102 | stdout = procutil.popen(cmd, mode='rb') | |
|
108 | b"Read changes affecting the path" | |
|
109 | cmd = b'p4 -G changes -s submitted %s' % procutil.shellquote(path) | |
|
110 | stdout = procutil.popen(cmd, mode=b'rb') | |
|
103 | 111 | p4changes = {} |
|
104 | 112 | for d in loaditer(stdout): |
|
105 | c = d.get("change", None) | |
|
113 | c = d.get(b"change", None) | |
|
106 | 114 | if c: |
|
107 | 115 | p4changes[c] = True |
|
108 | 116 | return p4changes |
|
109 | 117 | |
|
110 | 118 | def _parse(self, ui, path): |
|
111 | "Prepare list of P4 filenames and revisions to import" | |
|
119 | b"Prepare list of P4 filenames and revisions to import" | |
|
112 | 120 | p4changes = {} |
|
113 | 121 | changeset = {} |
|
114 | 122 | files_map = {} |
@@ -117,29 +125,29 b' class p4_source(common.converter_source)' | |||
|
117 | 125 | depotname = {} |
|
118 | 126 | heads = [] |
|
119 | 127 | |
|
120 | ui.status(_('reading p4 views\n')) | |
|
128 | ui.status(_(b'reading p4 views\n')) | |
|
121 | 129 | |
|
122 | 130 | # read client spec or view |
|
123 | if "/" in path: | |
|
131 | if b"/" in path: | |
|
124 | 132 | p4changes.update(self._parse_view(path)) |
|
125 | if path.startswith("//") and path.endswith("/..."): | |
|
126 | views = {path[:-3]: ""} | |
|
133 | if path.startswith(b"//") and path.endswith(b"/..."): | |
|
134 | views = {path[:-3]: b""} | |
|
127 | 135 | else: |
|
128 | views = {"//": ""} | |
|
136 | views = {b"//": b""} | |
|
129 | 137 | else: |
|
130 | cmd = 'p4 -G client -o %s' % procutil.shellquote(path) | |
|
131 | clientspec = marshal.load(procutil.popen(cmd, mode='rb')) | |
|
138 | cmd = b'p4 -G client -o %s' % procutil.shellquote(path) | |
|
139 | clientspec = marshal.load(procutil.popen(cmd, mode=b'rb')) | |
|
132 | 140 | |
|
133 | 141 | views = {} |
|
134 | 142 | for client in clientspec: |
|
135 | if client.startswith("View"): | |
|
143 | if client.startswith(b"View"): | |
|
136 | 144 | sview, cview = clientspec[client].split() |
|
137 | 145 | p4changes.update(self._parse_view(sview)) |
|
138 | if sview.endswith("...") and cview.endswith("..."): | |
|
146 | if sview.endswith(b"...") and cview.endswith(b"..."): | |
|
139 | 147 | sview = sview[:-3] |
|
140 | 148 | cview = cview[:-3] |
|
141 | 149 | cview = cview[2:] |
|
142 | cview = cview[cview.find("/") + 1 :] | |
|
150 | cview = cview[cview.find(b"/") + 1 :] | |
|
143 | 151 | views[sview] = cview |
|
144 | 152 | |
|
145 | 153 | # list of changes that affect our source files |
@@ -151,10 +159,10 b' class p4_source(common.converter_source)' | |||
|
151 | 159 | vieworder.sort(key=len, reverse=True) |
|
152 | 160 | |
|
153 | 161 | # handle revision limiting |
|
154 | startrev = self.ui.config('convert', 'p4.startrev') | |
|
162 | startrev = self.ui.config(b'convert', b'p4.startrev') | |
|
155 | 163 | |
|
156 | 164 | # now read the full changelists to get the list of file revisions |
|
157 | ui.status(_('collecting p4 changelists\n')) | |
|
165 | ui.status(_(b'collecting p4 changelists\n')) | |
|
158 | 166 | lastid = None |
|
159 | 167 | for change in p4changes: |
|
160 | 168 | if startrev and int(change) < int(startrev): |
@@ -176,28 +184,28 b' class p4_source(common.converter_source)' | |||
|
176 | 184 | |
|
177 | 185 | descarr = c.desc.splitlines(True) |
|
178 | 186 | if len(descarr) > 0: |
|
179 | shortdesc = descarr[0].rstrip('\r\n') | |
|
187 | shortdesc = descarr[0].rstrip(b'\r\n') | |
|
180 | 188 | else: |
|
181 | shortdesc = '**empty changelist description**' | |
|
189 | shortdesc = b'**empty changelist description**' | |
|
182 | 190 | |
|
183 | t = '%s %s' % (c.rev, repr(shortdesc)[1:-1]) | |
|
184 | ui.status(stringutil.ellipsis(t, 80) + '\n') | |
|
191 | t = b'%s %s' % (c.rev, repr(shortdesc)[1:-1]) | |
|
192 | ui.status(stringutil.ellipsis(t, 80) + b'\n') | |
|
185 | 193 | |
|
186 | 194 | files = [] |
|
187 | 195 | copies = {} |
|
188 | 196 | copiedfiles = [] |
|
189 | 197 | i = 0 |
|
190 | while ("depotFile%d" % i) in d and ("rev%d" % i) in d: | |
|
191 | oldname = d["depotFile%d" % i] | |
|
198 | while (b"depotFile%d" % i) in d and (b"rev%d" % i) in d: | |
|
199 | oldname = d[b"depotFile%d" % i] | |
|
192 | 200 | filename = None |
|
193 | 201 | for v in vieworder: |
|
194 | 202 | if oldname.lower().startswith(v.lower()): |
|
195 | 203 | filename = decodefilename(views[v] + oldname[len(v) :]) |
|
196 | 204 | break |
|
197 | 205 | if filename: |
|
198 | files.append((filename, d["rev%d" % i])) | |
|
206 | files.append((filename, d[b"rev%d" % i])) | |
|
199 | 207 | depotname[filename] = oldname |
|
200 | if d.get("action%d" % i) == "move/add": | |
|
208 | if d.get(b"action%d" % i) == b"move/add": | |
|
201 | 209 | copiedfiles.append(filename) |
|
202 | 210 | localname[oldname] = filename |
|
203 | 211 | i += 1 |
@@ -206,23 +214,23 b' class p4_source(common.converter_source)' | |||
|
206 | 214 | for filename in copiedfiles: |
|
207 | 215 | oldname = depotname[filename] |
|
208 | 216 | |
|
209 | flcmd = 'p4 -G filelog %s' % procutil.shellquote(oldname) | |
|
210 | flstdout = procutil.popen(flcmd, mode='rb') | |
|
217 | flcmd = b'p4 -G filelog %s' % procutil.shellquote(oldname) | |
|
218 | flstdout = procutil.popen(flcmd, mode=b'rb') | |
|
211 | 219 | |
|
212 | 220 | copiedfilename = None |
|
213 | 221 | for d in loaditer(flstdout): |
|
214 | 222 | copiedoldname = None |
|
215 | 223 | |
|
216 | 224 | i = 0 |
|
217 | while ("change%d" % i) in d: | |
|
225 | while (b"change%d" % i) in d: | |
|
218 | 226 | if ( |
|
219 | d["change%d" % i] == change | |
|
220 | and d["action%d" % i] == "move/add" | |
|
227 | d[b"change%d" % i] == change | |
|
228 | and d[b"action%d" % i] == b"move/add" | |
|
221 | 229 | ): |
|
222 | 230 | j = 0 |
|
223 | while ("file%d,%d" % (i, j)) in d: | |
|
224 | if d["how%d,%d" % (i, j)] == "moved from": | |
|
225 | copiedoldname = d["file%d,%d" % (i, j)] | |
|
231 | while (b"file%d,%d" % (i, j)) in d: | |
|
232 | if d[b"how%d,%d" % (i, j)] == b"moved from": | |
|
233 | copiedoldname = d[b"file%d,%d" % (i, j)] | |
|
226 | 234 | break |
|
227 | 235 | j += 1 |
|
228 | 236 | i += 1 |
@@ -235,7 +243,7 b' class p4_source(common.converter_source)' | |||
|
235 | 243 | copies[filename] = copiedfilename |
|
236 | 244 | else: |
|
237 | 245 | ui.warn( |
|
238 | _("cannot find source for copied file: %s@%s\n") | |
|
246 | _(b"cannot find source for copied file: %s@%s\n") | |
|
239 | 247 | % (filename, change) |
|
240 | 248 | ) |
|
241 | 249 | |
@@ -248,11 +256,11 b' class p4_source(common.converter_source)' | |||
|
248 | 256 | heads = [lastid] |
|
249 | 257 | |
|
250 | 258 | return { |
|
251 | 'changeset': changeset, | |
|
252 | 'files': files_map, | |
|
253 | 'copies': copies_map, | |
|
254 | 'heads': heads, | |
|
255 | 'depotname': depotname, | |
|
259 | b'changeset': changeset, | |
|
260 | b'files': files_map, | |
|
261 | b'copies': copies_map, | |
|
262 | b'heads': heads, | |
|
263 | b'depotname': depotname, | |
|
256 | 264 | } |
|
257 | 265 | |
|
258 | 266 | @util.propertycache |
@@ -261,74 +269,74 b' class p4_source(common.converter_source)' | |||
|
261 | 269 | |
|
262 | 270 | @util.propertycache |
|
263 | 271 | def copies(self): |
|
264 | return self._parse_once['copies'] | |
|
272 | return self._parse_once[b'copies'] | |
|
265 | 273 | |
|
266 | 274 | @util.propertycache |
|
267 | 275 | def files(self): |
|
268 | return self._parse_once['files'] | |
|
276 | return self._parse_once[b'files'] | |
|
269 | 277 | |
|
270 | 278 | @util.propertycache |
|
271 | 279 | def changeset(self): |
|
272 | return self._parse_once['changeset'] | |
|
280 | return self._parse_once[b'changeset'] | |
|
273 | 281 | |
|
274 | 282 | @util.propertycache |
|
275 | 283 | def heads(self): |
|
276 | return self._parse_once['heads'] | |
|
284 | return self._parse_once[b'heads'] | |
|
277 | 285 | |
|
278 | 286 | @util.propertycache |
|
279 | 287 | def depotname(self): |
|
280 | return self._parse_once['depotname'] | |
|
288 | return self._parse_once[b'depotname'] | |
|
281 | 289 | |
|
282 | 290 | def getheads(self): |
|
283 | 291 | return self.heads |
|
284 | 292 | |
|
285 | 293 | def getfile(self, name, rev): |
|
286 | cmd = 'p4 -G print %s' % procutil.shellquote( | |
|
287 | "%s#%s" % (self.depotname[name], rev) | |
|
294 | cmd = b'p4 -G print %s' % procutil.shellquote( | |
|
295 | b"%s#%s" % (self.depotname[name], rev) | |
|
288 | 296 | ) |
|
289 | 297 | |
|
290 | 298 | lasterror = None |
|
291 | 299 | while True: |
|
292 | stdout = procutil.popen(cmd, mode='rb') | |
|
300 | stdout = procutil.popen(cmd, mode=b'rb') | |
|
293 | 301 | |
|
294 | 302 | mode = None |
|
295 | 303 | contents = [] |
|
296 | 304 | keywords = None |
|
297 | 305 | |
|
298 | 306 | for d in loaditer(stdout): |
|
299 | code = d["code"] | |
|
300 | data = d.get("data") | |
|
307 | code = d[b"code"] | |
|
308 | data = d.get(b"data") | |
|
301 | 309 | |
|
302 | if code == "error": | |
|
310 | if code == b"error": | |
|
303 | 311 | # if this is the first time error happened |
|
304 | 312 | # re-attempt getting the file |
|
305 | 313 | if not lasterror: |
|
306 | lasterror = IOError(d["generic"], data) | |
|
314 | lasterror = IOError(d[b"generic"], data) | |
|
307 | 315 | # this will exit inner-most for-loop |
|
308 | 316 | break |
|
309 | 317 | else: |
|
310 | 318 | raise lasterror |
|
311 | 319 | |
|
312 | elif code == "stat": | |
|
313 | action = d.get("action") | |
|
314 | if action in ["purge", "delete", "move/delete"]: | |
|
320 | elif code == b"stat": | |
|
321 | action = d.get(b"action") | |
|
322 | if action in [b"purge", b"delete", b"move/delete"]: | |
|
315 | 323 | return None, None |
|
316 | p4type = self.re_type.match(d["type"]) | |
|
324 | p4type = self.re_type.match(d[b"type"]) | |
|
317 | 325 | if p4type: |
|
318 | mode = "" | |
|
319 | flags = (p4type.group(1) or "") + ( | |
|
320 | p4type.group(3) or "" | |
|
326 | mode = b"" | |
|
327 | flags = (p4type.group(1) or b"") + ( | |
|
328 | p4type.group(3) or b"" | |
|
321 | 329 | ) |
|
322 | if "x" in flags: | |
|
323 | mode = "x" | |
|
324 | if p4type.group(2) == "symlink": | |
|
325 | mode = "l" | |
|
326 | if "ko" in flags: | |
|
330 | if b"x" in flags: | |
|
331 | mode = b"x" | |
|
332 | if p4type.group(2) == b"symlink": | |
|
333 | mode = b"l" | |
|
334 | if b"ko" in flags: | |
|
327 | 335 | keywords = self.re_keywords_old |
|
328 | elif "k" in flags: | |
|
336 | elif b"k" in flags: | |
|
329 | 337 | keywords = self.re_keywords |
|
330 | 338 | |
|
331 | elif code == "text" or code == "binary": | |
|
339 | elif code == b"text" or code == b"binary": | |
|
332 | 340 | contents.append(data) |
|
333 | 341 | |
|
334 | 342 | lasterror = None |
@@ -339,18 +347,18 b' class p4_source(common.converter_source)' | |||
|
339 | 347 | if mode is None: |
|
340 | 348 | return None, None |
|
341 | 349 | |
|
342 | contents = ''.join(contents) | |
|
350 | contents = b''.join(contents) | |
|
343 | 351 | |
|
344 | 352 | if keywords: |
|
345 | contents = keywords.sub("$\\1$", contents) | |
|
346 | if mode == "l" and contents.endswith("\n"): | |
|
353 | contents = keywords.sub(b"$\\1$", contents) | |
|
354 | if mode == b"l" and contents.endswith(b"\n"): | |
|
347 | 355 | contents = contents[:-1] |
|
348 | 356 | |
|
349 | 357 | return contents, mode |
|
350 | 358 | |
|
351 | 359 | def getchanges(self, rev, full): |
|
352 | 360 | if full: |
|
353 | raise error.Abort(_("convert from p4 does not support --full")) | |
|
361 | raise error.Abort(_(b"convert from p4 does not support --full")) | |
|
354 | 362 | return self.files[rev], self.copies[rev], set() |
|
355 | 363 | |
|
356 | 364 | def _construct_commit(self, obj, parents=None): |
@@ -358,26 +366,26 b' class p4_source(common.converter_source)' | |||
|
358 | 366 | Constructs a common.commit object from an unmarshalled |
|
359 | 367 | `p4 describe` output |
|
360 | 368 | """ |
|
361 | desc = self.recode(obj.get("desc", "")) | |
|
362 | date = (int(obj["time"]), 0) # timezone not set | |
|
369 | desc = self.recode(obj.get(b"desc", b"")) | |
|
370 | date = (int(obj[b"time"]), 0) # timezone not set | |
|
363 | 371 | if parents is None: |
|
364 | 372 | parents = [] |
|
365 | 373 | |
|
366 | 374 | return common.commit( |
|
367 | author=self.recode(obj["user"]), | |
|
368 | date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), | |
|
375 | author=self.recode(obj[b"user"]), | |
|
376 | date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'), | |
|
369 | 377 | parents=parents, |
|
370 | 378 | desc=desc, |
|
371 | 379 | branch=None, |
|
372 | rev=obj['change'], | |
|
373 | extra={"p4": obj['change'], "convert_revision": obj['change']}, | |
|
380 | rev=obj[b'change'], | |
|
381 | extra={b"p4": obj[b'change'], b"convert_revision": obj[b'change']}, | |
|
374 | 382 | ) |
|
375 | 383 | |
|
376 | 384 | def _fetch_revision(self, rev): |
|
377 | 385 | """Return an output of `p4 describe` including author, commit date as |
|
378 | 386 | a dictionary.""" |
|
379 | cmd = "p4 -G describe -s %s" % rev | |
|
380 | stdout = procutil.popen(cmd, mode='rb') | |
|
387 | cmd = b"p4 -G describe -s %s" % rev | |
|
388 | stdout = procutil.popen(cmd, mode=b'rb') | |
|
381 | 389 | return marshal.load(stdout) |
|
382 | 390 | |
|
383 | 391 | def getcommit(self, rev): |
@@ -387,7 +395,7 b' class p4_source(common.converter_source)' | |||
|
387 | 395 | d = self._fetch_revision(rev) |
|
388 | 396 | return self._construct_commit(d, parents=None) |
|
389 | 397 | raise error.Abort( |
|
390 | _("cannot find %s in the revmap or parsed changesets") % rev | |
|
398 | _(b"cannot find %s in the revmap or parsed changesets") % rev | |
|
391 | 399 | ) |
|
392 | 400 | |
|
393 | 401 | def gettags(self): |
@@ -54,7 +54,7 b' try:' | |||
|
54 | 54 | import warnings |
|
55 | 55 | |
|
56 | 56 | warnings.filterwarnings( |
|
57 | 'ignore', module='svn.core', category=DeprecationWarning | |
|
57 | b'ignore', module=b'svn.core', category=DeprecationWarning | |
|
58 | 58 | ) |
|
59 | 59 | svn.core.SubversionException # trigger import to catch error |
|
60 | 60 | |
@@ -80,16 +80,16 b' def revsplit(rev):' | |||
|
80 | 80 | >>> revsplit(b'bad') |
|
81 | 81 | ('', '', 0) |
|
82 | 82 | """ |
|
83 | parts = rev.rsplit('@', 1) | |
|
83 | parts = rev.rsplit(b'@', 1) | |
|
84 | 84 | revnum = 0 |
|
85 | 85 | if len(parts) > 1: |
|
86 | 86 | revnum = int(parts[1]) |
|
87 | parts = parts[0].split('/', 1) | |
|
88 | uuid = '' | |
|
89 | mod = '' | |
|
90 | if len(parts) > 1 and parts[0].startswith('svn:'): | |
|
87 | parts = parts[0].split(b'/', 1) | |
|
88 | uuid = b'' | |
|
89 | mod = b'' | |
|
90 | if len(parts) > 1 and parts[0].startswith(b'svn:'): | |
|
91 | 91 | uuid = parts[0][4:] |
|
92 | mod = '/' + parts[1] | |
|
92 | mod = b'/' + parts[1] | |
|
93 | 93 | return uuid, mod, revnum |
|
94 | 94 | |
|
95 | 95 | |
@@ -101,7 +101,7 b' def quote(s):' | |||
|
101 | 101 | # so we can extend it safely with new components. The "safe" |
|
102 | 102 | # characters were taken from the "svn_uri__char_validity" table in |
|
103 | 103 | # libsvn_subr/path.c. |
|
104 | return urlreq.quote(s, "!$&'()*+,-./:=@_~") | |
|
104 | return urlreq.quote(s, b"!$&'()*+,-./:=@_~") | |
|
105 | 105 | |
|
106 | 106 | |
|
107 | 107 | def geturl(path): |
@@ -113,11 +113,11 b' def geturl(path):' | |||
|
113 | 113 | if os.path.isdir(path): |
|
114 | 114 | path = os.path.normpath(os.path.abspath(path)) |
|
115 | 115 | if pycompat.iswindows: |
|
116 | path = '/' + util.normpath(path) | |
|
116 | path = b'/' + util.normpath(path) | |
|
117 | 117 | # Module URL is later compared with the repository URL returned |
|
118 | 118 | # by svn API, which is UTF-8. |
|
119 | 119 | path = encoding.tolocal(path) |
|
120 | path = 'file://%s' % quote(path) | |
|
120 | path = b'file://%s' % quote(path) | |
|
121 | 121 | return svn.core.svn_path_canonicalize(path) |
|
122 | 122 | |
|
123 | 123 | |
@@ -188,7 +188,7 b' def debugsvnlog(ui, **opts):' | |||
|
188 | 188 | """ |
|
189 | 189 | if svn is None: |
|
190 | 190 | raise error.Abort( |
|
191 | _('debugsvnlog could not load Subversion python ' 'bindings') | |
|
191 | _(b'debugsvnlog could not load Subversion python ' b'bindings') | |
|
192 | 192 | ) |
|
193 | 193 | |
|
194 | 194 | args = decodeargs(ui.fin.read()) |
@@ -208,8 +208,8 b' class logstream(object):' | |||
|
208 | 208 | except EOFError: |
|
209 | 209 | raise error.Abort( |
|
210 | 210 | _( |
|
211 | 'Mercurial failed to run itself, check' | |
|
212 | ' hg executable is in PATH' | |
|
211 | b'Mercurial failed to run itself, check' | |
|
212 | b' hg executable is in PATH' | |
|
213 | 213 | ) |
|
214 | 214 | ) |
|
215 | 215 | try: |
@@ -217,7 +217,7 b' class logstream(object):' | |||
|
217 | 217 | except (TypeError, ValueError): |
|
218 | 218 | if entry is None: |
|
219 | 219 | break |
|
220 | raise error.Abort(_("log stream exception '%s'") % entry) | |
|
220 | raise error.Abort(_(b"log stream exception '%s'") % entry) | |
|
221 | 221 | yield entry |
|
222 | 222 | |
|
223 | 223 | def close(self): |
@@ -270,7 +270,7 b' class directlogstream(list):' | |||
|
270 | 270 | # looking for several svn-specific files and directories in the given |
|
271 | 271 | # directory. |
|
272 | 272 | def filecheck(ui, path, proto): |
|
273 | for x in ('locks', 'hooks', 'format', 'db'): | |
|
273 | for x in (b'locks', b'hooks', b'format', b'db'): | |
|
274 | 274 | if not os.path.exists(os.path.join(path, x)): |
|
275 | 275 | return False |
|
276 | 276 | return True |
@@ -282,16 +282,16 b' def filecheck(ui, path, proto):' | |||
|
282 | 282 | def httpcheck(ui, path, proto): |
|
283 | 283 | try: |
|
284 | 284 | opener = urlreq.buildopener() |
|
285 | rsp = opener.open('%s://%s/!svn/ver/0/.svn' % (proto, path), 'rb') | |
|
285 | rsp = opener.open(b'%s://%s/!svn/ver/0/.svn' % (proto, path), b'rb') | |
|
286 | 286 | data = rsp.read() |
|
287 | 287 | except urlerr.httperror as inst: |
|
288 | 288 | if inst.code != 404: |
|
289 | 289 | # Except for 404 we cannot know for sure this is not an svn repo |
|
290 | 290 | ui.warn( |
|
291 | 291 | _( |
|
292 | 'svn: cannot probe remote repository, assume it could ' | |
|
293 | 'be a subversion repository. Use --source-type if you ' | |
|
294 | 'know better.\n' | |
|
292 | b'svn: cannot probe remote repository, assume it could ' | |
|
293 | b'be a subversion repository. Use --source-type if you ' | |
|
294 | b'know better.\n' | |
|
295 | 295 | ) |
|
296 | 296 | ) |
|
297 | 297 | return True |
@@ -299,38 +299,38 b' def httpcheck(ui, path, proto):' | |||
|
299 | 299 | except Exception: |
|
300 | 300 | # Could be urlerr.urlerror if the URL is invalid or anything else. |
|
301 | 301 | return False |
|
302 | return '<m:human-readable errcode="160013">' in data | |
|
302 | return b'<m:human-readable errcode="160013">' in data | |
|
303 | 303 | |
|
304 | 304 | |
|
305 | 305 | protomap = { |
|
306 | 'http': httpcheck, | |
|
307 | 'https': httpcheck, | |
|
308 | 'file': filecheck, | |
|
306 | b'http': httpcheck, | |
|
307 | b'https': httpcheck, | |
|
308 | b'file': filecheck, | |
|
309 | 309 | } |
|
310 | 310 | |
|
311 | 311 | |
|
312 | 312 | def issvnurl(ui, url): |
|
313 | 313 | try: |
|
314 | proto, path = url.split('://', 1) | |
|
315 | if proto == 'file': | |
|
314 | proto, path = url.split(b'://', 1) | |
|
315 | if proto == b'file': | |
|
316 | 316 | if ( |
|
317 | 317 | pycompat.iswindows |
|
318 | and path[:1] == '/' | |
|
318 | and path[:1] == b'/' | |
|
319 | 319 | and path[1:2].isalpha() |
|
320 | and path[2:6].lower() == '%3a/' | |
|
320 | and path[2:6].lower() == b'%3a/' | |
|
321 | 321 | ): |
|
322 | path = path[:2] + ':/' + path[6:] | |
|
322 | path = path[:2] + b':/' + path[6:] | |
|
323 | 323 | path = urlreq.url2pathname(path) |
|
324 | 324 | except ValueError: |
|
325 | proto = 'file' | |
|
325 | proto = b'file' | |
|
326 | 326 | path = os.path.abspath(url) |
|
327 | if proto == 'file': | |
|
327 | if proto == b'file': | |
|
328 | 328 | path = util.pconvert(path) |
|
329 | 329 | check = protomap.get(proto, lambda *args: False) |
|
330 | while '/' in path: | |
|
330 | while b'/' in path: | |
|
331 | 331 | if check(ui, path, proto): |
|
332 | 332 | return True |
|
333 | path = path.rsplit('/', 1)[0] | |
|
333 | path = path.rsplit(b'/', 1)[0] | |
|
334 | 334 | return False |
|
335 | 335 | |
|
336 | 336 | |
@@ -353,35 +353,35 b' class svn_source(converter_source):' | |||
|
353 | 353 | super(svn_source, self).__init__(ui, repotype, url, revs=revs) |
|
354 | 354 | |
|
355 | 355 | if not ( |
|
356 | url.startswith('svn://') | |
|
357 | or url.startswith('svn+ssh://') | |
|
356 | url.startswith(b'svn://') | |
|
357 | or url.startswith(b'svn+ssh://') | |
|
358 | 358 | or ( |
|
359 | 359 | os.path.exists(url) |
|
360 | and os.path.exists(os.path.join(url, '.svn')) | |
|
360 | and os.path.exists(os.path.join(url, b'.svn')) | |
|
361 | 361 | ) |
|
362 | 362 | or issvnurl(ui, url) |
|
363 | 363 | ): |
|
364 | 364 | raise NoRepo( |
|
365 | _("%s does not look like a Subversion repository") % url | |
|
365 | _(b"%s does not look like a Subversion repository") % url | |
|
366 | 366 | ) |
|
367 | 367 | if svn is None: |
|
368 | raise MissingTool(_('could not load Subversion python bindings')) | |
|
368 | raise MissingTool(_(b'could not load Subversion python bindings')) | |
|
369 | 369 | |
|
370 | 370 | try: |
|
371 | 371 | version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR |
|
372 | 372 | if version < (1, 4): |
|
373 | 373 | raise MissingTool( |
|
374 | 374 | _( |
|
375 | 'Subversion python bindings %d.%d found, ' | |
|
376 | '1.4 or later required' | |
|
375 | b'Subversion python bindings %d.%d found, ' | |
|
376 | b'1.4 or later required' | |
|
377 | 377 | ) |
|
378 | 378 | % version |
|
379 | 379 | ) |
|
380 | 380 | except AttributeError: |
|
381 | 381 | raise MissingTool( |
|
382 | 382 | _( |
|
383 | 'Subversion python bindings are too old, 1.4 ' | |
|
384 | 'or later required' | |
|
383 | b'Subversion python bindings are too old, 1.4 ' | |
|
384 | b'or later required' | |
|
385 | 385 | ) |
|
386 | 386 | ) |
|
387 | 387 | |
@@ -391,14 +391,14 b' class svn_source(converter_source):' | |||
|
391 | 391 | try: |
|
392 | 392 | # Support file://path@rev syntax. Useful e.g. to convert |
|
393 | 393 | # deleted branches. |
|
394 | at = url.rfind('@') | |
|
394 | at = url.rfind(b'@') | |
|
395 | 395 | if at >= 0: |
|
396 | 396 | latest = int(url[at + 1 :]) |
|
397 | 397 | url = url[:at] |
|
398 | 398 | except ValueError: |
|
399 | 399 | pass |
|
400 | 400 | self.url = geturl(url) |
|
401 | self.encoding = 'UTF-8' # Subversion is always nominal UTF-8 | |
|
401 | self.encoding = b'UTF-8' # Subversion is always nominal UTF-8 | |
|
402 | 402 | try: |
|
403 | 403 | self.transport = transport.SvnRaTransport(url=self.url) |
|
404 | 404 | self.ra = self.transport.ra |
@@ -414,15 +414,15 b' class svn_source(converter_source):' | |||
|
414 | 414 | self.uuid = svn.ra.get_uuid(self.ra) |
|
415 | 415 | except svn.core.SubversionException: |
|
416 | 416 | ui.traceback() |
|
417 | svnversion = '%d.%d.%d' % ( | |
|
417 | svnversion = b'%d.%d.%d' % ( | |
|
418 | 418 | svn.core.SVN_VER_MAJOR, |
|
419 | 419 | svn.core.SVN_VER_MINOR, |
|
420 | 420 | svn.core.SVN_VER_MICRO, |
|
421 | 421 | ) |
|
422 | 422 | raise NoRepo( |
|
423 | 423 | _( |
|
424 | "%s does not look like a Subversion repository " | |
|
425 | "to libsvn version %s" | |
|
424 | b"%s does not look like a Subversion repository " | |
|
425 | b"to libsvn version %s" | |
|
426 | 426 | ) |
|
427 | 427 | % (self.url, svnversion) |
|
428 | 428 | ) |
@@ -431,29 +431,29 b' class svn_source(converter_source):' | |||
|
431 | 431 | if len(revs) > 1: |
|
432 | 432 | raise error.Abort( |
|
433 | 433 | _( |
|
434 | 'subversion source does not support ' | |
|
435 | 'specifying multiple revisions' | |
|
434 | b'subversion source does not support ' | |
|
435 | b'specifying multiple revisions' | |
|
436 | 436 | ) |
|
437 | 437 | ) |
|
438 | 438 | try: |
|
439 | 439 | latest = int(revs[0]) |
|
440 | 440 | except ValueError: |
|
441 | 441 | raise error.Abort( |
|
442 | _('svn: revision %s is not an integer') % revs[0] | |
|
442 | _(b'svn: revision %s is not an integer') % revs[0] | |
|
443 | 443 | ) |
|
444 | 444 | |
|
445 | trunkcfg = self.ui.config('convert', 'svn.trunk') | |
|
445 | trunkcfg = self.ui.config(b'convert', b'svn.trunk') | |
|
446 | 446 | if trunkcfg is None: |
|
447 | trunkcfg = 'trunk' | |
|
448 | self.trunkname = trunkcfg.strip('/') | |
|
449 | self.startrev = self.ui.config('convert', 'svn.startrev') | |
|
447 | trunkcfg = b'trunk' | |
|
448 | self.trunkname = trunkcfg.strip(b'/') | |
|
449 | self.startrev = self.ui.config(b'convert', b'svn.startrev') | |
|
450 | 450 | try: |
|
451 | 451 | self.startrev = int(self.startrev) |
|
452 | 452 | if self.startrev < 0: |
|
453 | 453 | self.startrev = 0 |
|
454 | 454 | except ValueError: |
|
455 | 455 | raise error.Abort( |
|
456 | _('svn: start revision %s is not an integer') % self.startrev | |
|
456 | _(b'svn: start revision %s is not an integer') % self.startrev | |
|
457 | 457 | ) |
|
458 | 458 | |
|
459 | 459 | try: |
@@ -461,12 +461,14 b' class svn_source(converter_source):' | |||
|
461 | 461 | except SvnPathNotFound: |
|
462 | 462 | self.head = None |
|
463 | 463 | if not self.head: |
|
464 | raise error.Abort(_('no revision found in module %s') % self.module) | |
|
464 | raise error.Abort( | |
|
465 | _(b'no revision found in module %s') % self.module | |
|
466 | ) | |
|
465 | 467 | self.last_changed = self.revnum(self.head) |
|
466 | 468 | |
|
467 | 469 | self._changescache = (None, None) |
|
468 | 470 | |
|
469 | if os.path.exists(os.path.join(url, '.svn/entries')): | |
|
471 | if os.path.exists(os.path.join(url, b'.svn/entries')): | |
|
470 | 472 | self.wc = url |
|
471 | 473 | else: |
|
472 | 474 | self.wc = None |
@@ -484,7 +486,7 b' class svn_source(converter_source):' | |||
|
484 | 486 | def exists(self, path, optrev): |
|
485 | 487 | try: |
|
486 | 488 | svn.client.ls( |
|
487 | self.url.rstrip('/') + '/' + quote(path), | |
|
489 | self.url.rstrip(b'/') + b'/' + quote(path), | |
|
488 | 490 | optrev, |
|
489 | 491 | False, |
|
490 | 492 | self.ctx, |
@@ -499,61 +501,62 b' class svn_source(converter_source):' | |||
|
499 | 501 | return kind == svn.core.svn_node_dir |
|
500 | 502 | |
|
501 | 503 | def getcfgpath(name, rev): |
|
502 | cfgpath = self.ui.config('convert', 'svn.' + name) | |
|
503 | if cfgpath is not None and cfgpath.strip() == '': | |
|
504 | cfgpath = self.ui.config(b'convert', b'svn.' + name) | |
|
505 | if cfgpath is not None and cfgpath.strip() == b'': | |
|
504 | 506 | return None |
|
505 | path = (cfgpath or name).strip('/') | |
|
507 | path = (cfgpath or name).strip(b'/') | |
|
506 | 508 | if not self.exists(path, rev): |
|
507 | if self.module.endswith(path) and name == 'trunk': | |
|
509 | if self.module.endswith(path) and name == b'trunk': | |
|
508 | 510 | # we are converting from inside this directory |
|
509 | 511 | return None |
|
510 | 512 | if cfgpath: |
|
511 | 513 | raise error.Abort( |
|
512 | _('expected %s to be at %r, but not found') | |
|
514 | _(b'expected %s to be at %r, but not found') | |
|
513 | 515 | % (name, path) |
|
514 | 516 | ) |
|
515 | 517 | return None |
|
516 | self.ui.note(_('found %s at %r\n') % (name, path)) | |
|
518 | self.ui.note(_(b'found %s at %r\n') % (name, path)) | |
|
517 | 519 | return path |
|
518 | 520 | |
|
519 | 521 | rev = optrev(self.last_changed) |
|
520 | oldmodule = '' | |
|
521 | trunk = getcfgpath('trunk', rev) | |
|
522 | self.tags = getcfgpath('tags', rev) | |
|
523 | branches = getcfgpath('branches', rev) | |
|
522 | oldmodule = b'' | |
|
523 | trunk = getcfgpath(b'trunk', rev) | |
|
524 | self.tags = getcfgpath(b'tags', rev) | |
|
525 | branches = getcfgpath(b'branches', rev) | |
|
524 | 526 | |
|
525 | 527 | # If the project has a trunk or branches, we will extract heads |
|
526 | 528 | # from them. We keep the project root otherwise. |
|
527 | 529 | if trunk: |
|
528 | oldmodule = self.module or '' | |
|
529 | self.module += '/' + trunk | |
|
530 | oldmodule = self.module or b'' | |
|
531 | self.module += b'/' + trunk | |
|
530 | 532 | self.head = self.latest(self.module, self.last_changed) |
|
531 | 533 | if not self.head: |
|
532 | 534 | raise error.Abort( |
|
533 | _('no revision found in module %s') % self.module | |
|
535 | _(b'no revision found in module %s') % self.module | |
|
534 | 536 | ) |
|
535 | 537 | |
|
536 | 538 | # First head in the list is the module's head |
|
537 | 539 | self.heads = [self.head] |
|
538 | 540 | if self.tags is not None: |
|
539 | self.tags = '%s/%s' % (oldmodule, (self.tags or 'tags')) | |
|
541 | self.tags = b'%s/%s' % (oldmodule, (self.tags or b'tags')) | |
|
540 | 542 | |
|
541 | 543 | # Check if branches bring a few more heads to the list |
|
542 | 544 | if branches: |
|
543 | rpath = self.url.strip('/') | |
|
545 | rpath = self.url.strip(b'/') | |
|
544 | 546 | branchnames = svn.client.ls( |
|
545 | rpath + '/' + quote(branches), rev, False, self.ctx | |
|
547 | rpath + b'/' + quote(branches), rev, False, self.ctx | |
|
546 | 548 | ) |
|
547 | 549 | for branch in sorted(branchnames): |
|
548 | module = '%s/%s/%s' % (oldmodule, branches, branch) | |
|
550 | module = b'%s/%s/%s' % (oldmodule, branches, branch) | |
|
549 | 551 | if not isdir(module, self.last_changed): |
|
550 | 552 | continue |
|
551 | 553 | brevid = self.latest(module, self.last_changed) |
|
552 | 554 | if not brevid: |
|
553 | self.ui.note(_('ignoring empty branch %s\n') % branch) | |
|
555 | self.ui.note(_(b'ignoring empty branch %s\n') % branch) | |
|
554 | 556 | continue |
|
555 | 557 | self.ui.note( |
|
556 |
_('found branch %s at %d\n') |
|
|
558 | _(b'found branch %s at %d\n') | |
|
559 | % (branch, self.revnum(brevid)) | |
|
557 | 560 | ) |
|
558 | 561 | self.heads.append(brevid) |
|
559 | 562 | |
@@ -561,14 +564,14 b' class svn_source(converter_source):' | |||
|
561 | 564 | if len(self.heads) > 1: |
|
562 | 565 | raise error.Abort( |
|
563 | 566 | _( |
|
564 | 'svn: start revision is not supported ' | |
|
565 | 'with more than one branch' | |
|
567 | b'svn: start revision is not supported ' | |
|
568 | b'with more than one branch' | |
|
566 | 569 | ) |
|
567 | 570 | ) |
|
568 | 571 | revnum = self.revnum(self.heads[0]) |
|
569 | 572 | if revnum < self.startrev: |
|
570 | 573 | raise error.Abort( |
|
571 | _('svn: no revision found after start revision %d') | |
|
574 | _(b'svn: no revision found after start revision %d') | |
|
572 | 575 | % self.startrev |
|
573 | 576 | ) |
|
574 | 577 | |
@@ -628,13 +631,13 b' class svn_source(converter_source):' | |||
|
628 | 631 | stop = revnum + 1 |
|
629 | 632 | self._fetch_revisions(revnum, stop) |
|
630 | 633 | if rev not in self.commits: |
|
631 | raise error.Abort(_('svn: revision %s not found') % revnum) | |
|
634 | raise error.Abort(_(b'svn: revision %s not found') % revnum) | |
|
632 | 635 | revcommit = self.commits[rev] |
|
633 | 636 | # caller caches the result, so free it here to release memory |
|
634 | 637 | del self.commits[rev] |
|
635 | 638 | return revcommit |
|
636 | 639 | |
|
637 | def checkrevformat(self, revstr, mapname='splicemap'): | |
|
640 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
|
638 | 641 | """ fails if revision format does not match the correct format""" |
|
639 | 642 | if not re.match( |
|
640 | 643 | r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' |
@@ -643,12 +646,12 b' class svn_source(converter_source):' | |||
|
643 | 646 | revstr, |
|
644 | 647 | ): |
|
645 | 648 | raise error.Abort( |
|
646 | _('%s entry %s is not a valid revision' ' identifier') | |
|
649 | _(b'%s entry %s is not a valid revision' b' identifier') | |
|
647 | 650 | % (mapname, revstr) |
|
648 | 651 | ) |
|
649 | 652 | |
|
650 | 653 | def numcommits(self): |
|
651 | return int(self.head.rsplit('@', 1)[1]) - self.startrev | |
|
654 | return int(self.head.rsplit(b'@', 1)[1]) - self.startrev | |
|
652 | 655 | |
|
653 | 656 | def gettags(self): |
|
654 | 657 | tags = {} |
@@ -689,7 +692,7 b' class svn_source(converter_source):' | |||
|
689 | 692 | srctagspath = copies.pop()[0] |
|
690 | 693 | |
|
691 | 694 | for source, sourcerev, dest in copies: |
|
692 | if not dest.startswith(tagspath + '/'): | |
|
695 | if not dest.startswith(tagspath + b'/'): | |
|
693 | 696 | continue |
|
694 | 697 | for tag in pendings: |
|
695 | 698 | if tag[0].startswith(dest): |
@@ -709,14 +712,14 b' class svn_source(converter_source):' | |||
|
709 | 712 | addeds = dict( |
|
710 | 713 | (p, e.copyfrom_path) |
|
711 | 714 | for p, e in origpaths.iteritems() |
|
712 | if e.action == 'A' and e.copyfrom_path | |
|
715 | if e.action == b'A' and e.copyfrom_path | |
|
713 | 716 | ) |
|
714 | 717 | badroots = set() |
|
715 | 718 | for destroot in addeds: |
|
716 | 719 | for source, sourcerev, dest in pendings: |
|
717 | 720 | if not dest.startswith( |
|
718 | destroot + '/' | |
|
719 | ) or source.startswith(addeds[destroot] + '/'): | |
|
721 | destroot + b'/' | |
|
722 | ) or source.startswith(addeds[destroot] + b'/'): | |
|
720 | 723 | continue |
|
721 | 724 | badroots.add(destroot) |
|
722 | 725 | break |
@@ -726,13 +729,13 b' class svn_source(converter_source):' | |||
|
726 | 729 | p |
|
727 | 730 | for p in pendings |
|
728 | 731 | if p[2] != badroot |
|
729 | and not p[2].startswith(badroot + '/') | |
|
732 | and not p[2].startswith(badroot + b'/') | |
|
730 | 733 | ] |
|
731 | 734 | |
|
732 | 735 | # Tell tag renamings from tag creations |
|
733 | 736 | renamings = [] |
|
734 | 737 | for source, sourcerev, dest in pendings: |
|
735 | tagname = dest.split('/')[-1] | |
|
738 | tagname = dest.split(b'/')[-1] | |
|
736 | 739 | if source.startswith(srctagspath): |
|
737 | 740 | renamings.append([source, sourcerev, tagname]) |
|
738 | 741 | continue |
@@ -761,18 +764,18 b' class svn_source(converter_source):' | |||
|
761 | 764 | return |
|
762 | 765 | if self.convertfp is None: |
|
763 | 766 | self.convertfp = open( |
|
764 | os.path.join(self.wc, '.svn', 'hg-shamap'), 'ab' | |
|
767 | os.path.join(self.wc, b'.svn', b'hg-shamap'), b'ab' | |
|
765 | 768 | ) |
|
766 | 769 | self.convertfp.write( |
|
767 | util.tonativeeol('%s %d\n' % (destrev, self.revnum(rev))) | |
|
770 | util.tonativeeol(b'%s %d\n' % (destrev, self.revnum(rev))) | |
|
768 | 771 | ) |
|
769 | 772 | self.convertfp.flush() |
|
770 | 773 | |
|
771 | 774 | def revid(self, revnum, module=None): |
|
772 | return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum) | |
|
775 | return b'svn:%s%s@%s' % (self.uuid, module or self.module, revnum) | |
|
773 | 776 | |
|
774 | 777 | def revnum(self, rev): |
|
775 | return int(rev.split('@')[-1]) | |
|
778 | return int(rev.split(b'@')[-1]) | |
|
776 | 779 | |
|
777 | 780 | def latest(self, path, stop=None): |
|
778 | 781 | """Find the latest revid affecting path, up to stop revision |
@@ -800,7 +803,7 b' class svn_source(converter_source):' | |||
|
800 | 803 | continue |
|
801 | 804 | newpath = paths[p].copyfrom_path + path[len(p) :] |
|
802 | 805 | self.ui.debug( |
|
803 | "branch renamed from %s to %s at %d\n" | |
|
806 | b"branch renamed from %s to %s at %d\n" | |
|
804 | 807 | % (path, newpath, revnum) |
|
805 | 808 | ) |
|
806 | 809 | path = newpath |
@@ -813,20 +816,20 b' class svn_source(converter_source):' | |||
|
813 | 816 | |
|
814 | 817 | if not path.startswith(self.rootmodule): |
|
815 | 818 | # Requests on foreign branches may be forbidden at server level |
|
816 | self.ui.debug('ignoring foreign branch %r\n' % path) | |
|
819 | self.ui.debug(b'ignoring foreign branch %r\n' % path) | |
|
817 | 820 | return None |
|
818 | 821 | |
|
819 | 822 | if stop is None: |
|
820 | 823 | stop = svn.ra.get_latest_revnum(self.ra) |
|
821 | 824 | try: |
|
822 | prevmodule = self.reparent('') | |
|
823 | dirent = svn.ra.stat(self.ra, path.strip('/'), stop) | |
|
825 | prevmodule = self.reparent(b'') | |
|
826 | dirent = svn.ra.stat(self.ra, path.strip(b'/'), stop) | |
|
824 | 827 | self.reparent(prevmodule) |
|
825 | 828 | except svn.core.SubversionException: |
|
826 | 829 | dirent = None |
|
827 | 830 | if not dirent: |
|
828 | 831 | raise SvnPathNotFound( |
|
829 | _('%s not found up to revision %d') % (path, stop) | |
|
832 | _(b'%s not found up to revision %d') % (path, stop) | |
|
830 | 833 | ) |
|
831 | 834 | |
|
832 | 835 | # stat() gives us the previous revision on this line of |
@@ -843,11 +846,11 b' class svn_source(converter_source):' | |||
|
843 | 846 | # the whole history. |
|
844 | 847 | revnum, realpath = findchanges(path, stop) |
|
845 | 848 | if revnum is None: |
|
846 | self.ui.debug('ignoring empty branch %r\n' % realpath) | |
|
849 | self.ui.debug(b'ignoring empty branch %r\n' % realpath) | |
|
847 | 850 | return None |
|
848 | 851 | |
|
849 | 852 | if not realpath.startswith(self.rootmodule): |
|
850 | self.ui.debug('ignoring foreign branch %r\n' % realpath) | |
|
853 | self.ui.debug(b'ignoring foreign branch %r\n' % realpath) | |
|
851 | 854 | return None |
|
852 | 855 | return self.revid(revnum, realpath) |
|
853 | 856 | |
@@ -858,8 +861,8 b' class svn_source(converter_source):' | |||
|
858 | 861 | svnurl = self.baseurl + quote(module) |
|
859 | 862 | prevmodule = self.prevmodule |
|
860 | 863 | if prevmodule is None: |
|
861 | prevmodule = '' | |
|
862 | self.ui.debug("reparent to %s\n" % svnurl) | |
|
864 | prevmodule = b'' | |
|
865 | self.ui.debug(b"reparent to %s\n" % svnurl) | |
|
863 | 866 | svn.ra.reparent(self.ra, svnurl) |
|
864 | 867 | self.prevmodule = module |
|
865 | 868 | return prevmodule |
@@ -874,7 +877,7 b' class svn_source(converter_source):' | |||
|
874 | 877 | self.reparent(self.module) |
|
875 | 878 | |
|
876 | 879 | progress = self.ui.makeprogress( |
|
877 | _('scanning paths'), unit=_('paths'), total=len(paths) | |
|
880 | _(b'scanning paths'), unit=_(b'paths'), total=len(paths) | |
|
878 | 881 | ) |
|
879 | 882 | for i, (path, ent) in enumerate(paths): |
|
880 | 883 | progress.update(i, item=path) |
@@ -894,37 +897,37 b' class svn_source(converter_source):' | |||
|
894 | 897 | if not copyfrom_path: |
|
895 | 898 | continue |
|
896 | 899 | self.ui.debug( |
|
897 | "copied to %s from %s@%s\n" | |
|
900 | b"copied to %s from %s@%s\n" | |
|
898 | 901 | % (entrypath, copyfrom_path, ent.copyfrom_rev) |
|
899 | 902 | ) |
|
900 | 903 | copies[self.recode(entrypath)] = self.recode(copyfrom_path) |
|
901 | 904 | elif kind == 0: # gone, but had better be a deleted *file* |
|
902 | self.ui.debug("gone from %s\n" % ent.copyfrom_rev) | |
|
905 | self.ui.debug(b"gone from %s\n" % ent.copyfrom_rev) | |
|
903 | 906 | pmodule, prevnum = revsplit(parents[0])[1:] |
|
904 | parentpath = pmodule + "/" + entrypath | |
|
907 | parentpath = pmodule + b"/" + entrypath | |
|
905 | 908 | fromkind = self._checkpath(entrypath, prevnum, pmodule) |
|
906 | 909 | |
|
907 | 910 | if fromkind == svn.core.svn_node_file: |
|
908 | 911 | removed.add(self.recode(entrypath)) |
|
909 | 912 | elif fromkind == svn.core.svn_node_dir: |
|
910 | oroot = parentpath.strip('/') | |
|
911 | nroot = path.strip('/') | |
|
913 | oroot = parentpath.strip(b'/') | |
|
914 | nroot = path.strip(b'/') | |
|
912 | 915 | children = self._iterfiles(oroot, prevnum) |
|
913 | 916 | for childpath in children: |
|
914 | 917 | childpath = childpath.replace(oroot, nroot) |
|
915 | childpath = self.getrelpath("/" + childpath, pmodule) | |
|
918 | childpath = self.getrelpath(b"/" + childpath, pmodule) | |
|
916 | 919 | if childpath: |
|
917 | 920 | removed.add(self.recode(childpath)) |
|
918 | 921 | else: |
|
919 | 922 | self.ui.debug( |
|
920 | 'unknown path in revision %d: %s\n' % (revnum, path) | |
|
923 | b'unknown path in revision %d: %s\n' % (revnum, path) | |
|
921 | 924 | ) |
|
922 | 925 | elif kind == svn.core.svn_node_dir: |
|
923 | if ent.action == 'M': | |
|
926 | if ent.action == b'M': | |
|
924 | 927 | # If the directory just had a prop change, |
|
925 | 928 | # then we shouldn't need to look for its children. |
|
926 | 929 | continue |
|
927 | if ent.action == 'R' and parents: | |
|
930 | if ent.action == b'R' and parents: | |
|
928 | 931 | # If a directory is replacing a file, mark the previous |
|
929 | 932 | # file as deleted |
|
930 | 933 | pmodule, prevnum = revsplit(parents[0])[1:] |
@@ -935,12 +938,12 b' class svn_source(converter_source):' | |||
|
935 | 938 | # We do not know what files were kept or removed, |
|
936 | 939 | # mark them all as changed. |
|
937 | 940 | for childpath in self._iterfiles(pmodule, prevnum): |
|
938 | childpath = self.getrelpath("/" + childpath) | |
|
941 | childpath = self.getrelpath(b"/" + childpath) | |
|
939 | 942 | if childpath: |
|
940 | 943 | changed.add(self.recode(childpath)) |
|
941 | 944 | |
|
942 | 945 | for childpath in self._iterfiles(path, revnum): |
|
943 | childpath = self.getrelpath("/" + childpath) | |
|
946 | childpath = self.getrelpath(b"/" + childpath) | |
|
944 | 947 | if childpath: |
|
945 | 948 | changed.add(self.recode(childpath)) |
|
946 | 949 | |
@@ -956,12 +959,12 b' class svn_source(converter_source):' | |||
|
956 | 959 | if not copyfrompath: |
|
957 | 960 | continue |
|
958 | 961 | self.ui.debug( |
|
959 | "mark %s came from %s:%d\n" | |
|
962 | b"mark %s came from %s:%d\n" | |
|
960 | 963 | % (path, copyfrompath, ent.copyfrom_rev) |
|
961 | 964 | ) |
|
962 | 965 | children = self._iterfiles(ent.copyfrom_path, ent.copyfrom_rev) |
|
963 | 966 | for childpath in children: |
|
964 | childpath = self.getrelpath("/" + childpath, pmodule) | |
|
967 | childpath = self.getrelpath(b"/" + childpath, pmodule) | |
|
965 | 968 | if not childpath: |
|
966 | 969 | continue |
|
967 | 970 | copytopath = path + childpath[len(copyfrompath) :] |
@@ -983,7 +986,8 b' class svn_source(converter_source):' | |||
|
983 | 986 | the revision is a branch root. |
|
984 | 987 | """ |
|
985 | 988 | self.ui.debug( |
|
986 |
"parsing revision %d (%d changes)\n" |
|
|
989 | b"parsing revision %d (%d changes)\n" | |
|
990 | % (revnum, len(orig_paths)) | |
|
987 | 991 | ) |
|
988 | 992 | |
|
989 | 993 | branched = False |
@@ -1012,11 +1016,11 b' class svn_source(converter_source):' | |||
|
1012 | 1016 | if prevnum >= self.startrev: |
|
1013 | 1017 | parents = [previd] |
|
1014 | 1018 | self.ui.note( |
|
1015 | _('found parent of branch %s at %d: %s\n') | |
|
1019 | _(b'found parent of branch %s at %d: %s\n') | |
|
1016 | 1020 | % (self.module, prevnum, prevmodule) |
|
1017 | 1021 | ) |
|
1018 | 1022 | else: |
|
1019 | self.ui.debug("no copyfrom path, don't know what to do.\n") | |
|
1023 | self.ui.debug(b"no copyfrom path, don't know what to do.\n") | |
|
1020 | 1024 | |
|
1021 | 1025 | paths = [] |
|
1022 | 1026 | # filter out unrelated paths |
@@ -1028,22 +1032,24 b' class svn_source(converter_source):' | |||
|
1028 | 1032 | # Example SVN datetime. Includes microseconds. |
|
1029 | 1033 | # ISO-8601 conformant |
|
1030 | 1034 | # '2007-01-04T17:35:00.902377Z' |
|
1031 |
date = dateutil.parsedate( |
|
|
1032 | if self.ui.configbool('convert', 'localtimezone'): | |
|
1035 | date = dateutil.parsedate( | |
|
1036 | date[:19] + b" UTC", [b"%Y-%m-%dT%H:%M:%S"] | |
|
1037 | ) | |
|
1038 | if self.ui.configbool(b'convert', b'localtimezone'): | |
|
1033 | 1039 | date = makedatetimestamp(date[0]) |
|
1034 | 1040 | |
|
1035 | 1041 | if message: |
|
1036 | 1042 | log = self.recode(message) |
|
1037 | 1043 | else: |
|
1038 | log = '' | |
|
1044 | log = b'' | |
|
1039 | 1045 | |
|
1040 | 1046 | if author: |
|
1041 | 1047 | author = self.recode(author) |
|
1042 | 1048 | else: |
|
1043 | author = '' | |
|
1049 | author = b'' | |
|
1044 | 1050 | |
|
1045 | 1051 | try: |
|
1046 | branch = self.module.split("/")[-1] | |
|
1052 | branch = self.module.split(b"/")[-1] | |
|
1047 | 1053 | if branch == self.trunkname: |
|
1048 | 1054 | branch = None |
|
1049 | 1055 | except IndexError: |
@@ -1051,7 +1057,7 b' class svn_source(converter_source):' | |||
|
1051 | 1057 | |
|
1052 | 1058 | cset = commit( |
|
1053 | 1059 | author=author, |
|
1054 | date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), | |
|
1060 | date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'), | |
|
1055 | 1061 | desc=log, |
|
1056 | 1062 | parents=parents, |
|
1057 | 1063 | branch=branch, |
@@ -1068,7 +1074,7 b' class svn_source(converter_source):' | |||
|
1068 | 1074 | return cset, branched |
|
1069 | 1075 | |
|
1070 | 1076 | self.ui.note( |
|
1071 | _('fetching revision log for "%s" from %d to %d\n') | |
|
1077 | _(b'fetching revision log for "%s" from %d to %d\n') | |
|
1072 | 1078 | % (self.module, from_revnum, to_revnum) |
|
1073 | 1079 | ) |
|
1074 | 1080 | |
@@ -1083,7 +1089,7 b' class svn_source(converter_source):' | |||
|
1083 | 1089 | lastonbranch = True |
|
1084 | 1090 | break |
|
1085 | 1091 | if not paths: |
|
1086 | self.ui.debug('revision %d has no entries\n' % revnum) | |
|
1092 | self.ui.debug(b'revision %d has no entries\n' % revnum) | |
|
1087 | 1093 | # If we ever leave the loop on an empty |
|
1088 | 1094 | # revision, do not try to get a parent branch |
|
1089 | 1095 | lastonbranch = lastonbranch or revnum == 0 |
@@ -1114,7 +1120,7 b' class svn_source(converter_source):' | |||
|
1114 | 1120 | (inst, num) = xxx_todo_changeme.args |
|
1115 | 1121 | if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: |
|
1116 | 1122 | raise error.Abort( |
|
1117 | _('svn: branch has no revision %s') % to_revnum | |
|
1123 | _(b'svn: branch has no revision %s') % to_revnum | |
|
1118 | 1124 | ) |
|
1119 | 1125 | raise |
|
1120 | 1126 | |
@@ -1135,8 +1141,8 b' class svn_source(converter_source):' | |||
|
1135 | 1141 | io.close() |
|
1136 | 1142 | if isinstance(info, list): |
|
1137 | 1143 | info = info[-1] |
|
1138 | mode = ("svn:executable" in info) and 'x' or '' | |
|
1139 | mode = ("svn:special" in info) and 'l' or mode | |
|
1144 | mode = (b"svn:executable" in info) and b'x' or b'' | |
|
1145 | mode = (b"svn:special" in info) and b'l' or mode | |
|
1140 | 1146 | except svn.core.SubversionException as e: |
|
1141 | 1147 | notfound = ( |
|
1142 | 1148 | svn.core.SVN_ERR_FS_NOT_FOUND, |
@@ -1145,20 +1151,20 b' class svn_source(converter_source):' | |||
|
1145 | 1151 | if e.apr_err in notfound: # File not found |
|
1146 | 1152 | return None, None |
|
1147 | 1153 | raise |
|
1148 | if mode == 'l': | |
|
1149 | link_prefix = "link " | |
|
1154 | if mode == b'l': | |
|
1155 | link_prefix = b"link " | |
|
1150 | 1156 | if data.startswith(link_prefix): |
|
1151 | 1157 | data = data[len(link_prefix) :] |
|
1152 | 1158 | return data, mode |
|
1153 | 1159 | |
|
1154 | 1160 | def _iterfiles(self, path, revnum): |
|
1155 | 1161 | """Enumerate all files in path at revnum, recursively.""" |
|
1156 | path = path.strip('/') | |
|
1162 | path = path.strip(b'/') | |
|
1157 | 1163 | pool = svn.core.Pool() |
|
1158 | rpath = '/'.join([self.baseurl, quote(path)]).strip('/') | |
|
1164 | rpath = b'/'.join([self.baseurl, quote(path)]).strip(b'/') | |
|
1159 | 1165 | entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool) |
|
1160 | 1166 | if path: |
|
1161 | path += '/' | |
|
1167 | path += b'/' | |
|
1162 | 1168 | return ( |
|
1163 | 1169 | (path + p) |
|
1164 | 1170 | for p, e in entries.iteritems() |
@@ -1175,24 +1181,24 b' class svn_source(converter_source):' | |||
|
1175 | 1181 | # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py" |
|
1176 | 1182 | # that is to say "tests/PloneTestCase.py" |
|
1177 | 1183 | if path.startswith(module): |
|
1178 | relative = path.rstrip('/')[len(module) :] | |
|
1179 | if relative.startswith('/'): | |
|
1184 | relative = path.rstrip(b'/')[len(module) :] | |
|
1185 | if relative.startswith(b'/'): | |
|
1180 | 1186 | return relative[1:] |
|
1181 | elif relative == '': | |
|
1187 | elif relative == b'': | |
|
1182 | 1188 | return relative |
|
1183 | 1189 | |
|
1184 | 1190 | # The path is outside our tracked tree... |
|
1185 | self.ui.debug('%r is not under %r, ignoring\n' % (path, module)) | |
|
1191 | self.ui.debug(b'%r is not under %r, ignoring\n' % (path, module)) | |
|
1186 | 1192 | return None |
|
1187 | 1193 | |
|
1188 | 1194 | def _checkpath(self, path, revnum, module=None): |
|
1189 | 1195 | if module is not None: |
|
1190 | prevmodule = self.reparent('') | |
|
1191 | path = module + '/' + path | |
|
1196 | prevmodule = self.reparent(b'') | |
|
1197 | path = module + b'/' + path | |
|
1192 | 1198 | try: |
|
1193 | 1199 | # ra.check_path does not like leading slashes very much, it leads |
|
1194 | 1200 | # to PROPFIND subversion errors |
|
1195 | return svn.ra.check_path(self.ra, path.strip('/'), revnum) | |
|
1201 | return svn.ra.check_path(self.ra, path.strip(b'/'), revnum) | |
|
1196 | 1202 | finally: |
|
1197 | 1203 | if module is not None: |
|
1198 | 1204 | self.reparent(prevmodule) |
@@ -1210,9 +1216,9 b' class svn_source(converter_source):' | |||
|
1210 | 1216 | # supplied URL |
|
1211 | 1217 | relpaths = [] |
|
1212 | 1218 | for p in paths: |
|
1213 | if not p.startswith('/'): | |
|
1214 | p = self.module + '/' + p | |
|
1215 | relpaths.append(p.strip('/')) | |
|
1219 | if not p.startswith(b'/'): | |
|
1220 | p = self.module + b'/' + p | |
|
1221 | relpaths.append(p.strip(b'/')) | |
|
1216 | 1222 | args = [ |
|
1217 | 1223 | self.baseurl, |
|
1218 | 1224 | relpaths, |
@@ -1223,11 +1229,11 b' class svn_source(converter_source):' | |||
|
1223 | 1229 | strict_node_history, |
|
1224 | 1230 | ] |
|
1225 | 1231 | # developer config: convert.svn.debugsvnlog |
|
1226 | if not self.ui.configbool('convert', 'svn.debugsvnlog'): | |
|
1232 | if not self.ui.configbool(b'convert', b'svn.debugsvnlog'): | |
|
1227 | 1233 | return directlogstream(*args) |
|
1228 | 1234 | arg = encodeargs(args) |
|
1229 | 1235 | hgexe = procutil.hgexecutable() |
|
1230 | cmd = '%s debugsvnlog' % procutil.shellquote(hgexe) | |
|
1236 | cmd = b'%s debugsvnlog' % procutil.shellquote(hgexe) | |
|
1231 | 1237 | stdin, stdout = procutil.popen2(procutil.quotecommand(cmd)) |
|
1232 | 1238 | stdin.write(arg) |
|
1233 | 1239 | try: |
@@ -1235,8 +1241,8 b' class svn_source(converter_source):' | |||
|
1235 | 1241 | except IOError: |
|
1236 | 1242 | raise error.Abort( |
|
1237 | 1243 | _( |
|
1238 | 'Mercurial failed to run itself, check' | |
|
1239 | ' hg executable is in PATH' | |
|
1244 | b'Mercurial failed to run itself, check' | |
|
1245 | b' hg executable is in PATH' | |
|
1240 | 1246 | ) |
|
1241 | 1247 | ) |
|
1242 | 1248 | return logstream(stdout) |
@@ -1272,18 +1278,18 b' class svn_sink(converter_sink, commandli' | |||
|
1272 | 1278 | os.chdir(self.cwd) |
|
1273 | 1279 | |
|
1274 | 1280 | def join(self, name): |
|
1275 | return os.path.join(self.wc, '.svn', name) | |
|
1281 | return os.path.join(self.wc, b'.svn', name) | |
|
1276 | 1282 | |
|
1277 | 1283 | def revmapfile(self): |
|
1278 | return self.join('hg-shamap') | |
|
1284 | return self.join(b'hg-shamap') | |
|
1279 | 1285 | |
|
1280 | 1286 | def authorfile(self): |
|
1281 | return self.join('hg-authormap') | |
|
1287 | return self.join(b'hg-authormap') | |
|
1282 | 1288 | |
|
1283 | 1289 | def __init__(self, ui, repotype, path): |
|
1284 | 1290 | |
|
1285 | 1291 | converter_sink.__init__(self, ui, repotype, path) |
|
1286 | commandline.__init__(self, ui, 'svn') | |
|
1292 | commandline.__init__(self, ui, b'svn') | |
|
1287 | 1293 | self.delete = [] |
|
1288 | 1294 | self.setexec = [] |
|
1289 | 1295 | self.delexec = [] |
@@ -1292,51 +1298,53 b' class svn_sink(converter_sink, commandli' | |||
|
1292 | 1298 | self.cwd = encoding.getcwd() |
|
1293 | 1299 | |
|
1294 | 1300 | created = False |
|
1295 | if os.path.isfile(os.path.join(path, '.svn', 'entries')): | |
|
1301 | if os.path.isfile(os.path.join(path, b'.svn', b'entries')): | |
|
1296 | 1302 | self.wc = os.path.realpath(path) |
|
1297 | self.run0('update') | |
|
1303 | self.run0(b'update') | |
|
1298 | 1304 | else: |
|
1299 | 1305 | if not re.search(br'^(file|http|https|svn|svn\+ssh)\://', path): |
|
1300 | 1306 | path = os.path.realpath(path) |
|
1301 | 1307 | if os.path.isdir(os.path.dirname(path)): |
|
1302 |
if not os.path.exists( |
|
|
1308 | if not os.path.exists( | |
|
1309 | os.path.join(path, b'db', b'fs-type') | |
|
1310 | ): | |
|
1303 | 1311 | ui.status( |
|
1304 | _("initializing svn repository '%s'\n") | |
|
1312 | _(b"initializing svn repository '%s'\n") | |
|
1305 | 1313 | % os.path.basename(path) |
|
1306 | 1314 | ) |
|
1307 | commandline(ui, 'svnadmin').run0('create', path) | |
|
1315 | commandline(ui, b'svnadmin').run0(b'create', path) | |
|
1308 | 1316 | created = path |
|
1309 | 1317 | path = util.normpath(path) |
|
1310 | if not path.startswith('/'): | |
|
1311 | path = '/' + path | |
|
1312 | path = 'file://' + path | |
|
1318 | if not path.startswith(b'/'): | |
|
1319 | path = b'/' + path | |
|
1320 | path = b'file://' + path | |
|
1313 | 1321 | |
|
1314 | 1322 | wcpath = os.path.join( |
|
1315 | encoding.getcwd(), os.path.basename(path) + '-wc' | |
|
1323 | encoding.getcwd(), os.path.basename(path) + b'-wc' | |
|
1316 | 1324 | ) |
|
1317 | 1325 | ui.status( |
|
1318 | _("initializing svn working copy '%s'\n") | |
|
1326 | _(b"initializing svn working copy '%s'\n") | |
|
1319 | 1327 | % os.path.basename(wcpath) |
|
1320 | 1328 | ) |
|
1321 | self.run0('checkout', path, wcpath) | |
|
1329 | self.run0(b'checkout', path, wcpath) | |
|
1322 | 1330 | |
|
1323 | 1331 | self.wc = wcpath |
|
1324 | 1332 | self.opener = vfsmod.vfs(self.wc) |
|
1325 | 1333 | self.wopener = vfsmod.vfs(self.wc) |
|
1326 | self.childmap = mapfile(ui, self.join('hg-childmap')) | |
|
1334 | self.childmap = mapfile(ui, self.join(b'hg-childmap')) | |
|
1327 | 1335 | if util.checkexec(self.wc): |
|
1328 | 1336 | self.is_exec = util.isexec |
|
1329 | 1337 | else: |
|
1330 | 1338 | self.is_exec = None |
|
1331 | 1339 | |
|
1332 | 1340 | if created: |
|
1333 | hook = os.path.join(created, 'hooks', 'pre-revprop-change') | |
|
1334 | fp = open(hook, 'wb') | |
|
1341 | hook = os.path.join(created, b'hooks', b'pre-revprop-change') | |
|
1342 | fp = open(hook, b'wb') | |
|
1335 | 1343 | fp.write(pre_revprop_change) |
|
1336 | 1344 | fp.close() |
|
1337 | 1345 | util.setflags(hook, False, True) |
|
1338 | 1346 | |
|
1339 | output = self.run0('info') | |
|
1347 | output = self.run0(b'info') | |
|
1340 | 1348 | self.uuid = self.uuid_re.search(output).group(1).strip() |
|
1341 | 1349 | |
|
1342 | 1350 | def wjoin(self, *names): |
@@ -1348,7 +1356,7 b' class svn_sink(converter_sink, commandli' | |||
|
1348 | 1356 | # already tracked entries, so we have to track and filter them |
|
1349 | 1357 | # ourselves. |
|
1350 | 1358 | m = set() |
|
1351 | output = self.run0('ls', recursive=True, xml=True) | |
|
1359 | output = self.run0(b'ls', recursive=True, xml=True) | |
|
1352 | 1360 | doc = xml.dom.minidom.parseString(output) |
|
1353 | 1361 | for e in doc.getElementsByTagName(r'entry'): |
|
1354 | 1362 | for n in e.childNodes: |
@@ -1367,7 +1375,7 b' class svn_sink(converter_sink, commandli' | |||
|
1367 | 1375 | return m |
|
1368 | 1376 | |
|
1369 | 1377 | def putfile(self, filename, flags, data): |
|
1370 | if 'l' in flags: | |
|
1378 | if b'l' in flags: | |
|
1371 | 1379 | self.wopener.symlink(data, filename) |
|
1372 | 1380 | else: |
|
1373 | 1381 | try: |
@@ -1387,12 +1395,12 b' class svn_sink(converter_sink, commandli' | |||
|
1387 | 1395 | |
|
1388 | 1396 | if self.is_exec: |
|
1389 | 1397 | if wasexec: |
|
1390 | if 'x' not in flags: | |
|
1398 | if b'x' not in flags: | |
|
1391 | 1399 | self.delexec.append(filename) |
|
1392 | 1400 | else: |
|
1393 | if 'x' in flags: | |
|
1401 | if b'x' in flags: | |
|
1394 | 1402 | self.setexec.append(filename) |
|
1395 | util.setflags(self.wjoin(filename), False, 'x' in flags) | |
|
1403 | util.setflags(self.wjoin(filename), False, b'x' in flags) | |
|
1396 | 1404 | |
|
1397 | 1405 | def _copyfile(self, source, dest): |
|
1398 | 1406 | # SVN's copy command pukes if the destination file exists, but |
@@ -1402,13 +1410,13 b' class svn_sink(converter_sink, commandli' | |||
|
1402 | 1410 | exists = os.path.lexists(wdest) |
|
1403 | 1411 | if exists: |
|
1404 | 1412 | fd, tempname = pycompat.mkstemp( |
|
1405 | prefix='hg-copy-', dir=os.path.dirname(wdest) | |
|
1413 | prefix=b'hg-copy-', dir=os.path.dirname(wdest) | |
|
1406 | 1414 | ) |
|
1407 | 1415 | os.close(fd) |
|
1408 | 1416 | os.unlink(tempname) |
|
1409 | 1417 | os.rename(wdest, tempname) |
|
1410 | 1418 | try: |
|
1411 | self.run0('copy', source, dest) | |
|
1419 | self.run0(b'copy', source, dest) | |
|
1412 | 1420 | finally: |
|
1413 | 1421 | self.manifest.add(dest) |
|
1414 | 1422 | if exists: |
@@ -1424,7 +1432,7 b' class svn_sink(converter_sink, commandli' | |||
|
1424 | 1432 | if os.path.isdir(self.wjoin(f)): |
|
1425 | 1433 | dirs.add(f) |
|
1426 | 1434 | i = len(f) |
|
1427 | for i in iter(lambda: f.rfind('/', 0, i), -1): | |
|
1435 | for i in iter(lambda: f.rfind(b'/', 0, i), -1): | |
|
1428 | 1436 | dirs.add(f[:i]) |
|
1429 | 1437 | return dirs |
|
1430 | 1438 | |
@@ -1434,21 +1442,21 b' class svn_sink(converter_sink, commandli' | |||
|
1434 | 1442 | ] |
|
1435 | 1443 | if add_dirs: |
|
1436 | 1444 | self.manifest.update(add_dirs) |
|
1437 | self.xargs(add_dirs, 'add', non_recursive=True, quiet=True) | |
|
1445 | self.xargs(add_dirs, b'add', non_recursive=True, quiet=True) | |
|
1438 | 1446 | return add_dirs |
|
1439 | 1447 | |
|
1440 | 1448 | def add_files(self, files): |
|
1441 | 1449 | files = [f for f in files if f not in self.manifest] |
|
1442 | 1450 | if files: |
|
1443 | 1451 | self.manifest.update(files) |
|
1444 | self.xargs(files, 'add', quiet=True) | |
|
1452 | self.xargs(files, b'add', quiet=True) | |
|
1445 | 1453 | return files |
|
1446 | 1454 | |
|
1447 | 1455 | def addchild(self, parent, child): |
|
1448 | 1456 | self.childmap[parent] = child |
|
1449 | 1457 | |
|
1450 | 1458 | def revid(self, rev): |
|
1451 | return "svn:%s@%s" % (self.uuid, rev) | |
|
1459 | return b"svn:%s@%s" % (self.uuid, rev) | |
|
1452 | 1460 | |
|
1453 | 1461 | def putcommit( |
|
1454 | 1462 | self, files, copies, parents, commit, source, revmap, full, cleanp2 |
@@ -1480,49 +1488,49 b' class svn_sink(converter_sink, commandli' | |||
|
1480 | 1488 | self._copyfile(s, d) |
|
1481 | 1489 | self.copies = [] |
|
1482 | 1490 | if self.delete: |
|
1483 | self.xargs(self.delete, 'delete') | |
|
1491 | self.xargs(self.delete, b'delete') | |
|
1484 | 1492 | for f in self.delete: |
|
1485 | 1493 | self.manifest.remove(f) |
|
1486 | 1494 | self.delete = [] |
|
1487 | 1495 | entries.update(self.add_files(files.difference(entries))) |
|
1488 | 1496 | if self.delexec: |
|
1489 | self.xargs(self.delexec, 'propdel', 'svn:executable') | |
|
1497 | self.xargs(self.delexec, b'propdel', b'svn:executable') | |
|
1490 | 1498 | self.delexec = [] |
|
1491 | 1499 | if self.setexec: |
|
1492 | self.xargs(self.setexec, 'propset', 'svn:executable', '*') | |
|
1500 | self.xargs(self.setexec, b'propset', b'svn:executable', b'*') | |
|
1493 | 1501 | self.setexec = [] |
|
1494 | 1502 | |
|
1495 | fd, messagefile = pycompat.mkstemp(prefix='hg-convert-') | |
|
1503 | fd, messagefile = pycompat.mkstemp(prefix=b'hg-convert-') | |
|
1496 | 1504 | fp = os.fdopen(fd, r'wb') |
|
1497 | 1505 | fp.write(util.tonativeeol(commit.desc)) |
|
1498 | 1506 | fp.close() |
|
1499 | 1507 | try: |
|
1500 | 1508 | output = self.run0( |
|
1501 | 'commit', | |
|
1509 | b'commit', | |
|
1502 | 1510 | username=stringutil.shortuser(commit.author), |
|
1503 | 1511 | file=messagefile, |
|
1504 | encoding='utf-8', | |
|
1512 | encoding=b'utf-8', | |
|
1505 | 1513 | ) |
|
1506 | 1514 | try: |
|
1507 | 1515 | rev = self.commit_re.search(output).group(1) |
|
1508 | 1516 | except AttributeError: |
|
1509 | 1517 | if not files: |
|
1510 | return parents[0] if parents else 'None' | |
|
1511 | self.ui.warn(_('unexpected svn output:\n')) | |
|
1518 | return parents[0] if parents else b'None' | |
|
1519 | self.ui.warn(_(b'unexpected svn output:\n')) | |
|
1512 | 1520 | self.ui.warn(output) |
|
1513 | raise error.Abort(_('unable to cope with svn output')) | |
|
1521 | raise error.Abort(_(b'unable to cope with svn output')) | |
|
1514 | 1522 | if commit.rev: |
|
1515 | 1523 | self.run( |
|
1516 | 'propset', | |
|
1517 | 'hg:convert-rev', | |
|
1524 | b'propset', | |
|
1525 | b'hg:convert-rev', | |
|
1518 | 1526 | commit.rev, |
|
1519 | 1527 | revprop=True, |
|
1520 | 1528 | revision=rev, |
|
1521 | 1529 | ) |
|
1522 | if commit.branch and commit.branch != 'default': | |
|
1530 | if commit.branch and commit.branch != b'default': | |
|
1523 | 1531 | self.run( |
|
1524 | 'propset', | |
|
1525 | 'hg:convert-branch', | |
|
1532 | b'propset', | |
|
1533 | b'hg:convert-branch', | |
|
1526 | 1534 | commit.branch, |
|
1527 | 1535 | revprop=True, |
|
1528 | 1536 | revision=rev, |
@@ -1534,7 +1542,7 b' class svn_sink(converter_sink, commandli' | |||
|
1534 | 1542 | os.unlink(messagefile) |
|
1535 | 1543 | |
|
1536 | 1544 | def puttags(self, tags): |
|
1537 | self.ui.warn(_('writing Subversion tags is not yet implemented\n')) | |
|
1545 | self.ui.warn(_(b'writing Subversion tags is not yet implemented\n')) | |
|
1538 | 1546 | return None, None |
|
1539 | 1547 | |
|
1540 | 1548 | def hascommitfrommap(self, rev): |
@@ -1549,8 +1557,8 b' class svn_sink(converter_sink, commandli' | |||
|
1549 | 1557 | return True |
|
1550 | 1558 | raise error.Abort( |
|
1551 | 1559 | _( |
|
1552 | 'splice map revision %s not found in subversion ' | |
|
1553 | 'child map (revision lookups are not implemented)' | |
|
1560 | b'splice map revision %s not found in subversion ' | |
|
1561 | b'child map (revision lookups are not implemented)' | |
|
1554 | 1562 | ) |
|
1555 | 1563 | % rev |
|
1556 | 1564 | ) |
@@ -54,13 +54,13 b' def _create_auth_baton(pool):' | |||
|
54 | 54 | ) |
|
55 | 55 | if getprovider: |
|
56 | 56 | # Available in svn >= 1.6 |
|
57 | for name in ('gnome_keyring', 'keychain', 'kwallet', 'windows'): | |
|
58 | for type in ('simple', 'ssl_client_cert_pw', 'ssl_server_trust'): | |
|
57 | for name in (b'gnome_keyring', b'keychain', b'kwallet', b'windows'): | |
|
58 | for type in (b'simple', b'ssl_client_cert_pw', b'ssl_server_trust'): | |
|
59 | 59 | p = getprovider(name, type, pool) |
|
60 | 60 | if p: |
|
61 | 61 | providers.append(p) |
|
62 | 62 | else: |
|
63 | if util.safehasattr(svn.client, 'get_windows_simple_provider'): | |
|
63 | if util.safehasattr(svn.client, b'get_windows_simple_provider'): | |
|
64 | 64 | providers.append(svn.client.get_windows_simple_provider(pool)) |
|
65 | 65 | |
|
66 | 66 | return svn.core.svn_auth_open(providers, pool) |
@@ -75,14 +75,14 b' class SvnRaTransport(object):' | |||
|
75 | 75 | Open an ra connection to a Subversion repository. |
|
76 | 76 | """ |
|
77 | 77 | |
|
78 | def __init__(self, url="", ra=None): | |
|
78 | def __init__(self, url=b"", ra=None): | |
|
79 | 79 | self.pool = Pool() |
|
80 | 80 | self.svn_url = url |
|
81 | self.username = '' | |
|
82 | self.password = '' | |
|
81 | self.username = b'' | |
|
82 | self.password = b'' | |
|
83 | 83 | |
|
84 | 84 | # Only Subversion 1.4 has reparent() |
|
85 | if ra is None or not util.safehasattr(svn.ra, 'reparent'): | |
|
85 | if ra is None or not util.safehasattr(svn.ra, b'reparent'): | |
|
86 | 86 | self.client = svn.client.create_context(self.pool) |
|
87 | 87 | ab = _create_auth_baton(self.pool) |
|
88 | 88 | self.client.auth_baton = ab |
@@ -112,41 +112,41 b' from mercurial.utils import stringutil' | |||
|
112 | 112 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
113 | 113 | # be specifying the version(s) of Mercurial they are tested with, or |
|
114 | 114 | # leave the attribute unspecified. |
|
115 | testedwith = 'ships-with-hg-core' | |
|
115 | testedwith = b'ships-with-hg-core' | |
|
116 | 116 | |
|
117 | 117 | configtable = {} |
|
118 | 118 | configitem = registrar.configitem(configtable) |
|
119 | 119 | |
|
120 | 120 | configitem( |
|
121 | 'eol', 'fix-trailing-newline', default=False, | |
|
121 | b'eol', b'fix-trailing-newline', default=False, | |
|
122 | 122 | ) |
|
123 | 123 | configitem( |
|
124 | 'eol', 'native', default=pycompat.oslinesep, | |
|
124 | b'eol', b'native', default=pycompat.oslinesep, | |
|
125 | 125 | ) |
|
126 | 126 | configitem( |
|
127 | 'eol', 'only-consistent', default=True, | |
|
127 | b'eol', b'only-consistent', default=True, | |
|
128 | 128 | ) |
|
129 | 129 | |
|
130 | 130 | # Matches a lone LF, i.e., one that is not part of CRLF. |
|
131 | singlelf = re.compile('(^|[^\r])\n') | |
|
131 | singlelf = re.compile(b'(^|[^\r])\n') | |
|
132 | 132 | |
|
133 | 133 | |
|
134 | 134 | def inconsistenteol(data): |
|
135 | return '\r\n' in data and singlelf.search(data) | |
|
135 | return b'\r\n' in data and singlelf.search(data) | |
|
136 | 136 | |
|
137 | 137 | |
|
138 | 138 | def tolf(s, params, ui, **kwargs): |
|
139 | 139 | """Filter to convert to LF EOLs.""" |
|
140 | 140 | if stringutil.binary(s): |
|
141 | 141 | return s |
|
142 | if ui.configbool('eol', 'only-consistent') and inconsistenteol(s): | |
|
142 | if ui.configbool(b'eol', b'only-consistent') and inconsistenteol(s): | |
|
143 | 143 | return s |
|
144 | 144 | if ( |
|
145 | ui.configbool('eol', 'fix-trailing-newline') | |
|
145 | ui.configbool(b'eol', b'fix-trailing-newline') | |
|
146 | 146 | and s |
|
147 | and not s.endswith('\n') | |
|
147 | and not s.endswith(b'\n') | |
|
148 | 148 | ): |
|
149 | s = s + '\n' | |
|
149 | s = s + b'\n' | |
|
150 | 150 | return util.tolf(s) |
|
151 | 151 | |
|
152 | 152 | |
@@ -154,14 +154,14 b' def tocrlf(s, params, ui, **kwargs):' | |||
|
154 | 154 | """Filter to convert to CRLF EOLs.""" |
|
155 | 155 | if stringutil.binary(s): |
|
156 | 156 | return s |
|
157 | if ui.configbool('eol', 'only-consistent') and inconsistenteol(s): | |
|
157 | if ui.configbool(b'eol', b'only-consistent') and inconsistenteol(s): | |
|
158 | 158 | return s |
|
159 | 159 | if ( |
|
160 | ui.configbool('eol', 'fix-trailing-newline') | |
|
160 | ui.configbool(b'eol', b'fix-trailing-newline') | |
|
161 | 161 | and s |
|
162 | and not s.endswith('\n') | |
|
162 | and not s.endswith(b'\n') | |
|
163 | 163 | ): |
|
164 | s = s + '\n' | |
|
164 | s = s + b'\n' | |
|
165 | 165 | return util.tocrlf(s) |
|
166 | 166 | |
|
167 | 167 | |
@@ -171,60 +171,68 b' def isbinary(s, params):' | |||
|
171 | 171 | |
|
172 | 172 | |
|
173 | 173 | filters = { |
|
174 | 'to-lf': tolf, | |
|
175 | 'to-crlf': tocrlf, | |
|
176 | 'is-binary': isbinary, | |
|
174 | b'to-lf': tolf, | |
|
175 | b'to-crlf': tocrlf, | |
|
176 | b'is-binary': isbinary, | |
|
177 | 177 | # The following provide backwards compatibility with win32text |
|
178 | 'cleverencode:': tolf, | |
|
179 | 'cleverdecode:': tocrlf, | |
|
178 | b'cleverencode:': tolf, | |
|
179 | b'cleverdecode:': tocrlf, | |
|
180 | 180 | } |
|
181 | 181 | |
|
182 | 182 | |
|
183 | 183 | class eolfile(object): |
|
184 | 184 | def __init__(self, ui, root, data): |
|
185 | self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} | |
|
186 | self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} | |
|
185 | self._decode = { | |
|
186 | b'LF': b'to-lf', | |
|
187 | b'CRLF': b'to-crlf', | |
|
188 | b'BIN': b'is-binary', | |
|
189 | } | |
|
190 | self._encode = { | |
|
191 | b'LF': b'to-lf', | |
|
192 | b'CRLF': b'to-crlf', | |
|
193 | b'BIN': b'is-binary', | |
|
194 | } | |
|
187 | 195 | |
|
188 | 196 | self.cfg = config.config() |
|
189 | 197 | # Our files should not be touched. The pattern must be |
|
190 | 198 | # inserted first override a '** = native' pattern. |
|
191 | self.cfg.set('patterns', '.hg*', 'BIN', 'eol') | |
|
199 | self.cfg.set(b'patterns', b'.hg*', b'BIN', b'eol') | |
|
192 | 200 | # We can then parse the user's patterns. |
|
193 | self.cfg.parse('.hgeol', data) | |
|
201 | self.cfg.parse(b'.hgeol', data) | |
|
194 | 202 | |
|
195 | isrepolf = self.cfg.get('repository', 'native') != 'CRLF' | |
|
196 | self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf' | |
|
197 | iswdlf = ui.config('eol', 'native') in ('LF', '\n') | |
|
198 | self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf' | |
|
203 | isrepolf = self.cfg.get(b'repository', b'native') != b'CRLF' | |
|
204 | self._encode[b'NATIVE'] = isrepolf and b'to-lf' or b'to-crlf' | |
|
205 | iswdlf = ui.config(b'eol', b'native') in (b'LF', b'\n') | |
|
206 | self._decode[b'NATIVE'] = iswdlf and b'to-lf' or b'to-crlf' | |
|
199 | 207 | |
|
200 | 208 | include = [] |
|
201 | 209 | exclude = [] |
|
202 | 210 | self.patterns = [] |
|
203 | for pattern, style in self.cfg.items('patterns'): | |
|
211 | for pattern, style in self.cfg.items(b'patterns'): | |
|
204 | 212 | key = style.upper() |
|
205 | if key == 'BIN': | |
|
213 | if key == b'BIN': | |
|
206 | 214 | exclude.append(pattern) |
|
207 | 215 | else: |
|
208 | 216 | include.append(pattern) |
|
209 | m = match.match(root, '', [pattern]) | |
|
217 | m = match.match(root, b'', [pattern]) | |
|
210 | 218 | self.patterns.append((pattern, key, m)) |
|
211 | 219 | # This will match the files for which we need to care |
|
212 | 220 | # about inconsistent newlines. |
|
213 | self.match = match.match(root, '', [], include, exclude) | |
|
221 | self.match = match.match(root, b'', [], include, exclude) | |
|
214 | 222 | |
|
215 | 223 | def copytoui(self, ui): |
|
216 | 224 | for pattern, key, m in self.patterns: |
|
217 | 225 | try: |
|
218 | ui.setconfig('decode', pattern, self._decode[key], 'eol') | |
|
219 | ui.setconfig('encode', pattern, self._encode[key], 'eol') | |
|
226 | ui.setconfig(b'decode', pattern, self._decode[key], b'eol') | |
|
227 | ui.setconfig(b'encode', pattern, self._encode[key], b'eol') | |
|
220 | 228 | except KeyError: |
|
221 | 229 | ui.warn( |
|
222 | _("ignoring unknown EOL style '%s' from %s\n") | |
|
223 | % (key, self.cfg.source('patterns', pattern)) | |
|
230 | _(b"ignoring unknown EOL style '%s' from %s\n") | |
|
231 | % (key, self.cfg.source(b'patterns', pattern)) | |
|
224 | 232 | ) |
|
225 | 233 | # eol.only-consistent can be specified in ~/.hgrc or .hgeol |
|
226 | for k, v in self.cfg.items('eol'): | |
|
227 | ui.setconfig('eol', k, v, 'eol') | |
|
234 | for k, v in self.cfg.items(b'eol'): | |
|
235 | ui.setconfig(b'eol', k, v, b'eol') | |
|
228 | 236 | |
|
229 | 237 | def checkrev(self, repo, ctx, files): |
|
230 | 238 | failed = [] |
@@ -237,9 +245,9 b' class eolfile(object):' | |||
|
237 | 245 | target = self._encode[key] |
|
238 | 246 | data = ctx[f].data() |
|
239 | 247 | if ( |
|
240 | target == "to-lf" | |
|
241 | and "\r\n" in data | |
|
242 | or target == "to-crlf" | |
|
248 | target == b"to-lf" | |
|
249 | and b"\r\n" in data | |
|
250 | or target == b"to-crlf" | |
|
243 | 251 | and singlelf.search(data) |
|
244 | 252 | ): |
|
245 | 253 | failed.append((f, target, bytes(ctx))) |
@@ -254,15 +262,18 b' def parseeol(ui, repo, nodes):' | |||
|
254 | 262 | if node is None: |
|
255 | 263 | # Cannot use workingctx.data() since it would load |
|
256 | 264 | # and cache the filters before we configure them. |
|
257 | data = repo.wvfs('.hgeol').read() | |
|
265 | data = repo.wvfs(b'.hgeol').read() | |
|
258 | 266 | else: |
|
259 | data = repo[node]['.hgeol'].data() | |
|
267 | data = repo[node][b'.hgeol'].data() | |
|
260 | 268 | return eolfile(ui, repo.root, data) |
|
261 | 269 | except (IOError, LookupError): |
|
262 | 270 | pass |
|
263 | 271 | except errormod.ParseError as inst: |
|
264 | 272 | ui.warn( |
|
265 | _("warning: ignoring .hgeol file due to parse error " "at %s: %s\n") | |
|
273 | _( | |
|
274 | b"warning: ignoring .hgeol file due to parse error " | |
|
275 | b"at %s: %s\n" | |
|
276 | ) | |
|
266 | 277 | % (inst.args[1], inst.args[0]) |
|
267 | 278 | ) |
|
268 | 279 | return None |
@@ -276,10 +287,10 b' def ensureenabled(ui):' | |||
|
276 | 287 | never loaded. This function ensure the extension is enabled when running |
|
277 | 288 | hooks. |
|
278 | 289 | """ |
|
279 | if 'eol' in ui._knownconfig: | |
|
290 | if b'eol' in ui._knownconfig: | |
|
280 | 291 | return |
|
281 | ui.setconfig('extensions', 'eol', '', source='internal') | |
|
282 | extensions.loadall(ui, ['eol']) | |
|
292 | ui.setconfig(b'extensions', b'eol', b'', source=b'internal') | |
|
293 | extensions.loadall(ui, [b'eol']) | |
|
283 | 294 | |
|
284 | 295 | |
|
285 | 296 | def _checkhook(ui, repo, node, headsonly): |
@@ -302,14 +313,16 b' def _checkhook(ui, repo, node, headsonly' | |||
|
302 | 313 | failed.extend(eol.checkrev(repo, ctx, files)) |
|
303 | 314 | |
|
304 | 315 | if failed: |
|
305 | eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'} | |
|
316 | eols = {b'to-lf': b'CRLF', b'to-crlf': b'LF'} | |
|
306 | 317 | msgs = [] |
|
307 | 318 | for f, target, node in sorted(failed): |
|
308 | 319 | msgs.append( |
|
309 | _(" %s in %s should not have %s line endings") | |
|
320 | _(b" %s in %s should not have %s line endings") | |
|
310 | 321 | % (f, node, eols[target]) |
|
311 | 322 | ) |
|
312 | raise errormod.Abort(_("end-of-line check failed:\n") + "\n".join(msgs)) | |
|
323 | raise errormod.Abort( | |
|
324 | _(b"end-of-line check failed:\n") + b"\n".join(msgs) | |
|
325 | ) | |
|
313 | 326 | |
|
314 | 327 | |
|
315 | 328 | def checkallhook(ui, repo, node, hooktype, **kwargs): |
@@ -333,16 +346,16 b' def preupdate(ui, repo, hooktype, parent' | |||
|
333 | 346 | |
|
334 | 347 | |
|
335 | 348 | def uisetup(ui): |
|
336 | ui.setconfig('hooks', 'preupdate.eol', preupdate, 'eol') | |
|
349 | ui.setconfig(b'hooks', b'preupdate.eol', preupdate, b'eol') | |
|
337 | 350 | |
|
338 | 351 | |
|
339 | 352 | def extsetup(ui): |
|
340 | 353 | try: |
|
341 | extensions.find('win32text') | |
|
354 | extensions.find(b'win32text') | |
|
342 | 355 | ui.warn( |
|
343 | 356 | _( |
|
344 | "the eol extension is incompatible with the " | |
|
345 | "win32text extension\n" | |
|
357 | b"the eol extension is incompatible with the " | |
|
358 | b"win32text extension\n" | |
|
346 | 359 | ) |
|
347 | 360 | ) |
|
348 | 361 | except KeyError: |
@@ -357,7 +370,7 b' def reposetup(ui, repo):' | |||
|
357 | 370 | for name, fn in filters.iteritems(): |
|
358 | 371 | repo.adddatafilter(name, fn) |
|
359 | 372 | |
|
360 | ui.setconfig('patch', 'eol', 'auto', 'eol') | |
|
373 | ui.setconfig(b'patch', b'eol', b'auto', b'eol') | |
|
361 | 374 | |
|
362 | 375 | class eolrepo(repo.__class__): |
|
363 | 376 | def loadeol(self, nodes): |
@@ -368,37 +381,37 b' def reposetup(ui, repo):' | |||
|
368 | 381 | return eol.match |
|
369 | 382 | |
|
370 | 383 | def _hgcleardirstate(self): |
|
371 | self._eolmatch = self.loadeol([None, 'tip']) | |
|
384 | self._eolmatch = self.loadeol([None, b'tip']) | |
|
372 | 385 | if not self._eolmatch: |
|
373 | 386 | self._eolmatch = util.never |
|
374 | 387 | return |
|
375 | 388 | |
|
376 | 389 | oldeol = None |
|
377 | 390 | try: |
|
378 | cachemtime = os.path.getmtime(self.vfs.join("eol.cache")) | |
|
391 | cachemtime = os.path.getmtime(self.vfs.join(b"eol.cache")) | |
|
379 | 392 | except OSError: |
|
380 | 393 | cachemtime = 0 |
|
381 | 394 | else: |
|
382 | olddata = self.vfs.read("eol.cache") | |
|
395 | olddata = self.vfs.read(b"eol.cache") | |
|
383 | 396 | if olddata: |
|
384 | 397 | oldeol = eolfile(self.ui, self.root, olddata) |
|
385 | 398 | |
|
386 | 399 | try: |
|
387 | eolmtime = os.path.getmtime(self.wjoin(".hgeol")) | |
|
400 | eolmtime = os.path.getmtime(self.wjoin(b".hgeol")) | |
|
388 | 401 | except OSError: |
|
389 | 402 | eolmtime = 0 |
|
390 | 403 | |
|
391 | 404 | if eolmtime > cachemtime: |
|
392 | self.ui.debug("eol: detected change in .hgeol\n") | |
|
405 | self.ui.debug(b"eol: detected change in .hgeol\n") | |
|
393 | 406 | |
|
394 | hgeoldata = self.wvfs.read('.hgeol') | |
|
407 | hgeoldata = self.wvfs.read(b'.hgeol') | |
|
395 | 408 | neweol = eolfile(self.ui, self.root, hgeoldata) |
|
396 | 409 | |
|
397 | 410 | wlock = None |
|
398 | 411 | try: |
|
399 | 412 | wlock = self.wlock() |
|
400 | 413 | for f in self.dirstate: |
|
401 | if self.dirstate[f] != 'n': | |
|
414 | if self.dirstate[f] != b'n': | |
|
402 | 415 | continue |
|
403 | 416 | if oldeol is not None: |
|
404 | 417 | if not oldeol.match(f) and not neweol.match(f): |
@@ -419,7 +432,7 b' def reposetup(ui, repo):' | |||
|
419 | 432 | # the new .hgeol file specify a different filter |
|
420 | 433 | self.dirstate.normallookup(f) |
|
421 | 434 | # Write the cache to update mtime and cache .hgeol |
|
422 | with self.vfs("eol.cache", "w") as f: | |
|
435 | with self.vfs(b"eol.cache", b"w") as f: | |
|
423 | 436 | f.write(hgeoldata) |
|
424 | 437 | except errormod.LockUnavailable: |
|
425 | 438 | # If we cannot lock the repository and clear the |
@@ -447,7 +460,7 b' def reposetup(ui, repo):' | |||
|
447 | 460 | continue |
|
448 | 461 | if inconsistenteol(data): |
|
449 | 462 | raise errormod.Abort( |
|
450 | _("inconsistent newline style " "in %s\n") % f | |
|
463 | _(b"inconsistent newline style " b"in %s\n") % f | |
|
451 | 464 | ) |
|
452 | 465 | return super(eolrepo, self).commitctx(ctx, error, origctx) |
|
453 | 466 |
@@ -118,26 +118,26 b' configtable = {}' | |||
|
118 | 118 | configitem = registrar.configitem(configtable) |
|
119 | 119 | |
|
120 | 120 | configitem( |
|
121 | 'extdiff', br'opts\..*', default='', generic=True, | |
|
121 | b'extdiff', br'opts\..*', default=b'', generic=True, | |
|
122 | 122 | ) |
|
123 | 123 | |
|
124 | 124 | configitem( |
|
125 | 'extdiff', br'gui\..*', generic=True, | |
|
125 | b'extdiff', br'gui\..*', generic=True, | |
|
126 | 126 | ) |
|
127 | 127 | |
|
128 | 128 | configitem( |
|
129 | 'diff-tools', br'.*\.diffargs$', default=None, generic=True, | |
|
129 | b'diff-tools', br'.*\.diffargs$', default=None, generic=True, | |
|
130 | 130 | ) |
|
131 | 131 | |
|
132 | 132 | configitem( |
|
133 | 'diff-tools', br'.*\.gui$', generic=True, | |
|
133 | b'diff-tools', br'.*\.gui$', generic=True, | |
|
134 | 134 | ) |
|
135 | 135 | |
|
136 | 136 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
137 | 137 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
138 | 138 | # be specifying the version(s) of Mercurial they are tested with, or |
|
139 | 139 | # leave the attribute unspecified. |
|
140 | testedwith = 'ships-with-hg-core' | |
|
140 | testedwith = b'ships-with-hg-core' | |
|
141 | 141 | |
|
142 | 142 | |
|
143 | 143 | def snapshot(ui, repo, files, node, tmproot, listsubrepos): |
@@ -145,40 +145,40 b' def snapshot(ui, repo, files, node, tmpr' | |||
|
145 | 145 | if not using snapshot, -I/-X does not work and recursive diff |
|
146 | 146 | in tools like kdiff3 and meld displays too many files.''' |
|
147 | 147 | dirname = os.path.basename(repo.root) |
|
148 | if dirname == "": | |
|
149 | dirname = "root" | |
|
148 | if dirname == b"": | |
|
149 | dirname = b"root" | |
|
150 | 150 | if node is not None: |
|
151 | dirname = '%s.%s' % (dirname, short(node)) | |
|
151 | dirname = b'%s.%s' % (dirname, short(node)) | |
|
152 | 152 | base = os.path.join(tmproot, dirname) |
|
153 | 153 | os.mkdir(base) |
|
154 | 154 | fnsandstat = [] |
|
155 | 155 | |
|
156 | 156 | if node is not None: |
|
157 | 157 | ui.note( |
|
158 | _('making snapshot of %d files from rev %s\n') | |
|
158 | _(b'making snapshot of %d files from rev %s\n') | |
|
159 | 159 | % (len(files), short(node)) |
|
160 | 160 | ) |
|
161 | 161 | else: |
|
162 | 162 | ui.note( |
|
163 | _('making snapshot of %d files from working directory\n') | |
|
163 | _(b'making snapshot of %d files from working directory\n') | |
|
164 | 164 | % (len(files)) |
|
165 | 165 | ) |
|
166 | 166 | |
|
167 | 167 | if files: |
|
168 | repo.ui.setconfig("ui", "archivemeta", False) | |
|
168 | repo.ui.setconfig(b"ui", b"archivemeta", False) | |
|
169 | 169 | |
|
170 | 170 | archival.archive( |
|
171 | 171 | repo, |
|
172 | 172 | base, |
|
173 | 173 | node, |
|
174 | 'files', | |
|
174 | b'files', | |
|
175 | 175 | match=scmutil.matchfiles(repo, files), |
|
176 | 176 | subrepos=listsubrepos, |
|
177 | 177 | ) |
|
178 | 178 | |
|
179 | 179 | for fn in sorted(files): |
|
180 | 180 | wfn = util.pconvert(fn) |
|
181 | ui.note(' %s\n' % wfn) | |
|
181 | ui.note(b' %s\n' % wfn) | |
|
182 | 182 | |
|
183 | 183 | if node is None: |
|
184 | 184 | dest = os.path.join(base, wfn) |
@@ -202,20 +202,20 b' def formatcmdline(' | |||
|
202 | 202 | # When not operating in 3-way mode, an empty string is |
|
203 | 203 | # returned for parent2 |
|
204 | 204 | replace = { |
|
205 | 'parent': parent1, | |
|
206 | 'parent1': parent1, | |
|
207 | 'parent2': parent2, | |
|
208 | 'plabel1': plabel1, | |
|
209 | 'plabel2': plabel2, | |
|
210 | 'child': child, | |
|
211 | 'clabel': clabel, | |
|
212 | 'root': repo_root, | |
|
205 | b'parent': parent1, | |
|
206 | b'parent1': parent1, | |
|
207 | b'parent2': parent2, | |
|
208 | b'plabel1': plabel1, | |
|
209 | b'plabel2': plabel2, | |
|
210 | b'child': child, | |
|
211 | b'clabel': clabel, | |
|
212 | b'root': repo_root, | |
|
213 | 213 | } |
|
214 | 214 | |
|
215 | 215 | def quote(match): |
|
216 | 216 | pre = match.group(2) |
|
217 | 217 | key = match.group(3) |
|
218 | if not do3way and key == 'parent2': | |
|
218 | if not do3way and key == b'parent2': | |
|
219 | 219 | return pre |
|
220 | 220 | return pre + procutil.shellquote(replace[key]) |
|
221 | 221 | |
@@ -225,7 +225,7 b' def formatcmdline(' | |||
|
225 | 225 | br'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1' |
|
226 | 226 | ) |
|
227 | 227 | if not do3way and not re.search(regex, cmdline): |
|
228 | cmdline += ' $parent1 $child' | |
|
228 | cmdline += b' $parent1 $child' | |
|
229 | 229 | return re.sub(regex, quote, cmdline) |
|
230 | 230 | |
|
231 | 231 | |
@@ -273,8 +273,8 b' def _runperfilediff(' | |||
|
273 | 273 | if not os.path.isfile(path1a): |
|
274 | 274 | path1a = os.devnull |
|
275 | 275 | |
|
276 | path1b = '' | |
|
277 | label1b = '' | |
|
276 | path1b = b'' | |
|
277 | label1b = b'' | |
|
278 | 278 | if do3way: |
|
279 | 279 | path1b = os.path.join(tmproot, dir1b, commonfile) |
|
280 | 280 | label1b = commonfile + rev1b |
@@ -286,24 +286,24 b' def _runperfilediff(' | |||
|
286 | 286 | |
|
287 | 287 | if confirm: |
|
288 | 288 | # Prompt before showing this diff |
|
289 | difffiles = _('diff %s (%d of %d)') % ( | |
|
289 | difffiles = _(b'diff %s (%d of %d)') % ( | |
|
290 | 290 | commonfile, |
|
291 | 291 | idx + 1, |
|
292 | 292 | totalfiles, |
|
293 | 293 | ) |
|
294 | 294 | responses = _( |
|
295 | '[Yns?]' | |
|
296 | '$$ &Yes, show diff' | |
|
297 | '$$ &No, skip this diff' | |
|
298 | '$$ &Skip remaining diffs' | |
|
299 | '$$ &? (display help)' | |
|
295 | b'[Yns?]' | |
|
296 | b'$$ &Yes, show diff' | |
|
297 | b'$$ &No, skip this diff' | |
|
298 | b'$$ &Skip remaining diffs' | |
|
299 | b'$$ &? (display help)' | |
|
300 | 300 | ) |
|
301 | r = ui.promptchoice('%s %s' % (difffiles, responses)) | |
|
301 | r = ui.promptchoice(b'%s %s' % (difffiles, responses)) | |
|
302 | 302 | if r == 3: # ? |
|
303 | 303 | while r == 3: |
|
304 | 304 | for c, t in ui.extractchoices(responses)[1]: |
|
305 | ui.write('%s - %s\n' % (c, encoding.lower(t))) | |
|
306 | r = ui.promptchoice('%s %s' % (difffiles, responses)) | |
|
305 | ui.write(b'%s - %s\n' % (c, encoding.lower(t))) | |
|
306 | r = ui.promptchoice(b'%s %s' % (difffiles, responses)) | |
|
307 | 307 | if r == 0: # yes |
|
308 | 308 | pass |
|
309 | 309 | elif r == 1: # no |
@@ -331,22 +331,22 b' def _runperfilediff(' | |||
|
331 | 331 | # as we know, the tool doesn't have a GUI, in which case |
|
332 | 332 | # we can't run multiple CLI programs at the same time. |
|
333 | 333 | ui.debug( |
|
334 | 'running %r in %s\n' % (pycompat.bytestr(curcmdline), tmproot) | |
|
334 | b'running %r in %s\n' % (pycompat.bytestr(curcmdline), tmproot) | |
|
335 | 335 | ) |
|
336 | ui.system(curcmdline, cwd=tmproot, blockedtag='extdiff') | |
|
336 | ui.system(curcmdline, cwd=tmproot, blockedtag=b'extdiff') | |
|
337 | 337 | else: |
|
338 | 338 | # Run the comparison program but don't wait, as we're |
|
339 | 339 | # going to rapid-fire each file diff and then wait on |
|
340 | 340 | # the whole group. |
|
341 | 341 | ui.debug( |
|
342 | 'running %r in %s (backgrounded)\n' | |
|
342 | b'running %r in %s (backgrounded)\n' | |
|
343 | 343 | % (pycompat.bytestr(curcmdline), tmproot) |
|
344 | 344 | ) |
|
345 | 345 | proc = _systembackground(curcmdline, cwd=tmproot) |
|
346 | 346 | waitprocs.append(proc) |
|
347 | 347 | |
|
348 | 348 | if waitprocs: |
|
349 | with ui.timeblockedsection('extdiff'): | |
|
349 | with ui.timeblockedsection(b'extdiff'): | |
|
350 | 350 | for proc in waitprocs: |
|
351 | 351 | proc.wait() |
|
352 | 352 | |
@@ -360,12 +360,12 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
360 | 360 | - just invoke the diff for a single file in the working dir |
|
361 | 361 | ''' |
|
362 | 362 | |
|
363 | revs = opts.get('rev') | |
|
364 | change = opts.get('change') | |
|
365 | do3way = '$parent2' in cmdline | |
|
363 | revs = opts.get(b'rev') | |
|
364 | change = opts.get(b'change') | |
|
365 | do3way = b'$parent2' in cmdline | |
|
366 | 366 | |
|
367 | 367 | if revs and change: |
|
368 | msg = _('cannot specify --rev and --change at the same time') | |
|
368 | msg = _(b'cannot specify --rev and --change at the same time') | |
|
369 | 369 | raise error.Abort(msg) |
|
370 | 370 | elif change: |
|
371 | 371 | ctx2 = scmutil.revsingle(repo, change, None) |
@@ -377,8 +377,8 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
377 | 377 | else: |
|
378 | 378 | ctx1b = repo[nullid] |
|
379 | 379 | |
|
380 | perfile = opts.get('per_file') | |
|
381 | confirm = opts.get('confirm') | |
|
380 | perfile = opts.get(b'per_file') | |
|
381 | confirm = opts.get(b'confirm') | |
|
382 | 382 | |
|
383 | 383 | node1a = ctx1a.node() |
|
384 | 384 | node1b = ctx1b.node() |
@@ -389,17 +389,17 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
389 | 389 | if node1b == nullid: |
|
390 | 390 | do3way = False |
|
391 | 391 | |
|
392 | subrepos = opts.get('subrepos') | |
|
392 | subrepos = opts.get(b'subrepos') | |
|
393 | 393 | |
|
394 | 394 | matcher = scmutil.match(repo[node2], pats, opts) |
|
395 | 395 | |
|
396 | if opts.get('patch'): | |
|
396 | if opts.get(b'patch'): | |
|
397 | 397 | if subrepos: |
|
398 | raise error.Abort(_('--patch cannot be used with --subrepos')) | |
|
398 | raise error.Abort(_(b'--patch cannot be used with --subrepos')) | |
|
399 | 399 | if perfile: |
|
400 | raise error.Abort(_('--patch cannot be used with --per-file')) | |
|
400 | raise error.Abort(_(b'--patch cannot be used with --per-file')) | |
|
401 | 401 | if node2 is None: |
|
402 | raise error.Abort(_('--patch requires two revisions')) | |
|
402 | raise error.Abort(_(b'--patch requires two revisions')) | |
|
403 | 403 | else: |
|
404 | 404 | mod_a, add_a, rem_a = map( |
|
405 | 405 | set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3] |
@@ -416,33 +416,33 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
416 | 416 | if not common: |
|
417 | 417 | return 0 |
|
418 | 418 | |
|
419 | tmproot = pycompat.mkdtemp(prefix='extdiff.') | |
|
419 | tmproot = pycompat.mkdtemp(prefix=b'extdiff.') | |
|
420 | 420 | try: |
|
421 | if not opts.get('patch'): | |
|
421 | if not opts.get(b'patch'): | |
|
422 | 422 | # Always make a copy of node1a (and node1b, if applicable) |
|
423 | 423 | dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) |
|
424 | 424 | dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[ |
|
425 | 425 | 0 |
|
426 | 426 | ] |
|
427 | rev1a = '@%d' % repo[node1a].rev() | |
|
427 | rev1a = b'@%d' % repo[node1a].rev() | |
|
428 | 428 | if do3way: |
|
429 | 429 | dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) |
|
430 | 430 | dir1b = snapshot( |
|
431 | 431 | ui, repo, dir1b_files, node1b, tmproot, subrepos |
|
432 | 432 | )[0] |
|
433 | rev1b = '@%d' % repo[node1b].rev() | |
|
433 | rev1b = b'@%d' % repo[node1b].rev() | |
|
434 | 434 | else: |
|
435 | 435 | dir1b = None |
|
436 | rev1b = '' | |
|
436 | rev1b = b'' | |
|
437 | 437 | |
|
438 | 438 | fnsandstat = [] |
|
439 | 439 | |
|
440 | 440 | # If node2 in not the wc or there is >1 change, copy it |
|
441 | dir2root = '' | |
|
442 | rev2 = '' | |
|
441 | dir2root = b'' | |
|
442 | rev2 = b'' | |
|
443 | 443 | if node2: |
|
444 | 444 | dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] |
|
445 | rev2 = '@%d' % repo[node2].rev() | |
|
445 | rev2 = b'@%d' % repo[node2].rev() | |
|
446 | 446 | elif len(common) > 1: |
|
447 | 447 | # we only actually need to get the files to copy back to |
|
448 | 448 | # the working dir in this case (because the other cases |
@@ -453,7 +453,7 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
453 | 453 | ) |
|
454 | 454 | else: |
|
455 | 455 | # This lets the diff tool open the changed file directly |
|
456 | dir2 = '' | |
|
456 | dir2 = b'' | |
|
457 | 457 | dir2root = repo.root |
|
458 | 458 | |
|
459 | 459 | label1a = rev1a |
@@ -476,8 +476,8 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
476 | 476 | dir2 = os.path.join(dir2root, dir2, common_file) |
|
477 | 477 | label2 = common_file + rev2 |
|
478 | 478 | else: |
|
479 | template = 'hg-%h.patch' | |
|
480 | with formatter.nullformatter(ui, 'extdiff', {}) as fm: | |
|
479 | template = b'hg-%h.patch' | |
|
480 | with formatter.nullformatter(ui, b'extdiff', {}) as fm: | |
|
481 | 481 | cmdutil.export( |
|
482 | 482 | repo, |
|
483 | 483 | [repo[node1a].rev(), repo[node2].rev()], |
@@ -507,9 +507,9 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
507 | 507 | clabel=label2, |
|
508 | 508 | ) |
|
509 | 509 | ui.debug( |
|
510 | 'running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot) | |
|
510 | b'running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot) | |
|
511 | 511 | ) |
|
512 | ui.system(cmdline, cwd=tmproot, blockedtag='extdiff') | |
|
512 | ui.system(cmdline, cwd=tmproot, blockedtag=b'extdiff') | |
|
513 | 513 | else: |
|
514 | 514 | # Run the external tool once for each pair of files |
|
515 | 515 | _runperfilediff( |
@@ -545,35 +545,41 b' def dodiff(ui, repo, cmdline, pats, opts' | |||
|
545 | 545 | or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100) |
|
546 | 546 | ): |
|
547 | 547 | ui.debug( |
|
548 | 'file changed while diffing. ' | |
|
549 | 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn) | |
|
548 | b'file changed while diffing. ' | |
|
549 | b'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn) | |
|
550 | 550 | ) |
|
551 | 551 | util.copyfile(copy_fn, working_fn) |
|
552 | 552 | |
|
553 | 553 | return 1 |
|
554 | 554 | finally: |
|
555 | ui.note(_('cleaning up temp directory\n')) | |
|
555 | ui.note(_(b'cleaning up temp directory\n')) | |
|
556 | 556 | shutil.rmtree(tmproot) |
|
557 | 557 | |
|
558 | 558 | |
|
559 | 559 | extdiffopts = ( |
|
560 | 560 | [ |
|
561 | ('o', 'option', [], _('pass option to comparison program'), _('OPT')), | |
|
562 | ('r', 'rev', [], _('revision'), _('REV')), | |
|
563 | ('c', 'change', '', _('change made by revision'), _('REV')), | |
|
564 | 561 | ( |
|
565 | '', | |
|
566 |
' |
|
|
562 | b'o', | |
|
563 | b'option', | |
|
564 | [], | |
|
565 | _(b'pass option to comparison program'), | |
|
566 | _(b'OPT'), | |
|
567 | ), | |
|
568 | (b'r', b'rev', [], _(b'revision'), _(b'REV')), | |
|
569 | (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')), | |
|
570 | ( | |
|
571 | b'', | |
|
572 | b'per-file', | |
|
567 | 573 | False, |
|
568 | _('compare each file instead of revision snapshots'), | |
|
574 | _(b'compare each file instead of revision snapshots'), | |
|
569 | 575 | ), |
|
570 | 576 | ( |
|
571 | '', | |
|
572 | 'confirm', | |
|
577 | b'', | |
|
578 | b'confirm', | |
|
573 | 579 | False, |
|
574 | _('prompt user before each external program invocation'), | |
|
580 | _(b'prompt user before each external program invocation'), | |
|
575 | 581 | ), |
|
576 | ('', 'patch', None, _('compare patches for two revisions')), | |
|
582 | (b'', b'patch', None, _(b'compare patches for two revisions')), | |
|
577 | 583 | ] |
|
578 | 584 | + cmdutil.walkopts |
|
579 | 585 | + cmdutil.subrepoopts |
@@ -581,10 +587,10 b' extdiffopts = (' | |||
|
581 | 587 | |
|
582 | 588 | |
|
583 | 589 | @command( |
|
584 | 'extdiff', | |
|
585 | [('p', 'program', '', _('comparison program to run'), _('CMD')),] | |
|
590 | b'extdiff', | |
|
591 | [(b'p', b'program', b'', _(b'comparison program to run'), _(b'CMD')),] | |
|
586 | 592 | + extdiffopts, |
|
587 | _('hg extdiff [OPT]... [FILE]...'), | |
|
593 | _(b'hg extdiff [OPT]... [FILE]...'), | |
|
588 | 594 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
589 | 595 | inferrepo=True, |
|
590 | 596 | ) |
@@ -620,12 +626,12 b' def extdiff(ui, repo, *pats, **opts):' | |||
|
620 | 626 | the external program. It is ignored if --per-file isn't specified. |
|
621 | 627 | ''' |
|
622 | 628 | opts = pycompat.byteskwargs(opts) |
|
623 | program = opts.get('program') | |
|
624 | option = opts.get('option') | |
|
629 | program = opts.get(b'program') | |
|
630 | option = opts.get(b'option') | |
|
625 | 631 | if not program: |
|
626 | program = 'diff' | |
|
627 | option = option or ['-Npru'] | |
|
628 | cmdline = ' '.join(map(procutil.shellquote, [program] + option)) | |
|
632 | program = b'diff' | |
|
633 | option = option or [b'-Npru'] | |
|
634 | cmdline = b' '.join(map(procutil.shellquote, [program] + option)) | |
|
629 | 635 | return dodiff(ui, repo, cmdline, pats, opts) |
|
630 | 636 | |
|
631 | 637 | |
@@ -655,29 +661,29 b' class savedcmd(object):' | |||
|
655 | 661 | |
|
656 | 662 | def __call__(self, ui, repo, *pats, **opts): |
|
657 | 663 | opts = pycompat.byteskwargs(opts) |
|
658 | options = ' '.join(map(procutil.shellquote, opts['option'])) | |
|
664 | options = b' '.join(map(procutil.shellquote, opts[b'option'])) | |
|
659 | 665 | if options: |
|
660 | options = ' ' + options | |
|
666 | options = b' ' + options | |
|
661 | 667 | return dodiff( |
|
662 | 668 | ui, repo, self._cmdline + options, pats, opts, guitool=self._isgui |
|
663 | 669 | ) |
|
664 | 670 | |
|
665 | 671 | |
|
666 | 672 | def uisetup(ui): |
|
667 | for cmd, path in ui.configitems('extdiff'): | |
|
673 | for cmd, path in ui.configitems(b'extdiff'): | |
|
668 | 674 | path = util.expandpath(path) |
|
669 | if cmd.startswith('cmd.'): | |
|
675 | if cmd.startswith(b'cmd.'): | |
|
670 | 676 | cmd = cmd[4:] |
|
671 | 677 | if not path: |
|
672 | 678 | path = procutil.findexe(cmd) |
|
673 | 679 | if path is None: |
|
674 | 680 | path = filemerge.findexternaltool(ui, cmd) or cmd |
|
675 | diffopts = ui.config('extdiff', 'opts.' + cmd) | |
|
681 | diffopts = ui.config(b'extdiff', b'opts.' + cmd) | |
|
676 | 682 | cmdline = procutil.shellquote(path) |
|
677 | 683 | if diffopts: |
|
678 | cmdline += ' ' + diffopts | |
|
679 | isgui = ui.configbool('extdiff', 'gui.' + cmd) | |
|
680 | elif cmd.startswith('opts.') or cmd.startswith('gui.'): | |
|
684 | cmdline += b' ' + diffopts | |
|
685 | isgui = ui.configbool(b'extdiff', b'gui.' + cmd) | |
|
686 | elif cmd.startswith(b'opts.') or cmd.startswith(b'gui.'): | |
|
681 | 687 | continue |
|
682 | 688 | else: |
|
683 | 689 | if path: |
@@ -691,21 +697,21 b' def uisetup(ui):' | |||
|
691 | 697 | path = filemerge.findexternaltool(ui, cmd) or cmd |
|
692 | 698 | cmdline = procutil.shellquote(path) |
|
693 | 699 | diffopts = False |
|
694 | isgui = ui.configbool('extdiff', 'gui.' + cmd) | |
|
700 | isgui = ui.configbool(b'extdiff', b'gui.' + cmd) | |
|
695 | 701 | # look for diff arguments in [diff-tools] then [merge-tools] |
|
696 | 702 | if not diffopts: |
|
697 | key = cmd + '.diffargs' | |
|
698 | for section in ('diff-tools', 'merge-tools'): | |
|
703 | key = cmd + b'.diffargs' | |
|
704 | for section in (b'diff-tools', b'merge-tools'): | |
|
699 | 705 | args = ui.config(section, key) |
|
700 | 706 | if args: |
|
701 | cmdline += ' ' + args | |
|
707 | cmdline += b' ' + args | |
|
702 | 708 | if isgui is None: |
|
703 | isgui = ui.configbool(section, cmd + '.gui') or False | |
|
709 | isgui = ui.configbool(section, cmd + b'.gui') or False | |
|
704 | 710 | break |
|
705 | 711 | command( |
|
706 | 712 | cmd, |
|
707 | 713 | extdiffopts[:], |
|
708 | _('hg %s [OPTION]... [FILE]...') % cmd, | |
|
714 | _(b'hg %s [OPTION]... [FILE]...') % cmd, | |
|
709 | 715 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
710 | 716 | inferrepo=True, |
|
711 | 717 | )(savedcmd(path, cmdline, isgui)) |
@@ -69,44 +69,44 b' configtable = {}' | |||
|
69 | 69 | configitem = registrar.configitem(configtable) |
|
70 | 70 | |
|
71 | 71 | configitem( |
|
72 | 'factotum', 'executable', default='/bin/auth/factotum', | |
|
72 | b'factotum', b'executable', default=b'/bin/auth/factotum', | |
|
73 | 73 | ) |
|
74 | 74 | configitem( |
|
75 | 'factotum', 'mountpoint', default='/mnt/factotum', | |
|
75 | b'factotum', b'mountpoint', default=b'/mnt/factotum', | |
|
76 | 76 | ) |
|
77 | 77 | configitem( |
|
78 | 'factotum', 'service', default='hg', | |
|
78 | b'factotum', b'service', default=b'hg', | |
|
79 | 79 | ) |
|
80 | 80 | |
|
81 | 81 | |
|
82 | 82 | def auth_getkey(self, params): |
|
83 | 83 | if not self.ui.interactive(): |
|
84 | raise error.Abort(_('factotum not interactive')) | |
|
85 | if 'user=' not in params: | |
|
86 | params = '%s user?' % params | |
|
87 | params = '%s !password?' % params | |
|
88 | os.system(procutil.tonativestr("%s -g '%s'" % (_executable, params))) | |
|
84 | raise error.Abort(_(b'factotum not interactive')) | |
|
85 | if b'user=' not in params: | |
|
86 | params = b'%s user?' % params | |
|
87 | params = b'%s !password?' % params | |
|
88 | os.system(procutil.tonativestr(b"%s -g '%s'" % (_executable, params))) | |
|
89 | 89 | |
|
90 | 90 | |
|
91 | 91 | def auth_getuserpasswd(self, getkey, params): |
|
92 | params = 'proto=pass %s' % params | |
|
92 | params = b'proto=pass %s' % params | |
|
93 | 93 | while True: |
|
94 | fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR) | |
|
94 | fd = os.open(b'%s/rpc' % _mountpoint, os.O_RDWR) | |
|
95 | 95 | try: |
|
96 | os.write(fd, 'start %s' % params) | |
|
96 | os.write(fd, b'start %s' % params) | |
|
97 | 97 | l = os.read(fd, ERRMAX).split() |
|
98 | if l[0] == 'ok': | |
|
99 | os.write(fd, 'read') | |
|
98 | if l[0] == b'ok': | |
|
99 | os.write(fd, b'read') | |
|
100 | 100 | status, user, passwd = os.read(fd, ERRMAX).split(None, 2) |
|
101 | if status == 'ok': | |
|
102 | if passwd.startswith("'"): | |
|
103 | if passwd.endswith("'"): | |
|
104 | passwd = passwd[1:-1].replace("''", "'") | |
|
101 | if status == b'ok': | |
|
102 | if passwd.startswith(b"'"): | |
|
103 | if passwd.endswith(b"'"): | |
|
104 | passwd = passwd[1:-1].replace(b"''", b"'") | |
|
105 | 105 | else: |
|
106 | raise error.Abort(_('malformed password string')) | |
|
106 | raise error.Abort(_(b'malformed password string')) | |
|
107 | 107 | return (user, passwd) |
|
108 | 108 | except (OSError, IOError): |
|
109 | raise error.Abort(_('factotum not responding')) | |
|
109 | raise error.Abort(_(b'factotum not responding')) | |
|
110 | 110 | finally: |
|
111 | 111 | os.close(fd) |
|
112 | 112 | getkey(self, params) |
@@ -127,18 +127,18 b' def find_user_password(self, realm, auth' | |||
|
127 | 127 | self._writedebug(user, passwd) |
|
128 | 128 | return (user, passwd) |
|
129 | 129 | |
|
130 | prefix = '' | |
|
130 | prefix = b'' | |
|
131 | 131 | res = httpconnection.readauthforuri(self.ui, authuri, user) |
|
132 | 132 | if res: |
|
133 | 133 | _, auth = res |
|
134 | prefix = auth.get('prefix') | |
|
135 | user, passwd = auth.get('username'), auth.get('password') | |
|
134 | prefix = auth.get(b'prefix') | |
|
135 | user, passwd = auth.get(b'username'), auth.get(b'password') | |
|
136 | 136 | if not user or not passwd: |
|
137 | 137 | if not prefix: |
|
138 | prefix = realm.split(' ')[0].lower() | |
|
139 | params = 'service=%s prefix=%s' % (_service, prefix) | |
|
138 | prefix = realm.split(b' ')[0].lower() | |
|
139 | params = b'service=%s prefix=%s' % (_service, prefix) | |
|
140 | 140 | if user: |
|
141 | params = '%s user=%s' % (params, user) | |
|
141 | params = b'%s user=%s' % (params, user) | |
|
142 | 142 | user, passwd = auth_getuserpasswd(self, auth_getkey, params) |
|
143 | 143 | |
|
144 | 144 | self.add_password(realm, authuri, user, passwd) |
@@ -148,8 +148,8 b' def find_user_password(self, realm, auth' | |||
|
148 | 148 | |
|
149 | 149 | def uisetup(ui): |
|
150 | 150 | global _executable |
|
151 | _executable = ui.config('factotum', 'executable') | |
|
151 | _executable = ui.config(b'factotum', b'executable') | |
|
152 | 152 | global _mountpoint |
|
153 | _mountpoint = ui.config('factotum', 'mountpoint') | |
|
153 | _mountpoint = ui.config(b'factotum', b'mountpoint') | |
|
154 | 154 | global _service |
|
155 | _service = ui.config('factotum', 'service') | |
|
155 | _service = ui.config(b'factotum', b'service') |
@@ -119,56 +119,56 b' from . import (' | |||
|
119 | 119 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
120 | 120 | # be specifying the version(s) of Mercurial they are tested with, or |
|
121 | 121 | # leave the attribute unspecified. |
|
122 | testedwith = 'ships-with-hg-core' | |
|
122 | testedwith = b'ships-with-hg-core' | |
|
123 | 123 | |
|
124 | 124 | cmdtable = commands.cmdtable |
|
125 | 125 | |
|
126 | 126 | configtable = {} |
|
127 | 127 | configitem = registrar.configitem(configtable) |
|
128 | 128 | |
|
129 | configitem('fastannotate', 'modes', default=['fastannotate']) | |
|
130 | configitem('fastannotate', 'server', default=False) | |
|
131 | configitem('fastannotate', 'client', default=False) | |
|
132 | configitem('fastannotate', 'unfilteredrepo', default=True) | |
|
133 | configitem('fastannotate', 'defaultformat', default=['number']) | |
|
134 | configitem('fastannotate', 'perfhack', default=False) | |
|
135 | configitem('fastannotate', 'mainbranch') | |
|
136 | configitem('fastannotate', 'forcetext', default=True) | |
|
137 | configitem('fastannotate', 'forcefollow', default=True) | |
|
138 | configitem('fastannotate', 'clientfetchthreshold', default=10) | |
|
139 | configitem('fastannotate', 'serverbuildondemand', default=True) | |
|
140 | configitem('fastannotate', 'remotepath', default='default') | |
|
129 | configitem(b'fastannotate', b'modes', default=[b'fastannotate']) | |
|
130 | configitem(b'fastannotate', b'server', default=False) | |
|
131 | configitem(b'fastannotate', b'client', default=False) | |
|
132 | configitem(b'fastannotate', b'unfilteredrepo', default=True) | |
|
133 | configitem(b'fastannotate', b'defaultformat', default=[b'number']) | |
|
134 | configitem(b'fastannotate', b'perfhack', default=False) | |
|
135 | configitem(b'fastannotate', b'mainbranch') | |
|
136 | configitem(b'fastannotate', b'forcetext', default=True) | |
|
137 | configitem(b'fastannotate', b'forcefollow', default=True) | |
|
138 | configitem(b'fastannotate', b'clientfetchthreshold', default=10) | |
|
139 | configitem(b'fastannotate', b'serverbuildondemand', default=True) | |
|
140 | configitem(b'fastannotate', b'remotepath', default=b'default') | |
|
141 | 141 | |
|
142 | 142 | |
|
143 | 143 | def uisetup(ui): |
|
144 | modes = set(ui.configlist('fastannotate', 'modes')) | |
|
145 | if 'fctx' in modes: | |
|
146 | modes.discard('hgweb') | |
|
144 | modes = set(ui.configlist(b'fastannotate', b'modes')) | |
|
145 | if b'fctx' in modes: | |
|
146 | modes.discard(b'hgweb') | |
|
147 | 147 | for name in modes: |
|
148 | if name == 'fastannotate': | |
|
148 | if name == b'fastannotate': | |
|
149 | 149 | commands.registercommand() |
|
150 | elif name == 'hgweb': | |
|
150 | elif name == b'hgweb': | |
|
151 | 151 | from . import support |
|
152 | 152 | |
|
153 | 153 | support.replacehgwebannotate() |
|
154 | elif name == 'fctx': | |
|
154 | elif name == b'fctx': | |
|
155 | 155 | from . import support |
|
156 | 156 | |
|
157 | 157 | support.replacefctxannotate() |
|
158 | 158 | commands.wrapdefault() |
|
159 | 159 | else: |
|
160 | raise hgerror.Abort(_('fastannotate: invalid mode: %s') % name) | |
|
160 | raise hgerror.Abort(_(b'fastannotate: invalid mode: %s') % name) | |
|
161 | 161 | |
|
162 | if ui.configbool('fastannotate', 'server'): | |
|
162 | if ui.configbool(b'fastannotate', b'server'): | |
|
163 | 163 | protocol.serveruisetup(ui) |
|
164 | 164 | |
|
165 | 165 | |
|
166 | 166 | def extsetup(ui): |
|
167 | 167 | # fastannotate has its own locking, without depending on repo lock |
|
168 | 168 | # TODO: avoid mutating this unless the specific repo has it enabled |
|
169 | localrepo.localrepository._wlockfreeprefix.add('fastannotate/') | |
|
169 | localrepo.localrepository._wlockfreeprefix.add(b'fastannotate/') | |
|
170 | 170 | |
|
171 | 171 | |
|
172 | 172 | def reposetup(ui, repo): |
|
173 | if ui.configbool('fastannotate', 'client'): | |
|
173 | if ui.configbool(b'fastannotate', b'client'): | |
|
174 | 174 | protocol.clientreposetup(ui, repo) |
@@ -34,7 +34,7 b' command = registrar.command(cmdtable)' | |||
|
34 | 34 | |
|
35 | 35 | def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts): |
|
36 | 36 | """generate paths matching given patterns""" |
|
37 | perfhack = repo.ui.configbool('fastannotate', 'perfhack') | |
|
37 | perfhack = repo.ui.configbool(b'fastannotate', b'perfhack') | |
|
38 | 38 | |
|
39 | 39 | # disable perfhack if: |
|
40 | 40 | # a) any walkopt is used |
@@ -44,8 +44,8 b' def _matchpaths(repo, rev, pats, opts, a' | |||
|
44 | 44 | # cwd related to reporoot |
|
45 | 45 | reporoot = os.path.dirname(repo.path) |
|
46 | 46 | reldir = os.path.relpath(encoding.getcwd(), reporoot) |
|
47 | if reldir == '.': | |
|
48 | reldir = '' | |
|
47 | if reldir == b'.': | |
|
48 | reldir = b'' | |
|
49 | 49 | if any(opts.get(o[1]) for o in commands.walkopts): # a) |
|
50 | 50 | perfhack = False |
|
51 | 51 | else: # b) |
@@ -56,7 +56,7 b' def _matchpaths(repo, rev, pats, opts, a' | |||
|
56 | 56 | # disable perfhack on '..' since it allows escaping from the repo |
|
57 | 57 | if any( |
|
58 | 58 | ( |
|
59 | '..' in f | |
|
59 | b'..' in f | |
|
60 | 60 | or not os.path.isfile( |
|
61 | 61 | facontext.pathhelper(repo, f, aopts).linelogpath |
|
62 | 62 | ) |
@@ -73,7 +73,7 b' def _matchpaths(repo, rev, pats, opts, a' | |||
|
73 | 73 | else: |
|
74 | 74 | |
|
75 | 75 | def bad(x, y): |
|
76 | raise error.Abort("%s: %s" % (x, y)) | |
|
76 | raise error.Abort(b"%s: %s" % (x, y)) | |
|
77 | 77 | |
|
78 | 78 | ctx = scmutil.revsingle(repo, rev) |
|
79 | 79 | m = scmutil.match(ctx, pats, opts, badfn=bad) |
@@ -83,42 +83,57 b' def _matchpaths(repo, rev, pats, opts, a' | |||
|
83 | 83 | |
|
84 | 84 | fastannotatecommandargs = { |
|
85 | 85 | r'options': [ |
|
86 | ('r', 'rev', '.', _('annotate the specified revision'), _('REV')), | |
|
87 | ('u', 'user', None, _('list the author (long with -v)')), | |
|
88 | ('f', 'file', None, _('list the filename')), | |
|
89 | ('d', 'date', None, _('list the date (short with -q)')), | |
|
90 | ('n', 'number', None, _('list the revision number (default)')), | |
|
91 | ('c', 'changeset', None, _('list the changeset')), | |
|
86 | (b'r', b'rev', b'.', _(b'annotate the specified revision'), _(b'REV')), | |
|
87 | (b'u', b'user', None, _(b'list the author (long with -v)')), | |
|
88 | (b'f', b'file', None, _(b'list the filename')), | |
|
89 | (b'd', b'date', None, _(b'list the date (short with -q)')), | |
|
90 | (b'n', b'number', None, _(b'list the revision number (default)')), | |
|
91 | (b'c', b'changeset', None, _(b'list the changeset')), | |
|
92 | ( | |
|
93 | b'l', | |
|
94 | b'line-number', | |
|
95 | None, | |
|
96 | _(b'show line number at the first ' b'appearance'), | |
|
97 | ), | |
|
92 | 98 | ( |
|
93 |
' |
|
|
94 |
' |
|
|
99 | b'e', | |
|
100 | b'deleted', | |
|
95 | 101 | None, |
|
96 | _('show line number at the first ' 'appearance'), | |
|
102 | _(b'show deleted lines (slow) (EXPERIMENTAL)'), | |
|
97 | 103 | ), |
|
98 | ('e', 'deleted', None, _('show deleted lines (slow) (EXPERIMENTAL)')), | |
|
99 | ('', 'no-content', None, _('do not show file content (EXPERIMENTAL)')), | |
|
100 | ('', 'no-follow', None, _("don't follow copies and renames")), | |
|
101 | 104 | ( |
|
102 | '', | |
|
103 |
' |
|
|
105 | b'', | |
|
106 | b'no-content', | |
|
107 | None, | |
|
108 | _(b'do not show file content (EXPERIMENTAL)'), | |
|
109 | ), | |
|
110 | (b'', b'no-follow', None, _(b"don't follow copies and renames")), | |
|
111 | ( | |
|
112 | b'', | |
|
113 | b'linear', | |
|
104 | 114 | None, |
|
105 | 115 | _( |
|
106 | 'enforce linear history, ignore second parent ' | |
|
107 | 'of merges (EXPERIMENTAL)' | |
|
116 | b'enforce linear history, ignore second parent ' | |
|
117 | b'of merges (EXPERIMENTAL)' | |
|
108 | 118 | ), |
|
109 | 119 | ), |
|
110 | ('', 'long-hash', None, _('show long changeset hash (EXPERIMENTAL)')), | |
|
111 | 120 | ( |
|
112 | '', | |
|
113 |
' |
|
|
121 | b'', | |
|
122 | b'long-hash', | |
|
114 | 123 | None, |
|
115 |
_(' |
|
|
124 | _(b'show long changeset hash (EXPERIMENTAL)'), | |
|
125 | ), | |
|
126 | ( | |
|
127 | b'', | |
|
128 | b'rebuild', | |
|
129 | None, | |
|
130 | _(b'rebuild cache even if it exists ' b'(EXPERIMENTAL)'), | |
|
116 | 131 | ), |
|
117 | 132 | ] |
|
118 | 133 | + commands.diffwsopts |
|
119 | 134 | + commands.walkopts |
|
120 | 135 | + commands.formatteropts, |
|
121 | r'synopsis': _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), | |
|
136 | r'synopsis': _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), | |
|
122 | 137 | r'inferrepo': True, |
|
123 | 138 | } |
|
124 | 139 | |
@@ -155,52 +170,55 b' def fastannotate(ui, repo, *pats, **opts' | |||
|
155 | 170 | affecting results are used. |
|
156 | 171 | """ |
|
157 | 172 | if not pats: |
|
158 | raise error.Abort(_('at least one filename or pattern is required')) | |
|
173 | raise error.Abort(_(b'at least one filename or pattern is required')) | |
|
159 | 174 | |
|
160 | 175 | # performance hack: filtered repo can be slow. unfilter by default. |
|
161 | if ui.configbool('fastannotate', 'unfilteredrepo'): | |
|
176 | if ui.configbool(b'fastannotate', b'unfilteredrepo'): | |
|
162 | 177 | repo = repo.unfiltered() |
|
163 | 178 | |
|
164 | 179 | opts = pycompat.byteskwargs(opts) |
|
165 | 180 | |
|
166 | rev = opts.get('rev', '.') | |
|
167 | rebuild = opts.get('rebuild', False) | |
|
181 | rev = opts.get(b'rev', b'.') | |
|
182 | rebuild = opts.get(b'rebuild', False) | |
|
168 | 183 | |
|
169 | 184 | diffopts = patch.difffeatureopts( |
|
170 | ui, opts, section='annotate', whitespace=True | |
|
185 | ui, opts, section=b'annotate', whitespace=True | |
|
171 | 186 | ) |
|
172 | 187 | aopts = facontext.annotateopts( |
|
173 | 188 | diffopts=diffopts, |
|
174 | followmerge=not opts.get('linear', False), | |
|
175 | followrename=not opts.get('no_follow', False), | |
|
189 | followmerge=not opts.get(b'linear', False), | |
|
190 | followrename=not opts.get(b'no_follow', False), | |
|
176 | 191 | ) |
|
177 | 192 | |
|
178 | 193 | if not any( |
|
179 | opts.get(s) for s in ['user', 'date', 'file', 'number', 'changeset'] | |
|
194 | opts.get(s) | |
|
195 | for s in [b'user', b'date', b'file', b'number', b'changeset'] | |
|
180 | 196 | ): |
|
181 | 197 | # default 'number' for compatibility. but fastannotate is more |
|
182 | 198 | # efficient with "changeset", "line-number" and "no-content". |
|
183 |
for name in ui.configlist( |
|
|
199 | for name in ui.configlist( | |
|
200 | b'fastannotate', b'defaultformat', [b'number'] | |
|
201 | ): | |
|
184 | 202 | opts[name] = True |
|
185 | 203 | |
|
186 | ui.pager('fastannotate') | |
|
187 | template = opts.get('template') | |
|
188 | if template == 'json': | |
|
204 | ui.pager(b'fastannotate') | |
|
205 | template = opts.get(b'template') | |
|
206 | if template == b'json': | |
|
189 | 207 | formatter = faformatter.jsonformatter(ui, repo, opts) |
|
190 | 208 | else: |
|
191 | 209 | formatter = faformatter.defaultformatter(ui, repo, opts) |
|
192 | showdeleted = opts.get('deleted', False) | |
|
193 | showlines = not bool(opts.get('no_content')) | |
|
194 | showpath = opts.get('file', False) | |
|
210 | showdeleted = opts.get(b'deleted', False) | |
|
211 | showlines = not bool(opts.get(b'no_content')) | |
|
212 | showpath = opts.get(b'file', False) | |
|
195 | 213 | |
|
196 | 214 | # find the head of the main (master) branch |
|
197 | master = ui.config('fastannotate', 'mainbranch') or rev | |
|
215 | master = ui.config(b'fastannotate', b'mainbranch') or rev | |
|
198 | 216 | |
|
199 | 217 | # paths will be used for prefetching and the real annotating |
|
200 | 218 | paths = list(_matchpaths(repo, rev, pats, opts, aopts)) |
|
201 | 219 | |
|
202 | 220 | # for client, prefetch from the server |
|
203 | if util.safehasattr(repo, 'prefetchfastannotate'): | |
|
221 | if util.safehasattr(repo, b'prefetchfastannotate'): | |
|
204 | 222 | repo.prefetchfastannotate(paths) |
|
205 | 223 | |
|
206 | 224 | for path in paths: |
@@ -238,7 +256,7 b' def fastannotate(ui, repo, *pats, **opts' | |||
|
238 | 256 | |
|
239 | 257 | _newopts = set() |
|
240 | 258 | _knownopts = { |
|
241 | opt[1].replace('-', '_') | |
|
259 | opt[1].replace(b'-', b'_') | |
|
242 | 260 | for opt in (fastannotatecommandargs[r'options'] + commands.globalopts) |
|
243 | 261 | } |
|
244 | 262 | |
@@ -246,16 +264,16 b' def fastannotate(ui, repo, *pats, **opts' | |||
|
246 | 264 | def _annotatewrapper(orig, ui, repo, *pats, **opts): |
|
247 | 265 | """used by wrapdefault""" |
|
248 | 266 | # we need this hack until the obsstore has 0.0 seconds perf impact |
|
249 | if ui.configbool('fastannotate', 'unfilteredrepo'): | |
|
267 | if ui.configbool(b'fastannotate', b'unfilteredrepo'): | |
|
250 | 268 | repo = repo.unfiltered() |
|
251 | 269 | |
|
252 | 270 | # treat the file as text (skip the isbinary check) |
|
253 | if ui.configbool('fastannotate', 'forcetext'): | |
|
271 | if ui.configbool(b'fastannotate', b'forcetext'): | |
|
254 | 272 | opts[r'text'] = True |
|
255 | 273 | |
|
256 | 274 | # check if we need to do prefetch (client-side) |
|
257 | 275 | rev = opts.get(r'rev') |
|
258 | if util.safehasattr(repo, 'prefetchfastannotate') and rev is not None: | |
|
276 | if util.safehasattr(repo, b'prefetchfastannotate') and rev is not None: | |
|
259 | 277 | paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) |
|
260 | 278 | repo.prefetchfastannotate(paths) |
|
261 | 279 | |
@@ -264,20 +282,20 b' def _annotatewrapper(orig, ui, repo, *pa' | |||
|
264 | 282 | |
|
265 | 283 | def registercommand(): |
|
266 | 284 | """register the fastannotate command""" |
|
267 | name = 'fastannotate|fastblame|fa' | |
|
285 | name = b'fastannotate|fastblame|fa' | |
|
268 | 286 | command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate) |
|
269 | 287 | |
|
270 | 288 | |
|
271 | 289 | def wrapdefault(): |
|
272 | 290 | """wrap the default annotate command, to be aware of the protocol""" |
|
273 | extensions.wrapcommand(commands.table, 'annotate', _annotatewrapper) | |
|
291 | extensions.wrapcommand(commands.table, b'annotate', _annotatewrapper) | |
|
274 | 292 | |
|
275 | 293 | |
|
276 | 294 | @command( |
|
277 | 'debugbuildannotatecache', | |
|
278 | [('r', 'rev', '', _('build up to the specific revision'), _('REV'))] | |
|
295 | b'debugbuildannotatecache', | |
|
296 | [(b'r', b'rev', b'', _(b'build up to the specific revision'), _(b'REV'))] | |
|
279 | 297 | + commands.walkopts, |
|
280 | _('[-r REV] FILE...'), | |
|
298 | _(b'[-r REV] FILE...'), | |
|
281 | 299 | ) |
|
282 | 300 | def debugbuildannotatecache(ui, repo, *pats, **opts): |
|
283 | 301 | """incrementally build fastannotate cache up to REV for specified files |
@@ -291,25 +309,25 b' def debugbuildannotatecache(ui, repo, *p' | |||
|
291 | 309 | options and lives in '.hg/fastannotate/default'. |
|
292 | 310 | """ |
|
293 | 311 | opts = pycompat.byteskwargs(opts) |
|
294 | rev = opts.get('REV') or ui.config('fastannotate', 'mainbranch') | |
|
312 | rev = opts.get(b'REV') or ui.config(b'fastannotate', b'mainbranch') | |
|
295 | 313 | if not rev: |
|
296 | 314 | raise error.Abort( |
|
297 | _('you need to provide a revision'), | |
|
298 | hint=_('set fastannotate.mainbranch or use --rev'), | |
|
315 | _(b'you need to provide a revision'), | |
|
316 | hint=_(b'set fastannotate.mainbranch or use --rev'), | |
|
299 | 317 | ) |
|
300 | if ui.configbool('fastannotate', 'unfilteredrepo'): | |
|
318 | if ui.configbool(b'fastannotate', b'unfilteredrepo'): | |
|
301 | 319 | repo = repo.unfiltered() |
|
302 | 320 | ctx = scmutil.revsingle(repo, rev) |
|
303 | 321 | m = scmutil.match(ctx, pats, opts) |
|
304 | 322 | paths = list(ctx.walk(m)) |
|
305 | if util.safehasattr(repo, 'prefetchfastannotate'): | |
|
323 | if util.safehasattr(repo, b'prefetchfastannotate'): | |
|
306 | 324 | # client |
|
307 | if opts.get('REV'): | |
|
308 | raise error.Abort(_('--rev cannot be used for client')) | |
|
325 | if opts.get(b'REV'): | |
|
326 | raise error.Abort(_(b'--rev cannot be used for client')) | |
|
309 | 327 | repo.prefetchfastannotate(paths) |
|
310 | 328 | else: |
|
311 | 329 | # server, or full repo |
|
312 | progress = ui.makeprogress(_('building'), total=len(paths)) | |
|
330 | progress = ui.makeprogress(_(b'building'), total=len(paths)) | |
|
313 | 331 | for i, path in enumerate(paths): |
|
314 | 332 | progress.update(i) |
|
315 | 333 | with facontext.annotatecontext(repo, path) as actx: |
@@ -321,7 +339,7 b' def debugbuildannotatecache(ui, repo, *p' | |||
|
321 | 339 | # the cache is broken (could happen with renaming so the |
|
322 | 340 | # file history gets invalidated). rebuild and try again. |
|
323 | 341 | ui.debug( |
|
324 | 'fastannotate: %s: rebuilding broken cache\n' % path | |
|
342 | b'fastannotate: %s: rebuilding broken cache\n' % path | |
|
325 | 343 | ) |
|
326 | 344 | actx.rebuild() |
|
327 | 345 | try: |
@@ -331,8 +349,8 b' def debugbuildannotatecache(ui, repo, *p' | |||
|
331 | 349 | # cache for other files. |
|
332 | 350 | ui.warn( |
|
333 | 351 | _( |
|
334 | 'fastannotate: %s: failed to ' | |
|
335 | 'build cache: %r\n' | |
|
352 | b'fastannotate: %s: failed to ' | |
|
353 | b'build cache: %r\n' | |
|
336 | 354 | ) |
|
337 | 355 | % (path, ex) |
|
338 | 356 | ) |
@@ -52,7 +52,7 b' def _parents(f, follow=True):' | |||
|
52 | 52 | # renamed filectx won't have a filelog yet, so set it |
|
53 | 53 | # from the cache to save time |
|
54 | 54 | for p in pl: |
|
55 | if not '_filelog' in p.__dict__: | |
|
55 | if not b'_filelog' in p.__dict__: | |
|
56 | 56 | p._filelog = _getflog(f._repo, p.path()) |
|
57 | 57 | |
|
58 | 58 | return pl |
@@ -62,8 +62,8 b' def _parents(f, follow=True):' | |||
|
62 | 62 | # so it takes a fctx instead of a pair of text and fctx. |
|
63 | 63 | def _decorate(fctx): |
|
64 | 64 | text = fctx.data() |
|
65 | linecount = text.count('\n') | |
|
66 | if text and not text.endswith('\n'): | |
|
65 | linecount = text.count(b'\n') | |
|
66 | if text and not text.endswith(b'\n'): | |
|
67 | 67 | linecount += 1 |
|
68 | 68 | return ([(fctx, i) for i in pycompat.xrange(linecount)], text) |
|
69 | 69 | |
@@ -75,7 +75,7 b' def _pair(parent, child, blocks):' | |||
|
75 | 75 | for (a1, a2, b1, b2), t in blocks: |
|
76 | 76 | # Changed blocks ('!') or blocks made only of blank lines ('~') |
|
77 | 77 | # belong to the child. |
|
78 | if t == '=': | |
|
78 | if t == b'=': | |
|
79 | 79 | child[0][b1:b2] = parent[0][a1:a2] |
|
80 | 80 | return child |
|
81 | 81 | |
@@ -119,7 +119,7 b' def resolvefctx(repo, rev, path, resolve' | |||
|
119 | 119 | fctx = repo.filectx(path, changeid=ctx.rev()) |
|
120 | 120 | else: |
|
121 | 121 | fctx = ctx[path] |
|
122 | if adjustctx == 'linkrev': | |
|
122 | if adjustctx == b'linkrev': | |
|
123 | 123 | introrev = fctx.linkrev() |
|
124 | 124 | else: |
|
125 | 125 | introrev = fctx.introrev() |
@@ -132,10 +132,10 b' def resolvefctx(repo, rev, path, resolve' | |||
|
132 | 132 | # like mercurial.store.encodedir, but use linelog suffixes: .m, .l, .lock |
|
133 | 133 | def encodedir(path): |
|
134 | 134 | return ( |
|
135 | path.replace('.hg/', '.hg.hg/') | |
|
136 | .replace('.l/', '.l.hg/') | |
|
137 | .replace('.m/', '.m.hg/') | |
|
138 | .replace('.lock/', '.lock.hg/') | |
|
135 | path.replace(b'.hg/', b'.hg.hg/') | |
|
136 | .replace(b'.l/', b'.l.hg/') | |
|
137 | .replace(b'.m/', b'.m.hg/') | |
|
138 | .replace(b'.lock/', b'.lock.hg/') | |
|
139 | 139 | ) |
|
140 | 140 | |
|
141 | 141 | |
@@ -157,9 +157,9 b' class annotateopts(object):' | |||
|
157 | 157 | """ |
|
158 | 158 | |
|
159 | 159 | defaults = { |
|
160 | 'diffopts': None, | |
|
161 | 'followrename': True, | |
|
162 | 'followmerge': True, | |
|
160 | b'diffopts': None, | |
|
161 | b'followrename': True, | |
|
162 | b'followmerge': True, | |
|
163 | 163 | } |
|
164 | 164 | |
|
165 | 165 | def __init__(self, **opts): |
@@ -170,17 +170,17 b' class annotateopts(object):' | |||
|
170 | 170 | @util.propertycache |
|
171 | 171 | def shortstr(self): |
|
172 | 172 | """represent opts in a short string, suitable for a directory name""" |
|
173 | result = '' | |
|
173 | result = b'' | |
|
174 | 174 | if not self.followrename: |
|
175 | result += 'r0' | |
|
175 | result += b'r0' | |
|
176 | 176 | if not self.followmerge: |
|
177 | result += 'm0' | |
|
177 | result += b'm0' | |
|
178 | 178 | if self.diffopts is not None: |
|
179 | 179 | assert isinstance(self.diffopts, mdiff.diffopts) |
|
180 | 180 | diffopthash = hashdiffopts(self.diffopts) |
|
181 | 181 | if diffopthash != _defaultdiffopthash: |
|
182 | result += 'i' + diffopthash | |
|
183 | return result or 'default' | |
|
182 | result += b'i' + diffopthash | |
|
183 | return result or b'default' | |
|
184 | 184 | |
|
185 | 185 | |
|
186 | 186 | defaultopts = annotateopts() |
@@ -206,7 +206,7 b' class _annotatecontext(object):' | |||
|
206 | 206 | def linelog(self): |
|
207 | 207 | if self._linelog is None: |
|
208 | 208 | if os.path.exists(self.linelogpath): |
|
209 | with open(self.linelogpath, 'rb') as f: | |
|
209 | with open(self.linelogpath, b'rb') as f: | |
|
210 | 210 | try: |
|
211 | 211 | self._linelog = linelogmod.linelog.fromdata(f.read()) |
|
212 | 212 | except linelogmod.LineLogError: |
@@ -226,7 +226,7 b' class _annotatecontext(object):' | |||
|
226 | 226 | self._revmap.flush() |
|
227 | 227 | self._revmap = None |
|
228 | 228 | if self._linelog is not None: |
|
229 | with open(self.linelogpath, 'wb') as f: | |
|
229 | with open(self.linelogpath, b'wb') as f: | |
|
230 | 230 | f.write(self._linelog.encode()) |
|
231 | 231 | self._linelog = None |
|
232 | 232 | |
@@ -308,11 +308,11 b' class _annotatecontext(object):' | |||
|
308 | 308 | if directly: |
|
309 | 309 | if self.ui.debugflag: |
|
310 | 310 | self.ui.debug( |
|
311 | 'fastannotate: %s: using fast path ' | |
|
312 | '(resolved fctx: %s)\n' | |
|
311 | b'fastannotate: %s: using fast path ' | |
|
312 | b'(resolved fctx: %s)\n' | |
|
313 | 313 | % ( |
|
314 | 314 | self.path, |
|
315 | stringutil.pprint(util.safehasattr(revfctx, 'node')), | |
|
315 | stringutil.pprint(util.safehasattr(revfctx, b'node')), | |
|
316 | 316 | ) |
|
317 | 317 | ) |
|
318 | 318 | return self.annotatedirectly(revfctx, showpath, showlines) |
@@ -356,8 +356,8 b' class _annotatecontext(object):' | |||
|
356 | 356 | if masterfctx: |
|
357 | 357 | if masterfctx.rev() is None: |
|
358 | 358 | raise error.Abort( |
|
359 | _('cannot update linelog to wdir()'), | |
|
360 | hint=_('set fastannotate.mainbranch'), | |
|
359 | _(b'cannot update linelog to wdir()'), | |
|
360 | hint=_(b'set fastannotate.mainbranch'), | |
|
361 | 361 | ) |
|
362 | 362 | initvisit.append(masterfctx) |
|
363 | 363 | visit = initvisit[:] |
@@ -403,13 +403,13 b' class _annotatecontext(object):' | |||
|
403 | 403 | if self.ui.debugflag: |
|
404 | 404 | if newmainbranch: |
|
405 | 405 | self.ui.debug( |
|
406 | 'fastannotate: %s: %d new changesets in the main' | |
|
407 | ' branch\n' % (self.path, len(newmainbranch)) | |
|
406 | b'fastannotate: %s: %d new changesets in the main' | |
|
407 | b' branch\n' % (self.path, len(newmainbranch)) | |
|
408 | 408 | ) |
|
409 | 409 | elif not hist: # no joints, no updates |
|
410 | 410 | self.ui.debug( |
|
411 | 'fastannotate: %s: linelog cannot help in ' | |
|
412 | 'annotating this revision\n' % self.path | |
|
411 | b'fastannotate: %s: linelog cannot help in ' | |
|
412 | b'annotating this revision\n' % self.path | |
|
413 | 413 | ) |
|
414 | 414 | |
|
415 | 415 | # prepare annotateresult so we can update linelog incrementally |
@@ -418,7 +418,7 b' class _annotatecontext(object):' | |||
|
418 | 418 | # 3rd DFS does the actual annotate |
|
419 | 419 | visit = initvisit[:] |
|
420 | 420 | progress = self.ui.makeprogress( |
|
421 | 'building cache', total=len(newmainbranch) | |
|
421 | b'building cache', total=len(newmainbranch) | |
|
422 | 422 | ) |
|
423 | 423 | while visit: |
|
424 | 424 | f = visit[-1] |
@@ -463,7 +463,7 b' class _annotatecontext(object):' | |||
|
463 | 463 | if len(pl) == 2 and self.opts.followmerge: # merge |
|
464 | 464 | bannotated = curr[0] |
|
465 | 465 | if blocks is None: # no parents, add an empty one |
|
466 | blocks = list(self._diffblocks('', curr[1])) | |
|
466 | blocks = list(self._diffblocks(b'', curr[1])) | |
|
467 | 467 | self._appendrev(f, blocks, bannotated) |
|
468 | 468 | elif showpath: # not append linelog, but we need to record path |
|
469 | 469 | self._node2path[f.node()] = f.path() |
@@ -490,7 +490,7 b' class _annotatecontext(object):' | |||
|
490 | 490 | if hsh is not None and (hsh, self.path) in self.revmap: |
|
491 | 491 | f = hsh |
|
492 | 492 | if f is None: |
|
493 | adjustctx = 'linkrev' if self._perfhack else True | |
|
493 | adjustctx = b'linkrev' if self._perfhack else True | |
|
494 | 494 | f = self._resolvefctx(rev, adjustctx=adjustctx, resolverev=True) |
|
495 | 495 | result = f in self.revmap |
|
496 | 496 | if not result and self._perfhack: |
@@ -511,7 +511,7 b' class _annotatecontext(object):' | |||
|
511 | 511 | # find a chain from rev to anything in the mainbranch |
|
512 | 512 | if revfctx not in self.revmap: |
|
513 | 513 | chain = [revfctx] |
|
514 | a = '' | |
|
514 | a = b'' | |
|
515 | 515 | while True: |
|
516 | 516 | f = chain[-1] |
|
517 | 517 | pl = self._parentfunc(f) |
@@ -589,8 +589,8 b' class _annotatecontext(object):' | |||
|
589 | 589 | hsh = annotateresult[idxs[0]][0] |
|
590 | 590 | if self.ui.debugflag: |
|
591 | 591 | self.ui.debug( |
|
592 | 'fastannotate: reading %s line #%d ' | |
|
593 | 'to resolve lines %r\n' | |
|
592 | b'fastannotate: reading %s line #%d ' | |
|
593 | b'to resolve lines %r\n' | |
|
594 | 594 | % (node.short(hsh), linenum, idxs) |
|
595 | 595 | ) |
|
596 | 596 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
@@ -603,14 +603,15 b' class _annotatecontext(object):' | |||
|
603 | 603 | |
|
604 | 604 | # run the annotate and the lines should match to the file content |
|
605 | 605 | self.ui.debug( |
|
606 |
'fastannotate: annotate %s to resolve lines\n' |
|
|
606 | b'fastannotate: annotate %s to resolve lines\n' | |
|
607 | % node.short(hsh) | |
|
607 | 608 | ) |
|
608 | 609 | linelog.annotate(rev) |
|
609 | 610 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
|
610 | 611 | annotated = linelog.annotateresult |
|
611 | 612 | lines = mdiff.splitnewlines(fctx.data()) |
|
612 | 613 | if len(lines) != len(annotated): |
|
613 | raise faerror.CorruptedFileError('unexpected annotated lines') | |
|
614 | raise faerror.CorruptedFileError(b'unexpected annotated lines') | |
|
614 | 615 | # resolve lines from the annotate result |
|
615 | 616 | for i, line in enumerate(lines): |
|
616 | 617 | k = annotated[i] |
@@ -633,11 +634,11 b' class _annotatecontext(object):' | |||
|
633 | 634 | llrev = self.revmap.hsh2rev(hsh) |
|
634 | 635 | if not llrev: |
|
635 | 636 | raise faerror.CorruptedFileError( |
|
636 | '%s is not in revmap' % node.hex(hsh) | |
|
637 | b'%s is not in revmap' % node.hex(hsh) | |
|
637 | 638 | ) |
|
638 | 639 | if (self.revmap.rev2flag(llrev) & revmapmod.sidebranchflag) != 0: |
|
639 | 640 | raise faerror.CorruptedFileError( |
|
640 | '%s is not in revmap mainbranch' % node.hex(hsh) | |
|
641 | b'%s is not in revmap mainbranch' % node.hex(hsh) | |
|
641 | 642 | ) |
|
642 | 643 | self.linelog.annotate(llrev) |
|
643 | 644 | result = [ |
@@ -677,7 +678,7 b' class _annotatecontext(object):' | |||
|
677 | 678 | """(fctx) -> int""" |
|
678 | 679 | # f should not be a linelog revision |
|
679 | 680 | if isinstance(f, int): |
|
680 | raise error.ProgrammingError('f should not be an int') | |
|
681 | raise error.ProgrammingError(b'f should not be an int') | |
|
681 | 682 | # f is a fctx, allocate linelog rev on demand |
|
682 | 683 | hsh = f.node() |
|
683 | 684 | rev = revmap.hsh2rev(hsh) |
@@ -690,7 +691,7 b' class _annotatecontext(object):' | |||
|
690 | 691 | siderevmap = {} # node: int |
|
691 | 692 | if bannotated is not None: |
|
692 | 693 | for (a1, a2, b1, b2), op in blocks: |
|
693 | if op != '=': | |
|
694 | if op != b'=': | |
|
694 | 695 | # f could be either linelong rev, or fctx. |
|
695 | 696 | siderevs += [ |
|
696 | 697 | f |
@@ -708,7 +709,7 b' class _annotatecontext(object):' | |||
|
708 | 709 | siderevmap[fctx] = llrev |
|
709 | 710 | |
|
710 | 711 | for (a1, a2, b1, b2), op in reversed(blocks): |
|
711 | if op == '=': | |
|
712 | if op == b'=': | |
|
712 | 713 | continue |
|
713 | 714 | if bannotated is None: |
|
714 | 715 | linelog.replacelines(llrev, a1, a2, b1, b2) |
@@ -760,7 +761,7 b' class _annotatecontext(object):' | |||
|
760 | 761 | |
|
761 | 762 | @util.propertycache |
|
762 | 763 | def _perfhack(self): |
|
763 | return self.ui.configbool('fastannotate', 'perfhack') | |
|
764 | return self.ui.configbool(b'fastannotate', b'perfhack') | |
|
764 | 765 | |
|
765 | 766 | def _resolvefctx(self, rev, path=None, **kwds): |
|
766 | 767 | return resolvefctx(self.repo, rev, (path or self.path), **kwds) |
@@ -781,7 +782,7 b' class pathhelper(object):' | |||
|
781 | 782 | def __init__(self, repo, path, opts=defaultopts): |
|
782 | 783 | # different options use different directories |
|
783 | 784 | self._vfspath = os.path.join( |
|
784 | 'fastannotate', opts.shortstr, encodedir(path) | |
|
785 | b'fastannotate', opts.shortstr, encodedir(path) | |
|
785 | 786 | ) |
|
786 | 787 | self._repo = repo |
|
787 | 788 | |
@@ -791,14 +792,14 b' class pathhelper(object):' | |||
|
791 | 792 | |
|
792 | 793 | @property |
|
793 | 794 | def linelogpath(self): |
|
794 | return self._repo.vfs.join(self._vfspath + '.l') | |
|
795 | return self._repo.vfs.join(self._vfspath + b'.l') | |
|
795 | 796 | |
|
796 | 797 | def lock(self): |
|
797 | return lockmod.lock(self._repo.vfs, self._vfspath + '.lock') | |
|
798 | return lockmod.lock(self._repo.vfs, self._vfspath + b'.lock') | |
|
798 | 799 | |
|
799 | 800 | @property |
|
800 | 801 | def revmappath(self): |
|
801 | return self._repo.vfs.join(self._vfspath + '.m') | |
|
802 | return self._repo.vfs.join(self._vfspath + b'.m') | |
|
802 | 803 | |
|
803 | 804 | |
|
804 | 805 | @contextlib.contextmanager |
@@ -831,7 +832,7 b' def annotatecontext(repo, path, opts=def' | |||
|
831 | 832 | except Exception: |
|
832 | 833 | if actx is not None: |
|
833 | 834 | actx.rebuild() |
|
834 | repo.ui.debug('fastannotate: %s: cache broken and deleted\n' % path) | |
|
835 | repo.ui.debug(b'fastannotate: %s: cache broken and deleted\n' % path) | |
|
835 | 836 | raise |
|
836 | 837 | finally: |
|
837 | 838 | if actx is not None: |
@@ -844,7 +845,7 b' def fctxannotatecontext(fctx, follow=Tru' | |||
|
844 | 845 | """ |
|
845 | 846 | repo = fctx._repo |
|
846 | 847 | path = fctx._path |
|
847 | if repo.ui.configbool('fastannotate', 'forcefollow', True): | |
|
848 | if repo.ui.configbool(b'fastannotate', b'forcefollow', True): | |
|
848 | 849 | follow = True |
|
849 | 850 | aopts = annotateopts(diffopts=diffopts, followrename=follow) |
|
850 | 851 | return annotatecontext(repo, path, aopts, rebuild) |
@@ -33,35 +33,35 b' class defaultformatter(object):' | |||
|
33 | 33 | hexfunc = self._hexfunc |
|
34 | 34 | |
|
35 | 35 | # special handling working copy "changeset" and "rev" functions |
|
36 | if self.opts.get('rev') == 'wdir()': | |
|
36 | if self.opts.get(b'rev') == b'wdir()': | |
|
37 | 37 | orig = hexfunc |
|
38 | 38 | hexfunc = lambda x: None if x is None else orig(x) |
|
39 | wnode = hexfunc(repo['.'].node()) + '+' | |
|
40 | wrev = '%d' % repo['.'].rev() | |
|
41 | wrevpad = '' | |
|
42 | if not opts.get('changeset'): # only show + if changeset is hidden | |
|
43 | wrev += '+' | |
|
44 | wrevpad = ' ' | |
|
45 | revenc = lambda x: wrev if x is None else ('%d' % x) + wrevpad | |
|
39 | wnode = hexfunc(repo[b'.'].node()) + b'+' | |
|
40 | wrev = b'%d' % repo[b'.'].rev() | |
|
41 | wrevpad = b'' | |
|
42 | if not opts.get(b'changeset'): # only show + if changeset is hidden | |
|
43 | wrev += b'+' | |
|
44 | wrevpad = b' ' | |
|
45 | revenc = lambda x: wrev if x is None else (b'%d' % x) + wrevpad | |
|
46 | 46 | |
|
47 | 47 | def csetenc(x): |
|
48 | 48 | if x is None: |
|
49 | 49 | return wnode |
|
50 | return pycompat.bytestr(x) + ' ' | |
|
50 | return pycompat.bytestr(x) + b' ' | |
|
51 | 51 | |
|
52 | 52 | else: |
|
53 | 53 | revenc = csetenc = pycompat.bytestr |
|
54 | 54 | |
|
55 | 55 | # opt name, separator, raw value (for json/plain), encoder (for plain) |
|
56 | 56 | opmap = [ |
|
57 | ('user', ' ', lambda x: getctx(x).user(), ui.shortuser), | |
|
58 | ('number', ' ', lambda x: getctx(x).rev(), revenc), | |
|
59 | ('changeset', ' ', lambda x: hexfunc(x[0]), csetenc), | |
|
60 | ('date', ' ', lambda x: getctx(x).date(), datefunc), | |
|
61 | ('file', ' ', lambda x: x[2], pycompat.bytestr), | |
|
62 | ('line_number', ':', lambda x: x[1] + 1, pycompat.bytestr), | |
|
57 | (b'user', b' ', lambda x: getctx(x).user(), ui.shortuser), | |
|
58 | (b'number', b' ', lambda x: getctx(x).rev(), revenc), | |
|
59 | (b'changeset', b' ', lambda x: hexfunc(x[0]), csetenc), | |
|
60 | (b'date', b' ', lambda x: getctx(x).date(), datefunc), | |
|
61 | (b'file', b' ', lambda x: x[2], pycompat.bytestr), | |
|
62 | (b'line_number', b':', lambda x: x[1] + 1, pycompat.bytestr), | |
|
63 | 63 | ] |
|
64 | fieldnamemap = {'number': 'rev', 'changeset': 'node'} | |
|
64 | fieldnamemap = {b'number': b'rev', b'changeset': b'node'} | |
|
65 | 65 | funcmap = [ |
|
66 | 66 | (get, sep, fieldnamemap.get(op, op), enc) |
|
67 | 67 | for op, sep, get, enc in opmap |
@@ -69,7 +69,7 b' class defaultformatter(object):' | |||
|
69 | 69 | ] |
|
70 | 70 | # no separator for first column |
|
71 | 71 | funcmap[0] = list(funcmap[0]) |
|
72 | funcmap[0][1] = '' | |
|
72 | funcmap[0][1] = b'' | |
|
73 | 73 | self.funcmap = funcmap |
|
74 | 74 | |
|
75 | 75 | def write(self, annotatedresult, lines=None, existinglines=None): |
@@ -83,39 +83,39 b' class defaultformatter(object):' | |||
|
83 | 83 | for f, sep, name, enc in self.funcmap: |
|
84 | 84 | l = [enc(f(x)) for x in annotatedresult] |
|
85 | 85 | pieces.append(l) |
|
86 | if name in ['node', 'date']: # node and date has fixed size | |
|
86 | if name in [b'node', b'date']: # node and date has fixed size | |
|
87 | 87 | l = l[:1] |
|
88 | 88 | widths = pycompat.maplist(encoding.colwidth, set(l)) |
|
89 | 89 | maxwidth = max(widths) if widths else 0 |
|
90 | 90 | maxwidths.append(maxwidth) |
|
91 | 91 | |
|
92 | 92 | # buffered output |
|
93 | result = '' | |
|
93 | result = b'' | |
|
94 | 94 | for i in pycompat.xrange(len(annotatedresult)): |
|
95 | 95 | for j, p in enumerate(pieces): |
|
96 | 96 | sep = self.funcmap[j][1] |
|
97 | padding = ' ' * (maxwidths[j] - len(p[i])) | |
|
97 | padding = b' ' * (maxwidths[j] - len(p[i])) | |
|
98 | 98 | result += sep + padding + p[i] |
|
99 | 99 | if lines: |
|
100 | 100 | if existinglines is None: |
|
101 | result += ': ' + lines[i] | |
|
101 | result += b': ' + lines[i] | |
|
102 | 102 | else: # extra formatting showing whether a line exists |
|
103 | 103 | key = (annotatedresult[i][0], annotatedresult[i][1]) |
|
104 | 104 | if key in existinglines: |
|
105 | result += ': ' + lines[i] | |
|
105 | result += b': ' + lines[i] | |
|
106 | 106 | else: |
|
107 | result += ': ' + self.ui.label( | |
|
108 | '-' + lines[i], 'diff.deleted' | |
|
107 | result += b': ' + self.ui.label( | |
|
108 | b'-' + lines[i], b'diff.deleted' | |
|
109 | 109 | ) |
|
110 | 110 | |
|
111 | if result[-1:] != '\n': | |
|
112 | result += '\n' | |
|
111 | if result[-1:] != b'\n': | |
|
112 | result += b'\n' | |
|
113 | 113 | |
|
114 | 114 | self.ui.write(result) |
|
115 | 115 | |
|
116 | 116 | @util.propertycache |
|
117 | 117 | def _hexfunc(self): |
|
118 | if self.ui.debugflag or self.opts.get('long_hash'): | |
|
118 | if self.ui.debugflag or self.opts.get(b'long_hash'): | |
|
119 | 119 | return node.hex |
|
120 | 120 | else: |
|
121 | 121 | return node.short |
@@ -127,7 +127,7 b' class defaultformatter(object):' | |||
|
127 | 127 | class jsonformatter(defaultformatter): |
|
128 | 128 | def __init__(self, ui, repo, opts): |
|
129 | 129 | super(jsonformatter, self).__init__(ui, repo, opts) |
|
130 | self.ui.write('[') | |
|
130 | self.ui.write(b'[') | |
|
131 | 131 | self.needcomma = False |
|
132 | 132 | |
|
133 | 133 | def write(self, annotatedresult, lines=None, existinglines=None): |
@@ -139,23 +139,23 b' class jsonformatter(defaultformatter):' | |||
|
139 | 139 | for f, sep, name, enc in self.funcmap |
|
140 | 140 | ] |
|
141 | 141 | if lines is not None: |
|
142 | pieces.append(('line', lines)) | |
|
142 | pieces.append((b'line', lines)) | |
|
143 | 143 | pieces.sort() |
|
144 | 144 | |
|
145 | seps = [','] * len(pieces[:-1]) + [''] | |
|
145 | seps = [b','] * len(pieces[:-1]) + [b''] | |
|
146 | 146 | |
|
147 | result = '' | |
|
147 | result = b'' | |
|
148 | 148 | lasti = len(annotatedresult) - 1 |
|
149 | 149 | for i in pycompat.xrange(len(annotatedresult)): |
|
150 | result += '\n {\n' | |
|
150 | result += b'\n {\n' | |
|
151 | 151 | for j, p in enumerate(pieces): |
|
152 | 152 | k, vs = p |
|
153 | result += ' "%s": %s%s\n' % ( | |
|
153 | result += b' "%s": %s%s\n' % ( | |
|
154 | 154 | k, |
|
155 | 155 | templatefilters.json(vs[i], paranoid=False), |
|
156 | 156 | seps[j], |
|
157 | 157 | ) |
|
158 | result += ' }%s' % ('' if i == lasti else ',') | |
|
158 | result += b' }%s' % (b'' if i == lasti else b',') | |
|
159 | 159 | if lasti >= 0: |
|
160 | 160 | self.needcomma = True |
|
161 | 161 | |
@@ -163,7 +163,7 b' class jsonformatter(defaultformatter):' | |||
|
163 | 163 | |
|
164 | 164 | def _writecomma(self): |
|
165 | 165 | if self.needcomma: |
|
166 | self.ui.write(',') | |
|
166 | self.ui.write(b',') | |
|
167 | 167 | self.needcomma = False |
|
168 | 168 | |
|
169 | 169 | @util.propertycache |
@@ -171,4 +171,4 b' class jsonformatter(defaultformatter):' | |||
|
171 | 171 | return node.hex |
|
172 | 172 | |
|
173 | 173 | def end(self): |
|
174 | self.ui.write('\n]\n') | |
|
174 | self.ui.write(b'\n]\n') |
@@ -25,12 +25,12 b' from . import context' | |||
|
25 | 25 | |
|
26 | 26 | def _getmaster(ui): |
|
27 | 27 | """get the mainbranch, and enforce it is set""" |
|
28 | master = ui.config('fastannotate', 'mainbranch') | |
|
28 | master = ui.config(b'fastannotate', b'mainbranch') | |
|
29 | 29 | if not master: |
|
30 | 30 | raise error.Abort( |
|
31 | 31 | _( |
|
32 | 'fastannotate.mainbranch is required ' | |
|
33 | 'for both the client and the server' | |
|
32 | b'fastannotate.mainbranch is required ' | |
|
33 | b'for both the client and the server' | |
|
34 | 34 | ) |
|
35 | 35 | ) |
|
36 | 36 | return master |
@@ -41,7 +41,7 b' def _getmaster(ui):' | |||
|
41 | 41 | |
|
42 | 42 | def _capabilities(orig, repo, proto): |
|
43 | 43 | result = orig(repo, proto) |
|
44 | result.append('getannotate') | |
|
44 | result.append(b'getannotate') | |
|
45 | 45 | return result |
|
46 | 46 | |
|
47 | 47 | |
@@ -49,9 +49,9 b' def _getannotate(repo, proto, path, last' | |||
|
49 | 49 | # output: |
|
50 | 50 | # FILE := vfspath + '\0' + str(size) + '\0' + content |
|
51 | 51 | # OUTPUT := '' | FILE + OUTPUT |
|
52 | result = '' | |
|
52 | result = b'' | |
|
53 | 53 | buildondemand = repo.ui.configbool( |
|
54 | 'fastannotate', 'serverbuildondemand', True | |
|
54 | b'fastannotate', b'serverbuildondemand', True | |
|
55 | 55 | ) |
|
56 | 56 | with context.annotatecontext(repo, path) as actx: |
|
57 | 57 | if buildondemand: |
@@ -80,25 +80,25 b' def _getannotate(repo, proto, path, last' | |||
|
80 | 80 | for p in [actx.revmappath, actx.linelogpath]: |
|
81 | 81 | if not os.path.exists(p): |
|
82 | 82 | continue |
|
83 | with open(p, 'rb') as f: | |
|
83 | with open(p, b'rb') as f: | |
|
84 | 84 | content = f.read() |
|
85 | vfsbaselen = len(repo.vfs.base + '/') | |
|
85 | vfsbaselen = len(repo.vfs.base + b'/') | |
|
86 | 86 | relpath = p[vfsbaselen:] |
|
87 | result += '%s\0%d\0%s' % (relpath, len(content), content) | |
|
87 | result += b'%s\0%d\0%s' % (relpath, len(content), content) | |
|
88 | 88 | return result |
|
89 | 89 | |
|
90 | 90 | |
|
91 | 91 | def _registerwireprotocommand(): |
|
92 | if 'getannotate' in wireprotov1server.commands: | |
|
92 | if b'getannotate' in wireprotov1server.commands: | |
|
93 | 93 | return |
|
94 | wireprotov1server.wireprotocommand('getannotate', 'path lastnode')( | |
|
94 | wireprotov1server.wireprotocommand(b'getannotate', b'path lastnode')( | |
|
95 | 95 | _getannotate |
|
96 | 96 | ) |
|
97 | 97 | |
|
98 | 98 | |
|
99 | 99 | def serveruisetup(ui): |
|
100 | 100 | _registerwireprotocommand() |
|
101 | extensions.wrapfunction(wireprotov1server, '_capabilities', _capabilities) | |
|
101 | extensions.wrapfunction(wireprotov1server, b'_capabilities', _capabilities) | |
|
102 | 102 | |
|
103 | 103 | |
|
104 | 104 | # client-side |
@@ -109,15 +109,15 b' def _parseresponse(payload):' | |||
|
109 | 109 | i = 0 |
|
110 | 110 | l = len(payload) - 1 |
|
111 | 111 | state = 0 # 0: vfspath, 1: size |
|
112 | vfspath = size = '' | |
|
112 | vfspath = size = b'' | |
|
113 | 113 | while i < l: |
|
114 | 114 | ch = payload[i : i + 1] |
|
115 | if ch == '\0': | |
|
115 | if ch == b'\0': | |
|
116 | 116 | if state == 1: |
|
117 | 117 | result[vfspath] = payload[i + 1 : i + 1 + int(size)] |
|
118 | 118 | i += int(size) |
|
119 | 119 | state = 0 |
|
120 | vfspath = size = '' | |
|
120 | vfspath = size = b'' | |
|
121 | 121 | elif state == 0: |
|
122 | 122 | state = 1 |
|
123 | 123 | else: |
@@ -133,11 +133,11 b' def peersetup(ui, peer):' | |||
|
133 | 133 | class fastannotatepeer(peer.__class__): |
|
134 | 134 | @wireprotov1peer.batchable |
|
135 | 135 | def getannotate(self, path, lastnode=None): |
|
136 | if not self.capable('getannotate'): | |
|
137 | ui.warn(_('remote peer cannot provide annotate cache\n')) | |
|
136 | if not self.capable(b'getannotate'): | |
|
137 | ui.warn(_(b'remote peer cannot provide annotate cache\n')) | |
|
138 | 138 | yield None, None |
|
139 | 139 | else: |
|
140 | args = {'path': path, 'lastnode': lastnode or ''} | |
|
140 | args = {b'path': path, b'lastnode': lastnode or b''} | |
|
141 | 141 | f = wireprotov1peer.future() |
|
142 | 142 | yield args, f |
|
143 | 143 | yield _parseresponse(f.value) |
@@ -150,7 +150,7 b' def annotatepeer(repo):' | |||
|
150 | 150 | ui = repo.ui |
|
151 | 151 | |
|
152 | 152 | remotepath = ui.expandpath( |
|
153 | ui.config('fastannotate', 'remotepath', 'default') | |
|
153 | ui.config(b'fastannotate', b'remotepath', b'default') | |
|
154 | 154 | ) |
|
155 | 155 | peer = hg.peer(ui, {}, remotepath) |
|
156 | 156 | |
@@ -175,11 +175,12 b' def clientfetch(repo, paths, lastnodemap' | |||
|
175 | 175 | ui = repo.ui |
|
176 | 176 | results = [] |
|
177 | 177 | with peer.commandexecutor() as batcher: |
|
178 | ui.debug('fastannotate: requesting %d files\n' % len(paths)) | |
|
178 | ui.debug(b'fastannotate: requesting %d files\n' % len(paths)) | |
|
179 | 179 | for p in paths: |
|
180 | 180 | results.append( |
|
181 | 181 | batcher.callcommand( |
|
182 |
'getannotate', |
|
|
182 | b'getannotate', | |
|
183 | {b'path': p, b'lastnode': lastnodemap.get(p)}, | |
|
183 | 184 | ) |
|
184 | 185 | ) |
|
185 | 186 | |
@@ -189,19 +190,21 b' def clientfetch(repo, paths, lastnodemap' | |||
|
189 | 190 | r = {util.pconvert(p): v for p, v in r.iteritems()} |
|
190 | 191 | for path in sorted(r): |
|
191 | 192 | # ignore malicious paths |
|
192 | if not path.startswith('fastannotate/') or '/../' in ( | |
|
193 | path + '/' | |
|
193 | if not path.startswith(b'fastannotate/') or b'/../' in ( | |
|
194 | path + b'/' | |
|
194 | 195 | ): |
|
195 | ui.debug('fastannotate: ignored malicious path %s\n' % path) | |
|
196 | ui.debug( | |
|
197 | b'fastannotate: ignored malicious path %s\n' % path | |
|
198 | ) | |
|
196 | 199 | continue |
|
197 | 200 | content = r[path] |
|
198 | 201 | if ui.debugflag: |
|
199 | 202 | ui.debug( |
|
200 | 'fastannotate: writing %d bytes to %s\n' | |
|
203 | b'fastannotate: writing %d bytes to %s\n' | |
|
201 | 204 | % (len(content), path) |
|
202 | 205 | ) |
|
203 | 206 | repo.vfs.makedirs(os.path.dirname(path)) |
|
204 | with repo.vfs(path, 'wb') as f: | |
|
207 | with repo.vfs(path, b'wb') as f: | |
|
205 | 208 | f.write(content) |
|
206 | 209 | |
|
207 | 210 | |
@@ -209,7 +212,7 b' def _filterfetchpaths(repo, paths):' | |||
|
209 | 212 | """return a subset of paths whose history is long and need to fetch linelog |
|
210 | 213 | from the server. works with remotefilelog and non-remotefilelog repos. |
|
211 | 214 | """ |
|
212 | threshold = repo.ui.configint('fastannotate', 'clientfetchthreshold', 10) | |
|
215 | threshold = repo.ui.configint(b'fastannotate', b'clientfetchthreshold', 10) | |
|
213 | 216 | if threshold <= 0: |
|
214 | 217 | return paths |
|
215 | 218 | |
@@ -240,7 +243,7 b' def localreposetup(ui, repo):' | |||
|
240 | 243 | clientfetch(self, needupdatepaths, lastnodemap, peer) |
|
241 | 244 | except Exception as ex: |
|
242 | 245 | # could be directory not writable or so, not fatal |
|
243 | self.ui.debug('fastannotate: prefetch failed: %r\n' % ex) | |
|
246 | self.ui.debug(b'fastannotate: prefetch failed: %r\n' % ex) | |
|
244 | 247 | |
|
245 | 248 | repo.__class__ = fastannotaterepo |
|
246 | 249 |
@@ -70,7 +70,7 b' class revmap(object):' | |||
|
70 | 70 | # since rename does not happen frequently, do not store path for every |
|
71 | 71 | # revision. self._renamerevs can be used for bisecting. |
|
72 | 72 | self._renamerevs = [0] |
|
73 | self._renamepaths = [''] | |
|
73 | self._renamepaths = [b''] | |
|
74 | 74 | self._lastmaxrev = -1 |
|
75 | 75 | if path: |
|
76 | 76 | if os.path.exists(path): |
@@ -98,9 +98,13 b' class revmap(object):' | |||
|
98 | 98 | if flush is True, incrementally update the file. |
|
99 | 99 | """ |
|
100 | 100 | if hsh in self._hsh2rev: |
|
101 |
raise error.CorruptedFileError( |
|
|
101 | raise error.CorruptedFileError( | |
|
102 | b'%r is in revmap already' % hex(hsh) | |
|
103 | ) | |
|
102 | 104 | if len(hsh) != _hshlen: |
|
103 |
raise hgerror.ProgrammingError( |
|
|
105 | raise hgerror.ProgrammingError( | |
|
106 | b'hsh must be %d-char long' % _hshlen | |
|
107 | ) | |
|
104 | 108 | idx = len(self._rev2hsh) |
|
105 | 109 | flag = 0 |
|
106 | 110 | if sidebranch: |
@@ -149,7 +153,7 b' class revmap(object):' | |||
|
149 | 153 | self._rev2hsh = [None] |
|
150 | 154 | self._rev2flag = [None] |
|
151 | 155 | self._hsh2rev = {} |
|
152 | self._rev2path = [''] | |
|
156 | self._rev2path = [b''] | |
|
153 | 157 | self._lastmaxrev = -1 |
|
154 | 158 | if flush: |
|
155 | 159 | self.flush() |
@@ -159,12 +163,12 b' class revmap(object):' | |||
|
159 | 163 | if not self.path: |
|
160 | 164 | return |
|
161 | 165 | if self._lastmaxrev == -1: # write the entire file |
|
162 | with open(self.path, 'wb') as f: | |
|
166 | with open(self.path, b'wb') as f: | |
|
163 | 167 | f.write(self.HEADER) |
|
164 | 168 | for i in pycompat.xrange(1, len(self._rev2hsh)): |
|
165 | 169 | self._writerev(i, f) |
|
166 | 170 | else: # append incrementally |
|
167 | with open(self.path, 'ab') as f: | |
|
171 | with open(self.path, b'ab') as f: | |
|
168 | 172 | for i in pycompat.xrange( |
|
169 | 173 | self._lastmaxrev + 1, len(self._rev2hsh) |
|
170 | 174 | ): |
@@ -179,7 +183,7 b' class revmap(object):' | |||
|
179 | 183 | # which is faster than both LOAD_CONST and LOAD_GLOBAL. |
|
180 | 184 | flaglen = 1 |
|
181 | 185 | hshlen = _hshlen |
|
182 | with open(self.path, 'rb') as f: | |
|
186 | with open(self.path, b'rb') as f: | |
|
183 | 187 | if f.read(len(self.HEADER)) != self.HEADER: |
|
184 | 188 | raise error.CorruptedFileError() |
|
185 | 189 | self.clear(flush=False) |
@@ -205,23 +209,23 b' class revmap(object):' | |||
|
205 | 209 | """append a revision data to file""" |
|
206 | 210 | flag = self._rev2flag[rev] |
|
207 | 211 | hsh = self._rev2hsh[rev] |
|
208 | f.write(struct.pack('B', flag)) | |
|
212 | f.write(struct.pack(b'B', flag)) | |
|
209 | 213 | if flag & renameflag: |
|
210 | 214 | path = self.rev2path(rev) |
|
211 | 215 | if path is None: |
|
212 | raise error.CorruptedFileError('cannot find path for %s' % rev) | |
|
216 | raise error.CorruptedFileError(b'cannot find path for %s' % rev) | |
|
213 | 217 | f.write(path + b'\0') |
|
214 | 218 | f.write(hsh) |
|
215 | 219 | |
|
216 | 220 | @staticmethod |
|
217 | 221 | def _readcstr(f): |
|
218 | 222 | """read a C-language-like '\0'-terminated string""" |
|
219 | buf = '' | |
|
223 | buf = b'' | |
|
220 | 224 | while True: |
|
221 | 225 | ch = f.read(1) |
|
222 | 226 | if not ch: # unexpected eof |
|
223 | 227 | raise error.CorruptedFileError() |
|
224 | if ch == '\0': | |
|
228 | if ch == b'\0': | |
|
225 | 229 | break |
|
226 | 230 | buf += ch |
|
227 | 231 | return buf |
@@ -249,7 +253,7 b' def getlastnode(path):' | |||
|
249 | 253 | """ |
|
250 | 254 | hsh = None |
|
251 | 255 | try: |
|
252 | with open(path, 'rb') as f: | |
|
256 | with open(path, b'rb') as f: | |
|
253 | 257 | f.seek(-_hshlen, io.SEEK_END) |
|
254 | 258 | if f.tell() > len(revmap.HEADER): |
|
255 | 259 | hsh = f.read(_hshlen) |
@@ -64,7 +64,7 b' def _convertoutputs(repo, annotated, con' | |||
|
64 | 64 | |
|
65 | 65 | def _getmaster(fctx): |
|
66 | 66 | """(fctx) -> str""" |
|
67 | return fctx._repo.ui.config('fastannotate', 'mainbranch') or 'default' | |
|
67 | return fctx._repo.ui.config(b'fastannotate', b'mainbranch') or b'default' | |
|
68 | 68 | |
|
69 | 69 | |
|
70 | 70 | def _doannotate(fctx, follow=True, diffopts=None): |
@@ -83,7 +83,7 b' def _doannotate(fctx, follow=True, diffo' | |||
|
83 | 83 | except Exception: |
|
84 | 84 | ac.rebuild() # try rebuild once |
|
85 | 85 | fctx._repo.ui.debug( |
|
86 | 'fastannotate: %s: rebuilding broken cache\n' % fctx._path | |
|
86 | b'fastannotate: %s: rebuilding broken cache\n' % fctx._path | |
|
87 | 87 | ) |
|
88 | 88 | try: |
|
89 | 89 | annotated, contents = ac.annotate( |
@@ -98,7 +98,7 b' def _doannotate(fctx, follow=True, diffo' | |||
|
98 | 98 | |
|
99 | 99 | def _hgwebannotate(orig, fctx, ui): |
|
100 | 100 | diffopts = patch.difffeatureopts( |
|
101 | ui, untrusted=True, section='annotate', whitespace=True | |
|
101 | ui, untrusted=True, section=b'annotate', whitespace=True | |
|
102 | 102 | ) |
|
103 | 103 | return _doannotate(fctx, diffopts=diffopts) |
|
104 | 104 | |
@@ -115,7 +115,7 b' def _fctxannotate(' | |||
|
115 | 115 | return _doannotate(self, follow, diffopts) |
|
116 | 116 | except Exception as ex: |
|
117 | 117 | self._repo.ui.debug( |
|
118 | 'fastannotate: falling back to the vanilla ' 'annotate: %r\n' % ex | |
|
118 | b'fastannotate: falling back to the vanilla ' b'annotate: %r\n' % ex | |
|
119 | 119 | ) |
|
120 | 120 | return orig(self, follow=follow, skiprevs=skiprevs, diffopts=diffopts) |
|
121 | 121 | |
@@ -130,8 +130,8 b' def _remotefctxannotate(orig, self, foll' | |||
|
130 | 130 | |
|
131 | 131 | |
|
132 | 132 | def replacehgwebannotate(): |
|
133 | extensions.wrapfunction(hgweb.webutil, 'annotate', _hgwebannotate) | |
|
133 | extensions.wrapfunction(hgweb.webutil, b'annotate', _hgwebannotate) | |
|
134 | 134 | |
|
135 | 135 | |
|
136 | 136 | def replacefctxannotate(): |
|
137 | extensions.wrapfunction(hgcontext.basefilectx, 'annotate', _fctxannotate) | |
|
137 | extensions.wrapfunction(hgcontext.basefilectx, b'annotate', _fctxannotate) |
@@ -30,30 +30,30 b' command = registrar.command(cmdtable)' | |||
|
30 | 30 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
31 | 31 | # be specifying the version(s) of Mercurial they are tested with, or |
|
32 | 32 | # leave the attribute unspecified. |
|
33 | testedwith = 'ships-with-hg-core' | |
|
33 | testedwith = b'ships-with-hg-core' | |
|
34 | 34 | |
|
35 | 35 | |
|
36 | 36 | @command( |
|
37 | 'fetch', | |
|
37 | b'fetch', | |
|
38 | 38 | [ |
|
39 | 39 | ( |
|
40 | 'r', | |
|
41 | 'rev', | |
|
40 | b'r', | |
|
41 | b'rev', | |
|
42 | 42 | [], |
|
43 | _('a specific revision you would like to pull'), | |
|
44 | _('REV'), | |
|
43 | _(b'a specific revision you would like to pull'), | |
|
44 | _(b'REV'), | |
|
45 | 45 | ), |
|
46 | ('', 'edit', None, _('invoke editor on commit messages')), | |
|
47 | ('', 'force-editor', None, _('edit commit message (DEPRECATED)')), | |
|
48 | ('', 'switch-parent', None, _('switch parents when merging')), | |
|
46 | (b'', b'edit', None, _(b'invoke editor on commit messages')), | |
|
47 | (b'', b'force-editor', None, _(b'edit commit message (DEPRECATED)')), | |
|
48 | (b'', b'switch-parent', None, _(b'switch parents when merging')), | |
|
49 | 49 | ] |
|
50 | 50 | + cmdutil.commitopts |
|
51 | 51 | + cmdutil.commitopts2 |
|
52 | 52 | + cmdutil.remoteopts, |
|
53 | _('hg fetch [SOURCE]'), | |
|
53 | _(b'hg fetch [SOURCE]'), | |
|
54 | 54 | helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT, |
|
55 | 55 | ) |
|
56 | def fetch(ui, repo, source='default', **opts): | |
|
56 | def fetch(ui, repo, source=b'default', **opts): | |
|
57 | 57 | '''pull changes from a remote repository, merge new changes if needed. |
|
58 | 58 | |
|
59 | 59 | This finds all changes from the repository at the specified path |
@@ -74,9 +74,9 b" def fetch(ui, repo, source='default', **" | |||
|
74 | 74 | ''' |
|
75 | 75 | |
|
76 | 76 | opts = pycompat.byteskwargs(opts) |
|
77 | date = opts.get('date') | |
|
77 | date = opts.get(b'date') | |
|
78 | 78 | if date: |
|
79 | opts['date'] = dateutil.parsedate(date) | |
|
79 | opts[b'date'] = dateutil.parsedate(date) | |
|
80 | 80 | |
|
81 | 81 | parent = repo.dirstate.p1() |
|
82 | 82 | branch = repo.dirstate.branch() |
@@ -86,8 +86,8 b" def fetch(ui, repo, source='default', **" | |||
|
86 | 86 | branchnode = None |
|
87 | 87 | if parent != branchnode: |
|
88 | 88 | raise error.Abort( |
|
89 | _('working directory not at branch tip'), | |
|
90 | hint=_("use 'hg update' to check out branch tip"), | |
|
89 | _(b'working directory not at branch tip'), | |
|
90 | hint=_(b"use 'hg update' to check out branch tip"), | |
|
91 | 91 | ) |
|
92 | 92 | |
|
93 | 93 | wlock = lock = None |
@@ -102,23 +102,23 b" def fetch(ui, repo, source='default', **" | |||
|
102 | 102 | if len(bheads) > 1: |
|
103 | 103 | raise error.Abort( |
|
104 | 104 | _( |
|
105 | 'multiple heads in this branch ' | |
|
106 | '(use "hg heads ." and "hg merge" to merge)' | |
|
105 | b'multiple heads in this branch ' | |
|
106 | b'(use "hg heads ." and "hg merge" to merge)' | |
|
107 | 107 | ) |
|
108 | 108 | ) |
|
109 | 109 | |
|
110 | 110 | other = hg.peer(repo, opts, ui.expandpath(source)) |
|
111 | 111 | ui.status( |
|
112 | _('pulling from %s\n') % util.hidepassword(ui.expandpath(source)) | |
|
112 | _(b'pulling from %s\n') % util.hidepassword(ui.expandpath(source)) | |
|
113 | 113 | ) |
|
114 | 114 | revs = None |
|
115 | if opts['rev']: | |
|
115 | if opts[b'rev']: | |
|
116 | 116 | try: |
|
117 | revs = [other.lookup(rev) for rev in opts['rev']] | |
|
117 | revs = [other.lookup(rev) for rev in opts[b'rev']] | |
|
118 | 118 | except error.CapabilityError: |
|
119 | 119 | err = _( |
|
120 | "other repository doesn't support revision lookup, " | |
|
121 | "so a rev cannot be specified." | |
|
120 | b"other repository doesn't support revision lookup, " | |
|
121 | b"so a rev cannot be specified." | |
|
122 | 122 | ) |
|
123 | 123 | raise error.Abort(err) |
|
124 | 124 | |
@@ -146,8 +146,8 b" def fetch(ui, repo, source='default', **" | |||
|
146 | 146 | if len(newheads) > 1: |
|
147 | 147 | ui.status( |
|
148 | 148 | _( |
|
149 | 'not merging with %d other new branch heads ' | |
|
150 | '(use "hg heads ." and "hg merge" to merge them)\n' | |
|
149 | b'not merging with %d other new branch heads ' | |
|
150 | b'(use "hg heads ." and "hg merge" to merge them)\n' | |
|
151 | 151 | ) |
|
152 | 152 | % (len(newheads) - 1) |
|
153 | 153 | ) |
@@ -162,17 +162,17 b" def fetch(ui, repo, source='default', **" | |||
|
162 | 162 | # By default, we consider the repository we're pulling |
|
163 | 163 | # *from* as authoritative, so we merge our changes into |
|
164 | 164 | # theirs. |
|
165 | if opts['switch_parent']: | |
|
165 | if opts[b'switch_parent']: | |
|
166 | 166 | firstparent, secondparent = newparent, newheads[0] |
|
167 | 167 | else: |
|
168 | 168 | firstparent, secondparent = newheads[0], newparent |
|
169 | 169 | ui.status( |
|
170 | _('updating to %d:%s\n') | |
|
170 | _(b'updating to %d:%s\n') | |
|
171 | 171 | % (repo.changelog.rev(firstparent), short(firstparent)) |
|
172 | 172 | ) |
|
173 | 173 | hg.clean(repo, firstparent) |
|
174 | 174 | ui.status( |
|
175 | _('merging with %d:%s\n') | |
|
175 | _(b'merging with %d:%s\n') | |
|
176 | 176 | % (repo.changelog.rev(secondparent), short(secondparent)) |
|
177 | 177 | ) |
|
178 | 178 | err = hg.merge(repo, secondparent, remind=False) |
@@ -180,13 +180,15 b" def fetch(ui, repo, source='default', **" | |||
|
180 | 180 | if not err: |
|
181 | 181 | # we don't translate commit messages |
|
182 | 182 | message = cmdutil.logmessage(ui, opts) or ( |
|
183 | 'Automated merge with %s' % util.removeauth(other.url()) | |
|
183 | b'Automated merge with %s' % util.removeauth(other.url()) | |
|
184 | 184 | ) |
|
185 | editopt = opts.get('edit') or opts.get('force_editor') | |
|
186 | editor = cmdutil.getcommiteditor(edit=editopt, editform='fetch') | |
|
187 | n = repo.commit(message, opts['user'], opts['date'], editor=editor) | |
|
185 | editopt = opts.get(b'edit') or opts.get(b'force_editor') | |
|
186 | editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch') | |
|
187 | n = repo.commit( | |
|
188 | message, opts[b'user'], opts[b'date'], editor=editor | |
|
189 | ) | |
|
188 | 190 | ui.status( |
|
189 | _('new changeset %d:%s merges remote changes ' 'with local\n') | |
|
191 | _(b'new changeset %d:%s merges remote changes ' b'with local\n') | |
|
190 | 192 | % (repo.changelog.rev(n), short(n)) |
|
191 | 193 | ) |
|
192 | 194 |
@@ -157,7 +157,7 b' from mercurial import (' | |||
|
157 | 157 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
158 | 158 | # be specifying the version(s) of Mercurial they are tested with, or |
|
159 | 159 | # leave the attribute unspecified. |
|
160 | testedwith = 'ships-with-hg-core' | |
|
160 | testedwith = b'ships-with-hg-core' | |
|
161 | 161 | |
|
162 | 162 | cmdtable = {} |
|
163 | 163 | command = registrar.command(cmdtable) |
@@ -167,61 +167,61 b' configitem = registrar.configitem(config' | |||
|
167 | 167 | |
|
168 | 168 | # Register the suboptions allowed for each configured fixer, and default values. |
|
169 | 169 | FIXER_ATTRS = { |
|
170 | 'command': None, | |
|
171 | 'linerange': None, | |
|
172 | 'pattern': None, | |
|
173 | 'priority': 0, | |
|
174 | 'metadata': 'false', | |
|
175 | 'skipclean': 'true', | |
|
176 | 'enabled': 'true', | |
|
170 | b'command': None, | |
|
171 | b'linerange': None, | |
|
172 | b'pattern': None, | |
|
173 | b'priority': 0, | |
|
174 | b'metadata': b'false', | |
|
175 | b'skipclean': b'true', | |
|
176 | b'enabled': b'true', | |
|
177 | 177 | } |
|
178 | 178 | |
|
179 | 179 | for key, default in FIXER_ATTRS.items(): |
|
180 | configitem('fix', '.*(:%s)?' % key, default=default, generic=True) | |
|
180 | configitem(b'fix', b'.*(:%s)?' % key, default=default, generic=True) | |
|
181 | 181 | |
|
182 | 182 | # A good default size allows most source code files to be fixed, but avoids |
|
183 | 183 | # letting fixer tools choke on huge inputs, which could be surprising to the |
|
184 | 184 | # user. |
|
185 | configitem('fix', 'maxfilesize', default='2MB') | |
|
185 | configitem(b'fix', b'maxfilesize', default=b'2MB') | |
|
186 | 186 | |
|
187 | 187 | # Allow fix commands to exit non-zero if an executed fixer tool exits non-zero. |
|
188 | 188 | # This helps users do shell scripts that stop when a fixer tool signals a |
|
189 | 189 | # problem. |
|
190 | configitem('fix', 'failure', default='continue') | |
|
190 | configitem(b'fix', b'failure', default=b'continue') | |
|
191 | 191 | |
|
192 | 192 | |
|
193 | 193 | def checktoolfailureaction(ui, message, hint=None): |
|
194 | 194 | """Abort with 'message' if fix.failure=abort""" |
|
195 | action = ui.config('fix', 'failure') | |
|
196 | if action not in ('continue', 'abort'): | |
|
195 | action = ui.config(b'fix', b'failure') | |
|
196 | if action not in (b'continue', b'abort'): | |
|
197 | 197 | raise error.Abort( |
|
198 | _('unknown fix.failure action: %s') % (action,), | |
|
199 | hint=_('use "continue" or "abort"'), | |
|
198 | _(b'unknown fix.failure action: %s') % (action,), | |
|
199 | hint=_(b'use "continue" or "abort"'), | |
|
200 | 200 | ) |
|
201 | if action == 'abort': | |
|
201 | if action == b'abort': | |
|
202 | 202 | raise error.Abort(message, hint=hint) |
|
203 | 203 | |
|
204 | 204 | |
|
205 | allopt = ('', 'all', False, _('fix all non-public non-obsolete revisions')) | |
|
205 | allopt = (b'', b'all', False, _(b'fix all non-public non-obsolete revisions')) | |
|
206 | 206 | baseopt = ( |
|
207 | '', | |
|
208 | 'base', | |
|
207 | b'', | |
|
208 | b'base', | |
|
209 | 209 | [], |
|
210 | 210 | _( |
|
211 | 'revisions to diff against (overrides automatic ' | |
|
212 | 'selection, and applies to every revision being ' | |
|
213 | 'fixed)' | |
|
211 | b'revisions to diff against (overrides automatic ' | |
|
212 | b'selection, and applies to every revision being ' | |
|
213 | b'fixed)' | |
|
214 | 214 | ), |
|
215 | _('REV'), | |
|
215 | _(b'REV'), | |
|
216 | 216 | ) |
|
217 | revopt = ('r', 'rev', [], _('revisions to fix'), _('REV')) | |
|
218 | wdiropt = ('w', 'working-dir', False, _('fix the working directory')) | |
|
219 | wholeopt = ('', 'whole', False, _('always fix every line of a file')) | |
|
220 | usage = _('[OPTION]... [FILE]...') | |
|
217 | revopt = (b'r', b'rev', [], _(b'revisions to fix'), _(b'REV')) | |
|
218 | wdiropt = (b'w', b'working-dir', False, _(b'fix the working directory')) | |
|
219 | wholeopt = (b'', b'whole', False, _(b'always fix every line of a file')) | |
|
220 | usage = _(b'[OPTION]... [FILE]...') | |
|
221 | 221 | |
|
222 | 222 | |
|
223 | 223 | @command( |
|
224 | 'fix', | |
|
224 | b'fix', | |
|
225 | 225 | [allopt, baseopt, revopt, wdiropt, wholeopt], |
|
226 | 226 | usage, |
|
227 | 227 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
@@ -250,12 +250,12 b' def fix(ui, repo, *pats, **opts):' | |||
|
250 | 250 | override this default behavior, though it is not usually desirable to do so. |
|
251 | 251 | """ |
|
252 | 252 | opts = pycompat.byteskwargs(opts) |
|
253 | if opts['all']: | |
|
254 | if opts['rev']: | |
|
255 | raise error.Abort(_('cannot specify both "--rev" and "--all"')) | |
|
256 | opts['rev'] = ['not public() and not obsolete()'] | |
|
257 | opts['working_dir'] = True | |
|
258 | with repo.wlock(), repo.lock(), repo.transaction('fix'): | |
|
253 | if opts[b'all']: | |
|
254 | if opts[b'rev']: | |
|
255 | raise error.Abort(_(b'cannot specify both "--rev" and "--all"')) | |
|
256 | opts[b'rev'] = [b'not public() and not obsolete()'] | |
|
257 | opts[b'working_dir'] = True | |
|
258 | with repo.wlock(), repo.lock(), repo.transaction(b'fix'): | |
|
259 | 259 | revstofix = getrevstofix(ui, repo, opts) |
|
260 | 260 | basectxs = getbasectxs(repo, opts, revstofix) |
|
261 | 261 | workqueue, numitems = getworkqueue( |
@@ -297,7 +297,7 b' def fix(ui, repo, *pats, **opts):' | |||
|
297 | 297 | wdirwritten = False |
|
298 | 298 | commitorder = sorted(revstofix, reverse=True) |
|
299 | 299 | with ui.makeprogress( |
|
300 | topic=_('fixing'), unit=_('files'), total=sum(numitems.values()) | |
|
300 | topic=_(b'fixing'), unit=_(b'files'), total=sum(numitems.values()) | |
|
301 | 301 | ) as progress: |
|
302 | 302 | for rev, path, filerevmetadata, newdata in results: |
|
303 | 303 | progress.increment(item=path) |
@@ -306,12 +306,12 b' def fix(ui, repo, *pats, **opts):' | |||
|
306 | 306 | if newdata is not None: |
|
307 | 307 | filedata[rev][path] = newdata |
|
308 | 308 | hookargs = { |
|
309 | 'rev': rev, | |
|
310 | 'path': path, | |
|
311 | 'metadata': filerevmetadata, | |
|
309 | b'rev': rev, | |
|
310 | b'path': path, | |
|
311 | b'metadata': filerevmetadata, | |
|
312 | 312 | } |
|
313 | 313 | repo.hook( |
|
314 | 'postfixfile', | |
|
314 | b'postfixfile', | |
|
315 | 315 | throw=False, |
|
316 | 316 | **pycompat.strkwargs(hookargs) |
|
317 | 317 | ) |
@@ -332,11 +332,11 b' def fix(ui, repo, *pats, **opts):' | |||
|
332 | 332 | |
|
333 | 333 | cleanup(repo, replacements, wdirwritten) |
|
334 | 334 | hookargs = { |
|
335 | 'replacements': replacements, | |
|
336 | 'wdirwritten': wdirwritten, | |
|
337 | 'metadata': aggregatemetadata, | |
|
335 | b'replacements': replacements, | |
|
336 | b'wdirwritten': wdirwritten, | |
|
337 | b'metadata': aggregatemetadata, | |
|
338 | 338 | } |
|
339 | repo.hook('postfix', throw=True, **pycompat.strkwargs(hookargs)) | |
|
339 | repo.hook(b'postfix', throw=True, **pycompat.strkwargs(hookargs)) | |
|
340 | 340 | |
|
341 | 341 | |
|
342 | 342 | def cleanup(repo, replacements, wdirwritten): |
@@ -353,7 +353,7 b' def cleanup(repo, replacements, wdirwrit' | |||
|
353 | 353 | effects of the command, though we choose not to output anything here. |
|
354 | 354 | """ |
|
355 | 355 | replacements = {prec: [succ] for prec, succ in replacements.iteritems()} |
|
356 | scmutil.cleanupnodes(repo, replacements, 'fix', fixphase=True) | |
|
356 | scmutil.cleanupnodes(repo, replacements, b'fix', fixphase=True) | |
|
357 | 357 | |
|
358 | 358 | |
|
359 | 359 | def getworkqueue(ui, repo, pats, opts, revstofix, basectxs): |
@@ -375,7 +375,7 b' def getworkqueue(ui, repo, pats, opts, r' | |||
|
375 | 375 | """ |
|
376 | 376 | workqueue = [] |
|
377 | 377 | numitems = collections.defaultdict(int) |
|
378 | maxfilesize = ui.configbytes('fix', 'maxfilesize') | |
|
378 | maxfilesize = ui.configbytes(b'fix', b'maxfilesize') | |
|
379 | 379 | for rev in sorted(revstofix): |
|
380 | 380 | fixctx = repo[rev] |
|
381 | 381 | match = scmutil.match(fixctx, pats, opts) |
@@ -387,7 +387,7 b' def getworkqueue(ui, repo, pats, opts, r' | |||
|
387 | 387 | continue |
|
388 | 388 | if fctx.size() > maxfilesize: |
|
389 | 389 | ui.warn( |
|
390 | _('ignoring file larger than %s: %s\n') | |
|
390 | _(b'ignoring file larger than %s: %s\n') | |
|
391 | 391 | % (util.bytecount(maxfilesize), path) |
|
392 | 392 | ) |
|
393 | 393 | continue |
@@ -398,29 +398,29 b' def getworkqueue(ui, repo, pats, opts, r' | |||
|
398 | 398 | |
|
399 | 399 | def getrevstofix(ui, repo, opts): |
|
400 | 400 | """Returns the set of revision numbers that should be fixed""" |
|
401 | revs = set(scmutil.revrange(repo, opts['rev'])) | |
|
401 | revs = set(scmutil.revrange(repo, opts[b'rev'])) | |
|
402 | 402 | for rev in revs: |
|
403 | 403 | checkfixablectx(ui, repo, repo[rev]) |
|
404 | 404 | if revs: |
|
405 | 405 | cmdutil.checkunfinished(repo) |
|
406 | 406 | checknodescendants(repo, revs) |
|
407 | if opts.get('working_dir'): | |
|
407 | if opts.get(b'working_dir'): | |
|
408 | 408 | revs.add(wdirrev) |
|
409 | 409 | if list(merge.mergestate.read(repo).unresolved()): |
|
410 | raise error.Abort('unresolved conflicts', hint="use 'hg resolve'") | |
|
410 | raise error.Abort(b'unresolved conflicts', hint=b"use 'hg resolve'") | |
|
411 | 411 | if not revs: |
|
412 | 412 | raise error.Abort( |
|
413 | 'no changesets specified', hint='use --rev or --working-dir' | |
|
413 | b'no changesets specified', hint=b'use --rev or --working-dir' | |
|
414 | 414 | ) |
|
415 | 415 | return revs |
|
416 | 416 | |
|
417 | 417 | |
|
418 | 418 | def checknodescendants(repo, revs): |
|
419 | 419 | if not obsolete.isenabled(repo, obsolete.allowunstableopt) and repo.revs( |
|
420 | '(%ld::) - (%ld)', revs, revs | |
|
420 | b'(%ld::) - (%ld)', revs, revs | |
|
421 | 421 | ): |
|
422 | 422 | raise error.Abort( |
|
423 | _('can only fix a changeset together ' 'with all its descendants') | |
|
423 | _(b'can only fix a changeset together ' b'with all its descendants') | |
|
424 | 424 | ) |
|
425 | 425 | |
|
426 | 426 | |
@@ -428,15 +428,18 b' def checkfixablectx(ui, repo, ctx):' | |||
|
428 | 428 | """Aborts if the revision shouldn't be replaced with a fixed one.""" |
|
429 | 429 | if not ctx.mutable(): |
|
430 | 430 | raise error.Abort( |
|
431 |
'can\'t fix immutable changeset %s' |
|
|
431 | b'can\'t fix immutable changeset %s' | |
|
432 | % (scmutil.formatchangeid(ctx),) | |
|
432 | 433 | ) |
|
433 | 434 | if ctx.obsolete(): |
|
434 | 435 | # It would be better to actually check if the revision has a successor. |
|
435 | 436 | allowdivergence = ui.configbool( |
|
436 | 'experimental', 'evolution.allowdivergence' | |
|
437 | b'experimental', b'evolution.allowdivergence' | |
|
437 | 438 | ) |
|
438 | 439 | if not allowdivergence: |
|
439 | raise error.Abort('fixing obsolete revision could cause divergence') | |
|
440 | raise error.Abort( | |
|
441 | b'fixing obsolete revision could cause divergence' | |
|
442 | ) | |
|
440 | 443 | |
|
441 | 444 | |
|
442 | 445 | def pathstofix(ui, repo, pats, opts, match, basectxs, fixctx): |
@@ -473,10 +476,10 b' def lineranges(opts, path, basectxs, fix' | |||
|
473 | 476 | Another way to understand this is that we exclude line ranges that are |
|
474 | 477 | common to the file in all base contexts. |
|
475 | 478 | """ |
|
476 | if opts.get('whole'): | |
|
479 | if opts.get(b'whole'): | |
|
477 | 480 | # Return a range containing all lines. Rely on the diff implementation's |
|
478 | 481 | # idea of how many lines are in the file, instead of reimplementing it. |
|
479 | return difflineranges('', content2) | |
|
482 | return difflineranges(b'', content2) | |
|
480 | 483 | |
|
481 | 484 | rangeslist = [] |
|
482 | 485 | for basectx in basectxs: |
@@ -484,7 +487,7 b' def lineranges(opts, path, basectxs, fix' | |||
|
484 | 487 | if basepath in basectx: |
|
485 | 488 | content1 = basectx[basepath].data() |
|
486 | 489 | else: |
|
487 | content1 = '' | |
|
490 | content1 = b'' | |
|
488 | 491 | rangeslist.extend(difflineranges(content1, content2)) |
|
489 | 492 | return unionranges(rangeslist) |
|
490 | 493 | |
@@ -566,7 +569,7 b' def difflineranges(content1, content2):' | |||
|
566 | 569 | ranges = [] |
|
567 | 570 | for lines, kind in mdiff.allblocks(content1, content2): |
|
568 | 571 | firstline, lastline = lines[2:4] |
|
569 | if kind == '!' and firstline != lastline: | |
|
572 | if kind == b'!' and firstline != lastline: | |
|
570 | 573 | ranges.append((firstline + 1, lastline)) |
|
571 | 574 | return ranges |
|
572 | 575 | |
@@ -581,8 +584,8 b' def getbasectxs(repo, opts, revstofix):' | |||
|
581 | 584 | """ |
|
582 | 585 | # The --base flag overrides the usual logic, and we give every revision |
|
583 | 586 | # exactly the set of baserevs that the user specified. |
|
584 | if opts.get('base'): | |
|
585 | baserevs = set(scmutil.revrange(repo, opts.get('base'))) | |
|
587 | if opts.get(b'base'): | |
|
588 | baserevs = set(scmutil.revrange(repo, opts.get(b'base'))) | |
|
586 | 589 | if not baserevs: |
|
587 | 590 | baserevs = {nullrev} |
|
588 | 591 | basectxs = {repo[rev] for rev in baserevs} |
@@ -621,7 +624,7 b' def fixfile(ui, repo, opts, fixers, fixc' | |||
|
621 | 624 | command = fixer.command(ui, path, ranges) |
|
622 | 625 | if command is None: |
|
623 | 626 | continue |
|
624 | ui.debug('subprocess: %s\n' % (command,)) | |
|
627 | ui.debug(b'subprocess: %s\n' % (command,)) | |
|
625 | 628 | proc = subprocess.Popen( |
|
626 | 629 | procutil.tonativestr(command), |
|
627 | 630 | shell=True, |
@@ -636,11 +639,11 b' def fixfile(ui, repo, opts, fixers, fixc' | |||
|
636 | 639 | newerdata = stdout |
|
637 | 640 | if fixer.shouldoutputmetadata(): |
|
638 | 641 | try: |
|
639 | metadatajson, newerdata = stdout.split('\0', 1) | |
|
642 | metadatajson, newerdata = stdout.split(b'\0', 1) | |
|
640 | 643 | metadata[fixername] = json.loads(metadatajson) |
|
641 | 644 | except ValueError: |
|
642 | 645 | ui.warn( |
|
643 | _('ignored invalid output from fixer tool: %s\n') | |
|
646 | _(b'ignored invalid output from fixer tool: %s\n') | |
|
644 | 647 | % (fixername,) |
|
645 | 648 | ) |
|
646 | 649 | continue |
@@ -650,14 +653,14 b' def fixfile(ui, repo, opts, fixers, fixc' | |||
|
650 | 653 | newdata = newerdata |
|
651 | 654 | else: |
|
652 | 655 | if not stderr: |
|
653 | message = _('exited with status %d\n') % (proc.returncode,) | |
|
656 | message = _(b'exited with status %d\n') % (proc.returncode,) | |
|
654 | 657 | showstderr(ui, fixctx.rev(), fixername, message) |
|
655 | 658 | checktoolfailureaction( |
|
656 | 659 | ui, |
|
657 | _('no fixes will be applied'), | |
|
660 | _(b'no fixes will be applied'), | |
|
658 | 661 | hint=_( |
|
659 | 'use --config fix.failure=continue to apply any ' | |
|
660 | 'successful fixes anyway' | |
|
662 | b'use --config fix.failure=continue to apply any ' | |
|
663 | b'successful fixes anyway' | |
|
661 | 664 | ), |
|
662 | 665 | ) |
|
663 | 666 | return metadata, newdata |
@@ -671,14 +674,14 b' def showstderr(ui, rev, fixername, stder' | |||
|
671 | 674 | space and would tend to be included in the error message if they were |
|
672 | 675 | relevant. |
|
673 | 676 | """ |
|
674 | for line in re.split('[\r\n]+', stderr): | |
|
677 | for line in re.split(b'[\r\n]+', stderr): | |
|
675 | 678 | if line: |
|
676 | ui.warn('[') | |
|
679 | ui.warn(b'[') | |
|
677 | 680 | if rev is None: |
|
678 | ui.warn(_('wdir'), label='evolve.rev') | |
|
681 | ui.warn(_(b'wdir'), label=b'evolve.rev') | |
|
679 | 682 | else: |
|
680 | ui.warn((str(rev)), label='evolve.rev') | |
|
681 | ui.warn('] %s: %s\n' % (fixername, line)) | |
|
683 | ui.warn((str(rev)), label=b'evolve.rev') | |
|
684 | ui.warn(b'] %s: %s\n' % (fixername, line)) | |
|
682 | 685 | |
|
683 | 686 | |
|
684 | 687 | def writeworkingdir(repo, ctx, filedata, replacements): |
@@ -694,7 +697,7 b' def writeworkingdir(repo, ctx, filedata,' | |||
|
694 | 697 | for path, data in filedata.iteritems(): |
|
695 | 698 | fctx = ctx[path] |
|
696 | 699 | fctx.write(data, fctx.flags()) |
|
697 | if repo.dirstate[path] == 'n': | |
|
700 | if repo.dirstate[path] == b'n': | |
|
698 | 701 | repo.dirstate.normallookup(path) |
|
699 | 702 | |
|
700 | 703 | oldparentnodes = repo.dirstate.parents() |
@@ -757,7 +760,7 b' def replacerev(ui, repo, ctx, filedata, ' | |||
|
757 | 760 | ) |
|
758 | 761 | |
|
759 | 762 | extra = ctx.extra().copy() |
|
760 | extra['fix_source'] = ctx.hex() | |
|
763 | extra[b'fix_source'] = ctx.hex() | |
|
761 | 764 | |
|
762 | 765 | memctx = context.memctx( |
|
763 | 766 | repo, |
@@ -774,7 +777,7 b' def replacerev(ui, repo, ctx, filedata, ' | |||
|
774 | 777 | sucnode = memctx.commit() |
|
775 | 778 | prenode = ctx.node() |
|
776 | 779 | if prenode == sucnode: |
|
777 | ui.debug('node %s already existed\n' % (ctx.hex())) | |
|
780 | ui.debug(b'node %s already existed\n' % (ctx.hex())) | |
|
778 | 781 | else: |
|
779 | 782 | replacements[ctx.node()] = sucnode |
|
780 | 783 | |
@@ -788,11 +791,11 b' def getfixers(ui):' | |||
|
788 | 791 | fixers = {} |
|
789 | 792 | for name in fixernames(ui): |
|
790 | 793 | fixers[name] = Fixer() |
|
791 | attrs = ui.configsuboptions('fix', name)[1] | |
|
794 | attrs = ui.configsuboptions(b'fix', name)[1] | |
|
792 | 795 | for key, default in FIXER_ATTRS.items(): |
|
793 | 796 | setattr( |
|
794 | 797 | fixers[name], |
|
795 | pycompat.sysstr('_' + key), | |
|
798 | pycompat.sysstr(b'_' + key), | |
|
796 | 799 | attrs.get(key, default), |
|
797 | 800 | ) |
|
798 | 801 | fixers[name]._priority = int(fixers[name]._priority) |
@@ -805,11 +808,11 b' def getfixers(ui):' | |||
|
805 | 808 | # default. |
|
806 | 809 | if fixers[name]._pattern is None: |
|
807 | 810 | ui.warn( |
|
808 | _('fixer tool has no pattern configuration: %s\n') % (name,) | |
|
811 | _(b'fixer tool has no pattern configuration: %s\n') % (name,) | |
|
809 | 812 | ) |
|
810 | 813 | del fixers[name] |
|
811 | 814 | elif not fixers[name]._enabled: |
|
812 | ui.debug('ignoring disabled fixer tool: %s\n' % (name,)) | |
|
815 | ui.debug(b'ignoring disabled fixer tool: %s\n' % (name,)) | |
|
813 | 816 | del fixers[name] |
|
814 | 817 | return collections.OrderedDict( |
|
815 | 818 | sorted(fixers.items(), key=lambda item: item[1]._priority, reverse=True) |
@@ -819,9 +822,9 b' def getfixers(ui):' | |||
|
819 | 822 | def fixernames(ui): |
|
820 | 823 | """Returns the names of [fix] config options that have suboptions""" |
|
821 | 824 | names = set() |
|
822 | for k, v in ui.configitems('fix'): | |
|
823 | if ':' in k: | |
|
824 | names.add(k.split(':', 1)[0]) | |
|
825 | for k, v in ui.configitems(b'fix'): | |
|
826 | if b':' in k: | |
|
827 | names.add(k.split(b':', 1)[0]) | |
|
825 | 828 | return names |
|
826 | 829 | |
|
827 | 830 | |
@@ -849,7 +852,7 b' class Fixer(object):' | |||
|
849 | 852 | expand( |
|
850 | 853 | ui, |
|
851 | 854 | self._command, |
|
852 | {'rootpath': path, 'basename': os.path.basename(path)}, | |
|
855 | {b'rootpath': path, b'basename': os.path.basename(path)}, | |
|
853 | 856 | ) |
|
854 | 857 | ] |
|
855 | 858 | if self._linerange: |
@@ -858,6 +861,8 b' class Fixer(object):' | |||
|
858 | 861 | return None |
|
859 | 862 | for first, last in ranges: |
|
860 | 863 | parts.append( |
|
861 | expand(ui, self._linerange, {'first': first, 'last': last}) | |
|
864 | expand( | |
|
865 | ui, self._linerange, {b'first': first, b'last': last} | |
|
862 | 866 | ) |
|
863 | return ' '.join(parts) | |
|
867 | ) | |
|
868 | return b' '.join(parts) |
@@ -143,60 +143,60 b' from . import (' | |||
|
143 | 143 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
144 | 144 | # be specifying the version(s) of Mercurial they are tested with, or |
|
145 | 145 | # leave the attribute unspecified. |
|
146 | testedwith = 'ships-with-hg-core' | |
|
146 | testedwith = b'ships-with-hg-core' | |
|
147 | 147 | |
|
148 | 148 | configtable = {} |
|
149 | 149 | configitem = registrar.configitem(configtable) |
|
150 | 150 | |
|
151 | 151 | configitem( |
|
152 | 'fsmonitor', 'mode', default='on', | |
|
152 | b'fsmonitor', b'mode', default=b'on', | |
|
153 | 153 | ) |
|
154 | 154 | configitem( |
|
155 | 'fsmonitor', 'walk_on_invalidate', default=False, | |
|
155 | b'fsmonitor', b'walk_on_invalidate', default=False, | |
|
156 | 156 | ) |
|
157 | 157 | configitem( |
|
158 | 'fsmonitor', 'timeout', default='2', | |
|
158 | b'fsmonitor', b'timeout', default=b'2', | |
|
159 | 159 | ) |
|
160 | 160 | configitem( |
|
161 | 'fsmonitor', 'blacklistusers', default=list, | |
|
161 | b'fsmonitor', b'blacklistusers', default=list, | |
|
162 | 162 | ) |
|
163 | 163 | configitem( |
|
164 | 'fsmonitor', 'watchman_exe', default='watchman', | |
|
164 | b'fsmonitor', b'watchman_exe', default=b'watchman', | |
|
165 | 165 | ) |
|
166 | 166 | configitem( |
|
167 | 'fsmonitor', 'verbose', default=True, experimental=True, | |
|
167 | b'fsmonitor', b'verbose', default=True, experimental=True, | |
|
168 | 168 | ) |
|
169 | 169 | configitem( |
|
170 | 'experimental', 'fsmonitor.transaction_notify', default=False, | |
|
170 | b'experimental', b'fsmonitor.transaction_notify', default=False, | |
|
171 | 171 | ) |
|
172 | 172 | |
|
173 | 173 | # This extension is incompatible with the following blacklisted extensions |
|
174 | 174 | # and will disable itself when encountering one of these: |
|
175 | _blacklist = ['largefiles', 'eol'] | |
|
175 | _blacklist = [b'largefiles', b'eol'] | |
|
176 | 176 | |
|
177 | 177 | |
|
178 | 178 | def debuginstall(ui, fm): |
|
179 | 179 | fm.write( |
|
180 | "fsmonitor-watchman", | |
|
181 | _("fsmonitor checking for watchman binary... (%s)\n"), | |
|
182 | ui.configpath("fsmonitor", "watchman_exe"), | |
|
180 | b"fsmonitor-watchman", | |
|
181 | _(b"fsmonitor checking for watchman binary... (%s)\n"), | |
|
182 | ui.configpath(b"fsmonitor", b"watchman_exe"), | |
|
183 | 183 | ) |
|
184 | 184 | root = tempfile.mkdtemp() |
|
185 | 185 | c = watchmanclient.client(ui, root) |
|
186 | 186 | err = None |
|
187 | 187 | try: |
|
188 | v = c.command("version") | |
|
188 | v = c.command(b"version") | |
|
189 | 189 | fm.write( |
|
190 | "fsmonitor-watchman-version", | |
|
191 | _(" watchman binary version %s\n"), | |
|
192 | v["version"], | |
|
190 | b"fsmonitor-watchman-version", | |
|
191 | _(b" watchman binary version %s\n"), | |
|
192 | v[b"version"], | |
|
193 | 193 | ) |
|
194 | 194 | except watchmanclient.Unavailable as e: |
|
195 | 195 | err = str(e) |
|
196 | 196 | fm.condwrite( |
|
197 | 197 | err, |
|
198 | "fsmonitor-watchman-error", | |
|
199 | _(" watchman binary missing or broken: %s\n"), | |
|
198 | b"fsmonitor-watchman-error", | |
|
199 | _(b" watchman binary missing or broken: %s\n"), | |
|
200 | 200 | err, |
|
201 | 201 | ) |
|
202 | 202 | return 1 if err else 0 |
@@ -206,16 +206,16 b' def _handleunavailable(ui, state, ex):' | |||
|
206 | 206 | """Exception handler for Watchman interaction exceptions""" |
|
207 | 207 | if isinstance(ex, watchmanclient.Unavailable): |
|
208 | 208 | # experimental config: fsmonitor.verbose |
|
209 | if ex.warn and ui.configbool('fsmonitor', 'verbose'): | |
|
210 | if 'illegal_fstypes' not in str(ex): | |
|
211 | ui.warn(str(ex) + '\n') | |
|
209 | if ex.warn and ui.configbool(b'fsmonitor', b'verbose'): | |
|
210 | if b'illegal_fstypes' not in str(ex): | |
|
211 | ui.warn(str(ex) + b'\n') | |
|
212 | 212 | if ex.invalidate: |
|
213 | 213 | state.invalidate() |
|
214 | 214 | # experimental config: fsmonitor.verbose |
|
215 | if ui.configbool('fsmonitor', 'verbose'): | |
|
216 | ui.log('fsmonitor', 'Watchman unavailable: %s\n', ex.msg) | |
|
215 | if ui.configbool(b'fsmonitor', b'verbose'): | |
|
216 | ui.log(b'fsmonitor', b'Watchman unavailable: %s\n', ex.msg) | |
|
217 | 217 | else: |
|
218 | ui.log('fsmonitor', 'Watchman exception: %s\n', ex) | |
|
218 | ui.log(b'fsmonitor', b'Watchman exception: %s\n', ex) | |
|
219 | 219 | |
|
220 | 220 | |
|
221 | 221 | def _hashignore(ignore): |
@@ -245,7 +245,7 b' def _watchmantofsencoding(path):' | |||
|
245 | 245 | try: |
|
246 | 246 | decoded = path.decode(_watchmanencoding) |
|
247 | 247 | except UnicodeDecodeError as e: |
|
248 | raise error.Abort(str(e), hint='watchman encoding error') | |
|
248 | raise error.Abort(str(e), hint=b'watchman encoding error') | |
|
249 | 249 | |
|
250 | 250 | try: |
|
251 | 251 | encoded = decoded.encode(_fsencoding, 'strict') |
@@ -263,34 +263,34 b' def overridewalk(orig, self, match, subr' | |||
|
263 | 263 | subset of files.''' |
|
264 | 264 | |
|
265 | 265 | def bail(reason): |
|
266 | self._ui.debug('fsmonitor: fallback to core status, %s\n' % reason) | |
|
266 | self._ui.debug(b'fsmonitor: fallback to core status, %s\n' % reason) | |
|
267 | 267 | return orig(match, subrepos, unknown, ignored, full=True) |
|
268 | 268 | |
|
269 | 269 | if full: |
|
270 | return bail('full rewalk requested') | |
|
270 | return bail(b'full rewalk requested') | |
|
271 | 271 | if ignored: |
|
272 | return bail('listing ignored files') | |
|
272 | return bail(b'listing ignored files') | |
|
273 | 273 | if not self._watchmanclient.available(): |
|
274 | return bail('client unavailable') | |
|
274 | return bail(b'client unavailable') | |
|
275 | 275 | state = self._fsmonitorstate |
|
276 | 276 | clock, ignorehash, notefiles = state.get() |
|
277 | 277 | if not clock: |
|
278 | 278 | if state.walk_on_invalidate: |
|
279 | return bail('no clock') | |
|
279 | return bail(b'no clock') | |
|
280 | 280 | # Initial NULL clock value, see |
|
281 | 281 | # https://facebook.github.io/watchman/docs/clockspec.html |
|
282 | clock = 'c:0:0' | |
|
282 | clock = b'c:0:0' | |
|
283 | 283 | notefiles = [] |
|
284 | 284 | |
|
285 | 285 | ignore = self._ignore |
|
286 | 286 | dirignore = self._dirignore |
|
287 | 287 | if unknown: |
|
288 | if _hashignore(ignore) != ignorehash and clock != 'c:0:0': | |
|
288 | if _hashignore(ignore) != ignorehash and clock != b'c:0:0': | |
|
289 | 289 | # ignore list changed -- can't rely on Watchman state any more |
|
290 | 290 | if state.walk_on_invalidate: |
|
291 | return bail('ignore rules changed') | |
|
291 | return bail(b'ignore rules changed') | |
|
292 | 292 | notefiles = [] |
|
293 | clock = 'c:0:0' | |
|
293 | clock = b'c:0:0' | |
|
294 | 294 | else: |
|
295 | 295 | # always ignore |
|
296 | 296 | ignore = util.always |
@@ -299,7 +299,7 b' def overridewalk(orig, self, match, subr' | |||
|
299 | 299 | matchfn = match.matchfn |
|
300 | 300 | matchalways = match.always() |
|
301 | 301 | dmap = self._map |
|
302 | if util.safehasattr(dmap, '_map'): | |
|
302 | if util.safehasattr(dmap, b'_map'): | |
|
303 | 303 | # for better performance, directly access the inner dirstate map if the |
|
304 | 304 | # standard dirstate implementation is in use. |
|
305 | 305 | dmap = dmap._map |
@@ -339,7 +339,7 b' def overridewalk(orig, self, match, subr' | |||
|
339 | 339 | if not work and (exact or skipstep3): |
|
340 | 340 | for s in subrepos: |
|
341 | 341 | del results[s] |
|
342 | del results['.hg'] | |
|
342 | del results[b'.hg'] | |
|
343 | 343 | return results |
|
344 | 344 | |
|
345 | 345 | # step 2: query Watchman |
@@ -349,30 +349,34 b' def overridewalk(orig, self, match, subr' | |||
|
349 | 349 | # overheads while transferring the data |
|
350 | 350 | self._watchmanclient.settimeout(state.timeout + 0.1) |
|
351 | 351 | result = self._watchmanclient.command( |
|
352 | 'query', | |
|
352 | b'query', | |
|
353 | 353 | { |
|
354 | 'fields': ['mode', 'mtime', 'size', 'exists', 'name'], | |
|
355 | 'since': clock, | |
|
356 | 'expression': [ | |
|
357 | 'not', | |
|
358 | ['anyof', ['dirname', '.hg'], ['name', '.hg', 'wholename']], | |
|
354 | b'fields': [b'mode', b'mtime', b'size', b'exists', b'name'], | |
|
355 | b'since': clock, | |
|
356 | b'expression': [ | |
|
357 | b'not', | |
|
358 | [ | |
|
359 | b'anyof', | |
|
360 | [b'dirname', b'.hg'], | |
|
361 | [b'name', b'.hg', b'wholename'], | |
|
359 | 362 | ], |
|
360 | 'sync_timeout': int(state.timeout * 1000), | |
|
361 | 'empty_on_fresh_instance': state.walk_on_invalidate, | |
|
363 | ], | |
|
364 | b'sync_timeout': int(state.timeout * 1000), | |
|
365 | b'empty_on_fresh_instance': state.walk_on_invalidate, | |
|
362 | 366 | }, |
|
363 | 367 | ) |
|
364 | 368 | except Exception as ex: |
|
365 | 369 | _handleunavailable(self._ui, state, ex) |
|
366 | 370 | self._watchmanclient.clearconnection() |
|
367 | return bail('exception during run') | |
|
371 | return bail(b'exception during run') | |
|
368 | 372 | else: |
|
369 | 373 | # We need to propagate the last observed clock up so that we |
|
370 | 374 | # can use it for our next query |
|
371 | state.setlastclock(result['clock']) | |
|
372 | if result['is_fresh_instance']: | |
|
375 | state.setlastclock(result[b'clock']) | |
|
376 | if result[b'is_fresh_instance']: | |
|
373 | 377 | if state.walk_on_invalidate: |
|
374 | 378 | state.invalidate() |
|
375 | return bail('fresh instance') | |
|
379 | return bail(b'fresh instance') | |
|
376 | 380 | fresh_instance = True |
|
377 | 381 | # Ignore any prior noteable files from the state info |
|
378 | 382 | notefiles = [] |
@@ -382,7 +386,7 b' def overridewalk(orig, self, match, subr' | |||
|
382 | 386 | if normalize: |
|
383 | 387 | foldmap = dict((normcase(k), k) for k in results) |
|
384 | 388 | |
|
385 | switch_slashes = pycompat.ossep == '\\' | |
|
389 | switch_slashes = pycompat.ossep == b'\\' | |
|
386 | 390 | # The order of the results is, strictly speaking, undefined. |
|
387 | 391 | # For case changes on a case insensitive filesystem we may receive |
|
388 | 392 | # two entries, one with exists=True and another with exists=False. |
@@ -390,22 +394,22 b' def overridewalk(orig, self, match, subr' | |||
|
390 | 394 | # as being happens-after the exists=False entries due to the way that |
|
391 | 395 | # Watchman tracks files. We use this property to reconcile deletes |
|
392 | 396 | # for name case changes. |
|
393 | for entry in result['files']: | |
|
394 | fname = entry['name'] | |
|
397 | for entry in result[b'files']: | |
|
398 | fname = entry[b'name'] | |
|
395 | 399 | if _fixencoding: |
|
396 | 400 | fname = _watchmantofsencoding(fname) |
|
397 | 401 | if switch_slashes: |
|
398 | fname = fname.replace('\\', '/') | |
|
402 | fname = fname.replace(b'\\', b'/') | |
|
399 | 403 | if normalize: |
|
400 | 404 | normed = normcase(fname) |
|
401 | 405 | fname = normalize(fname, True, True) |
|
402 | 406 | foldmap[normed] = fname |
|
403 | fmode = entry['mode'] | |
|
404 | fexists = entry['exists'] | |
|
407 | fmode = entry[b'mode'] | |
|
408 | fexists = entry[b'exists'] | |
|
405 | 409 | kind = getkind(fmode) |
|
406 | 410 | |
|
407 | if '/.hg/' in fname or fname.endswith('/.hg'): | |
|
408 | return bail('nested-repo-detected') | |
|
411 | if b'/.hg/' in fname or fname.endswith(b'/.hg'): | |
|
412 | return bail(b'nested-repo-detected') | |
|
409 | 413 | |
|
410 | 414 | if not fexists: |
|
411 | 415 | # if marked as deleted and we don't already have a change |
@@ -488,14 +492,14 b' def overridewalk(orig, self, match, subr' | |||
|
488 | 492 | |
|
489 | 493 | for s in subrepos: |
|
490 | 494 | del results[s] |
|
491 | del results['.hg'] | |
|
495 | del results[b'.hg'] | |
|
492 | 496 | return results |
|
493 | 497 | |
|
494 | 498 | |
|
495 | 499 | def overridestatus( |
|
496 | 500 | orig, |
|
497 | 501 | self, |
|
498 | node1='.', | |
|
502 | node1=b'.', | |
|
499 | 503 | node2=None, |
|
500 | 504 | match=None, |
|
501 | 505 | ignored=False, |
@@ -509,22 +513,22 b' def overridestatus(' | |||
|
509 | 513 | |
|
510 | 514 | def _cmpsets(l1, l2): |
|
511 | 515 | try: |
|
512 | if 'FSMONITOR_LOG_FILE' in encoding.environ: | |
|
513 | fn = encoding.environ['FSMONITOR_LOG_FILE'] | |
|
514 | f = open(fn, 'wb') | |
|
516 | if b'FSMONITOR_LOG_FILE' in encoding.environ: | |
|
517 | fn = encoding.environ[b'FSMONITOR_LOG_FILE'] | |
|
518 | f = open(fn, b'wb') | |
|
515 | 519 | else: |
|
516 | fn = 'fsmonitorfail.log' | |
|
517 | f = self.vfs.open(fn, 'wb') | |
|
520 | fn = b'fsmonitorfail.log' | |
|
521 | f = self.vfs.open(fn, b'wb') | |
|
518 | 522 | except (IOError, OSError): |
|
519 | self.ui.warn(_('warning: unable to write to %s\n') % fn) | |
|
523 | self.ui.warn(_(b'warning: unable to write to %s\n') % fn) | |
|
520 | 524 | return |
|
521 | 525 | |
|
522 | 526 | try: |
|
523 | 527 | for i, (s1, s2) in enumerate(zip(l1, l2)): |
|
524 | 528 | if set(s1) != set(s2): |
|
525 | f.write('sets at position %d are unequal\n' % i) | |
|
526 | f.write('watchman returned: %s\n' % s1) | |
|
527 | f.write('stat returned: %s\n' % s2) | |
|
529 | f.write(b'sets at position %d are unequal\n' % i) | |
|
530 | f.write(b'watchman returned: %s\n' % s1) | |
|
531 | f.write(b'stat returned: %s\n' % s2) | |
|
528 | 532 | finally: |
|
529 | 533 | f.close() |
|
530 | 534 | |
@@ -538,7 +542,7 b' def overridestatus(' | |||
|
538 | 542 | ctx2 = self[node2] |
|
539 | 543 | |
|
540 | 544 | working = ctx2.rev() is None |
|
541 | parentworking = working and ctx1 == self['.'] | |
|
545 | parentworking = working and ctx1 == self[b'.'] | |
|
542 | 546 | match = match or matchmod.always() |
|
543 | 547 | |
|
544 | 548 | # Maybe we can use this opportunity to update Watchman's state. |
@@ -552,7 +556,7 b' def overridestatus(' | |||
|
552 | 556 | parentworking |
|
553 | 557 | and match.always() |
|
554 | 558 | and not isinstance(ctx2, (context.workingcommitctx, context.memctx)) |
|
555 | and 'HG_PENDING' not in encoding.environ | |
|
559 | and b'HG_PENDING' not in encoding.environ | |
|
556 | 560 | ) |
|
557 | 561 | |
|
558 | 562 | try: |
@@ -607,7 +611,7 b' def overridestatus(' | |||
|
607 | 611 | |
|
608 | 612 | # don't do paranoid checks if we're not going to query Watchman anyway |
|
609 | 613 | full = listclean or match.traversedir is not None |
|
610 | if self._fsmonitorstate.mode == 'paranoid' and not full: | |
|
614 | if self._fsmonitorstate.mode == b'paranoid' and not full: | |
|
611 | 615 | # run status again and fall back to the old walk this time |
|
612 | 616 | self.dirstate._fsmonitordisable = True |
|
613 | 617 | |
@@ -615,7 +619,7 b' def overridestatus(' | |||
|
615 | 619 | quiet = self.ui.quiet |
|
616 | 620 | self.ui.quiet = True |
|
617 | 621 | fout, ferr = self.ui.fout, self.ui.ferr |
|
618 | self.ui.fout = self.ui.ferr = open(os.devnull, 'wb') | |
|
622 | self.ui.fout = self.ui.ferr = open(os.devnull, b'wb') | |
|
619 | 623 | |
|
620 | 624 | try: |
|
621 | 625 | rv2 = orig( |
@@ -692,20 +696,20 b' def makedirstate(repo, dirstate):' | |||
|
692 | 696 | def wrapdirstate(orig, self): |
|
693 | 697 | ds = orig(self) |
|
694 | 698 | # only override the dirstate when Watchman is available for the repo |
|
695 | if util.safehasattr(self, '_fsmonitorstate'): | |
|
699 | if util.safehasattr(self, b'_fsmonitorstate'): | |
|
696 | 700 | makedirstate(self, ds) |
|
697 | 701 | return ds |
|
698 | 702 | |
|
699 | 703 | |
|
700 | 704 | def extsetup(ui): |
|
701 | 705 | extensions.wrapfilecache( |
|
702 | localrepo.localrepository, 'dirstate', wrapdirstate | |
|
706 | localrepo.localrepository, b'dirstate', wrapdirstate | |
|
703 | 707 | ) |
|
704 | 708 | if pycompat.isdarwin: |
|
705 | 709 | # An assist for avoiding the dangling-symlink fsevents bug |
|
706 | extensions.wrapfunction(os, 'symlink', wrapsymlink) | |
|
710 | extensions.wrapfunction(os, b'symlink', wrapsymlink) | |
|
707 | 711 | |
|
708 | extensions.wrapfunction(merge, 'update', wrapupdate) | |
|
712 | extensions.wrapfunction(merge, b'update', wrapupdate) | |
|
709 | 713 | |
|
710 | 714 | |
|
711 | 715 | def wrapsymlink(orig, source, link_name): |
@@ -756,14 +760,14 b' class state_update(object):' | |||
|
756 | 760 | # merge.update is going to take the wlock almost immediately. We are |
|
757 | 761 | # effectively extending the lock around several short sanity checks. |
|
758 | 762 | if self.oldnode is None: |
|
759 | self.oldnode = self.repo['.'].node() | |
|
763 | self.oldnode = self.repo[b'.'].node() | |
|
760 | 764 | |
|
761 | 765 | if self.repo.currentwlock() is None: |
|
762 | if util.safehasattr(self.repo, 'wlocknostateupdate'): | |
|
766 | if util.safehasattr(self.repo, b'wlocknostateupdate'): | |
|
763 | 767 | self._lock = self.repo.wlocknostateupdate() |
|
764 | 768 | else: |
|
765 | 769 | self._lock = self.repo.wlock() |
|
766 | self.need_leave = self._state('state-enter', hex(self.oldnode)) | |
|
770 | self.need_leave = self._state(b'state-enter', hex(self.oldnode)) | |
|
767 | 771 | return self |
|
768 | 772 | |
|
769 | 773 | def __exit__(self, type_, value, tb): |
@@ -773,36 +777,36 b' class state_update(object):' | |||
|
773 | 777 | def exit(self, abort=False): |
|
774 | 778 | try: |
|
775 | 779 | if self.need_leave: |
|
776 | status = 'failed' if abort else 'ok' | |
|
780 | status = b'failed' if abort else b'ok' | |
|
777 | 781 | if self.newnode is None: |
|
778 | self.newnode = self.repo['.'].node() | |
|
782 | self.newnode = self.repo[b'.'].node() | |
|
779 | 783 | if self.distance is None: |
|
780 | 784 | self.distance = calcdistance( |
|
781 | 785 | self.repo, self.oldnode, self.newnode |
|
782 | 786 | ) |
|
783 | self._state('state-leave', hex(self.newnode), status=status) | |
|
787 | self._state(b'state-leave', hex(self.newnode), status=status) | |
|
784 | 788 | finally: |
|
785 | 789 | self.need_leave = False |
|
786 | 790 | if self._lock: |
|
787 | 791 | self._lock.release() |
|
788 | 792 | |
|
789 | def _state(self, cmd, commithash, status='ok'): | |
|
790 | if not util.safehasattr(self.repo, '_watchmanclient'): | |
|
793 | def _state(self, cmd, commithash, status=b'ok'): | |
|
794 | if not util.safehasattr(self.repo, b'_watchmanclient'): | |
|
791 | 795 | return False |
|
792 | 796 | try: |
|
793 | 797 | self.repo._watchmanclient.command( |
|
794 | 798 | cmd, |
|
795 | 799 | { |
|
796 | 'name': self.name, | |
|
797 | 'metadata': { | |
|
800 | b'name': self.name, | |
|
801 | b'metadata': { | |
|
798 | 802 | # the target revision |
|
799 | 'rev': commithash, | |
|
803 | b'rev': commithash, | |
|
800 | 804 | # approximate number of commits between current and target |
|
801 | 'distance': self.distance if self.distance else 0, | |
|
805 | b'distance': self.distance if self.distance else 0, | |
|
802 | 806 | # success/failure (only really meaningful for state-leave) |
|
803 | 'status': status, | |
|
807 | b'status': status, | |
|
804 | 808 | # whether the working copy parent is changing |
|
805 | 'partial': self.partial, | |
|
809 | b'partial': self.partial, | |
|
806 | 810 | }, |
|
807 | 811 | }, |
|
808 | 812 | ) |
@@ -810,7 +814,7 b' class state_update(object):' | |||
|
810 | 814 | except Exception as e: |
|
811 | 815 | # Swallow any errors; fire and forget |
|
812 | 816 | self.repo.ui.log( |
|
813 | 'watchman', 'Exception %s while running %s\n', e, cmd | |
|
817 | b'watchman', b'Exception %s while running %s\n', e, cmd | |
|
814 | 818 | ) |
|
815 | 819 | return False |
|
816 | 820 | |
@@ -844,7 +848,7 b' def wrapupdate(' | |||
|
844 | 848 | |
|
845 | 849 | distance = 0 |
|
846 | 850 | partial = True |
|
847 | oldnode = repo['.'].node() | |
|
851 | oldnode = repo[b'.'].node() | |
|
848 | 852 | newnode = repo[node].node() |
|
849 | 853 | if matcher is None or matcher.always(): |
|
850 | 854 | partial = False |
@@ -852,7 +856,7 b' def wrapupdate(' | |||
|
852 | 856 | |
|
853 | 857 | with state_update( |
|
854 | 858 | repo, |
|
855 | name="hg.update", | |
|
859 | name=b"hg.update", | |
|
856 | 860 | oldnode=oldnode, |
|
857 | 861 | newnode=newnode, |
|
858 | 862 | distance=distance, |
@@ -873,8 +877,8 b' def wrapupdate(' | |||
|
873 | 877 | |
|
874 | 878 | def repo_has_depth_one_nested_repo(repo): |
|
875 | 879 | for f in repo.wvfs.listdir(): |
|
876 | if os.path.isdir(os.path.join(repo.root, f, '.hg')): | |
|
877 | msg = 'fsmonitor: sub-repository %r detected, fsmonitor disabled\n' | |
|
880 | if os.path.isdir(os.path.join(repo.root, f, b'.hg')): | |
|
881 | msg = b'fsmonitor: sub-repository %r detected, fsmonitor disabled\n' | |
|
878 | 882 | repo.ui.debug(msg % f) |
|
879 | 883 | return True |
|
880 | 884 | return False |
@@ -887,8 +891,8 b' def reposetup(ui, repo):' | |||
|
887 | 891 | if ext in exts: |
|
888 | 892 | ui.warn( |
|
889 | 893 | _( |
|
890 | 'The fsmonitor extension is incompatible with the %s ' | |
|
891 | 'extension and has been disabled.\n' | |
|
894 | b'The fsmonitor extension is incompatible with the %s ' | |
|
895 | b'extension and has been disabled.\n' | |
|
892 | 896 | ) |
|
893 | 897 | % ext |
|
894 | 898 | ) |
@@ -899,14 +903,14 b' def reposetup(ui, repo):' | |||
|
899 | 903 | # |
|
900 | 904 | # if repo[None].substate can cause a dirstate parse, which is too |
|
901 | 905 | # slow. Instead, look for a file called hgsubstate, |
|
902 | if repo.wvfs.exists('.hgsubstate') or repo.wvfs.exists('.hgsub'): | |
|
906 | if repo.wvfs.exists(b'.hgsubstate') or repo.wvfs.exists(b'.hgsub'): | |
|
903 | 907 | return |
|
904 | 908 | |
|
905 | 909 | if repo_has_depth_one_nested_repo(repo): |
|
906 | 910 | return |
|
907 | 911 | |
|
908 | 912 | fsmonitorstate = state.state(repo) |
|
909 | if fsmonitorstate.mode == 'off': | |
|
913 | if fsmonitorstate.mode == b'off': | |
|
910 | 914 | return |
|
911 | 915 | |
|
912 | 916 | try: |
@@ -918,7 +922,7 b' def reposetup(ui, repo):' | |||
|
918 | 922 | repo._fsmonitorstate = fsmonitorstate |
|
919 | 923 | repo._watchmanclient = client |
|
920 | 924 | |
|
921 | dirstate, cached = localrepo.isfilecached(repo, 'dirstate') | |
|
925 | dirstate, cached = localrepo.isfilecached(repo, b'dirstate') | |
|
922 | 926 | if cached: |
|
923 | 927 | # at this point since fsmonitorstate wasn't present, |
|
924 | 928 | # repo.dirstate is not a fsmonitordirstate |
@@ -935,7 +939,7 b' def reposetup(ui, repo):' | |||
|
935 | 939 | def wlock(self, *args, **kwargs): |
|
936 | 940 | l = super(fsmonitorrepo, self).wlock(*args, **kwargs) |
|
937 | 941 | if not ui.configbool( |
|
938 | "experimental", "fsmonitor.transaction_notify" | |
|
942 | b"experimental", b"fsmonitor.transaction_notify" | |
|
939 | 943 | ): |
|
940 | 944 | return l |
|
941 | 945 | if l.held != 1: |
@@ -951,12 +955,14 b' def reposetup(ui, repo):' | |||
|
951 | 955 | |
|
952 | 956 | try: |
|
953 | 957 | l.stateupdate = None |
|
954 | l.stateupdate = state_update(self, name="hg.transaction") | |
|
958 | l.stateupdate = state_update(self, name=b"hg.transaction") | |
|
955 | 959 | l.stateupdate.enter() |
|
956 | 960 | l.releasefn = staterelease |
|
957 | 961 | except Exception as e: |
|
958 | 962 | # Swallow any errors; fire and forget |
|
959 | self.ui.log('watchman', 'Exception in state update %s\n', e) | |
|
963 | self.ui.log( | |
|
964 | b'watchman', b'Exception in state update %s\n', e | |
|
965 | ) | |
|
960 | 966 | return l |
|
961 | 967 | |
|
962 | 968 | repo.__class__ = fsmonitorrepo |
@@ -19,7 +19,7 b' from mercurial import (' | |||
|
19 | 19 | ) |
|
20 | 20 | |
|
21 | 21 | _version = 4 |
|
22 | _versionformat = ">I" | |
|
22 | _versionformat = b">I" | |
|
23 | 23 | |
|
24 | 24 | |
|
25 | 25 | class state(object): |
@@ -30,15 +30,15 b' class state(object):' | |||
|
30 | 30 | self._lastclock = None |
|
31 | 31 | self._identity = util.filestat(None) |
|
32 | 32 | |
|
33 | self.mode = self._ui.config('fsmonitor', 'mode') | |
|
33 | self.mode = self._ui.config(b'fsmonitor', b'mode') | |
|
34 | 34 | self.walk_on_invalidate = self._ui.configbool( |
|
35 | 'fsmonitor', 'walk_on_invalidate' | |
|
35 | b'fsmonitor', b'walk_on_invalidate' | |
|
36 | 36 | ) |
|
37 | self.timeout = float(self._ui.config('fsmonitor', 'timeout')) | |
|
37 | self.timeout = float(self._ui.config(b'fsmonitor', b'timeout')) | |
|
38 | 38 | |
|
39 | 39 | def get(self): |
|
40 | 40 | try: |
|
41 | file = self._vfs('fsmonitor.state', 'rb') | |
|
41 | file = self._vfs(b'fsmonitor.state', b'rb') | |
|
42 | 42 | except IOError as inst: |
|
43 | 43 | self._identity = util.filestat(None) |
|
44 | 44 | if inst.errno != errno.ENOENT: |
@@ -50,9 +50,9 b' class state(object):' | |||
|
50 | 50 | versionbytes = file.read(4) |
|
51 | 51 | if len(versionbytes) < 4: |
|
52 | 52 | self._ui.log( |
|
53 | 'fsmonitor', | |
|
54 | 'fsmonitor: state file only has %d bytes, ' | |
|
55 | 'nuking state\n' % len(versionbytes), | |
|
53 | b'fsmonitor', | |
|
54 | b'fsmonitor: state file only has %d bytes, ' | |
|
55 | b'nuking state\n' % len(versionbytes), | |
|
56 | 56 | ) |
|
57 | 57 | self.invalidate() |
|
58 | 58 | return None, None, None |
@@ -61,21 +61,21 b' class state(object):' | |||
|
61 | 61 | if diskversion != _version: |
|
62 | 62 | # different version, nuke state and start over |
|
63 | 63 | self._ui.log( |
|
64 | 'fsmonitor', | |
|
65 | 'fsmonitor: version switch from %d to ' | |
|
66 | '%d, nuking state\n' % (diskversion, _version), | |
|
64 | b'fsmonitor', | |
|
65 | b'fsmonitor: version switch from %d to ' | |
|
66 | b'%d, nuking state\n' % (diskversion, _version), | |
|
67 | 67 | ) |
|
68 | 68 | self.invalidate() |
|
69 | 69 | return None, None, None |
|
70 | 70 | |
|
71 | state = file.read().split('\0') | |
|
71 | state = file.read().split(b'\0') | |
|
72 | 72 | # state = hostname\0clock\0ignorehash\0 + list of files, each |
|
73 | 73 | # followed by a \0 |
|
74 | 74 | if len(state) < 3: |
|
75 | 75 | self._ui.log( |
|
76 | 'fsmonitor', | |
|
77 | 'fsmonitor: state file truncated (expected ' | |
|
78 | '3 chunks, found %d), nuking state\n', | |
|
76 | b'fsmonitor', | |
|
77 | b'fsmonitor: state file truncated (expected ' | |
|
78 | b'3 chunks, found %d), nuking state\n', | |
|
79 | 79 | len(state), |
|
80 | 80 | ) |
|
81 | 81 | self.invalidate() |
@@ -85,9 +85,9 b' class state(object):' | |||
|
85 | 85 | if diskhostname != hostname: |
|
86 | 86 | # file got moved to a different host |
|
87 | 87 | self._ui.log( |
|
88 | 'fsmonitor', | |
|
89 | 'fsmonitor: stored hostname "%s" ' | |
|
90 | 'different from current "%s", nuking state\n' | |
|
88 | b'fsmonitor', | |
|
89 | b'fsmonitor: stored hostname "%s" ' | |
|
90 | b'different from current "%s", nuking state\n' | |
|
91 | 91 | % (diskhostname, hostname), |
|
92 | 92 | ) |
|
93 | 93 | self.invalidate() |
@@ -110,31 +110,33 b' class state(object):' | |||
|
110 | 110 | |
|
111 | 111 | # Read the identity from the file on disk rather than from the open file |
|
112 | 112 | # pointer below, because the latter is actually a brand new file. |
|
113 | identity = util.filestat.frompath(self._vfs.join('fsmonitor.state')) | |
|
113 | identity = util.filestat.frompath(self._vfs.join(b'fsmonitor.state')) | |
|
114 | 114 | if identity != self._identity: |
|
115 | self._ui.debug('skip updating fsmonitor.state: identity mismatch\n') | |
|
115 | self._ui.debug( | |
|
116 | b'skip updating fsmonitor.state: identity mismatch\n' | |
|
117 | ) | |
|
116 | 118 | return |
|
117 | 119 | |
|
118 | 120 | try: |
|
119 | 121 | file = self._vfs( |
|
120 | 'fsmonitor.state', 'wb', atomictemp=True, checkambig=True | |
|
122 | b'fsmonitor.state', b'wb', atomictemp=True, checkambig=True | |
|
121 | 123 | ) |
|
122 | 124 | except (IOError, OSError): |
|
123 | self._ui.warn(_("warning: unable to write out fsmonitor state\n")) | |
|
125 | self._ui.warn(_(b"warning: unable to write out fsmonitor state\n")) | |
|
124 | 126 | return |
|
125 | 127 | |
|
126 | 128 | with file: |
|
127 | 129 | file.write(struct.pack(_versionformat, _version)) |
|
128 | file.write(socket.gethostname() + '\0') | |
|
129 | file.write(clock + '\0') | |
|
130 | file.write(ignorehash + '\0') | |
|
130 | file.write(socket.gethostname() + b'\0') | |
|
131 | file.write(clock + b'\0') | |
|
132 | file.write(ignorehash + b'\0') | |
|
131 | 133 | if notefiles: |
|
132 | file.write('\0'.join(notefiles)) | |
|
133 | file.write('\0') | |
|
134 | file.write(b'\0'.join(notefiles)) | |
|
135 | file.write(b'\0') | |
|
134 | 136 | |
|
135 | 137 | def invalidate(self): |
|
136 | 138 | try: |
|
137 | os.unlink(os.path.join(self._rootdir, '.hg', 'fsmonitor.state')) | |
|
139 | os.unlink(os.path.join(self._rootdir, b'.hg', b'fsmonitor.state')) | |
|
138 | 140 | except OSError as inst: |
|
139 | 141 | if inst.errno != errno.ENOENT: |
|
140 | 142 | raise |
@@ -18,15 +18,15 b' class Unavailable(Exception):' | |||
|
18 | 18 | def __init__(self, msg, warn=True, invalidate=False): |
|
19 | 19 | self.msg = msg |
|
20 | 20 | self.warn = warn |
|
21 | if self.msg == 'timed out waiting for response': | |
|
21 | if self.msg == b'timed out waiting for response': | |
|
22 | 22 | self.warn = False |
|
23 | 23 | self.invalidate = invalidate |
|
24 | 24 | |
|
25 | 25 | def __str__(self): |
|
26 | 26 | if self.warn: |
|
27 | return 'warning: Watchman unavailable: %s' % self.msg | |
|
27 | return b'warning: Watchman unavailable: %s' % self.msg | |
|
28 | 28 | else: |
|
29 | return 'Watchman unavailable: %s' % self.msg | |
|
29 | return b'Watchman unavailable: %s' % self.msg | |
|
30 | 30 | |
|
31 | 31 | |
|
32 | 32 | class WatchmanNoRoot(Unavailable): |
@@ -39,10 +39,10 b' class client(object):' | |||
|
39 | 39 | def __init__(self, ui, root, timeout=1.0): |
|
40 | 40 | err = None |
|
41 | 41 | if not self._user: |
|
42 | err = "couldn't get user" | |
|
42 | err = b"couldn't get user" | |
|
43 | 43 | warn = True |
|
44 | if self._user in ui.configlist('fsmonitor', 'blacklistusers'): | |
|
45 | err = 'user %s in blacklist' % self._user | |
|
44 | if self._user in ui.configlist(b'fsmonitor', b'blacklistusers'): | |
|
45 | err = b'user %s in blacklist' % self._user | |
|
46 | 46 | warn = False |
|
47 | 47 | |
|
48 | 48 | if err: |
@@ -60,10 +60,10 b' class client(object):' | |||
|
60 | 60 | self._watchmanclient.setTimeout(timeout) |
|
61 | 61 | |
|
62 | 62 | def getcurrentclock(self): |
|
63 | result = self.command('clock') | |
|
64 | if not util.safehasattr(result, 'clock'): | |
|
63 | result = self.command(b'clock') | |
|
64 | if not util.safehasattr(result, b'clock'): | |
|
65 | 65 | raise Unavailable( |
|
66 | 'clock result is missing clock value', invalidate=True | |
|
66 | b'clock result is missing clock value', invalidate=True | |
|
67 | 67 | ) |
|
68 | 68 | return result.clock |
|
69 | 69 | |
@@ -86,7 +86,9 b' class client(object):' | |||
|
86 | 86 | try: |
|
87 | 87 | if self._watchmanclient is None: |
|
88 | 88 | self._firsttime = False |
|
89 |
watchman_exe = self._ui.configpath( |
|
|
89 | watchman_exe = self._ui.configpath( | |
|
90 | b'fsmonitor', b'watchman_exe' | |
|
91 | ) | |
|
90 | 92 | self._watchmanclient = pywatchman.client( |
|
91 | 93 | timeout=self._timeout, |
|
92 | 94 | useImmutableBser=True, |
@@ -94,7 +96,7 b' class client(object):' | |||
|
94 | 96 | ) |
|
95 | 97 | return self._watchmanclient.query(*watchmanargs) |
|
96 | 98 | except pywatchman.CommandError as ex: |
|
97 | if 'unable to resolve root' in ex.msg: | |
|
99 | if b'unable to resolve root' in ex.msg: | |
|
98 | 100 | raise WatchmanNoRoot(self._root, ex.msg) |
|
99 | 101 | raise Unavailable(ex.msg) |
|
100 | 102 | except pywatchman.WatchmanError as ex: |
@@ -107,7 +109,7 b' class client(object):' | |||
|
107 | 109 | except WatchmanNoRoot: |
|
108 | 110 | # this 'watch' command can also raise a WatchmanNoRoot if |
|
109 | 111 | # watchman refuses to accept this root |
|
110 | self._command('watch') | |
|
112 | self._command(b'watch') | |
|
111 | 113 | return self._command(*args) |
|
112 | 114 | except Unavailable: |
|
113 | 115 | # this is in an outer scope to catch Unavailable form any of the |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
General Comments 0
You need to be logged in to leave comments.
Login now