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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
59 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
60 | # be specifying the version(s) of Mercurial they are tested with, or |
|
60 | # be specifying the version(s) of Mercurial they are tested with, or | |
61 | # leave the attribute unspecified. |
|
61 | # leave the attribute unspecified. | |
62 | testedwith = 'ships-with-hg-core' |
|
62 | testedwith = b'ships-with-hg-core' | |
63 |
|
63 | |||
64 | cmdtable = {} |
|
64 | cmdtable = {} | |
65 | command = registrar.command(cmdtable) |
|
65 | command = registrar.command(cmdtable) | |
@@ -67,14 +67,14 b' command = registrar.command(cmdtable)' | |||||
67 | configtable = {} |
|
67 | configtable = {} | |
68 | configitem = registrar.configitem(configtable) |
|
68 | configitem = registrar.configitem(configtable) | |
69 |
|
69 | |||
70 | configitem('absorb', 'add-noise', default=True) |
|
70 | configitem(b'absorb', b'add-noise', default=True) | |
71 | configitem('absorb', 'amend-flag', default=None) |
|
71 | configitem(b'absorb', b'amend-flag', default=None) | |
72 | configitem('absorb', 'max-stack-size', default=50) |
|
72 | configitem(b'absorb', b'max-stack-size', default=50) | |
73 |
|
73 | |||
74 | colortable = { |
|
74 | colortable = { | |
75 | 'absorb.description': 'yellow', |
|
75 | b'absorb.description': b'yellow', | |
76 | 'absorb.node': 'blue bold', |
|
76 | b'absorb.node': b'blue bold', | |
77 | 'absorb.path': 'bold', |
|
77 | b'absorb.path': b'bold', | |
78 | } |
|
78 | } | |
79 |
|
79 | |||
80 | defaultdict = collections.defaultdict |
|
80 | defaultdict = collections.defaultdict | |
@@ -98,7 +98,7 b' class emptyfilecontext(object):' | |||||
98 | """minimal filecontext representing an empty file""" |
|
98 | """minimal filecontext representing an empty file""" | |
99 |
|
99 | |||
100 | def data(self): |
|
100 | def data(self): | |
101 | return '' |
|
101 | return b'' | |
102 |
|
102 | |||
103 | def node(self): |
|
103 | def node(self): | |
104 | return node.nullid |
|
104 | return node.nullid | |
@@ -364,11 +364,11 b' class filefixupstate(object):' | |||||
364 | if self.ui.debugflag: |
|
364 | if self.ui.debugflag: | |
365 | idx = (max(rev - 1, 0)) // 2 |
|
365 | idx = (max(rev - 1, 0)) // 2 | |
366 | self.ui.write( |
|
366 | self.ui.write( | |
367 | _('%s: chunk %d:%d -> %d lines\n') |
|
367 | _(b'%s: chunk %d:%d -> %d lines\n') | |
368 | % (node.short(self.fctxs[idx].node()), a1, a2, len(blines)) |
|
368 | % (node.short(self.fctxs[idx].node()), a1, a2, len(blines)) | |
369 | ) |
|
369 | ) | |
370 | self.linelog.replacelines(rev, a1, a2, b1, b2) |
|
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 | self.finalcontents = self._checkoutlinelogwithedits() |
|
372 | self.finalcontents = self._checkoutlinelogwithedits() | |
373 | else: |
|
373 | else: | |
374 | self.finalcontents = self._checkoutlinelog() |
|
374 | self.finalcontents = self._checkoutlinelog() | |
@@ -434,7 +434,7 b' class filefixupstate(object):' | |||||
434 | """like mdiff.allblocks, but only care about differences""" |
|
434 | """like mdiff.allblocks, but only care about differences""" | |
435 | blocks = mdiff.allblocks(a, b, lines1=alines, lines2=blines) |
|
435 | blocks = mdiff.allblocks(a, b, lines1=alines, lines2=blines) | |
436 | for chunk, btype in blocks: |
|
436 | for chunk, btype in blocks: | |
437 | if btype != '!': |
|
437 | if btype != b'!': | |
438 | continue |
|
438 | continue | |
439 | yield chunk |
|
439 | yield chunk | |
440 |
|
440 | |||
@@ -443,7 +443,7 b' class filefixupstate(object):' | |||||
443 | this is similar to running a partial "annotate". |
|
443 | this is similar to running a partial "annotate". | |
444 | """ |
|
444 | """ | |
445 | llog = linelog.linelog() |
|
445 | llog = linelog.linelog() | |
446 | a, alines = '', [] |
|
446 | a, alines = b'', [] | |
447 | for i in pycompat.xrange(len(self.contents)): |
|
447 | for i in pycompat.xrange(len(self.contents)): | |
448 | b, blines = self.contents[i], self.contentlines[i] |
|
448 | b, blines = self.contents[i], self.contentlines[i] | |
449 | llrev = i * 2 + 1 |
|
449 | llrev = i * 2 + 1 | |
@@ -459,7 +459,7 b' class filefixupstate(object):' | |||||
459 | for i in pycompat.xrange(len(self.contents)): |
|
459 | for i in pycompat.xrange(len(self.contents)): | |
460 | rev = (i + 1) * 2 |
|
460 | rev = (i + 1) * 2 | |
461 | self.linelog.annotate(rev) |
|
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 | contents.append(content) |
|
463 | contents.append(content) | |
464 | return contents |
|
464 | return contents | |
465 |
|
465 | |||
@@ -469,8 +469,8 b' class filefixupstate(object):' | |||||
469 | # header |
|
469 | # header | |
470 | editortext = ( |
|
470 | editortext = ( | |
471 | _( |
|
471 | _( | |
472 | 'HG: editing %s\nHG: "y" means the line to the right ' |
|
472 | b'HG: editing %s\nHG: "y" means the line to the right ' | |
473 | 'exists in the changeset to the top\nHG:\n' |
|
473 | b'exists in the changeset to the top\nHG:\n' | |
474 | ) |
|
474 | ) | |
475 | % self.fctxs[-1].path() |
|
475 | % self.fctxs[-1].path() | |
476 | ) |
|
476 | ) | |
@@ -481,13 +481,13 b' class filefixupstate(object):' | |||||
481 | if not isinstance(f, emptyfilecontext) |
|
481 | if not isinstance(f, emptyfilecontext) | |
482 | ] |
|
482 | ] | |
483 | for i, (j, f) in enumerate(visiblefctxs): |
|
483 | for i, (j, f) in enumerate(visiblefctxs): | |
484 | editortext += _('HG: %s/%s %s %s\n') % ( |
|
484 | editortext += _(b'HG: %s/%s %s %s\n') % ( | |
485 | '|' * i, |
|
485 | b'|' * i, | |
486 | '-' * (len(visiblefctxs) - i + 1), |
|
486 | b'-' * (len(visiblefctxs) - i + 1), | |
487 | node.short(f.node()), |
|
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 | # figure out the lifetime of a line, this is relatively inefficient, |
|
491 | # figure out the lifetime of a line, this is relatively inefficient, | |
492 | # but probably fine |
|
492 | # but probably fine | |
493 | lineset = defaultdict(lambda: set()) # {(llrev, linenum): {llrev}} |
|
493 | lineset = defaultdict(lambda: set()) # {(llrev, linenum): {llrev}} | |
@@ -497,33 +497,33 b' class filefixupstate(object):' | |||||
497 | lineset[l].add(i) |
|
497 | lineset[l].add(i) | |
498 | # append lines |
|
498 | # append lines | |
499 | for l in alllines: |
|
499 | for l in alllines: | |
500 | editortext += ' %s : %s' % ( |
|
500 | editortext += b' %s : %s' % ( | |
501 | ''.join( |
|
501 | b''.join( | |
502 | [ |
|
502 | [ | |
503 | ('y' if i in lineset[l] else ' ') |
|
503 | (b'y' if i in lineset[l] else b' ') | |
504 | for i, _f in visiblefctxs |
|
504 | for i, _f in visiblefctxs | |
505 | ] |
|
505 | ] | |
506 | ), |
|
506 | ), | |
507 | self._getline(l), |
|
507 | self._getline(l), | |
508 | ) |
|
508 | ) | |
509 | # run editor |
|
509 | # run editor | |
510 | editedtext = self.ui.edit(editortext, '', action='absorb') |
|
510 | editedtext = self.ui.edit(editortext, b'', action=b'absorb') | |
511 | if not editedtext: |
|
511 | if not editedtext: | |
512 | raise error.Abort(_('empty editor text')) |
|
512 | raise error.Abort(_(b'empty editor text')) | |
513 | # parse edited result |
|
513 | # parse edited result | |
514 | contents = ['' for i in self.fctxs] |
|
514 | contents = [b'' for i in self.fctxs] | |
515 | leftpadpos = 4 |
|
515 | leftpadpos = 4 | |
516 | colonpos = leftpadpos + len(visiblefctxs) + 1 |
|
516 | colonpos = leftpadpos + len(visiblefctxs) + 1 | |
517 | for l in mdiff.splitnewlines(editedtext): |
|
517 | for l in mdiff.splitnewlines(editedtext): | |
518 | if l.startswith('HG:'): |
|
518 | if l.startswith(b'HG:'): | |
519 | continue |
|
519 | continue | |
520 | if l[colonpos - 1 : colonpos + 2] != ' : ': |
|
520 | if l[colonpos - 1 : colonpos + 2] != b' : ': | |
521 | raise error.Abort(_('malformed line: %s') % l) |
|
521 | raise error.Abort(_(b'malformed line: %s') % l) | |
522 | linecontent = l[colonpos + 2 :] |
|
522 | linecontent = l[colonpos + 2 :] | |
523 | for i, ch in enumerate( |
|
523 | for i, ch in enumerate( | |
524 | pycompat.bytestr(l[leftpadpos : colonpos - 1]) |
|
524 | pycompat.bytestr(l[leftpadpos : colonpos - 1]) | |
525 | ): |
|
525 | ): | |
526 | if ch == 'y': |
|
526 | if ch == b'y': | |
527 | contents[visiblefctxs[i][0]] += linecontent |
|
527 | contents[visiblefctxs[i][0]] += linecontent | |
528 | # chunkstats is hard to calculate if anything changes, therefore |
|
528 | # chunkstats is hard to calculate if anything changes, therefore | |
529 | # set them to just a simple value (1, 1). |
|
529 | # set them to just a simple value (1, 1). | |
@@ -589,7 +589,7 b' class filefixupstate(object):' | |||||
589 |
|
589 | |||
590 | def _showchanges(self, fm, alines, blines, chunk, fixups): |
|
590 | def _showchanges(self, fm, alines, blines, chunk, fixups): | |
591 | def trim(line): |
|
591 | def trim(line): | |
592 | if line.endswith('\n'): |
|
592 | if line.endswith(b'\n'): | |
593 | line = line[:-1] |
|
593 | line = line[:-1] | |
594 | return line |
|
594 | return line | |
595 |
|
595 | |||
@@ -605,25 +605,25 b' class filefixupstate(object):' | |||||
605 |
|
605 | |||
606 | fm.startitem() |
|
606 | fm.startitem() | |
607 | fm.write( |
|
607 | fm.write( | |
608 | 'hunk', |
|
608 | b'hunk', | |
609 | ' %s\n', |
|
609 | b' %s\n', | |
610 | '@@ -%d,%d +%d,%d @@' % (a1, a2 - a1, b1, b2 - b1), |
|
610 | b'@@ -%d,%d +%d,%d @@' % (a1, a2 - a1, b1, b2 - b1), | |
611 | label='diff.hunk', |
|
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 | def writeline(idx, diffchar, line, linetype, linelabel): |
|
615 | def writeline(idx, diffchar, line, linetype, linelabel): | |
616 | fm.startitem() |
|
616 | fm.startitem() | |
617 | node = '' |
|
617 | node = b'' | |
618 | if idx: |
|
618 | if idx: | |
619 | ctx = self.fctxs[idx] |
|
619 | ctx = self.fctxs[idx] | |
620 | fm.context(fctx=ctx) |
|
620 | fm.context(fctx=ctx) | |
621 | node = ctx.hex() |
|
621 | node = ctx.hex() | |
622 | self.ctxaffected.add(ctx.changectx()) |
|
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 | fm.write( |
|
624 | fm.write( | |
625 | 'diffchar ' + linetype, |
|
625 | b'diffchar ' + linetype, | |
626 | '%s%s\n', |
|
626 | b'%s%s\n', | |
627 | diffchar, |
|
627 | diffchar, | |
628 | line, |
|
628 | line, | |
629 | label=linelabel, |
|
629 | label=linelabel, | |
@@ -632,11 +632,19 b' class filefixupstate(object):' | |||||
632 |
|
632 | |||
633 | for i in pycompat.xrange(a1, a2): |
|
633 | for i in pycompat.xrange(a1, a2): | |
634 | writeline( |
|
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 | for i in pycompat.xrange(b1, b2): |
|
641 | for i in pycompat.xrange(b1, b2): | |
638 | writeline( |
|
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 | self.paths = [] |
|
689 | self.paths = [] | |
682 | # but if --edit-lines is used, the user may want to edit files |
|
690 | # but if --edit-lines is used, the user may want to edit files | |
683 | # even if they are not modified |
|
691 | # even if they are not modified | |
684 | editopt = self.opts.get('edit_lines') |
|
692 | editopt = self.opts.get(b'edit_lines') | |
685 | if not self.status.modified and editopt and match: |
|
693 | if not self.status.modified and editopt and match: | |
686 | interestingpaths = match.files() |
|
694 | interestingpaths = match.files() | |
687 | else: |
|
695 | else: | |
@@ -691,7 +699,7 b' class fixupstate(object):' | |||||
691 | # sorting is necessary to eliminate ambiguity for the "double move" |
|
699 | # sorting is necessary to eliminate ambiguity for the "double move" | |
692 | # case: "hg cp A B; hg cp A C; hg rm A", then only "B" can affect "A". |
|
700 | # case: "hg cp A B; hg cp A C; hg rm A", then only "B" can affect "A". | |
693 | for path in sorted(interestingpaths): |
|
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 | targetfctx = targetctx[path] |
|
703 | targetfctx = targetctx[path] | |
696 | fctxs, ctx2fctx = getfilestack(self.stack, path, seenfctxs) |
|
704 | fctxs, ctx2fctx = getfilestack(self.stack, path, seenfctxs) | |
697 | # ignore symbolic links or binary, or unchanged files |
|
705 | # ignore symbolic links or binary, or unchanged files | |
@@ -708,9 +716,9 b' class fixupstate(object):' | |||||
708 | fstate = filefixupstate(fctxs, path, ui=self.ui, opts=self.opts) |
|
716 | fstate = filefixupstate(fctxs, path, ui=self.ui, opts=self.opts) | |
709 | if fm is not None: |
|
717 | if fm is not None: | |
710 | fm.startitem() |
|
718 | fm.startitem() | |
711 | fm.plain('showing changes for ') |
|
719 | fm.plain(b'showing changes for ') | |
712 | fm.write('path', '%s\n', path, label='absorb.path') |
|
720 | fm.write(b'path', b'%s\n', path, label=b'absorb.path') | |
713 | fm.data(linetype='path') |
|
721 | fm.data(linetype=b'path') | |
714 | fstate.diffwith(targetfctx, fm) |
|
722 | fstate.diffwith(targetfctx, fm) | |
715 | self.fixupmap[path] = fstate |
|
723 | self.fixupmap[path] = fstate | |
716 | self.paths.append(path) |
|
724 | self.paths.append(path) | |
@@ -720,7 +728,7 b' class fixupstate(object):' | |||||
720 | """apply fixups to individual filefixupstates""" |
|
728 | """apply fixups to individual filefixupstates""" | |
721 | for path, state in self.fixupmap.iteritems(): |
|
729 | for path, state in self.fixupmap.iteritems(): | |
722 | if self.ui.debugflag: |
|
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 | state.apply() |
|
732 | state.apply() | |
725 |
|
733 | |||
726 | @property |
|
734 | @property | |
@@ -733,10 +741,10 b' class fixupstate(object):' | |||||
733 |
|
741 | |||
734 | def commit(self): |
|
742 | def commit(self): | |
735 | """commit changes. update self.finalnode, self.replacemap""" |
|
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 | self._commitstack() |
|
745 | self._commitstack() | |
738 | self._movebookmarks(tr) |
|
746 | self._movebookmarks(tr) | |
739 | if self.repo['.'].node() in self.replacemap: |
|
747 | if self.repo[b'.'].node() in self.replacemap: | |
740 | self._moveworkingdirectoryparent() |
|
748 | self._moveworkingdirectoryparent() | |
741 | self._cleanupoldcommits() |
|
749 | self._cleanupoldcommits() | |
742 | return self.finalnode |
|
750 | return self.finalnode | |
@@ -750,14 +758,14 b' class fixupstate(object):' | |||||
750 | for path, stat in chunkstats.iteritems(): |
|
758 | for path, stat in chunkstats.iteritems(): | |
751 | if stat[0]: |
|
759 | if stat[0]: | |
752 | ui.write( |
|
760 | ui.write( | |
753 | _('%s: %d of %d chunk(s) applied\n') |
|
761 | _(b'%s: %d of %d chunk(s) applied\n') | |
754 | % (path, stat[0], stat[1]) |
|
762 | % (path, stat[0], stat[1]) | |
755 | ) |
|
763 | ) | |
756 | elif not ui.quiet: |
|
764 | elif not ui.quiet: | |
757 | # a summary for all files |
|
765 | # a summary for all files | |
758 | stats = chunkstats.values() |
|
766 | stats = chunkstats.values() | |
759 | applied, total = (sum(s[i] for s in stats) for i in (0, 1)) |
|
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 | def _commitstack(self): |
|
770 | def _commitstack(self): | |
763 | """make new commits. update self.finalnode, self.replacemap. |
|
771 | """make new commits. update self.finalnode, self.replacemap. | |
@@ -777,7 +785,7 b' class fixupstate(object):' | |||||
777 | if self._willbecomenoop(memworkingcopy, ctx, nextp1): |
|
785 | if self._willbecomenoop(memworkingcopy, ctx, nextp1): | |
778 | # changeset is no longer necessary |
|
786 | # changeset is no longer necessary | |
779 | self.replacemap[ctx.node()] = None |
|
787 | self.replacemap[ctx.node()] = None | |
780 | msg = _('became empty and was dropped') |
|
788 | msg = _(b'became empty and was dropped') | |
781 | else: |
|
789 | else: | |
782 | # changeset needs re-commit |
|
790 | # changeset needs re-commit | |
783 | nodestr = self._commitsingle(memworkingcopy, ctx, p1=nextp1) |
|
791 | nodestr = self._commitsingle(memworkingcopy, ctx, p1=nextp1) | |
@@ -785,21 +793,21 b' class fixupstate(object):' | |||||
785 | nextp1 = lastcommitted |
|
793 | nextp1 = lastcommitted | |
786 | self.replacemap[ctx.node()] = lastcommitted.node() |
|
794 | self.replacemap[ctx.node()] = lastcommitted.node() | |
787 | if memworkingcopy: |
|
795 | if memworkingcopy: | |
788 | msg = _('%d file(s) changed, became %s') % ( |
|
796 | msg = _(b'%d file(s) changed, became %s') % ( | |
789 | len(memworkingcopy), |
|
797 | len(memworkingcopy), | |
790 | self._ctx2str(lastcommitted), |
|
798 | self._ctx2str(lastcommitted), | |
791 | ) |
|
799 | ) | |
792 | else: |
|
800 | else: | |
793 | msg = _('became %s') % self._ctx2str(lastcommitted) |
|
801 | msg = _(b'became %s') % self._ctx2str(lastcommitted) | |
794 | if self.ui.verbose and msg: |
|
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 | self.finalnode = lastcommitted and lastcommitted.node() |
|
804 | self.finalnode = lastcommitted and lastcommitted.node() | |
797 |
|
805 | |||
798 | def _ctx2str(self, ctx): |
|
806 | def _ctx2str(self, ctx): | |
799 | if self.ui.debugflag: |
|
807 | if self.ui.debugflag: | |
800 | return '%d:%s' % (ctx.rev(), ctx.hex()) |
|
808 | return b'%d:%s' % (ctx.rev(), ctx.hex()) | |
801 | else: |
|
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 | def _getnewfilecontents(self, ctx): |
|
812 | def _getnewfilecontents(self, ctx): | |
805 | """(ctx) -> {path: str} |
|
813 | """(ctx) -> {path: str} | |
@@ -832,18 +840,18 b' class fixupstate(object):' | |||||
832 | changes.append((name, hsh)) |
|
840 | changes.append((name, hsh)) | |
833 | if self.ui.verbose: |
|
841 | if self.ui.verbose: | |
834 | self.ui.write( |
|
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 | else: |
|
845 | else: | |
838 | changes.append((name, None)) |
|
846 | changes.append((name, None)) | |
839 | if self.ui.verbose: |
|
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 | repo._bookmarks.applychanges(repo, tr, changes) |
|
849 | repo._bookmarks.applychanges(repo, tr, changes) | |
842 |
|
850 | |||
843 | def _moveworkingdirectoryparent(self): |
|
851 | def _moveworkingdirectoryparent(self): | |
844 | if not self.finalnode: |
|
852 | if not self.finalnode: | |
845 | # Find the latest not-{obsoleted,stripped} parent. |
|
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 | ctx = self.repo[revs.first()] |
|
855 | ctx = self.repo[revs.first()] | |
848 | self.finalnode = ctx.node() |
|
856 | self.finalnode = ctx.node() | |
849 | else: |
|
857 | else: | |
@@ -854,7 +862,7 b' class fixupstate(object):' | |||||
854 | # be slow. in absorb's case, no need to invalidate fsmonitorstate. |
|
862 | # be slow. in absorb's case, no need to invalidate fsmonitorstate. | |
855 | noop = lambda: 0 |
|
863 | noop = lambda: 0 | |
856 | restore = noop |
|
864 | restore = noop | |
857 | if util.safehasattr(dirstate, '_fsmonitorstate'): |
|
865 | if util.safehasattr(dirstate, b'_fsmonitorstate'): | |
858 | bak = dirstate._fsmonitorstate.invalidate |
|
866 | bak = dirstate._fsmonitorstate.invalidate | |
859 |
|
867 | |||
860 | def restore(): |
|
868 | def restore(): | |
@@ -901,8 +909,8 b' class fixupstate(object):' | |||||
901 | """ |
|
909 | """ | |
902 | parents = p1 and (p1, node.nullid) |
|
910 | parents = p1 and (p1, node.nullid) | |
903 | extra = ctx.extra() |
|
911 | extra = ctx.extra() | |
904 | if self._useobsolete and self.ui.configbool('absorb', 'add-noise'): |
|
912 | if self._useobsolete and self.ui.configbool(b'absorb', b'add-noise'): | |
905 | extra['absorb_source'] = ctx.hex() |
|
913 | extra[b'absorb_source'] = ctx.hex() | |
906 | mctx = overlaycontext(memworkingcopy, ctx, parents, extra=extra) |
|
914 | mctx = overlaycontext(memworkingcopy, ctx, parents, extra=extra) | |
907 | return mctx.commit() |
|
915 | return mctx.commit() | |
908 |
|
916 | |||
@@ -918,7 +926,7 b' class fixupstate(object):' | |||||
918 | } |
|
926 | } | |
919 | if replacements: |
|
927 | if replacements: | |
920 | scmutil.cleanupnodes( |
|
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 | patchlines = mdiff.splitnewlines(buf.getvalue()) |
|
943 | patchlines = mdiff.splitnewlines(buf.getvalue()) | |
936 | # hunk.prettystr() will update hunk.removed |
|
944 | # hunk.prettystr() will update hunk.removed | |
937 | a2 = a1 + hunk.removed |
|
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 | return path, (a1, a2, blines) |
|
947 | return path, (a1, a2, blines) | |
940 |
|
948 | |||
941 |
|
949 | |||
@@ -967,7 +975,7 b' def overlaydiffcontext(ctx, chunks):' | |||||
967 | lines = mdiff.splitnewlines(ctx[path].data()) |
|
975 | lines = mdiff.splitnewlines(ctx[path].data()) | |
968 | for a1, a2, blines in patches: |
|
976 | for a1, a2, blines in patches: | |
969 | lines[a1:a2] = blines |
|
977 | lines[a1:a2] = blines | |
970 | memworkingcopy[path] = ''.join(lines) |
|
978 | memworkingcopy[path] = b''.join(lines) | |
971 | return overlaycontext(memworkingcopy, ctx) |
|
979 | return overlaycontext(memworkingcopy, ctx) | |
972 |
|
980 | |||
973 |
|
981 | |||
@@ -979,18 +987,21 b' def absorb(ui, repo, stack=None, targetc' | |||||
979 | return fixupstate. |
|
987 | return fixupstate. | |
980 | """ |
|
988 | """ | |
981 | if stack is None: |
|
989 | if stack is None: | |
982 | limit = ui.configint('absorb', 'max-stack-size') |
|
990 | limit = ui.configint(b'absorb', b'max-stack-size') | |
983 | headctx = repo['.'] |
|
991 | headctx = repo[b'.'] | |
984 | if len(headctx.parents()) > 1: |
|
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 | stack = getdraftstack(headctx, limit) |
|
994 | stack = getdraftstack(headctx, limit) | |
987 | if limit and len(stack) >= limit: |
|
995 | if limit and len(stack) >= limit: | |
988 | ui.warn( |
|
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 | % limit |
|
1001 | % limit | |
991 | ) |
|
1002 | ) | |
992 | if not stack: |
|
1003 | if not stack: | |
993 | raise error.Abort(_('no mutable changeset to change')) |
|
1004 | raise error.Abort(_(b'no mutable changeset to change')) | |
994 | if targetctx is None: # default to working copy |
|
1005 | if targetctx is None: # default to working copy | |
995 | targetctx = repo[None] |
|
1006 | targetctx = repo[None] | |
996 | if pats is None: |
|
1007 | if pats is None: | |
@@ -999,85 +1010,89 b' def absorb(ui, repo, stack=None, targetc' | |||||
999 | opts = {} |
|
1010 | opts = {} | |
1000 | state = fixupstate(stack, ui=ui, opts=opts) |
|
1011 | state = fixupstate(stack, ui=ui, opts=opts) | |
1001 | matcher = scmutil.match(targetctx, pats, opts) |
|
1012 | matcher = scmutil.match(targetctx, pats, opts) | |
1002 | if opts.get('interactive'): |
|
1013 | if opts.get(b'interactive'): | |
1003 | diff = patch.diff(repo, stack[-1].node(), targetctx.node(), matcher) |
|
1014 | diff = patch.diff(repo, stack[-1].node(), targetctx.node(), matcher) | |
1004 | origchunks = patch.parsepatch(diff) |
|
1015 | origchunks = patch.parsepatch(diff) | |
1005 | chunks = cmdutil.recordfilter(ui, origchunks, matcher)[0] |
|
1016 | chunks = cmdutil.recordfilter(ui, origchunks, matcher)[0] | |
1006 | targetctx = overlaydiffcontext(stack[-1], chunks) |
|
1017 | targetctx = overlaydiffcontext(stack[-1], chunks) | |
1007 | fm = None |
|
1018 | fm = None | |
1008 | if opts.get('print_changes') or not opts.get('apply_changes'): |
|
1019 | if opts.get(b'print_changes') or not opts.get(b'apply_changes'): | |
1009 | fm = ui.formatter('absorb', opts) |
|
1020 | fm = ui.formatter(b'absorb', opts) | |
1010 | state.diffwith(targetctx, matcher, fm) |
|
1021 | state.diffwith(targetctx, matcher, fm) | |
1011 | if fm is not None: |
|
1022 | if fm is not None: | |
1012 | fm.startitem() |
|
1023 | fm.startitem() | |
1013 | fm.write("count", "\n%d changesets affected\n", len(state.ctxaffected)) |
|
1024 | fm.write( | |
1014 | fm.data(linetype='summary') |
|
1025 | b"count", b"\n%d changesets affected\n", len(state.ctxaffected) | |
|
1026 | ) | |||
|
1027 | fm.data(linetype=b'summary') | |||
1015 | for ctx in reversed(stack): |
|
1028 | for ctx in reversed(stack): | |
1016 | if ctx not in state.ctxaffected: |
|
1029 | if ctx not in state.ctxaffected: | |
1017 | continue |
|
1030 | continue | |
1018 | fm.startitem() |
|
1031 | fm.startitem() | |
1019 | fm.context(ctx=ctx) |
|
1032 | fm.context(ctx=ctx) | |
1020 | fm.data(linetype='changeset') |
|
1033 | fm.data(linetype=b'changeset') | |
1021 | fm.write('node', '%-7.7s ', ctx.hex(), label='absorb.node') |
|
1034 | fm.write(b'node', b'%-7.7s ', ctx.hex(), label=b'absorb.node') | |
1022 | descfirstline = ctx.description().splitlines()[0] |
|
1035 | descfirstline = ctx.description().splitlines()[0] | |
1023 | fm.write( |
|
1036 | fm.write( | |
1024 | 'descfirstline', |
|
1037 | b'descfirstline', | |
1025 | '%s\n', |
|
1038 | b'%s\n', | |
1026 | descfirstline, |
|
1039 | descfirstline, | |
1027 | label='absorb.description', |
|
1040 | label=b'absorb.description', | |
1028 | ) |
|
1041 | ) | |
1029 | fm.end() |
|
1042 | fm.end() | |
1030 | if not opts.get('dry_run'): |
|
1043 | if not opts.get(b'dry_run'): | |
1031 | if ( |
|
1044 | if ( | |
1032 | not opts.get('apply_changes') |
|
1045 | not opts.get(b'apply_changes') | |
1033 | and state.ctxaffected |
|
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 | state.apply() |
|
1053 | state.apply() | |
1039 | if state.commit(): |
|
1054 | if state.commit(): | |
1040 | state.printchunkstats() |
|
1055 | state.printchunkstats() | |
1041 | elif not ui.quiet: |
|
1056 | elif not ui.quiet: | |
1042 | ui.write(_('nothing applied\n')) |
|
1057 | ui.write(_(b'nothing applied\n')) | |
1043 | return state |
|
1058 | return state | |
1044 |
|
1059 | |||
1045 |
|
1060 | |||
1046 | @command( |
|
1061 | @command( | |
1047 | 'absorb', |
|
1062 | b'absorb', | |
1048 | [ |
|
1063 | [ | |
1049 | ( |
|
1064 | ( | |
1050 | 'a', |
|
1065 | b'a', | |
1051 | 'apply-changes', |
|
1066 | b'apply-changes', | |
1052 | None, |
|
1067 | None, | |
1053 | _('apply changes without prompting for confirmation'), |
|
1068 | _(b'apply changes without prompting for confirmation'), | |
1054 | ), |
|
1069 | ), | |
1055 | ( |
|
1070 | ( | |
1056 | 'p', |
|
1071 | b'p', | |
1057 | 'print-changes', |
|
1072 | b'print-changes', | |
1058 | None, |
|
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', |
|
1077 | b'i', | |
1063 | 'interactive', |
|
1078 | b'interactive', | |
1064 | None, |
|
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', |
|
1083 | b'e', | |
1069 | 'edit-lines', |
|
1084 | b'edit-lines', | |
1070 | None, |
|
1085 | None, | |
1071 | _( |
|
1086 | _( | |
1072 | 'edit what lines belong to which changesets before commit ' |
|
1087 | b'edit what lines belong to which changesets before commit ' | |
1073 | '(EXPERIMENTAL)' |
|
1088 | b'(EXPERIMENTAL)' | |
1074 | ), |
|
1089 | ), | |
1075 | ), |
|
1090 | ), | |
1076 | ] |
|
1091 | ] | |
1077 | + commands.dryrunopts |
|
1092 | + commands.dryrunopts | |
1078 | + commands.templateopts |
|
1093 | + commands.templateopts | |
1079 | + commands.walkopts, |
|
1094 | + commands.walkopts, | |
1080 | _('hg absorb [OPTION] [FILE]...'), |
|
1095 | _(b'hg absorb [OPTION] [FILE]...'), | |
1081 | helpcategory=command.CATEGORY_COMMITTING, |
|
1096 | helpcategory=command.CATEGORY_COMMITTING, | |
1082 | helpbasic=True, |
|
1097 | helpbasic=True, | |
1083 | ) |
|
1098 | ) | |
@@ -1108,7 +1123,7 b' def absorbcmd(ui, repo, *pats, **opts):' | |||||
1108 | opts = pycompat.byteskwargs(opts) |
|
1123 | opts = pycompat.byteskwargs(opts) | |
1109 |
|
1124 | |||
1110 | with repo.wlock(), repo.lock(): |
|
1125 | with repo.wlock(), repo.lock(): | |
1111 | if not opts['dry_run']: |
|
1126 | if not opts[b'dry_run']: | |
1112 | cmdutil.checkunfinished(repo) |
|
1127 | cmdutil.checkunfinished(repo) | |
1113 |
|
1128 | |||
1114 | state = absorb(ui, repo, pats=pats, opts=opts) |
|
1129 | state = absorb(ui, repo, pats=pats, opts=opts) |
@@ -232,66 +232,66 b' urlreq = util.urlreq' | |||||
232 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
232 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
233 | # be specifying the version(s) of Mercurial they are tested with, or |
|
233 | # be specifying the version(s) of Mercurial they are tested with, or | |
234 | # leave the attribute unspecified. |
|
234 | # leave the attribute unspecified. | |
235 | testedwith = 'ships-with-hg-core' |
|
235 | testedwith = b'ships-with-hg-core' | |
236 |
|
236 | |||
237 | configtable = {} |
|
237 | configtable = {} | |
238 | configitem = registrar.configitem(configtable) |
|
238 | configitem = registrar.configitem(configtable) | |
239 |
|
239 | |||
240 | # deprecated config: acl.config |
|
240 | # deprecated config: acl.config | |
241 | configitem( |
|
241 | configitem( | |
242 | 'acl', 'config', default=None, |
|
242 | b'acl', b'config', default=None, | |
243 | ) |
|
243 | ) | |
244 | configitem( |
|
244 | configitem( | |
245 | 'acl.groups', '.*', default=None, generic=True, |
|
245 | b'acl.groups', b'.*', default=None, generic=True, | |
246 | ) |
|
246 | ) | |
247 | configitem( |
|
247 | configitem( | |
248 | 'acl.deny.branches', '.*', default=None, generic=True, |
|
248 | b'acl.deny.branches', b'.*', default=None, generic=True, | |
249 | ) |
|
249 | ) | |
250 | configitem( |
|
250 | configitem( | |
251 | 'acl.allow.branches', '.*', default=None, generic=True, |
|
251 | b'acl.allow.branches', b'.*', default=None, generic=True, | |
252 | ) |
|
252 | ) | |
253 | configitem( |
|
253 | configitem( | |
254 | 'acl.deny', '.*', default=None, generic=True, |
|
254 | b'acl.deny', b'.*', default=None, generic=True, | |
255 | ) |
|
255 | ) | |
256 | configitem( |
|
256 | configitem( | |
257 | 'acl.allow', '.*', default=None, generic=True, |
|
257 | b'acl.allow', b'.*', default=None, generic=True, | |
258 | ) |
|
258 | ) | |
259 | configitem( |
|
259 | configitem( | |
260 | 'acl', 'sources', default=lambda: ['serve'], |
|
260 | b'acl', b'sources', default=lambda: [b'serve'], | |
261 | ) |
|
261 | ) | |
262 |
|
262 | |||
263 |
|
263 | |||
264 | def _getusers(ui, group): |
|
264 | def _getusers(ui, group): | |
265 |
|
265 | |||
266 | # First, try to use group definition from section [acl.groups] |
|
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 | if hgrcusers: |
|
268 | if hgrcusers: | |
269 | return hgrcusers |
|
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 | # If no users found in group definition, get users from OS-level group |
|
272 | # If no users found in group definition, get users from OS-level group | |
273 | try: |
|
273 | try: | |
274 | return util.groupmembers(group) |
|
274 | return util.groupmembers(group) | |
275 | except KeyError: |
|
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 | def _usermatch(ui, user, usersorgroups): |
|
279 | def _usermatch(ui, user, usersorgroups): | |
280 |
|
280 | |||
281 | if usersorgroups == '*': |
|
281 | if usersorgroups == b'*': | |
282 | return True |
|
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 | # Test for excluded user or group. Format: |
|
287 | # Test for excluded user or group. Format: | |
288 | # if ug is a user name: !username |
|
288 | # if ug is a user name: !username | |
289 | # if ug is a group name: !@groupname |
|
289 | # if ug is a group name: !@groupname | |
290 | ug = ug[1:] |
|
290 | ug = ug[1:] | |
291 | if ( |
|
291 | if ( | |
292 | not ug.startswith('@') |
|
292 | not ug.startswith(b'@') | |
293 | and user != ug |
|
293 | and user != ug | |
294 | or ug.startswith('@') |
|
294 | or ug.startswith(b'@') | |
295 | and user not in _getusers(ui, ug[1:]) |
|
295 | and user not in _getusers(ui, ug[1:]) | |
296 | ): |
|
296 | ): | |
297 | return True |
|
297 | return True | |
@@ -299,7 +299,9 b' def _usermatch(ui, user, usersorgroups):' | |||||
299 | # Test for user or group. Format: |
|
299 | # Test for user or group. Format: | |
300 | # if ug is a user name: username |
|
300 | # if ug is a user name: username | |
301 | # if ug is a group name: @groupname |
|
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 | return True |
|
305 | return True | |
304 |
|
306 | |||
305 | return False |
|
307 | return False | |
@@ -308,14 +310,14 b' def _usermatch(ui, user, usersorgroups):' | |||||
308 | def buildmatch(ui, repo, user, key): |
|
310 | def buildmatch(ui, repo, user, key): | |
309 | '''return tuple of (match function, list enabled).''' |
|
311 | '''return tuple of (match function, list enabled).''' | |
310 | if not ui.has_section(key): |
|
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 | return None |
|
314 | return None | |
313 |
|
315 | |||
314 | pats = [ |
|
316 | pats = [ | |
315 | pat for pat, users in ui.configitems(key) if _usermatch(ui, user, users) |
|
317 | pat for pat, users in ui.configitems(key) if _usermatch(ui, user, users) | |
316 | ] |
|
318 | ] | |
317 | ui.debug( |
|
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 | # Branch-based ACL |
|
323 | # Branch-based ACL | |
@@ -323,14 +325,14 b' def buildmatch(ui, repo, user, key):' | |||||
323 | if pats: |
|
325 | if pats: | |
324 | # If there's an asterisk (meaning "any branch"), always return True; |
|
326 | # If there's an asterisk (meaning "any branch"), always return True; | |
325 | # Otherwise, test if b is in pats |
|
327 | # Otherwise, test if b is in pats | |
326 | if '*' in pats: |
|
328 | if b'*' in pats: | |
327 | return util.always |
|
329 | return util.always | |
328 | return lambda b: b in pats |
|
330 | return lambda b: b in pats | |
329 | return util.never |
|
331 | return util.never | |
330 |
|
332 | |||
331 | # Path-based ACL |
|
333 | # Path-based ACL | |
332 | if pats: |
|
334 | if pats: | |
333 | return match.match(repo.root, '', pats) |
|
335 | return match.match(repo.root, b'', pats) | |
334 | return util.never |
|
336 | return util.never | |
335 |
|
337 | |||
336 |
|
338 | |||
@@ -342,122 +344,128 b' def ensureenabled(ui):' | |||||
342 | never loaded. This function ensure the extension is enabled when running |
|
344 | never loaded. This function ensure the extension is enabled when running | |
343 | hooks. |
|
345 | hooks. | |
344 | """ |
|
346 | """ | |
345 | if 'acl' in ui._knownconfig: |
|
347 | if b'acl' in ui._knownconfig: | |
346 | return |
|
348 | return | |
347 | ui.setconfig('extensions', 'acl', '', source='internal') |
|
349 | ui.setconfig(b'extensions', b'acl', b'', source=b'internal') | |
348 | extensions.loadall(ui, ['acl']) |
|
350 | extensions.loadall(ui, [b'acl']) | |
349 |
|
351 | |||
350 |
|
352 | |||
351 | def hook(ui, repo, hooktype, node=None, source=None, **kwargs): |
|
353 | def hook(ui, repo, hooktype, node=None, source=None, **kwargs): | |
352 |
|
354 | |||
353 | ensureenabled(ui) |
|
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 | raise error.Abort( |
|
358 | raise error.Abort( | |
357 | _( |
|
359 | _( | |
358 | 'config error - hook type "%s" cannot stop ' |
|
360 | b'config error - hook type "%s" cannot stop ' | |
359 | 'incoming changesets, commits, nor bookmarks' |
|
361 | b'incoming changesets, commits, nor bookmarks' | |
360 | ) |
|
362 | ) | |
361 | % hooktype |
|
363 | % hooktype | |
362 | ) |
|
364 | ) | |
363 | if hooktype == 'pretxnchangegroup' and source not in ui.configlist( |
|
365 | if hooktype == b'pretxnchangegroup' and source not in ui.configlist( | |
364 | 'acl', 'sources' |
|
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 | return |
|
369 | return | |
368 |
|
370 | |||
369 | user = None |
|
371 | user = None | |
370 | if source == 'serve' and r'url' in kwargs: |
|
372 | if source == b'serve' and r'url' in kwargs: | |
371 | url = kwargs[r'url'].split(':') |
|
373 | url = kwargs[r'url'].split(b':') | |
372 | if url[0] == 'remote' and url[1].startswith('http'): |
|
374 | if url[0] == b'remote' and url[1].startswith(b'http'): | |
373 | user = urlreq.unquote(url[3]) |
|
375 | user = urlreq.unquote(url[3]) | |
374 |
|
376 | |||
375 | if user is None: |
|
377 | if user is None: | |
376 | user = procutil.getuser() |
|
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 | _pkhook(ui, repo, hooktype, node, source, user, **kwargs) |
|
383 | _pkhook(ui, repo, hooktype, node, source, user, **kwargs) | |
382 | else: |
|
384 | else: | |
383 | _txnhook(ui, repo, hooktype, node, source, user, **kwargs) |
|
385 | _txnhook(ui, repo, hooktype, node, source, user, **kwargs) | |
384 |
|
386 | |||
385 |
|
387 | |||
386 | def _pkhook(ui, repo, hooktype, node, source, user, **kwargs): |
|
388 | def _pkhook(ui, repo, hooktype, node, source, user, **kwargs): | |
387 | if kwargs[r'namespace'] == 'bookmarks': |
|
389 | if kwargs[r'namespace'] == b'bookmarks': | |
388 | bookmark = kwargs[r'key'] |
|
390 | bookmark = kwargs[r'key'] | |
389 | ctx = kwargs[r'new'] |
|
391 | ctx = kwargs[r'new'] | |
390 | allowbookmarks = buildmatch(ui, None, user, 'acl.allow.bookmarks') |
|
392 | allowbookmarks = buildmatch(ui, None, user, b'acl.allow.bookmarks') | |
391 | denybookmarks = buildmatch(ui, None, user, 'acl.deny.bookmarks') |
|
393 | denybookmarks = buildmatch(ui, None, user, b'acl.deny.bookmarks') | |
392 |
|
394 | |||
393 | if denybookmarks and denybookmarks(bookmark): |
|
395 | if denybookmarks and denybookmarks(bookmark): | |
394 | raise error.Abort( |
|
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 | % (user, bookmark, ctx) |
|
401 | % (user, bookmark, ctx) | |
397 | ) |
|
402 | ) | |
398 | if allowbookmarks and not allowbookmarks(bookmark): |
|
403 | if allowbookmarks and not allowbookmarks(bookmark): | |
399 | raise error.Abort( |
|
404 | raise error.Abort( | |
400 | _( |
|
405 | _( | |
401 | 'acl: user "%s" not allowed on bookmark "%s"' |
|
406 | b'acl: user "%s" not allowed on bookmark "%s"' | |
402 | ' (changeset "%s")' |
|
407 | b' (changeset "%s")' | |
403 | ) |
|
408 | ) | |
404 | % (user, bookmark, ctx) |
|
409 | % (user, bookmark, ctx) | |
405 | ) |
|
410 | ) | |
406 | ui.debug( |
|
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 | % (ctx, bookmark) |
|
413 | % (ctx, bookmark) | |
409 | ) |
|
414 | ) | |
410 |
|
415 | |||
411 |
|
416 | |||
412 | def _txnhook(ui, repo, hooktype, node, source, user, **kwargs): |
|
417 | def _txnhook(ui, repo, hooktype, node, source, user, **kwargs): | |
413 | # deprecated config: acl.config |
|
418 | # deprecated config: acl.config | |
414 | cfg = ui.config('acl', 'config') |
|
419 | cfg = ui.config(b'acl', b'config') | |
415 | if cfg: |
|
420 | if cfg: | |
416 | ui.readconfig( |
|
421 | ui.readconfig( | |
417 | cfg, |
|
422 | cfg, | |
418 | sections=[ |
|
423 | sections=[ | |
419 | 'acl.groups', |
|
424 | b'acl.groups', | |
420 | 'acl.allow.branches', |
|
425 | b'acl.allow.branches', | |
421 | 'acl.deny.branches', |
|
426 | b'acl.deny.branches', | |
422 | 'acl.allow', |
|
427 | b'acl.allow', | |
423 | 'acl.deny', |
|
428 | b'acl.deny', | |
424 | ], |
|
429 | ], | |
425 | ) |
|
430 | ) | |
426 |
|
431 | |||
427 | allowbranches = buildmatch(ui, None, user, 'acl.allow.branches') |
|
432 | allowbranches = buildmatch(ui, None, user, b'acl.allow.branches') | |
428 | denybranches = buildmatch(ui, None, user, 'acl.deny.branches') |
|
433 | denybranches = buildmatch(ui, None, user, b'acl.deny.branches') | |
429 | allow = buildmatch(ui, repo, user, 'acl.allow') |
|
434 | allow = buildmatch(ui, repo, user, b'acl.allow') | |
430 | deny = buildmatch(ui, repo, user, 'acl.deny') |
|
435 | deny = buildmatch(ui, repo, user, b'acl.deny') | |
431 |
|
436 | |||
432 | for rev in pycompat.xrange(repo[node].rev(), len(repo)): |
|
437 | for rev in pycompat.xrange(repo[node].rev(), len(repo)): | |
433 | ctx = repo[rev] |
|
438 | ctx = repo[rev] | |
434 | branch = ctx.branch() |
|
439 | branch = ctx.branch() | |
435 | if denybranches and denybranches(branch): |
|
440 | if denybranches and denybranches(branch): | |
436 | raise error.Abort( |
|
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 | % (user, branch, ctx) |
|
443 | % (user, branch, ctx) | |
439 | ) |
|
444 | ) | |
440 | if allowbranches and not allowbranches(branch): |
|
445 | if allowbranches and not allowbranches(branch): | |
441 | raise error.Abort( |
|
446 | raise error.Abort( | |
442 | _( |
|
447 | _( | |
443 | 'acl: user "%s" not allowed on branch "%s"' |
|
448 | b'acl: user "%s" not allowed on branch "%s"' | |
444 | ' (changeset "%s")' |
|
449 | b' (changeset "%s")' | |
445 | ) |
|
450 | ) | |
446 | % (user, branch, ctx) |
|
451 | % (user, branch, ctx) | |
447 | ) |
|
452 | ) | |
448 | ui.debug( |
|
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 | for f in ctx.files(): |
|
457 | for f in ctx.files(): | |
453 | if deny and deny(f): |
|
458 | if deny and deny(f): | |
454 | raise error.Abort( |
|
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 | % (user, f, ctx) |
|
461 | % (user, f, ctx) | |
457 | ) |
|
462 | ) | |
458 | if allow and not allow(f): |
|
463 | if allow and not allow(f): | |
459 | raise error.Abort( |
|
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 | % (user, f, ctx) |
|
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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
25 | # be specifying the version(s) of Mercurial they are tested with, or | |
26 | # leave the attribute unspecified. |
|
26 | # leave the attribute unspecified. | |
27 | testedwith = 'ships-with-hg-core' |
|
27 | testedwith = b'ships-with-hg-core' | |
28 |
|
28 | |||
29 | cmdtable = {} |
|
29 | cmdtable = {} | |
30 | command = registrar.command(cmdtable) |
|
30 | command = registrar.command(cmdtable) | |
31 |
|
31 | |||
32 |
|
32 | |||
33 | @command( |
|
33 | @command( | |
34 | 'amend', |
|
34 | b'amend', | |
35 | [ |
|
35 | [ | |
36 | ( |
|
36 | ( | |
37 | 'A', |
|
37 | b'A', | |
38 | 'addremove', |
|
38 | b'addremove', | |
39 | None, |
|
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')), |
|
42 | (b'e', b'edit', None, _(b'invoke editor on commit messages')), | |
43 | ('i', 'interactive', None, _('use interactive mode')), |
|
43 | (b'i', b'interactive', None, _(b'use interactive mode')), | |
44 | ( |
|
44 | ( | |
45 | b'', |
|
45 | b'', | |
46 | b'close-branch', |
|
46 | b'close-branch', | |
@@ -48,13 +48,13 b' command = registrar.command(cmdtable)' | |||||
48 | _(b'mark a branch as closed, hiding it from the branch list'), |
|
48 | _(b'mark a branch as closed, hiding it from the branch list'), | |
49 | ), |
|
49 | ), | |
50 | (b's', b'secret', None, _(b'use the secret phase for committing')), |
|
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 | + cmdutil.walkopts |
|
53 | + cmdutil.walkopts | |
54 | + cmdutil.commitopts |
|
54 | + cmdutil.commitopts | |
55 | + cmdutil.commitopts2 |
|
55 | + cmdutil.commitopts2 | |
56 | + cmdutil.commitopts3, |
|
56 | + cmdutil.commitopts3, | |
57 | _('[OPTION]... [FILE]...'), |
|
57 | _(b'[OPTION]... [FILE]...'), | |
58 | helpcategory=command.CATEGORY_COMMITTING, |
|
58 | helpcategory=command.CATEGORY_COMMITTING, | |
59 | inferrepo=True, |
|
59 | inferrepo=True, | |
60 | ) |
|
60 | ) | |
@@ -70,7 +70,7 b' def amend(ui, repo, *pats, **opts):' | |||||
70 | cmdutil.checknotesize(ui, opts) |
|
70 | cmdutil.checknotesize(ui, opts) | |
71 |
|
71 | |||
72 | with repo.wlock(), repo.lock(): |
|
72 | with repo.wlock(), repo.lock(): | |
73 | if not opts.get('logfile'): |
|
73 | if not opts.get(b'logfile'): | |
74 | opts['message'] = opts.get('message') or repo['.'].description() |
|
74 | opts[b'message'] = opts.get(b'message') or repo[b'.'].description() | |
75 | opts['amend'] = True |
|
75 | opts[b'amend'] = True | |
76 | return commands._docommit(ui, repo, *pats, **pycompat.strkwargs(opts)) |
|
76 | return commands._docommit(ui, repo, *pats, **pycompat.strkwargs(opts)) |
@@ -42,14 +42,14 b' configtable = {}' | |||||
42 | configitem = registrar.configitem(configtable) |
|
42 | configitem = registrar.configitem(configtable) | |
43 |
|
43 | |||
44 | configitem( |
|
44 | configitem( | |
45 | 'automv', 'similarity', default=95, |
|
45 | b'automv', b'similarity', default=95, | |
46 | ) |
|
46 | ) | |
47 |
|
47 | |||
48 |
|
48 | |||
49 | def extsetup(ui): |
|
49 | def extsetup(ui): | |
50 | entry = extensions.wrapcommand(commands.table, 'commit', mvcheck) |
|
50 | entry = extensions.wrapcommand(commands.table, b'commit', mvcheck) | |
51 | entry[1].append( |
|
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 | """Hook to check for moves at commit time""" |
|
57 | """Hook to check for moves at commit time""" | |
58 | opts = pycompat.byteskwargs(opts) |
|
58 | opts = pycompat.byteskwargs(opts) | |
59 | renames = None |
|
59 | renames = None | |
60 | disabled = opts.pop('no_automv', False) |
|
60 | disabled = opts.pop(b'no_automv', False) | |
61 | if not disabled: |
|
61 | if not disabled: | |
62 | threshold = ui.configint('automv', 'similarity') |
|
62 | threshold = ui.configint(b'automv', b'similarity') | |
63 | if not 0 <= threshold <= 100: |
|
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 | if threshold > 0: |
|
65 | if threshold > 0: | |
66 | match = scmutil.match(repo[None], pats, opts) |
|
66 | match = scmutil.match(repo[None], pats, opts) | |
67 | added, removed = _interestingfiles(repo, match) |
|
67 | added, removed = _interestingfiles(repo, match) | |
@@ -87,7 +87,7 b' def _interestingfiles(repo, matcher):' | |||||
87 | added = stat.added |
|
87 | added = stat.added | |
88 | removed = stat.removed |
|
88 | removed = stat.removed | |
89 |
|
89 | |||
90 | copy = copies.pathcopies(repo['.'], repo[None], matcher) |
|
90 | copy = copies.pathcopies(repo[b'.'], repo[None], matcher) | |
91 | # remove the copy files for which we already have copy info |
|
91 | # remove the copy files for which we already have copy info | |
92 | added = [f for f in added if f not in copy] |
|
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 | if repo.ui.verbose: |
|
109 | if repo.ui.verbose: | |
110 | repo.ui.status( |
|
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 | % (uipathfn(src), uipathfn(dst), score * 100) |
|
112 | % (uipathfn(src), uipathfn(dst), score * 100) | |
113 | ) |
|
113 | ) | |
114 | renames[dst] = src |
|
114 | renames[dst] = src | |
115 | if renames: |
|
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 | return renames |
|
117 | return renames |
@@ -26,33 +26,33 b' from mercurial import (' | |||||
26 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
26 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
27 | # be specifying the version(s) of Mercurial they are tested with, or |
|
27 | # be specifying the version(s) of Mercurial they are tested with, or | |
28 | # leave the attribute unspecified. |
|
28 | # leave the attribute unspecified. | |
29 | testedwith = 'ships-with-hg-core' |
|
29 | testedwith = b'ships-with-hg-core' | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | def prettyedge(before, edge, after): |
|
32 | def prettyedge(before, edge, after): | |
33 | if edge == '~': |
|
33 | if edge == b'~': | |
34 | return '\xE2\x95\xA7' # U+2567 ╧ |
|
34 | return b'\xE2\x95\xA7' # U+2567 ╧ | |
35 | if edge == '/': |
|
35 | if edge == b'/': | |
36 | return '\xE2\x95\xB1' # U+2571 ╱ |
|
36 | return b'\xE2\x95\xB1' # U+2571 ╱ | |
37 | if edge == '-': |
|
37 | if edge == b'-': | |
38 | return '\xE2\x94\x80' # U+2500 ─ |
|
38 | return b'\xE2\x94\x80' # U+2500 ─ | |
39 | if edge == '|': |
|
39 | if edge == b'|': | |
40 | return '\xE2\x94\x82' # U+2502 │ |
|
40 | return b'\xE2\x94\x82' # U+2502 │ | |
41 | if edge == ':': |
|
41 | if edge == b':': | |
42 | return '\xE2\x94\x86' # U+2506 ┆ |
|
42 | return b'\xE2\x94\x86' # U+2506 ┆ | |
43 | if edge == '\\': |
|
43 | if edge == b'\\': | |
44 | return '\xE2\x95\xB2' # U+2572 ╲ |
|
44 | return b'\xE2\x95\xB2' # U+2572 ╲ | |
45 | if edge == '+': |
|
45 | if edge == b'+': | |
46 | if before == ' ' and not after == ' ': |
|
46 | if before == b' ' and not after == b' ': | |
47 | return '\xE2\x94\x9C' # U+251C ├ |
|
47 | return b'\xE2\x94\x9C' # U+251C ├ | |
48 | if after == ' ' and not before == ' ': |
|
48 | if after == b' ' and not before == b' ': | |
49 | return '\xE2\x94\xA4' # U+2524 ┤ |
|
49 | return b'\xE2\x94\xA4' # U+2524 ┤ | |
50 | return '\xE2\x94\xBC' # U+253C ┼ |
|
50 | return b'\xE2\x94\xBC' # U+253C ┼ | |
51 | return edge |
|
51 | return edge | |
52 |
|
52 | |||
53 |
|
53 | |||
54 | def convertedges(line): |
|
54 | def convertedges(line): | |
55 | line = ' %s ' % line |
|
55 | line = b' %s ' % line | |
56 | pretty = [] |
|
56 | pretty = [] | |
57 | for idx in pycompat.xrange(len(line) - 2): |
|
57 | for idx in pycompat.xrange(len(line) - 2): | |
58 | pretty.append( |
|
58 | pretty.append( | |
@@ -62,21 +62,21 b' def convertedges(line):' | |||||
62 | line[idx + 2 : idx + 3], |
|
62 | line[idx + 2 : idx + 3], | |
63 | ) |
|
63 | ) | |
64 | ) |
|
64 | ) | |
65 | return ''.join(pretty) |
|
65 | return b''.join(pretty) | |
66 |
|
66 | |||
67 |
|
67 | |||
68 | def getprettygraphnode(orig, *args, **kwargs): |
|
68 | def getprettygraphnode(orig, *args, **kwargs): | |
69 | node = orig(*args, **kwargs) |
|
69 | node = orig(*args, **kwargs) | |
70 | if node == 'o': |
|
70 | if node == b'o': | |
71 | return '\xE2\x97\x8B' # U+25CB ○ |
|
71 | return b'\xE2\x97\x8B' # U+25CB ○ | |
72 | if node == '@': |
|
72 | if node == b'@': | |
73 | return '\xE2\x97\x8D' # U+25CD ◍ |
|
73 | return b'\xE2\x97\x8D' # U+25CD ◍ | |
74 | if node == '*': |
|
74 | if node == b'*': | |
75 | return '\xE2\x88\x97' # U+2217 ∗ |
|
75 | return b'\xE2\x88\x97' # U+2217 ∗ | |
76 | if node == 'x': |
|
76 | if node == b'x': | |
77 | return '\xE2\x97\x8C' # U+25CC ◌ |
|
77 | return b'\xE2\x97\x8C' # U+25CC ◌ | |
78 | if node == '_': |
|
78 | if node == b'_': | |
79 | return '\xE2\x95\xA4' # U+2564 ╤ |
|
79 | return b'\xE2\x95\xA4' # U+2564 ╤ | |
80 | return node |
|
80 | return node | |
81 |
|
81 | |||
82 |
|
82 | |||
@@ -87,21 +87,21 b' def outputprettygraph(orig, ui, graph, *' | |||||
87 |
|
87 | |||
88 |
|
88 | |||
89 | def extsetup(ui): |
|
89 | def extsetup(ui): | |
90 | if ui.plain('graph'): |
|
90 | if ui.plain(b'graph'): | |
91 | return |
|
91 | return | |
92 |
|
92 | |||
93 | if encoding.encoding != 'UTF-8': |
|
93 | if encoding.encoding != b'UTF-8': | |
94 | ui.warn(_('beautifygraph: unsupported encoding, UTF-8 required\n')) |
|
94 | ui.warn(_(b'beautifygraph: unsupported encoding, UTF-8 required\n')) | |
95 | return |
|
95 | return | |
96 |
|
96 | |||
97 | if r'A' in encoding._wide: |
|
97 | if r'A' in encoding._wide: | |
98 | ui.warn( |
|
98 | ui.warn( | |
99 | _( |
|
99 | _( | |
100 | 'beautifygraph: unsupported terminal settings, ' |
|
100 | b'beautifygraph: unsupported terminal settings, ' | |
101 | 'monospace narrow text required\n' |
|
101 | b'monospace narrow text required\n' | |
102 | ) |
|
102 | ) | |
103 | ) |
|
103 | ) | |
104 | return |
|
104 | return | |
105 |
|
105 | |||
106 | extensions.wrapfunction(graphmod, 'outputgraph', outputprettygraph) |
|
106 | extensions.wrapfunction(graphmod, b'outputgraph', outputprettygraph) | |
107 | extensions.wrapfunction(templatekw, 'getgraphnode', getprettygraphnode) |
|
107 | extensions.wrapfunction(templatekw, b'getgraphnode', getprettygraphnode) |
@@ -63,7 +63,7 b' from mercurial.utils import (' | |||||
63 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
63 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
64 | # be specifying the version(s) of Mercurial they are tested with, or |
|
64 | # be specifying the version(s) of Mercurial they are tested with, or | |
65 | # leave the attribute unspecified. |
|
65 | # leave the attribute unspecified. | |
66 | testedwith = 'ships-with-hg-core' |
|
66 | testedwith = b'ships-with-hg-core' | |
67 |
|
67 | |||
68 | cmdtable = {} |
|
68 | cmdtable = {} | |
69 | command = registrar.command(cmdtable) |
|
69 | command = registrar.command(cmdtable) | |
@@ -72,27 +72,27 b' configtable = {}' | |||||
72 | configitem = registrar.configitem(configtable) |
|
72 | configitem = registrar.configitem(configtable) | |
73 |
|
73 | |||
74 | configitem( |
|
74 | configitem( | |
75 | 'blackbox', 'dirty', default=False, |
|
75 | b'blackbox', b'dirty', default=False, | |
76 | ) |
|
76 | ) | |
77 | configitem( |
|
77 | configitem( | |
78 | 'blackbox', 'maxsize', default='1 MB', |
|
78 | b'blackbox', b'maxsize', default=b'1 MB', | |
79 | ) |
|
79 | ) | |
80 | configitem( |
|
80 | configitem( | |
81 | 'blackbox', 'logsource', default=False, |
|
81 | b'blackbox', b'logsource', default=False, | |
82 | ) |
|
82 | ) | |
83 | configitem( |
|
83 | configitem( | |
84 | 'blackbox', 'maxfiles', default=7, |
|
84 | b'blackbox', b'maxfiles', default=7, | |
85 | ) |
|
85 | ) | |
86 | configitem( |
|
86 | configitem( | |
87 | 'blackbox', 'track', default=lambda: ['*'], |
|
87 | b'blackbox', b'track', default=lambda: [b'*'], | |
88 | ) |
|
88 | ) | |
89 | configitem( |
|
89 | configitem( | |
90 | 'blackbox', |
|
90 | b'blackbox', | |
91 | 'ignore', |
|
91 | b'ignore', | |
92 | default=lambda: ['chgserver', 'cmdserver', 'extension'], |
|
92 | default=lambda: [b'chgserver', b'cmdserver', b'extension'], | |
93 | ) |
|
93 | ) | |
94 | configitem( |
|
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 | _lastlogger = loggingutil.proxylogger() |
|
98 | _lastlogger = loggingutil.proxylogger() | |
@@ -101,10 +101,10 b' configitem(' | |||||
101 | class blackboxlogger(object): |
|
101 | class blackboxlogger(object): | |
102 | def __init__(self, ui, repo): |
|
102 | def __init__(self, ui, repo): | |
103 | self._repo = repo |
|
103 | self._repo = repo | |
104 | self._trackedevents = set(ui.configlist('blackbox', 'track')) |
|
104 | self._trackedevents = set(ui.configlist(b'blackbox', b'track')) | |
105 | self._ignoredevents = set(ui.configlist('blackbox', 'ignore')) |
|
105 | self._ignoredevents = set(ui.configlist(b'blackbox', b'ignore')) | |
106 | self._maxfiles = ui.configint('blackbox', 'maxfiles') |
|
106 | self._maxfiles = ui.configint(b'blackbox', b'maxfiles') | |
107 | self._maxsize = ui.configbytes('blackbox', 'maxsize') |
|
107 | self._maxsize = ui.configbytes(b'blackbox', b'maxsize') | |
108 | self._inlog = False |
|
108 | self._inlog = False | |
109 |
|
109 | |||
110 | def tracked(self, event): |
|
110 | def tracked(self, event): | |
@@ -125,29 +125,29 b' class blackboxlogger(object):' | |||||
125 | self._inlog = False |
|
125 | self._inlog = False | |
126 |
|
126 | |||
127 | def _log(self, ui, event, msg, opts): |
|
127 | def _log(self, ui, event, msg, opts): | |
128 | default = ui.configdate('devel', 'default-date') |
|
128 | default = ui.configdate(b'devel', b'default-date') | |
129 | date = dateutil.datestr(default, ui.config('blackbox', 'date-format')) |
|
129 | date = dateutil.datestr(default, ui.config(b'blackbox', b'date-format')) | |
130 | user = procutil.getuser() |
|
130 | user = procutil.getuser() | |
131 | pid = '%d' % procutil.getpid() |
|
131 | pid = b'%d' % procutil.getpid() | |
132 | changed = '' |
|
132 | changed = b'' | |
133 | ctx = self._repo[None] |
|
133 | ctx = self._repo[None] | |
134 | parents = ctx.parents() |
|
134 | parents = ctx.parents() | |
135 | rev = '+'.join([hex(p.node()) for p in parents]) |
|
135 | rev = b'+'.join([hex(p.node()) for p in parents]) | |
136 | if ui.configbool('blackbox', 'dirty') and ctx.dirty( |
|
136 | if ui.configbool(b'blackbox', b'dirty') and ctx.dirty( | |
137 | missing=True, merge=False, branch=False |
|
137 | missing=True, merge=False, branch=False | |
138 | ): |
|
138 | ): | |
139 | changed = '+' |
|
139 | changed = b'+' | |
140 | if ui.configbool('blackbox', 'logsource'): |
|
140 | if ui.configbool(b'blackbox', b'logsource'): | |
141 | src = ' [%s]' % event |
|
141 | src = b' [%s]' % event | |
142 | else: |
|
142 | else: | |
143 | src = '' |
|
143 | src = b'' | |
144 | try: |
|
144 | try: | |
145 | fmt = '%s %s @%s%s (%s)%s> %s' |
|
145 | fmt = b'%s %s @%s%s (%s)%s> %s' | |
146 | args = (date, user, rev, changed, pid, src, msg) |
|
146 | args = (date, user, rev, changed, pid, src, msg) | |
147 | with loggingutil.openlogfile( |
|
147 | with loggingutil.openlogfile( | |
148 | ui, |
|
148 | ui, | |
149 | self._repo.vfs, |
|
149 | self._repo.vfs, | |
150 | name='blackbox.log', |
|
150 | name=b'blackbox.log', | |
151 | maxfiles=self._maxfiles, |
|
151 | maxfiles=self._maxfiles, | |
152 | maxsize=self._maxsize, |
|
152 | maxsize=self._maxsize, | |
153 | ) as fp: |
|
153 | ) as fp: | |
@@ -156,7 +156,7 b' class blackboxlogger(object):' | |||||
156 | # deactivate this to avoid failed logging again |
|
156 | # deactivate this to avoid failed logging again | |
157 | self._trackedevents.clear() |
|
157 | self._trackedevents.clear() | |
158 | ui.debug( |
|
158 | ui.debug( | |
159 | 'warning: cannot write to blackbox.log: %s\n' |
|
159 | b'warning: cannot write to blackbox.log: %s\n' | |
160 | % encoding.strtolocal(err.strerror) |
|
160 | % encoding.strtolocal(err.strerror) | |
161 | ) |
|
161 | ) | |
162 | return |
|
162 | return | |
@@ -184,13 +184,13 b' def reposetup(ui, repo):' | |||||
184 | if _lastlogger.logger is None: |
|
184 | if _lastlogger.logger is None: | |
185 | _lastlogger.logger = logger |
|
185 | _lastlogger.logger = logger | |
186 |
|
186 | |||
187 | repo._wlockfreeprefix.add('blackbox.log') |
|
187 | repo._wlockfreeprefix.add(b'blackbox.log') | |
188 |
|
188 | |||
189 |
|
189 | |||
190 | @command( |
|
190 | @command( | |
191 | 'blackbox', |
|
191 | b'blackbox', | |
192 | [('l', 'limit', 10, _('the number of events to show')),], |
|
192 | [(b'l', b'limit', 10, _(b'the number of events to show')),], | |
193 | _('hg blackbox [OPTION]...'), |
|
193 | _(b'hg blackbox [OPTION]...'), | |
194 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
194 | helpcategory=command.CATEGORY_MAINTENANCE, | |
195 | helpbasic=True, |
|
195 | helpbasic=True, | |
196 | ) |
|
196 | ) | |
@@ -198,12 +198,12 b' def blackbox(ui, repo, *revs, **opts):' | |||||
198 | '''view the recent repository events |
|
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 | return |
|
202 | return | |
203 |
|
203 | |||
204 | limit = opts.get(r'limit') |
|
204 | limit = opts.get(r'limit') | |
205 | fp = repo.vfs('blackbox.log', 'r') |
|
205 | fp = repo.vfs(b'blackbox.log', b'r') | |
206 | lines = fp.read().split('\n') |
|
206 | lines = fp.read().split(b'\n') | |
207 |
|
207 | |||
208 | count = 0 |
|
208 | count = 0 | |
209 | output = [] |
|
209 | output = [] | |
@@ -216,4 +216,4 b' def blackbox(ui, repo, *revs, **opts):' | |||||
216 | count += 1 |
|
216 | count += 1 | |
217 | output.append(line) |
|
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 | registrar, |
|
24 | registrar, | |
25 | ) |
|
25 | ) | |
26 |
|
26 | |||
27 | MY_NAME = 'bookflow' |
|
27 | MY_NAME = b'bookflow' | |
28 |
|
28 | |||
29 | configtable = {} |
|
29 | configtable = {} | |
30 | configitem = registrar.configitem(configtable) |
|
30 | configitem = registrar.configitem(configtable) | |
31 |
|
31 | |||
32 | configitem(MY_NAME, 'protect', ['@']) |
|
32 | configitem(MY_NAME, b'protect', [b'@']) | |
33 | configitem(MY_NAME, 'require-bookmark', True) |
|
33 | configitem(MY_NAME, b'require-bookmark', True) | |
34 | configitem(MY_NAME, 'enable-branches', False) |
|
34 | configitem(MY_NAME, b'enable-branches', False) | |
35 |
|
35 | |||
36 | cmdtable = {} |
|
36 | cmdtable = {} | |
37 | command = registrar.command(cmdtable) |
|
37 | command = registrar.command(cmdtable) | |
@@ -40,19 +40,19 b' command = registrar.command(cmdtable)' | |||||
40 | def commit_hook(ui, repo, **kwargs): |
|
40 | def commit_hook(ui, repo, **kwargs): | |
41 | active = repo._bookmarks.active |
|
41 | active = repo._bookmarks.active | |
42 | if active: |
|
42 | if active: | |
43 | if active in ui.configlist(MY_NAME, 'protect'): |
|
43 | if active in ui.configlist(MY_NAME, b'protect'): | |
44 | raise error.Abort( |
|
44 | raise error.Abort( | |
45 | _('cannot commit, bookmark %s is protected') % active |
|
45 | _(b'cannot commit, bookmark %s is protected') % active | |
46 | ) |
|
46 | ) | |
47 | if not cwd_at_bookmark(repo, active): |
|
47 | if not cwd_at_bookmark(repo, active): | |
48 | raise error.Abort( |
|
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): |
|
54 | elif ui.configbool(MY_NAME, b'require-bookmark', True): | |
55 | raise error.Abort(_('cannot commit without an active bookmark')) |
|
55 | raise error.Abort(_(b'cannot commit without an active bookmark')) | |
56 | return 0 |
|
56 | return 0 | |
57 |
|
57 | |||
58 |
|
58 | |||
@@ -74,7 +74,7 b' def bookmarks_addbookmarks(' | |||||
74 | if name in marks: |
|
74 | if name in marks: | |
75 | raise error.Abort( |
|
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 | % name |
|
79 | % name | |
80 | ) |
|
80 | ) | |
@@ -92,8 +92,8 b' def commands_pull(orig, ui, repo, *args,' | |||||
92 | if active and not cwd_at_bookmark(repo, active): |
|
92 | if active and not cwd_at_bookmark(repo, active): | |
93 | ui.warn( |
|
93 | ui.warn( | |
94 | _( |
|
94 | _( | |
95 | "working directory out of sync with active bookmark, run " |
|
95 | b"working directory out of sync with active bookmark, run " | |
96 | "'hg up %s'" |
|
96 | b"'hg up %s'" | |
97 | ) |
|
97 | ) | |
98 | % active |
|
98 | % active | |
99 | ) |
|
99 | ) | |
@@ -104,23 +104,23 b' def commands_branch(orig, ui, repo, labe' | |||||
104 | if label and not opts.get(r'clean') and not opts.get(r'rev'): |
|
104 | if label and not opts.get(r'clean') and not opts.get(r'rev'): | |
105 | raise error.Abort( |
|
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 | return orig(ui, repo, label, **opts) |
|
111 | return orig(ui, repo, label, **opts) | |
112 |
|
112 | |||
113 |
|
113 | |||
114 | def cwd_at_bookmark(repo, mark): |
|
114 | def cwd_at_bookmark(repo, mark): | |
115 | mark_id = repo._bookmarks[mark] |
|
115 | mark_id = repo._bookmarks[mark] | |
116 | cur_id = repo.lookup('.') |
|
116 | cur_id = repo.lookup(b'.') | |
117 | return cur_id == mark_id |
|
117 | return cur_id == mark_id | |
118 |
|
118 | |||
119 |
|
119 | |||
120 | def uisetup(ui): |
|
120 | def uisetup(ui): | |
121 | extensions.wrapfunction(bookmarks, 'update', bookmarks_update) |
|
121 | extensions.wrapfunction(bookmarks, b'update', bookmarks_update) | |
122 | extensions.wrapfunction(bookmarks, 'addbookmarks', bookmarks_addbookmarks) |
|
122 | extensions.wrapfunction(bookmarks, b'addbookmarks', bookmarks_addbookmarks) | |
123 | extensions.wrapcommand(commands.table, 'commit', commands_commit) |
|
123 | extensions.wrapcommand(commands.table, b'commit', commands_commit) | |
124 | extensions.wrapcommand(commands.table, 'pull', commands_pull) |
|
124 | extensions.wrapcommand(commands.table, b'pull', commands_pull) | |
125 | if not ui.configbool(MY_NAME, 'enable-branches'): |
|
125 | if not ui.configbool(MY_NAME, b'enable-branches'): | |
126 | extensions.wrapcommand(commands.table, 'branch', commands_branch) |
|
126 | extensions.wrapcommand(commands.table, b'branch', commands_branch) |
@@ -319,32 +319,32 b' xmlrpclib = util.xmlrpclib' | |||||
319 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
319 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
320 | # be specifying the version(s) of Mercurial they are tested with, or |
|
320 | # be specifying the version(s) of Mercurial they are tested with, or | |
321 | # leave the attribute unspecified. |
|
321 | # leave the attribute unspecified. | |
322 | testedwith = 'ships-with-hg-core' |
|
322 | testedwith = b'ships-with-hg-core' | |
323 |
|
323 | |||
324 | configtable = {} |
|
324 | configtable = {} | |
325 | configitem = registrar.configitem(configtable) |
|
325 | configitem = registrar.configitem(configtable) | |
326 |
|
326 | |||
327 | configitem( |
|
327 | configitem( | |
328 | 'bugzilla', 'apikey', default='', |
|
328 | b'bugzilla', b'apikey', default=b'', | |
329 | ) |
|
329 | ) | |
330 | configitem( |
|
330 | configitem( | |
331 | 'bugzilla', 'bzdir', default='/var/www/html/bugzilla', |
|
331 | b'bugzilla', b'bzdir', default=b'/var/www/html/bugzilla', | |
332 | ) |
|
332 | ) | |
333 | configitem( |
|
333 | configitem( | |
334 | 'bugzilla', 'bzemail', default=None, |
|
334 | b'bugzilla', b'bzemail', default=None, | |
335 | ) |
|
335 | ) | |
336 | configitem( |
|
336 | configitem( | |
337 | 'bugzilla', 'bzurl', default='http://localhost/bugzilla/', |
|
337 | b'bugzilla', b'bzurl', default=b'http://localhost/bugzilla/', | |
338 | ) |
|
338 | ) | |
339 | configitem( |
|
339 | configitem( | |
340 | 'bugzilla', 'bzuser', default=None, |
|
340 | b'bugzilla', b'bzuser', default=None, | |
341 | ) |
|
341 | ) | |
342 | configitem( |
|
342 | configitem( | |
343 | 'bugzilla', 'db', default='bugs', |
|
343 | b'bugzilla', b'db', default=b'bugs', | |
344 | ) |
|
344 | ) | |
345 | configitem( |
|
345 | configitem( | |
346 | 'bugzilla', |
|
346 | b'bugzilla', | |
347 | 'fixregexp', |
|
347 | b'fixregexp', | |
348 | default=( |
|
348 | default=( | |
349 | br'fix(?:es)?\s*(?:bugs?\s*)?,?\s*' |
|
349 | br'fix(?:es)?\s*(?:bugs?\s*)?,?\s*' | |
350 | br'(?:nos?\.?|num(?:ber)?s?)?\s*' |
|
350 | br'(?:nos?\.?|num(?:ber)?s?)?\s*' | |
@@ -353,23 +353,23 b' configitem(' | |||||
353 | ), |
|
353 | ), | |
354 | ) |
|
354 | ) | |
355 | configitem( |
|
355 | configitem( | |
356 | 'bugzilla', 'fixresolution', default='FIXED', |
|
356 | b'bugzilla', b'fixresolution', default=b'FIXED', | |
357 | ) |
|
357 | ) | |
358 | configitem( |
|
358 | configitem( | |
359 | 'bugzilla', 'fixstatus', default='RESOLVED', |
|
359 | b'bugzilla', b'fixstatus', default=b'RESOLVED', | |
360 | ) |
|
360 | ) | |
361 | configitem( |
|
361 | configitem( | |
362 | 'bugzilla', 'host', default='localhost', |
|
362 | b'bugzilla', b'host', default=b'localhost', | |
363 | ) |
|
363 | ) | |
364 | configitem( |
|
364 | configitem( | |
365 | 'bugzilla', 'notify', default=configitem.dynamicdefault, |
|
365 | b'bugzilla', b'notify', default=configitem.dynamicdefault, | |
366 | ) |
|
366 | ) | |
367 | configitem( |
|
367 | configitem( | |
368 | 'bugzilla', 'password', default=None, |
|
368 | b'bugzilla', b'password', default=None, | |
369 | ) |
|
369 | ) | |
370 | configitem( |
|
370 | configitem( | |
371 | 'bugzilla', |
|
371 | b'bugzilla', | |
372 | 'regexp', |
|
372 | b'regexp', | |
373 | default=( |
|
373 | default=( | |
374 | br'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' |
|
374 | br'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' | |
375 | br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' |
|
375 | br'(?P<ids>(?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)' | |
@@ -377,25 +377,25 b' configitem(' | |||||
377 | ), |
|
377 | ), | |
378 | ) |
|
378 | ) | |
379 | configitem( |
|
379 | configitem( | |
380 | 'bugzilla', 'strip', default=0, |
|
380 | b'bugzilla', b'strip', default=0, | |
381 | ) |
|
381 | ) | |
382 | configitem( |
|
382 | configitem( | |
383 | 'bugzilla', 'style', default=None, |
|
383 | b'bugzilla', b'style', default=None, | |
384 | ) |
|
384 | ) | |
385 | configitem( |
|
385 | configitem( | |
386 | 'bugzilla', 'template', default=None, |
|
386 | b'bugzilla', b'template', default=None, | |
387 | ) |
|
387 | ) | |
388 | configitem( |
|
388 | configitem( | |
389 | 'bugzilla', 'timeout', default=5, |
|
389 | b'bugzilla', b'timeout', default=5, | |
390 | ) |
|
390 | ) | |
391 | configitem( |
|
391 | configitem( | |
392 | 'bugzilla', 'user', default='bugs', |
|
392 | b'bugzilla', b'user', default=b'bugs', | |
393 | ) |
|
393 | ) | |
394 | configitem( |
|
394 | configitem( | |
395 | 'bugzilla', 'usermap', default=None, |
|
395 | b'bugzilla', b'usermap', default=None, | |
396 | ) |
|
396 | ) | |
397 | configitem( |
|
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 | def __init__(self, ui): |
|
405 | def __init__(self, ui): | |
406 | self.ui = ui |
|
406 | self.ui = ui | |
407 | usermap = self.ui.config('bugzilla', 'usermap') |
|
407 | usermap = self.ui.config(b'bugzilla', b'usermap') | |
408 | if usermap: |
|
408 | if usermap: | |
409 | self.ui.readconfig(usermap, sections=['usermap']) |
|
409 | self.ui.readconfig(usermap, sections=[b'usermap']) | |
410 |
|
410 | |||
411 | def map_committer(self, user): |
|
411 | def map_committer(self, user): | |
412 | '''map name of committer to Bugzilla user name.''' |
|
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 | if committer.lower() == user.lower(): |
|
414 | if committer.lower() == user.lower(): | |
415 | return bzuser |
|
415 | return bzuser | |
416 | return user |
|
416 | return user | |
@@ -457,7 +457,7 b' class bzmysql(bzaccess):' | |||||
457 | @staticmethod |
|
457 | @staticmethod | |
458 | def sql_buglist(ids): |
|
458 | def sql_buglist(ids): | |
459 | '''return SQL-friendly list of bug ids''' |
|
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 | _MySQLdb = None |
|
462 | _MySQLdb = None | |
463 |
|
463 | |||
@@ -467,18 +467,20 b' class bzmysql(bzaccess):' | |||||
467 |
|
467 | |||
468 | bzmysql._MySQLdb = mysql |
|
468 | bzmysql._MySQLdb = mysql | |
469 | except ImportError as err: |
|
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 | bzaccess.__init__(self, ui) |
|
474 | bzaccess.__init__(self, ui) | |
473 |
|
475 | |||
474 | host = self.ui.config('bugzilla', 'host') |
|
476 | host = self.ui.config(b'bugzilla', b'host') | |
475 | user = self.ui.config('bugzilla', 'user') |
|
477 | user = self.ui.config(b'bugzilla', b'user') | |
476 | passwd = self.ui.config('bugzilla', 'password') |
|
478 | passwd = self.ui.config(b'bugzilla', b'password') | |
477 | db = self.ui.config('bugzilla', 'db') |
|
479 | db = self.ui.config(b'bugzilla', b'db') | |
478 | timeout = int(self.ui.config('bugzilla', 'timeout')) |
|
480 | timeout = int(self.ui.config(b'bugzilla', b'timeout')) | |
479 | self.ui.note( |
|
481 | self.ui.note( | |
480 | _('connecting to %s:%s as %s, password %s\n') |
|
482 | _(b'connecting to %s:%s as %s, password %s\n') | |
481 | % (host, db, user, '*' * len(passwd)) |
|
483 | % (host, db, user, b'*' * len(passwd)) | |
482 | ) |
|
484 | ) | |
483 | self.conn = bzmysql._MySQLdb.connect( |
|
485 | self.conn = bzmysql._MySQLdb.connect( | |
484 | host=host, user=user, passwd=passwd, db=db, connect_timeout=timeout |
|
486 | host=host, user=user, passwd=passwd, db=db, connect_timeout=timeout | |
@@ -486,35 +488,35 b' class bzmysql(bzaccess):' | |||||
486 | self.cursor = self.conn.cursor() |
|
488 | self.cursor = self.conn.cursor() | |
487 | self.longdesc_id = self.get_longdesc_id() |
|
489 | self.longdesc_id = self.get_longdesc_id() | |
488 | self.user_ids = {} |
|
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 | def run(self, *args, **kwargs): |
|
493 | def run(self, *args, **kwargs): | |
492 | '''run a query.''' |
|
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 | try: |
|
496 | try: | |
495 | self.cursor.execute(*args, **kwargs) |
|
497 | self.cursor.execute(*args, **kwargs) | |
496 | except bzmysql._MySQLdb.MySQLError: |
|
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 | raise |
|
500 | raise | |
499 |
|
501 | |||
500 | def get_longdesc_id(self): |
|
502 | def get_longdesc_id(self): | |
501 | '''get identity of longdesc field''' |
|
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 | ids = self.cursor.fetchall() |
|
505 | ids = self.cursor.fetchall() | |
504 | if len(ids) != 1: |
|
506 | if len(ids) != 1: | |
505 | raise error.Abort(_('unknown database schema')) |
|
507 | raise error.Abort(_(b'unknown database schema')) | |
506 | return ids[0][0] |
|
508 | return ids[0][0] | |
507 |
|
509 | |||
508 | def filter_real_bug_ids(self, bugs): |
|
510 | def filter_real_bug_ids(self, bugs): | |
509 | '''filter not-existing bugs from set.''' |
|
511 | '''filter not-existing bugs from set.''' | |
510 | self.run( |
|
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 | % bzmysql.sql_buglist(bugs.keys()) |
|
514 | % bzmysql.sql_buglist(bugs.keys()) | |
513 | ) |
|
515 | ) | |
514 | existing = [id for (id,) in self.cursor.fetchall()] |
|
516 | existing = [id for (id,) in self.cursor.fetchall()] | |
515 | for id in bugs.keys(): |
|
517 | for id in bugs.keys(): | |
516 | if id not in existing: |
|
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 | del bugs[id] |
|
520 | del bugs[id] | |
519 |
|
521 | |||
520 | def filter_cset_known_bug_ids(self, node, bugs): |
|
522 | def filter_cset_known_bug_ids(self, node, bugs): | |
@@ -526,36 +528,36 b' class bzmysql(bzaccess):' | |||||
526 | ) |
|
528 | ) | |
527 | for (id,) in self.cursor.fetchall(): |
|
529 | for (id,) in self.cursor.fetchall(): | |
528 | self.ui.status( |
|
530 | self.ui.status( | |
529 | _('bug %d already knows about changeset %s\n') |
|
531 | _(b'bug %d already knows about changeset %s\n') | |
530 | % (id, short(node)) |
|
532 | % (id, short(node)) | |
531 | ) |
|
533 | ) | |
532 | del bugs[id] |
|
534 | del bugs[id] | |
533 |
|
535 | |||
534 | def notify(self, bugs, committer): |
|
536 | def notify(self, bugs, committer): | |
535 | '''tell bugzilla to send mail.''' |
|
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 | (user, userid) = self.get_bugzilla_user(committer) |
|
539 | (user, userid) = self.get_bugzilla_user(committer) | |
538 | for id in bugs.keys(): |
|
540 | for id in bugs.keys(): | |
539 | self.ui.status(_(' bug %s\n') % id) |
|
541 | self.ui.status(_(b' bug %s\n') % id) | |
540 | cmdfmt = self.ui.config('bugzilla', 'notify', self.default_notify) |
|
542 | cmdfmt = self.ui.config(b'bugzilla', b'notify', self.default_notify) | |
541 | bzdir = self.ui.config('bugzilla', 'bzdir') |
|
543 | bzdir = self.ui.config(b'bugzilla', b'bzdir') | |
542 | try: |
|
544 | try: | |
543 | # Backwards-compatible with old notify string, which |
|
545 | # Backwards-compatible with old notify string, which | |
544 | # took one string. This will throw with a new format |
|
546 | # took one string. This will throw with a new format | |
545 | # string. |
|
547 | # string. | |
546 | cmd = cmdfmt % id |
|
548 | cmd = cmdfmt % id | |
547 | except TypeError: |
|
549 | except TypeError: | |
548 | cmd = cmdfmt % {'bzdir': bzdir, 'id': id, 'user': user} |
|
550 | cmd = cmdfmt % {b'bzdir': bzdir, b'id': id, b'user': user} | |
549 | self.ui.note(_('running notify command %s\n') % cmd) |
|
551 | self.ui.note(_(b'running notify command %s\n') % cmd) | |
550 | fp = procutil.popen('(%s) 2>&1' % cmd, 'rb') |
|
552 | fp = procutil.popen(b'(%s) 2>&1' % cmd, b'rb') | |
551 | out = util.fromnativeeol(fp.read()) |
|
553 | out = util.fromnativeeol(fp.read()) | |
552 | ret = fp.close() |
|
554 | ret = fp.close() | |
553 | if ret: |
|
555 | if ret: | |
554 | self.ui.warn(out) |
|
556 | self.ui.warn(out) | |
555 | raise error.Abort( |
|
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 | def get_user_id(self, user): |
|
562 | def get_user_id(self, user): | |
561 | '''look up numeric bugzilla user id.''' |
|
563 | '''look up numeric bugzilla user id.''' | |
@@ -565,7 +567,7 b' class bzmysql(bzaccess):' | |||||
565 | try: |
|
567 | try: | |
566 | userid = int(user) |
|
568 | userid = int(user) | |
567 | except ValueError: |
|
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 | self.run( |
|
571 | self.run( | |
570 | '''select userid from profiles |
|
572 | '''select userid from profiles | |
571 | where login_name like %s''', |
|
573 | where login_name like %s''', | |
@@ -587,16 +589,16 b' class bzmysql(bzaccess):' | |||||
587 | userid = self.get_user_id(user) |
|
589 | userid = self.get_user_id(user) | |
588 | except KeyError: |
|
590 | except KeyError: | |
589 | try: |
|
591 | try: | |
590 | defaultuser = self.ui.config('bugzilla', 'bzuser') |
|
592 | defaultuser = self.ui.config(b'bugzilla', b'bzuser') | |
591 | if not defaultuser: |
|
593 | if not defaultuser: | |
592 | raise error.Abort( |
|
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 | userid = self.get_user_id(defaultuser) |
|
597 | userid = self.get_user_id(defaultuser) | |
596 | user = defaultuser |
|
598 | user = defaultuser | |
597 | except KeyError: |
|
599 | except KeyError: | |
598 | raise error.Abort( |
|
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 | % (user, defaultuser) |
|
602 | % (user, defaultuser) | |
601 | ) |
|
603 | ) | |
602 | return (user, userid) |
|
604 | return (user, userid) | |
@@ -607,7 +609,7 b' class bzmysql(bzaccess):' | |||||
607 | Try adding comment as committer of changeset, otherwise as |
|
609 | Try adding comment as committer of changeset, otherwise as | |
608 | default bugzilla user.''' |
|
610 | default bugzilla user.''' | |
609 | if len(newstate) > 0: |
|
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 | (user, userid) = self.get_bugzilla_user(committer) |
|
614 | (user, userid) = self.get_bugzilla_user(committer) | |
613 | now = time.strftime(r'%Y-%m-%d %H:%M:%S') |
|
615 | now = time.strftime(r'%Y-%m-%d %H:%M:%S') | |
@@ -631,7 +633,7 b' class bzmysql_2_18(bzmysql):' | |||||
631 | def __init__(self, ui): |
|
633 | def __init__(self, ui): | |
632 | bzmysql.__init__(self, ui) |
|
634 | bzmysql.__init__(self, ui) | |
633 | self.default_notify = ( |
|
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 | def get_longdesc_id(self): |
|
646 | def get_longdesc_id(self): | |
645 | '''get identity of longdesc field''' |
|
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 | ids = self.cursor.fetchall() |
|
649 | ids = self.cursor.fetchall() | |
648 | if len(ids) != 1: |
|
650 | if len(ids) != 1: | |
649 | raise error.Abort(_('unknown database schema')) |
|
651 | raise error.Abort(_(b'unknown database schema')) | |
650 | return ids[0][0] |
|
652 | return ids[0][0] | |
651 |
|
653 | |||
652 |
|
654 | |||
@@ -674,7 +676,7 b' class cookietransportrequest(object):' | |||||
674 | def send_cookies(self, connection): |
|
676 | def send_cookies(self, connection): | |
675 | if self.cookies: |
|
677 | if self.cookies: | |
676 | for cookie in self.cookies: |
|
678 | for cookie in self.cookies: | |
677 | connection.putheader("Cookie", cookie) |
|
679 | connection.putheader(b"Cookie", cookie) | |
678 |
|
680 | |||
679 | def request(self, host, handler, request_body, verbose=0): |
|
681 | def request(self, host, handler, request_body, verbose=0): | |
680 | self.verbose = verbose |
|
682 | self.verbose = verbose | |
@@ -702,9 +704,9 b' class cookietransportrequest(object):' | |||||
702 | response = h._conn.getresponse() |
|
704 | response = h._conn.getresponse() | |
703 |
|
705 | |||
704 | # Add any cookie definitions to our list. |
|
706 | # Add any cookie definitions to our list. | |
705 | for header in response.msg.getallmatchingheaders("Set-Cookie"): |
|
707 | for header in response.msg.getallmatchingheaders(b"Set-Cookie"): | |
706 | val = header.split(": ", 1)[1] |
|
708 | val = header.split(b": ", 1)[1] | |
707 | cookie = val.split(";", 1)[0] |
|
709 | cookie = val.split(b";", 1)[0] | |
708 | self.cookies.append(cookie) |
|
710 | self.cookies.append(cookie) | |
709 |
|
711 | |||
710 | if response.status != 200: |
|
712 | if response.status != 200: | |
@@ -729,13 +731,13 b' class cookietransportrequest(object):' | |||||
729 | # inheritance with a new-style class. |
|
731 | # inheritance with a new-style class. | |
730 | class cookietransport(cookietransportrequest, xmlrpclib.Transport): |
|
732 | class cookietransport(cookietransportrequest, xmlrpclib.Transport): | |
731 | def __init__(self, use_datetime=0): |
|
733 | def __init__(self, use_datetime=0): | |
732 | if util.safehasattr(xmlrpclib.Transport, "__init__"): |
|
734 | if util.safehasattr(xmlrpclib.Transport, b"__init__"): | |
733 | xmlrpclib.Transport.__init__(self, use_datetime) |
|
735 | xmlrpclib.Transport.__init__(self, use_datetime) | |
734 |
|
736 | |||
735 |
|
737 | |||
736 | class cookiesafetransport(cookietransportrequest, xmlrpclib.SafeTransport): |
|
738 | class cookiesafetransport(cookietransportrequest, xmlrpclib.SafeTransport): | |
737 | def __init__(self, use_datetime=0): |
|
739 | def __init__(self, use_datetime=0): | |
738 | if util.safehasattr(xmlrpclib.Transport, "__init__"): |
|
740 | if util.safehasattr(xmlrpclib.Transport, b"__init__"): | |
739 | xmlrpclib.SafeTransport.__init__(self, use_datetime) |
|
741 | xmlrpclib.SafeTransport.__init__(self, use_datetime) | |
740 |
|
742 | |||
741 |
|
743 | |||
@@ -748,26 +750,26 b' class bzxmlrpc(bzaccess):' | |||||
748 | def __init__(self, ui): |
|
750 | def __init__(self, ui): | |
749 | bzaccess.__init__(self, ui) |
|
751 | bzaccess.__init__(self, ui) | |
750 |
|
752 | |||
751 | bzweb = self.ui.config('bugzilla', 'bzurl') |
|
753 | bzweb = self.ui.config(b'bugzilla', b'bzurl') | |
752 | bzweb = bzweb.rstrip("/") + "/xmlrpc.cgi" |
|
754 | bzweb = bzweb.rstrip(b"/") + b"/xmlrpc.cgi" | |
753 |
|
755 | |||
754 | user = self.ui.config('bugzilla', 'user') |
|
756 | user = self.ui.config(b'bugzilla', b'user') | |
755 | passwd = self.ui.config('bugzilla', 'password') |
|
757 | passwd = self.ui.config(b'bugzilla', b'password') | |
756 |
|
758 | |||
757 | self.fixstatus = self.ui.config('bugzilla', 'fixstatus') |
|
759 | self.fixstatus = self.ui.config(b'bugzilla', b'fixstatus') | |
758 | self.fixresolution = self.ui.config('bugzilla', 'fixresolution') |
|
760 | self.fixresolution = self.ui.config(b'bugzilla', b'fixresolution') | |
759 |
|
761 | |||
760 | self.bzproxy = xmlrpclib.ServerProxy(bzweb, self.transport(bzweb)) |
|
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 | self.bzvermajor = int(ver[0]) |
|
764 | self.bzvermajor = int(ver[0]) | |
763 | self.bzverminor = int(ver[1]) |
|
765 | self.bzverminor = int(ver[1]) | |
764 | login = self.bzproxy.User.login( |
|
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 | def transport(self, uri): |
|
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 | return cookiesafetransport() |
|
773 | return cookiesafetransport() | |
772 | else: |
|
774 | else: | |
773 | return cookietransport() |
|
775 | return cookietransport() | |
@@ -775,56 +777,58 b' class bzxmlrpc(bzaccess):' | |||||
775 | def get_bug_comments(self, id): |
|
777 | def get_bug_comments(self, id): | |
776 | """Return a string with all comment text for a bug.""" |
|
778 | """Return a string with all comment text for a bug.""" | |
777 | c = self.bzproxy.Bug.comments( |
|
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 | def filter_real_bug_ids(self, bugs): |
|
786 | def filter_real_bug_ids(self, bugs): | |
783 | probe = self.bzproxy.Bug.get( |
|
787 | probe = self.bzproxy.Bug.get( | |
784 | { |
|
788 | { | |
785 | 'ids': sorted(bugs.keys()), |
|
789 | b'ids': sorted(bugs.keys()), | |
786 | 'include_fields': [], |
|
790 | b'include_fields': [], | |
787 | 'permissive': True, |
|
791 | b'permissive': True, | |
788 | 'token': self.bztoken, |
|
792 | b'token': self.bztoken, | |
789 | } |
|
793 | } | |
790 | ) |
|
794 | ) | |
791 | for badbug in probe['faults']: |
|
795 | for badbug in probe[b'faults']: | |
792 | id = badbug['id'] |
|
796 | id = badbug[b'id'] | |
793 | self.ui.status(_('bug %d does not exist\n') % id) |
|
797 | self.ui.status(_(b'bug %d does not exist\n') % id) | |
794 | del bugs[id] |
|
798 | del bugs[id] | |
795 |
|
799 | |||
796 | def filter_cset_known_bug_ids(self, node, bugs): |
|
800 | def filter_cset_known_bug_ids(self, node, bugs): | |
797 | for id in sorted(bugs.keys()): |
|
801 | for id in sorted(bugs.keys()): | |
798 | if self.get_bug_comments(id).find(short(node)) != -1: |
|
802 | if self.get_bug_comments(id).find(short(node)) != -1: | |
799 | self.ui.status( |
|
803 | self.ui.status( | |
800 | _('bug %d already knows about changeset %s\n') |
|
804 | _(b'bug %d already knows about changeset %s\n') | |
801 | % (id, short(node)) |
|
805 | % (id, short(node)) | |
802 | ) |
|
806 | ) | |
803 | del bugs[id] |
|
807 | del bugs[id] | |
804 |
|
808 | |||
805 | def updatebug(self, bugid, newstate, text, committer): |
|
809 | def updatebug(self, bugid, newstate, text, committer): | |
806 | args = {} |
|
810 | args = {} | |
807 | if 'hours' in newstate: |
|
811 | if b'hours' in newstate: | |
808 | args['work_time'] = newstate['hours'] |
|
812 | args[b'work_time'] = newstate[b'hours'] | |
809 |
|
813 | |||
810 | if self.bzvermajor >= 4: |
|
814 | if self.bzvermajor >= 4: | |
811 | args['ids'] = [bugid] |
|
815 | args[b'ids'] = [bugid] | |
812 | args['comment'] = {'body': text} |
|
816 | args[b'comment'] = {b'body': text} | |
813 | if 'fix' in newstate: |
|
817 | if b'fix' in newstate: | |
814 | args['status'] = self.fixstatus |
|
818 | args[b'status'] = self.fixstatus | |
815 | args['resolution'] = self.fixresolution |
|
819 | args[b'resolution'] = self.fixresolution | |
816 | args['token'] = self.bztoken |
|
820 | args[b'token'] = self.bztoken | |
817 | self.bzproxy.Bug.update(args) |
|
821 | self.bzproxy.Bug.update(args) | |
818 | else: |
|
822 | else: | |
819 | if 'fix' in newstate: |
|
823 | if b'fix' in newstate: | |
820 | self.ui.warn( |
|
824 | self.ui.warn( | |
821 | _( |
|
825 | _( | |
822 | "Bugzilla/XMLRPC needs Bugzilla 4.0 or later " |
|
826 | b"Bugzilla/XMLRPC needs Bugzilla 4.0 or later " | |
823 | "to mark bugs fixed\n" |
|
827 | b"to mark bugs fixed\n" | |
824 | ) |
|
828 | ) | |
825 | ) |
|
829 | ) | |
826 | args['id'] = bugid |
|
830 | args[b'id'] = bugid | |
827 | args['comment'] = text |
|
831 | args[b'comment'] = text | |
828 | self.bzproxy.Bug.add_comment(args) |
|
832 | self.bzproxy.Bug.add_comment(args) | |
829 |
|
833 | |||
830 |
|
834 | |||
@@ -851,18 +855,18 b' class bzxmlrpcemail(bzxmlrpc):' | |||||
851 | def __init__(self, ui): |
|
855 | def __init__(self, ui): | |
852 | bzxmlrpc.__init__(self, ui) |
|
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 | if not self.bzemail: |
|
859 | if not self.bzemail: | |
856 | raise error.Abort(_("configuration 'bzemail' missing")) |
|
860 | raise error.Abort(_(b"configuration 'bzemail' missing")) | |
857 | mail.validateconfig(self.ui) |
|
861 | mail.validateconfig(self.ui) | |
858 |
|
862 | |||
859 | def makecommandline(self, fieldname, value): |
|
863 | def makecommandline(self, fieldname, value): | |
860 | if self.bzvermajor >= 4: |
|
864 | if self.bzvermajor >= 4: | |
861 | return "@%s %s" % (fieldname, pycompat.bytestr(value)) |
|
865 | return b"@%s %s" % (fieldname, pycompat.bytestr(value)) | |
862 | else: |
|
866 | else: | |
863 | if fieldname == "id": |
|
867 | if fieldname == b"id": | |
864 | fieldname = "bug_id" |
|
868 | fieldname = b"bug_id" | |
865 | return "@%s = %s" % (fieldname, pycompat.bytestr(value)) |
|
869 | return b"@%s = %s" % (fieldname, pycompat.bytestr(value)) | |
866 |
|
870 | |||
867 | def send_bug_modify_email(self, bugid, commands, comment, committer): |
|
871 | def send_bug_modify_email(self, bugid, commands, comment, committer): | |
868 | '''send modification message to Bugzilla bug via email. |
|
872 | '''send modification message to Bugzilla bug via email. | |
@@ -877,39 +881,41 b' class bzxmlrpcemail(bzxmlrpc):' | |||||
877 | ''' |
|
881 | ''' | |
878 | user = self.map_committer(committer) |
|
882 | user = self.map_committer(committer) | |
879 | matches = self.bzproxy.User.get( |
|
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']: |
|
886 | if not matches[b'users']: | |
883 | user = self.ui.config('bugzilla', 'user') |
|
887 | user = self.ui.config(b'bugzilla', b'user') | |
884 | matches = self.bzproxy.User.get( |
|
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 | raise error.Abort( |
|
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'] |
|
895 | user = matches[b'users'][0][b'email'] | |
892 | commands.append(self.makecommandline("id", bugid)) |
|
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 | _charsets = mail._charsets(self.ui) |
|
900 | _charsets = mail._charsets(self.ui) | |
897 | user = mail.addressencode(self.ui, user, _charsets) |
|
901 | user = mail.addressencode(self.ui, user, _charsets) | |
898 | bzemail = mail.addressencode(self.ui, self.bzemail, _charsets) |
|
902 | bzemail = mail.addressencode(self.ui, self.bzemail, _charsets) | |
899 | msg = mail.mimeencode(self.ui, text, _charsets) |
|
903 | msg = mail.mimeencode(self.ui, text, _charsets) | |
900 | msg['From'] = user |
|
904 | msg[b'From'] = user | |
901 | msg['To'] = bzemail |
|
905 | msg[b'To'] = bzemail | |
902 |
msg['Subject'] = mail.headencode( |
|
906 | msg[b'Subject'] = mail.headencode( | |
|
907 | self.ui, b"Bug modification", _charsets | |||
|
908 | ) | |||
903 | sendmail = mail.connect(self.ui) |
|
909 | sendmail = mail.connect(self.ui) | |
904 | sendmail(user, bzemail, msg.as_string()) |
|
910 | sendmail(user, bzemail, msg.as_string()) | |
905 |
|
911 | |||
906 | def updatebug(self, bugid, newstate, text, committer): |
|
912 | def updatebug(self, bugid, newstate, text, committer): | |
907 | cmds = [] |
|
913 | cmds = [] | |
908 | if 'hours' in newstate: |
|
914 | if b'hours' in newstate: | |
909 | cmds.append(self.makecommandline("work_time", newstate['hours'])) |
|
915 | cmds.append(self.makecommandline(b"work_time", newstate[b'hours'])) | |
910 | if 'fix' in newstate: |
|
916 | if b'fix' in newstate: | |
911 | cmds.append(self.makecommandline("bug_status", self.fixstatus)) |
|
917 | cmds.append(self.makecommandline(b"bug_status", self.fixstatus)) | |
912 | cmds.append(self.makecommandline("resolution", self.fixresolution)) |
|
918 | cmds.append(self.makecommandline(b"resolution", self.fixresolution)) | |
913 | self.send_bug_modify_email(bugid, cmds, text, committer) |
|
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 | def __init__(self, ui): |
|
931 | def __init__(self, ui): | |
926 | bzaccess.__init__(self, ui) |
|
932 | bzaccess.__init__(self, ui) | |
927 | bz = self.ui.config('bugzilla', 'bzurl') |
|
933 | bz = self.ui.config(b'bugzilla', b'bzurl') | |
928 | self.bzroot = '/'.join([bz, 'rest']) |
|
934 | self.bzroot = b'/'.join([bz, b'rest']) | |
929 | self.apikey = self.ui.config('bugzilla', 'apikey') |
|
935 | self.apikey = self.ui.config(b'bugzilla', b'apikey') | |
930 | self.user = self.ui.config('bugzilla', 'user') |
|
936 | self.user = self.ui.config(b'bugzilla', b'user') | |
931 | self.passwd = self.ui.config('bugzilla', 'password') |
|
937 | self.passwd = self.ui.config(b'bugzilla', b'password') | |
932 | self.fixstatus = self.ui.config('bugzilla', 'fixstatus') |
|
938 | self.fixstatus = self.ui.config(b'bugzilla', b'fixstatus') | |
933 | self.fixresolution = self.ui.config('bugzilla', 'fixresolution') |
|
939 | self.fixresolution = self.ui.config(b'bugzilla', b'fixresolution') | |
934 |
|
940 | |||
935 | def apiurl(self, targets, include_fields=None): |
|
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 | qv = {} |
|
943 | qv = {} | |
938 | if self.apikey: |
|
944 | if self.apikey: | |
939 | qv['api_key'] = self.apikey |
|
945 | qv[b'api_key'] = self.apikey | |
940 | elif self.user and self.passwd: |
|
946 | elif self.user and self.passwd: | |
941 | qv['login'] = self.user |
|
947 | qv[b'login'] = self.user | |
942 | qv['password'] = self.passwd |
|
948 | qv[b'password'] = self.passwd | |
943 | if include_fields: |
|
949 | if include_fields: | |
944 | qv['include_fields'] = include_fields |
|
950 | qv[b'include_fields'] = include_fields | |
945 | if qv: |
|
951 | if qv: | |
946 | url = '%s?%s' % (url, util.urlreq.urlencode(qv)) |
|
952 | url = b'%s?%s' % (url, util.urlreq.urlencode(qv)) | |
947 | return url |
|
953 | return url | |
948 |
|
954 | |||
949 | def _fetch(self, burl): |
|
955 | def _fetch(self, burl): | |
@@ -952,30 +958,30 b' class bzrestapi(bzaccess):' | |||||
952 | return json.loads(resp.read()) |
|
958 | return json.loads(resp.read()) | |
953 | except util.urlerr.httperror as inst: |
|
959 | except util.urlerr.httperror as inst: | |
954 | if inst.code == 401: |
|
960 | if inst.code == 401: | |
955 | raise error.Abort(_('authorization failed')) |
|
961 | raise error.Abort(_(b'authorization failed')) | |
956 | if inst.code == 404: |
|
962 | if inst.code == 404: | |
957 | raise NotFound() |
|
963 | raise NotFound() | |
958 | else: |
|
964 | else: | |
959 | raise |
|
965 | raise | |
960 |
|
966 | |||
961 | def _submit(self, burl, data, method='POST'): |
|
967 | def _submit(self, burl, data, method=b'POST'): | |
962 | data = json.dumps(data) |
|
968 | data = json.dumps(data) | |
963 | if method == 'PUT': |
|
969 | if method == b'PUT': | |
964 |
|
970 | |||
965 | class putrequest(util.urlreq.request): |
|
971 | class putrequest(util.urlreq.request): | |
966 | def get_method(self): |
|
972 | def get_method(self): | |
967 | return 'PUT' |
|
973 | return b'PUT' | |
968 |
|
974 | |||
969 | request_type = putrequest |
|
975 | request_type = putrequest | |
970 | else: |
|
976 | else: | |
971 | request_type = util.urlreq.request |
|
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 | try: |
|
979 | try: | |
974 | resp = url.opener(self.ui).open(req) |
|
980 | resp = url.opener(self.ui).open(req) | |
975 | return json.loads(resp.read()) |
|
981 | return json.loads(resp.read()) | |
976 | except util.urlerr.httperror as inst: |
|
982 | except util.urlerr.httperror as inst: | |
977 | if inst.code == 401: |
|
983 | if inst.code == 401: | |
978 | raise error.Abort(_('authorization failed')) |
|
984 | raise error.Abort(_(b'authorization failed')) | |
979 | if inst.code == 404: |
|
985 | if inst.code == 404: | |
980 | raise NotFound() |
|
986 | raise NotFound() | |
981 | else: |
|
987 | else: | |
@@ -985,7 +991,7 b' class bzrestapi(bzaccess):' | |||||
985 | '''remove bug IDs that do not exist in Bugzilla from bugs.''' |
|
991 | '''remove bug IDs that do not exist in Bugzilla from bugs.''' | |
986 | badbugs = set() |
|
992 | badbugs = set() | |
987 | for bugid in bugs: |
|
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 | try: |
|
995 | try: | |
990 | self._fetch(burl) |
|
996 | self._fetch(burl) | |
991 | except NotFound: |
|
997 | except NotFound: | |
@@ -997,12 +1003,15 b' class bzrestapi(bzaccess):' | |||||
997 | '''remove bug IDs where node occurs in comment text from bugs.''' |
|
1003 | '''remove bug IDs where node occurs in comment text from bugs.''' | |
998 | sn = short(node) |
|
1004 | sn = short(node) | |
999 | for bugid in bugs.keys(): |
|
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 | result = self._fetch(burl) |
|
1009 | result = self._fetch(burl) | |
1002 | comments = result['bugs'][pycompat.bytestr(bugid)]['comments'] |
|
1010 | comments = result[b'bugs'][pycompat.bytestr(bugid)][b'comments'] | |
1003 | if any(sn in c['text'] for c in comments): |
|
1011 | if any(sn in c[b'text'] for c in comments): | |
1004 | self.ui.status( |
|
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 | del bugs[bugid] |
|
1016 | del bugs[bugid] | |
1008 |
|
1017 | |||
@@ -1013,28 +1022,32 b' class bzrestapi(bzaccess):' | |||||
1013 | the changeset. Otherwise use the default Bugzilla user. |
|
1022 | the changeset. Otherwise use the default Bugzilla user. | |
1014 | ''' |
|
1023 | ''' | |
1015 | bugmod = {} |
|
1024 | bugmod = {} | |
1016 | if 'hours' in newstate: |
|
1025 | if b'hours' in newstate: | |
1017 | bugmod['work_time'] = newstate['hours'] |
|
1026 | bugmod[b'work_time'] = newstate[b'hours'] | |
1018 | if 'fix' in newstate: |
|
1027 | if b'fix' in newstate: | |
1019 | bugmod['status'] = self.fixstatus |
|
1028 | bugmod[b'status'] = self.fixstatus | |
1020 | bugmod['resolution'] = self.fixresolution |
|
1029 | bugmod[b'resolution'] = self.fixresolution | |
1021 | if bugmod: |
|
1030 | if bugmod: | |
1022 | # if we have to change the bugs state do it here |
|
1031 | # if we have to change the bugs state do it here | |
1023 | bugmod['comment'] = { |
|
1032 | bugmod[b'comment'] = { | |
1024 | 'comment': text, |
|
1033 | b'comment': text, | |
1025 | 'is_private': False, |
|
1034 | b'is_private': False, | |
1026 | 'is_markdown': False, |
|
1035 | b'is_markdown': False, | |
1027 | } |
|
1036 | } | |
1028 | burl = self.apiurl(('bug', bugid)) |
|
1037 | burl = self.apiurl((b'bug', bugid)) | |
1029 | self._submit(burl, bugmod, method='PUT') |
|
1038 | self._submit(burl, bugmod, method=b'PUT') | |
1030 | self.ui.debug('updated bug %s\n' % bugid) |
|
1039 | self.ui.debug(b'updated bug %s\n' % bugid) | |
1031 | else: |
|
1040 | else: | |
1032 | burl = self.apiurl(('bug', bugid, 'comment')) |
|
1041 | burl = self.apiurl((b'bug', bugid, b'comment')) | |
1033 | self._submit( |
|
1042 | self._submit( | |
1034 | burl, |
|
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 | def notify(self, bugs, committer): |
|
1052 | def notify(self, bugs, committer): | |
1040 | '''Force sending of Bugzilla notification emails. |
|
1053 | '''Force sending of Bugzilla notification emails. | |
@@ -1049,32 +1062,32 b' class bugzilla(object):' | |||||
1049 | # supported versions of bugzilla. different versions have |
|
1062 | # supported versions of bugzilla. different versions have | |
1050 | # different schemas. |
|
1063 | # different schemas. | |
1051 | _versions = { |
|
1064 | _versions = { | |
1052 | '2.16': bzmysql, |
|
1065 | b'2.16': bzmysql, | |
1053 | '2.18': bzmysql_2_18, |
|
1066 | b'2.18': bzmysql_2_18, | |
1054 | '3.0': bzmysql_3_0, |
|
1067 | b'3.0': bzmysql_3_0, | |
1055 | 'xmlrpc': bzxmlrpc, |
|
1068 | b'xmlrpc': bzxmlrpc, | |
1056 | 'xmlrpc+email': bzxmlrpcemail, |
|
1069 | b'xmlrpc+email': bzxmlrpcemail, | |
1057 | 'restapi': bzrestapi, |
|
1070 | b'restapi': bzrestapi, | |
1058 | } |
|
1071 | } | |
1059 |
|
1072 | |||
1060 | def __init__(self, ui, repo): |
|
1073 | def __init__(self, ui, repo): | |
1061 | self.ui = ui |
|
1074 | self.ui = ui | |
1062 | self.repo = repo |
|
1075 | self.repo = repo | |
1063 |
|
1076 | |||
1064 | bzversion = self.ui.config('bugzilla', 'version') |
|
1077 | bzversion = self.ui.config(b'bugzilla', b'version') | |
1065 | try: |
|
1078 | try: | |
1066 | bzclass = bugzilla._versions[bzversion] |
|
1079 | bzclass = bugzilla._versions[bzversion] | |
1067 | except KeyError: |
|
1080 | except KeyError: | |
1068 | raise error.Abort( |
|
1081 | raise error.Abort( | |
1069 | _('bugzilla version %s not supported') % bzversion |
|
1082 | _(b'bugzilla version %s not supported') % bzversion | |
1070 | ) |
|
1083 | ) | |
1071 | self.bzdriver = bzclass(self.ui) |
|
1084 | self.bzdriver = bzclass(self.ui) | |
1072 |
|
1085 | |||
1073 | self.bug_re = re.compile( |
|
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 | self.fix_re = re.compile( |
|
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 | self.split_re = re.compile(br'\D+') |
|
1092 | self.split_re = re.compile(br'\D+') | |
1080 |
|
1093 | |||
@@ -1106,25 +1119,25 b' class bugzilla(object):' | |||||
1106 | start = m.end() |
|
1119 | start = m.end() | |
1107 | if m is bugmatch: |
|
1120 | if m is bugmatch: | |
1108 | bugmatch = self.bug_re.search(ctx.description(), start) |
|
1121 | bugmatch = self.bug_re.search(ctx.description(), start) | |
1109 | if 'fix' in bugattribs: |
|
1122 | if b'fix' in bugattribs: | |
1110 | del bugattribs['fix'] |
|
1123 | del bugattribs[b'fix'] | |
1111 | else: |
|
1124 | else: | |
1112 | fixmatch = self.fix_re.search(ctx.description(), start) |
|
1125 | fixmatch = self.fix_re.search(ctx.description(), start) | |
1113 | bugattribs['fix'] = None |
|
1126 | bugattribs[b'fix'] = None | |
1114 |
|
1127 | |||
1115 | try: |
|
1128 | try: | |
1116 | ids = m.group('ids') |
|
1129 | ids = m.group(b'ids') | |
1117 | except IndexError: |
|
1130 | except IndexError: | |
1118 | ids = m.group(1) |
|
1131 | ids = m.group(1) | |
1119 | try: |
|
1132 | try: | |
1120 | hours = float(m.group('hours')) |
|
1133 | hours = float(m.group(b'hours')) | |
1121 | bugattribs['hours'] = hours |
|
1134 | bugattribs[b'hours'] = hours | |
1122 | except IndexError: |
|
1135 | except IndexError: | |
1123 | pass |
|
1136 | pass | |
1124 | except TypeError: |
|
1137 | except TypeError: | |
1125 | pass |
|
1138 | pass | |
1126 | except ValueError: |
|
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 | for id in self.split_re.split(ids): |
|
1142 | for id in self.split_re.split(ids): | |
1130 | if not id: |
|
1143 | if not id: | |
@@ -1142,10 +1155,10 b' class bugzilla(object):' | |||||
1142 | def webroot(root): |
|
1155 | def webroot(root): | |
1143 | '''strip leading prefix of repo root and turn into |
|
1156 | '''strip leading prefix of repo root and turn into | |
1144 | url-safe path.''' |
|
1157 | url-safe path.''' | |
1145 | count = int(self.ui.config('bugzilla', 'strip')) |
|
1158 | count = int(self.ui.config(b'bugzilla', b'strip')) | |
1146 | root = util.pconvert(root) |
|
1159 | root = util.pconvert(root) | |
1147 | while count > 0: |
|
1160 | while count > 0: | |
1148 | c = root.find('/') |
|
1161 | c = root.find(b'/') | |
1149 | if c == -1: |
|
1162 | if c == -1: | |
1150 | break |
|
1163 | break | |
1151 | root = root[c + 1 :] |
|
1164 | root = root[c + 1 :] | |
@@ -1153,13 +1166,13 b' class bugzilla(object):' | |||||
1153 | return root |
|
1166 | return root | |
1154 |
|
1167 | |||
1155 | mapfile = None |
|
1168 | mapfile = None | |
1156 | tmpl = self.ui.config('bugzilla', 'template') |
|
1169 | tmpl = self.ui.config(b'bugzilla', b'template') | |
1157 | if not tmpl: |
|
1170 | if not tmpl: | |
1158 | mapfile = self.ui.config('bugzilla', 'style') |
|
1171 | mapfile = self.ui.config(b'bugzilla', b'style') | |
1159 | if not mapfile and not tmpl: |
|
1172 | if not mapfile and not tmpl: | |
1160 | tmpl = _( |
|
1173 | tmpl = _( | |
1161 | 'changeset {node|short} in repo {root} refers ' |
|
1174 | b'changeset {node|short} in repo {root} refers ' | |
1162 | 'to bug {bug}.\ndetails:\n\t{desc|tabindent}' |
|
1175 | b'to bug {bug}.\ndetails:\n\t{desc|tabindent}' | |
1163 | ) |
|
1176 | ) | |
1164 | spec = logcmdutil.templatespec(tmpl, mapfile) |
|
1177 | spec = logcmdutil.templatespec(tmpl, mapfile) | |
1165 | t = logcmdutil.changesettemplater(self.ui, self.repo, spec) |
|
1178 | t = logcmdutil.changesettemplater(self.ui, self.repo, spec) | |
@@ -1168,7 +1181,7 b' class bugzilla(object):' | |||||
1168 | ctx, |
|
1181 | ctx, | |
1169 | changes=ctx.changeset(), |
|
1182 | changes=ctx.changeset(), | |
1170 | bug=pycompat.bytestr(bugid), |
|
1183 | bug=pycompat.bytestr(bugid), | |
1171 | hgweb=self.ui.config('web', 'baseurl'), |
|
1184 | hgweb=self.ui.config(b'web', b'baseurl'), | |
1172 | root=self.repo.root, |
|
1185 | root=self.repo.root, | |
1173 | webroot=webroot(self.repo.root), |
|
1186 | webroot=webroot(self.repo.root), | |
1174 | ) |
|
1187 | ) | |
@@ -1188,7 +1201,7 b' def hook(ui, repo, hooktype, node=None, ' | |||||
1188 | seen multiple times does not fill bug with duplicate data.''' |
|
1201 | seen multiple times does not fill bug with duplicate data.''' | |
1189 | if node is None: |
|
1202 | if node is None: | |
1190 | raise error.Abort( |
|
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 | try: |
|
1206 | try: | |
1194 | bz = bugzilla(ui, repo) |
|
1207 | bz = bugzilla(ui, repo) | |
@@ -1199,4 +1212,4 b' def hook(ui, repo, hooktype, node=None, ' | |||||
1199 | bz.update(bug, bugs[bug], ctx) |
|
1212 | bz.update(bug, bugs[bug], ctx) | |
1200 | bz.notify(bugs, stringutil.email(ctx.user())) |
|
1213 | bz.notify(bugs, stringutil.email(ctx.user())) | |
1201 | except Exception as e: |
|
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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
42 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
43 | # be specifying the version(s) of Mercurial they are tested with, or |
|
43 | # be specifying the version(s) of Mercurial they are tested with, or | |
44 | # leave the attribute unspecified. |
|
44 | # leave the attribute unspecified. | |
45 | testedwith = 'ships-with-hg-core' |
|
45 | testedwith = b'ships-with-hg-core' | |
46 |
|
46 | |||
47 |
|
47 | |||
48 | @command( |
|
48 | @command( | |
49 | 'censor', |
|
49 | b'censor', | |
50 | [ |
|
50 | [ | |
51 | ('r', 'rev', '', _('censor file from specified revision'), _('REV')), |
|
51 | ( | |
52 | ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT')), |
|
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 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
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 | with repo.wlock(), repo.lock(): |
|
64 | with repo.wlock(), repo.lock(): | |
59 | return _docensor(ui, repo, path, rev, tombstone, **opts) |
|
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 | if not path: |
|
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 | if not rev: |
|
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 | wctx = repo[None] |
|
74 | wctx = repo[None] | |
69 |
|
75 | |||
70 | m = scmutil.match(wctx, (path,)) |
|
76 | m = scmutil.match(wctx, (path,)) | |
71 | if m.anypats() or len(m.files()) != 1: |
|
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 | path = m.files()[0] |
|
79 | path = m.files()[0] | |
74 | flog = repo.file(path) |
|
80 | flog = repo.file(path) | |
75 | if not len(flog): |
|
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 | rev = scmutil.revsingle(repo, rev, rev).rev() |
|
84 | rev = scmutil.revsingle(repo, rev, rev).rev() | |
79 | try: |
|
85 | try: | |
80 | ctx = repo[rev] |
|
86 | ctx = repo[rev] | |
81 | except KeyError: |
|
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 | try: |
|
90 | try: | |
85 | fctx = ctx.filectx(path) |
|
91 | fctx = ctx.filectx(path) | |
86 | except error.LookupError: |
|
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 | fnode = fctx.filenode() |
|
95 | fnode = fctx.filenode() | |
90 | heads = [] |
|
96 | heads = [] | |
@@ -93,17 +99,17 b" def _docensor(ui, repo, path, rev='', to" | |||||
93 | if path in hc and hc.filenode(path) == fnode: |
|
99 | if path in hc and hc.filenode(path) == fnode: | |
94 | heads.append(hc) |
|
100 | heads.append(hc) | |
95 | if heads: |
|
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 | raise error.Abort( |
|
103 | raise error.Abort( | |
98 | _('cannot censor file in heads (%s)') % headlist, |
|
104 | _(b'cannot censor file in heads (%s)') % headlist, | |
99 | hint=_('clean/delete and commit first'), |
|
105 | hint=_(b'clean/delete and commit first'), | |
100 | ) |
|
106 | ) | |
101 |
|
107 | |||
102 | wp = wctx.parents() |
|
108 | wp = wctx.parents() | |
103 | if ctx.node() in [p.node() for p in wp]: |
|
109 | if ctx.node() in [p.node() for p in wp]: | |
104 | raise error.Abort( |
|
110 | raise error.Abort( | |
105 | _('cannot censor working directory'), |
|
111 | _(b'cannot censor working directory'), | |
106 | hint=_('clean/delete/update first'), |
|
112 | hint=_(b'clean/delete/update first'), | |
107 | ) |
|
113 | ) | |
108 |
|
114 | |||
109 | with repo.transaction(b'censor') as tr: |
|
115 | with repo.transaction(b'censor') as tr: |
@@ -33,14 +33,22 b' command = registrar.command(cmdtable)' | |||||
33 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
33 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
34 | # be specifying the version(s) of Mercurial they are tested with, or |
|
34 | # be specifying the version(s) of Mercurial they are tested with, or | |
35 | # leave the attribute unspecified. |
|
35 | # leave the attribute unspecified. | |
36 | testedwith = 'ships-with-hg-core' |
|
36 | testedwith = b'ships-with-hg-core' | |
37 |
|
37 | |||
38 |
|
38 | |||
39 | @command( |
|
39 | @command( | |
40 | 'children', |
|
40 | b'children', | |
41 | [('r', 'rev', '.', _('show children of the specified revision'), _('REV')),] |
|
41 | [ | |
|
42 | ( | |||
|
43 | b'r', | |||
|
44 | b'rev', | |||
|
45 | b'.', | |||
|
46 | _(b'show children of the specified revision'), | |||
|
47 | _(b'REV'), | |||
|
48 | ), | |||
|
49 | ] | |||
42 | + templateopts, |
|
50 | + templateopts, | |
43 | _('hg children [-r REV] [FILE]'), |
|
51 | _(b'hg children [-r REV] [FILE]'), | |
44 | helpcategory=command.CATEGORY_CHANGE_NAVIGATION, |
|
52 | helpcategory=command.CATEGORY_CHANGE_NAVIGATION, | |
45 | inferrepo=True, |
|
53 | inferrepo=True, | |
46 | ) |
|
54 | ) | |
@@ -62,7 +70,7 b' def children(ui, repo, file_=None, **opt' | |||||
62 |
|
70 | |||
63 | """ |
|
71 | """ | |
64 | opts = pycompat.byteskwargs(opts) |
|
72 | opts = pycompat.byteskwargs(opts) | |
65 | rev = opts.get('rev') |
|
73 | rev = opts.get(b'rev') | |
66 | ctx = scmutil.revsingle(repo, rev) |
|
74 | ctx = scmutil.revsingle(repo, rev) | |
67 | if file_: |
|
75 | if file_: | |
68 | fctx = repo.filectx(file_, changeid=ctx.rev()) |
|
76 | fctx = repo.filectx(file_, changeid=ctx.rev()) |
@@ -32,17 +32,17 b' command = registrar.command(cmdtable)' | |||||
32 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
32 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
33 | # be specifying the version(s) of Mercurial they are tested with, or |
|
33 | # be specifying the version(s) of Mercurial they are tested with, or | |
34 | # leave the attribute unspecified. |
|
34 | # leave the attribute unspecified. | |
35 | testedwith = 'ships-with-hg-core' |
|
35 | testedwith = b'ships-with-hg-core' | |
36 |
|
36 | |||
37 |
|
37 | |||
38 | def changedlines(ui, repo, ctx1, ctx2, fns): |
|
38 | def changedlines(ui, repo, ctx1, ctx2, fns): | |
39 | added, removed = 0, 0 |
|
39 | added, removed = 0, 0 | |
40 | fmatch = scmutil.matchfiles(repo, fns) |
|
40 | fmatch = scmutil.matchfiles(repo, fns) | |
41 | diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) |
|
41 | diff = b''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) | |
42 | for l in diff.split('\n'): |
|
42 | for l in diff.split(b'\n'): | |
43 | if l.startswith("+") and not l.startswith("+++ "): |
|
43 | if l.startswith(b"+") and not l.startswith(b"+++ "): | |
44 | added += 1 |
|
44 | added += 1 | |
45 | elif l.startswith("-") and not l.startswith("--- "): |
|
45 | elif l.startswith(b"-") and not l.startswith(b"--- "): | |
46 | removed += 1 |
|
46 | removed += 1 | |
47 | return (added, removed) |
|
47 | return (added, removed) | |
48 |
|
48 | |||
@@ -50,17 +50,17 b' def changedlines(ui, repo, ctx1, ctx2, f' | |||||
50 | def countrate(ui, repo, amap, *pats, **opts): |
|
50 | def countrate(ui, repo, amap, *pats, **opts): | |
51 | """Calculate stats""" |
|
51 | """Calculate stats""" | |
52 | opts = pycompat.byteskwargs(opts) |
|
52 | opts = pycompat.byteskwargs(opts) | |
53 | if opts.get('dateformat'): |
|
53 | if opts.get(b'dateformat'): | |
54 |
|
54 | |||
55 | def getkey(ctx): |
|
55 | def getkey(ctx): | |
56 | t, tz = ctx.date() |
|
56 | t, tz = ctx.date() | |
57 | date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) |
|
57 | date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) | |
58 | return encoding.strtolocal( |
|
58 | return encoding.strtolocal( | |
59 | date.strftime(encoding.strfromlocal(opts['dateformat'])) |
|
59 | date.strftime(encoding.strfromlocal(opts[b'dateformat'])) | |
60 | ) |
|
60 | ) | |
61 |
|
61 | |||
62 | else: |
|
62 | else: | |
63 | tmpl = opts.get('oldtemplate') or opts.get('template') |
|
63 | tmpl = opts.get(b'oldtemplate') or opts.get(b'template') | |
64 | tmpl = logcmdutil.maketemplater(ui, repo, tmpl) |
|
64 | tmpl = logcmdutil.maketemplater(ui, repo, tmpl) | |
65 |
|
65 | |||
66 | def getkey(ctx): |
|
66 | def getkey(ctx): | |
@@ -69,12 +69,12 b' def countrate(ui, repo, amap, *pats, **o' | |||||
69 | return ui.popbuffer() |
|
69 | return ui.popbuffer() | |
70 |
|
70 | |||
71 | progress = ui.makeprogress( |
|
71 | progress = ui.makeprogress( | |
72 | _('analyzing'), unit=_('revisions'), total=len(repo) |
|
72 | _(b'analyzing'), unit=_(b'revisions'), total=len(repo) | |
73 | ) |
|
73 | ) | |
74 | rate = {} |
|
74 | rate = {} | |
75 | df = False |
|
75 | df = False | |
76 | if opts.get('date'): |
|
76 | if opts.get(b'date'): | |
77 | df = dateutil.matchdate(opts['date']) |
|
77 | df = dateutil.matchdate(opts[b'date']) | |
78 |
|
78 | |||
79 | m = scmutil.match(repo[None], pats, opts) |
|
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 | key = getkey(ctx).strip() |
|
86 | key = getkey(ctx).strip() | |
87 | key = amap.get(key, key) # alias remap |
|
87 | key = amap.get(key, key) # alias remap | |
88 | if opts.get('changesets'): |
|
88 | if opts.get(b'changesets'): | |
89 | rate[key] = (rate.get(key, (0,))[0] + 1, 0) |
|
89 | rate[key] = (rate.get(key, (0,))[0] + 1, 0) | |
90 | else: |
|
90 | else: | |
91 | parents = ctx.parents() |
|
91 | parents = ctx.parents() | |
92 | if len(parents) > 1: |
|
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 | return |
|
94 | return | |
95 |
|
95 | |||
96 | ctx1 = parents[0] |
|
96 | ctx1 = parents[0] | |
@@ -108,50 +108,50 b' def countrate(ui, repo, amap, *pats, **o' | |||||
108 |
|
108 | |||
109 |
|
109 | |||
110 | @command( |
|
110 | @command( | |
111 | 'churn', |
|
111 | b'churn', | |
112 | [ |
|
112 | [ | |
113 | ( |
|
113 | ( | |
114 | 'r', |
|
114 | b'r', | |
115 | 'rev', |
|
115 | b'rev', | |
116 | [], |
|
116 | [], | |
117 | _('count rate for the specified revision or revset'), |
|
117 | _(b'count rate for the specified revision or revset'), | |
118 | _('REV'), |
|
118 | _(b'REV'), | |
119 | ), |
|
119 | ), | |
120 | ( |
|
120 | ( | |
121 | 'd', |
|
121 | b'd', | |
122 | 'date', |
|
122 | b'date', | |
123 | '', |
|
123 | b'', | |
124 | _('count rate for revisions matching date spec'), |
|
124 | _(b'count rate for revisions matching date spec'), | |
125 | _('DATE'), |
|
125 | _(b'DATE'), | |
126 | ), |
|
126 | ), | |
127 | ( |
|
127 | ( | |
128 | 't', |
|
128 | b't', | |
129 | 'oldtemplate', |
|
129 | b'oldtemplate', | |
130 | '', |
|
130 | b'', | |
131 | _('template to group changesets (DEPRECATED)'), |
|
131 | _(b'template to group changesets (DEPRECATED)'), | |
132 | _('TEMPLATE'), |
|
132 | _(b'TEMPLATE'), | |
133 | ), |
|
133 | ), | |
134 | ( |
|
134 | ( | |
135 | 'T', |
|
135 | b'T', | |
136 | 'template', |
|
136 | b'template', | |
137 | '{author|email}', |
|
137 | b'{author|email}', | |
138 | _('template to group changesets'), |
|
138 | _(b'template to group changesets'), | |
139 | _('TEMPLATE'), |
|
139 | _(b'TEMPLATE'), | |
140 | ), |
|
140 | ), | |
141 | ( |
|
141 | ( | |
142 | 'f', |
|
142 | b'f', | |
143 | 'dateformat', |
|
143 | b'dateformat', | |
144 | '', |
|
144 | b'', | |
145 | _('strftime-compatible format for grouping by date'), |
|
145 | _(b'strftime-compatible format for grouping by date'), | |
146 | _('FORMAT'), |
|
146 | _(b'FORMAT'), | |
147 | ), |
|
147 | ), | |
148 | ('c', 'changesets', False, _('count rate by number of changesets')), |
|
148 | (b'c', b'changesets', False, _(b'count rate by number of changesets')), | |
149 | ('s', 'sort', False, _('sort by key (default: sort by count)')), |
|
149 | (b's', b'sort', False, _(b'sort by key (default: sort by count)')), | |
150 | ('', 'diffstat', False, _('display added/removed lines separately')), |
|
150 | (b'', b'diffstat', False, _(b'display added/removed lines separately')), | |
151 | ('', 'aliases', '', _('file with email aliases'), _('FILE')), |
|
151 | (b'', b'aliases', b'', _(b'file with email aliases'), _(b'FILE')), | |
152 | ] |
|
152 | ] | |
153 | + cmdutil.walkopts, |
|
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 | helpcategory=command.CATEGORY_MAINTENANCE, |
|
155 | helpcategory=command.CATEGORY_MAINTENANCE, | |
156 | inferrepo=True, |
|
156 | inferrepo=True, | |
157 | ) |
|
157 | ) | |
@@ -193,21 +193,21 b' def churn(ui, repo, *pats, **opts):' | |||||
193 | ''' |
|
193 | ''' | |
194 |
|
194 | |||
195 | def pad(s, l): |
|
195 | def pad(s, l): | |
196 | return s + " " * (l - encoding.colwidth(s)) |
|
196 | return s + b" " * (l - encoding.colwidth(s)) | |
197 |
|
197 | |||
198 | amap = {} |
|
198 | amap = {} | |
199 | aliases = opts.get(r'aliases') |
|
199 | aliases = opts.get(r'aliases') | |
200 | if not aliases and os.path.exists(repo.wjoin('.hgchurn')): |
|
200 | if not aliases and os.path.exists(repo.wjoin(b'.hgchurn')): | |
201 | aliases = repo.wjoin('.hgchurn') |
|
201 | aliases = repo.wjoin(b'.hgchurn') | |
202 | if aliases: |
|
202 | if aliases: | |
203 | for l in open(aliases, "rb"): |
|
203 | for l in open(aliases, b"rb"): | |
204 | try: |
|
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 | amap[alias.strip()] = actual.strip() |
|
206 | amap[alias.strip()] = actual.strip() | |
207 | except ValueError: |
|
207 | except ValueError: | |
208 | l = l.strip() |
|
208 | l = l.strip() | |
209 | if l: |
|
209 | if l: | |
210 | ui.warn(_("skipping malformed alias: %s\n") % l) |
|
210 | ui.warn(_(b"skipping malformed alias: %s\n") % l) | |
211 | continue |
|
211 | continue | |
212 |
|
212 | |||
213 | rate = list(countrate(ui, repo, amap, *pats, **opts).items()) |
|
213 | rate = list(countrate(ui, repo, amap, *pats, **opts).items()) | |
@@ -224,7 +224,7 b' def churn(ui, repo, *pats, **opts):' | |||||
224 | maxname = max(len(k) for k, v in rate) |
|
224 | maxname = max(len(k) for k, v in rate) | |
225 |
|
225 | |||
226 | ttywidth = ui.termwidth() |
|
226 | ttywidth = ui.termwidth() | |
227 | ui.debug("assuming %i character terminal\n" % ttywidth) |
|
227 | ui.debug(b"assuming %i character terminal\n" % ttywidth) | |
228 | width = ttywidth - maxname - 2 - 2 - 2 |
|
228 | width = ttywidth - maxname - 2 - 2 - 2 | |
229 |
|
229 | |||
230 | if opts.get(r'diffstat'): |
|
230 | if opts.get(r'diffstat'): | |
@@ -232,21 +232,21 b' def churn(ui, repo, *pats, **opts):' | |||||
232 |
|
232 | |||
233 | def format(name, diffstat): |
|
233 | def format(name, diffstat): | |
234 | added, removed = diffstat |
|
234 | added, removed = diffstat | |
235 | return "%s %15s %s%s\n" % ( |
|
235 | return b"%s %15s %s%s\n" % ( | |
236 | pad(name, maxname), |
|
236 | pad(name, maxname), | |
237 | '+%d/-%d' % (added, removed), |
|
237 | b'+%d/-%d' % (added, removed), | |
238 | ui.label('+' * charnum(added), 'diffstat.inserted'), |
|
238 | ui.label(b'+' * charnum(added), b'diffstat.inserted'), | |
239 | ui.label('-' * charnum(removed), 'diffstat.deleted'), |
|
239 | ui.label(b'-' * charnum(removed), b'diffstat.deleted'), | |
240 | ) |
|
240 | ) | |
241 |
|
241 | |||
242 | else: |
|
242 | else: | |
243 | width -= 6 |
|
243 | width -= 6 | |
244 |
|
244 | |||
245 | def format(name, count): |
|
245 | def format(name, count): | |
246 | return "%s %6d %s\n" % ( |
|
246 | return b"%s %6d %s\n" % ( | |
247 | pad(name, maxname), |
|
247 | pad(name, maxname), | |
248 | sum(count), |
|
248 | sum(count), | |
249 | '*' * charnum(sum(count)), |
|
249 | b'*' * charnum(sum(count)), | |
250 | ) |
|
250 | ) | |
251 |
|
251 | |||
252 | def charnum(count): |
|
252 | def charnum(count): |
@@ -201,7 +201,7 b' from mercurial import (' | |||||
201 | wireprotov1server, |
|
201 | wireprotov1server, | |
202 | ) |
|
202 | ) | |
203 |
|
203 | |||
204 | testedwith = 'ships-with-hg-core' |
|
204 | testedwith = b'ships-with-hg-core' | |
205 |
|
205 | |||
206 |
|
206 | |||
207 | def capabilities(orig, repo, proto): |
|
207 | def capabilities(orig, repo, proto): | |
@@ -210,11 +210,11 b' def capabilities(orig, repo, proto):' | |||||
210 | # Only advertise if a manifest exists. This does add some I/O to requests. |
|
210 | # Only advertise if a manifest exists. This does add some I/O to requests. | |
211 | # But this should be cheaper than a wasted network round trip due to |
|
211 | # But this should be cheaper than a wasted network round trip due to | |
212 | # missing file. |
|
212 | # missing file. | |
213 | if repo.vfs.exists('clonebundles.manifest'): |
|
213 | if repo.vfs.exists(b'clonebundles.manifest'): | |
214 | caps.append('clonebundles') |
|
214 | caps.append(b'clonebundles') | |
215 |
|
215 | |||
216 | return caps |
|
216 | return caps | |
217 |
|
217 | |||
218 |
|
218 | |||
219 | def extsetup(ui): |
|
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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
25 | # be specifying the version(s) of Mercurial they are tested with, or | |
26 | # leave the attribute unspecified. |
|
26 | # leave the attribute unspecified. | |
27 | testedwith = 'ships-with-hg-core' |
|
27 | testedwith = b'ships-with-hg-core' | |
28 |
|
28 | |||
29 | commitopts = cmdutil.commitopts |
|
29 | commitopts = cmdutil.commitopts | |
30 | commitopts2 = cmdutil.commitopts2 |
|
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 | @command( |
|
34 | @command( | |
35 | 'close-head|close-heads', |
|
35 | b'close-head|close-heads', | |
36 | commitopts + commitopts2 + commitopts3, |
|
36 | commitopts + commitopts2 + commitopts3, | |
37 | _('[OPTION]... [REV]...'), |
|
37 | _(b'[OPTION]... [REV]...'), | |
38 | helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, |
|
38 | helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, | |
39 | inferrepo=True, |
|
39 | inferrepo=True, | |
40 | ) |
|
40 | ) | |
@@ -55,11 +55,11 b' def close_branch(ui, repo, *revs, **opts' | |||||
55 | text=message, |
|
55 | text=message, | |
56 | files=[], |
|
56 | files=[], | |
57 | filectxfn=None, |
|
57 | filectxfn=None, | |
58 | user=opts.get('user'), |
|
58 | user=opts.get(b'user'), | |
59 | date=opts.get('date'), |
|
59 | date=opts.get(b'date'), | |
60 | extra=extra, |
|
60 | extra=extra, | |
61 | ) |
|
61 | ) | |
62 | tr = repo.transaction('commit') |
|
62 | tr = repo.transaction(b'commit') | |
63 | ret = repo.commitctx(cctx, True) |
|
63 | ret = repo.commitctx(cctx, True) | |
64 | bookmarks.update(repo, [rev, None], ret) |
|
64 | bookmarks.update(repo, [rev, None], ret) | |
65 | cctx.markcommitted(ret) |
|
65 | cctx.markcommitted(ret) | |
@@ -67,11 +67,11 b' def close_branch(ui, repo, *revs, **opts' | |||||
67 |
|
67 | |||
68 | opts = pycompat.byteskwargs(opts) |
|
68 | opts = pycompat.byteskwargs(opts) | |
69 |
|
69 | |||
70 | revs += tuple(opts.get('rev', [])) |
|
70 | revs += tuple(opts.get(b'rev', [])) | |
71 | revs = scmutil.revrange(repo, revs) |
|
71 | revs = scmutil.revrange(repo, revs) | |
72 |
|
72 | |||
73 | if not revs: |
|
73 | if not revs: | |
74 | raise error.Abort(_('no revisions specified')) |
|
74 | raise error.Abort(_(b'no revisions specified')) | |
75 |
|
75 | |||
76 | heads = [] |
|
76 | heads = [] | |
77 | for branch in repo.branchmap(): |
|
77 | for branch in repo.branchmap(): | |
@@ -79,17 +79,17 b' def close_branch(ui, repo, *revs, **opts' | |||||
79 | heads = set(repo[h].rev() for h in heads) |
|
79 | heads = set(repo[h].rev() for h in heads) | |
80 | for rev in revs: |
|
80 | for rev in revs: | |
81 | if rev not in heads: |
|
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 | message = cmdutil.logmessage(ui, opts) |
|
84 | message = cmdutil.logmessage(ui, opts) | |
85 | if not message: |
|
85 | if not message: | |
86 | raise error.Abort(_("no commit message specified with -l or -m")) |
|
86 | raise error.Abort(_(b"no commit message specified with -l or -m")) | |
87 | extra = {'close': '1'} |
|
87 | extra = {b'close': b'1'} | |
88 |
|
88 | |||
89 | with repo.wlock(), repo.lock(): |
|
89 | with repo.wlock(), repo.lock(): | |
90 | for rev in revs: |
|
90 | for rev in revs: | |
91 | r = repo[rev] |
|
91 | r = repo[rev] | |
92 | branch = r.branch() |
|
92 | branch = r.branch() | |
93 | extra['branch'] = branch |
|
93 | extra[b'branch'] = branch | |
94 | docommit(r) |
|
94 | docommit(r) | |
95 | return 0 |
|
95 | return 0 |
@@ -22,57 +22,64 b' from mercurial import (' | |||||
22 |
|
22 | |||
23 | cmdtable = {} |
|
23 | cmdtable = {} | |
24 | command = registrar.command(cmdtable) |
|
24 | command = registrar.command(cmdtable) | |
25 | testedwith = 'ships-with-hg-core' |
|
25 | testedwith = b'ships-with-hg-core' | |
26 |
|
26 | |||
27 | usedinternally = { |
|
27 | usedinternally = { | |
28 | 'amend_source', |
|
28 | b'amend_source', | |
29 | 'branch', |
|
29 | b'branch', | |
30 | 'close', |
|
30 | b'close', | |
31 | 'histedit_source', |
|
31 | b'histedit_source', | |
32 | 'topic', |
|
32 | b'topic', | |
33 | 'rebase_source', |
|
33 | b'rebase_source', | |
34 | 'intermediate-source', |
|
34 | b'intermediate-source', | |
35 | '__touch-noise__', |
|
35 | b'__touch-noise__', | |
36 | 'source', |
|
36 | b'source', | |
37 | 'transplant_source', |
|
37 | b'transplant_source', | |
38 | } |
|
38 | } | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | def extsetup(ui): |
|
41 | def extsetup(ui): | |
42 | entry = extensions.wrapcommand(commands.table, 'commit', _commit) |
|
42 | entry = extensions.wrapcommand(commands.table, b'commit', _commit) | |
43 | options = entry[1] |
|
43 | options = entry[1] | |
44 | options.append( |
|
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 | def _commit(orig, ui, repo, *pats, **opts): |
|
55 | def _commit(orig, ui, repo, *pats, **opts): | |
50 | if util.safehasattr(repo, 'unfiltered'): |
|
56 | if util.safehasattr(repo, b'unfiltered'): | |
51 | repo = repo.unfiltered() |
|
57 | repo = repo.unfiltered() | |
52 |
|
58 | |||
53 | class repoextra(repo.__class__): |
|
59 | class repoextra(repo.__class__): | |
54 | def commit(self, *innerpats, **inneropts): |
|
60 | def commit(self, *innerpats, **inneropts): | |
55 | extras = opts.get(r'extra') |
|
61 | extras = opts.get(r'extra') | |
56 | for raw in extras: |
|
62 | for raw in extras: | |
57 | if '=' not in raw: |
|
63 | if b'=' not in raw: | |
58 | msg = _( |
|
64 | msg = _( | |
59 | "unable to parse '%s', should follow " |
|
65 | b"unable to parse '%s', should follow " | |
60 | "KEY=VALUE format" |
|
66 | b"KEY=VALUE format" | |
61 | ) |
|
67 | ) | |
62 | raise error.Abort(msg % raw) |
|
68 | raise error.Abort(msg % raw) | |
63 | k, v = raw.split('=', 1) |
|
69 | k, v = raw.split(b'=', 1) | |
64 | if not k: |
|
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 | raise error.Abort(msg % raw) |
|
72 | raise error.Abort(msg % raw) | |
67 | if re.search(br'[^\w-]', k): |
|
73 | if re.search(br'[^\w-]', k): | |
68 | msg = _( |
|
74 | msg = _( | |
69 | "keys can only contain ascii letters, digits," |
|
75 | b"keys can only contain ascii letters, digits," | |
70 | " '_' and '-'" |
|
76 | b" '_' and '-'" | |
71 | ) |
|
77 | ) | |
72 | raise error.Abort(msg) |
|
78 | raise error.Abort(msg) | |
73 | if k in usedinternally: |
|
79 | if k in usedinternally: | |
74 | msg = _( |
|
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 | raise error.Abort(msg % k) |
|
84 | raise error.Abort(msg % k) | |
78 | inneropts[r'extra'][k] = v |
|
85 | inneropts[r'extra'][k] = v |
@@ -24,60 +24,72 b' command = registrar.command(cmdtable)' | |||||
24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
24 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
25 | # be specifying the version(s) of Mercurial they are tested with, or |
|
25 | # be specifying the version(s) of Mercurial they are tested with, or | |
26 | # leave the attribute unspecified. |
|
26 | # leave the attribute unspecified. | |
27 | testedwith = 'ships-with-hg-core' |
|
27 | testedwith = b'ships-with-hg-core' | |
28 |
|
28 | |||
29 | # Commands definition was moved elsewhere to ease demandload job. |
|
29 | # Commands definition was moved elsewhere to ease demandload job. | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | @command( |
|
32 | @command( | |
33 | 'convert', |
|
33 | b'convert', | |
34 | [ |
|
34 | [ | |
35 | ( |
|
35 | ( | |
36 | '', |
|
36 | b'', | |
37 | 'authors', |
|
37 | b'authors', | |
38 | '', |
|
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')), |
|
44 | (b's', b'source-type', b'', _(b'source repository type'), _(b'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')), |
|
|||
48 | ( |
|
45 | ( | |
49 | '', |
|
46 | b'd', | |
50 |
' |
|
47 | b'dest-type', | |
51 | '', |
|
48 | b'', | |
52 | _('remap file names using contents of file'), |
|
49 | _(b'destination repository type'), | |
53 |
_(' |
|
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 | '', |
|
61 | b'', | |
57 |
'f |
|
62 | b'filemap', | |
58 |
|
|
63 | b'', | |
59 |
_(' |
|
64 | _(b'remap file names using contents of file'), | |
|
65 | _(b'FILE'), | |||
60 | ), |
|
66 | ), | |
61 | ( |
|
67 | ( | |
62 | '', |
|
68 | b'', | |
63 |
' |
|
69 | b'full', | |
64 |
|
|
70 | None, | |
65 | _('splice synthesized history into place'), |
|
71 | _(b'apply filemap changes by converting all files again'), | |
66 | _('FILE'), |
|
|||
67 | ), |
|
72 | ), | |
68 | ( |
|
73 | ( | |
69 | '', |
|
74 | b'', | |
70 |
' |
|
75 | b'splicemap', | |
71 | '', |
|
76 | b'', | |
72 | _('change branch names while converting'), |
|
77 | _(b'splice synthesized history into place'), | |
73 | _('FILE'), |
|
78 | _(b'FILE'), | |
74 | ), |
|
79 | ), | |
75 | ('', 'branchsort', None, _('try to sort changesets by branches')), |
|
80 | ( | |
76 | ('', 'datesort', None, _('try to sort changesets by date')), |
|
81 | b'', | |
77 | ('', 'sourcesort', None, _('preserve source changesets order')), |
|
82 | b'branchmap', | |
78 | ('', 'closesort', None, _('try to reorder closed revisions')), |
|
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 | norepo=True, |
|
93 | norepo=True, | |
82 | ) |
|
94 | ) | |
83 | def convert(ui, src, dest=None, revmapfile=None, **opts): |
|
95 | def convert(ui, src, dest=None, revmapfile=None, **opts): | |
@@ -483,34 +495,44 b' def convert(ui, src, dest=None, revmapfi' | |||||
483 | return convcmd.convert(ui, src, dest, revmapfile, **opts) |
|
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 | def debugsvnlog(ui, **opts): |
|
499 | def debugsvnlog(ui, **opts): | |
488 | return subversion.debugsvnlog(ui, **opts) |
|
500 | return subversion.debugsvnlog(ui, **opts) | |
489 |
|
501 | |||
490 |
|
502 | |||
491 | @command( |
|
503 | @command( | |
492 | 'debugcvsps', |
|
504 | b'debugcvsps', | |
493 | [ |
|
505 | [ | |
494 | # Main options shared with cvsps-2.1 |
|
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 |
' |
|
508 | b'b', | |
499 |
're |
|
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")), |
|
520 | (b'u', b'update-cache', None, _(b"update cvs log cache")), | |
504 | ('x', 'new-cache', None, _("create new cvs log cache")), |
|
521 | (b'x', b'new-cache', None, _(b"create new cvs log cache")), | |
505 | ('z', 'fuzz', 60, _('set commit time fuzz in seconds')), |
|
522 | (b'z', b'fuzz', 60, _(b'set commit time fuzz in seconds')), | |
506 | ('', 'root', '', _('specify cvsroot')), |
|
523 | (b'', b'root', b'', _(b'specify cvsroot')), | |
507 | # Options specific to builtin cvsps |
|
524 | # Options specific to builtin cvsps | |
508 | ('', 'parents', '', _('show parent changesets')), |
|
525 | (b'', b'parents', b'', _(b'show parent changesets')), | |
509 | ('', 'ancestors', '', _('show current changeset in ancestor branches')), |
|
526 | ( | |
|
527 | b'', | |||
|
528 | b'ancestors', | |||
|
529 | b'', | |||
|
530 | _(b'show current changeset in ancestor branches'), | |||
|
531 | ), | |||
510 | # Options that are ignored for compatibility with cvsps-2.1 |
|
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 | norepo=True, |
|
536 | norepo=True, | |
515 | ) |
|
537 | ) | |
516 | def debugcvsps(ui, *args, **opts): |
|
538 | def debugcvsps(ui, *args, **opts): | |
@@ -528,14 +550,14 b' def debugcvsps(ui, *args, **opts):' | |||||
528 |
|
550 | |||
529 |
|
551 | |||
530 | def kwconverted(context, mapping, name): |
|
552 | def kwconverted(context, mapping, name): | |
531 | ctx = context.resource(mapping, 'ctx') |
|
553 | ctx = context.resource(mapping, b'ctx') | |
532 | rev = ctx.extra().get('convert_revision', '') |
|
554 | rev = ctx.extra().get(b'convert_revision', b'') | |
533 | if rev.startswith('svn:'): |
|
555 | if rev.startswith(b'svn:'): | |
534 | if name == 'svnrev': |
|
556 | if name == b'svnrev': | |
535 | return b"%d" % subversion.revsplit(rev)[2] |
|
557 | return b"%d" % subversion.revsplit(rev)[2] | |
536 | elif name == 'svnpath': |
|
558 | elif name == b'svnpath': | |
537 | return subversion.revsplit(rev)[1] |
|
559 | return subversion.revsplit(rev)[1] | |
538 | elif name == 'svnuuid': |
|
560 | elif name == b'svnuuid': | |
539 | return subversion.revsplit(rev)[0] |
|
561 | return subversion.revsplit(rev)[0] | |
540 | return rev |
|
562 | return rev | |
541 |
|
563 | |||
@@ -543,22 +565,22 b' def kwconverted(context, mapping, name):' | |||||
543 | templatekeyword = registrar.templatekeyword() |
|
565 | templatekeyword = registrar.templatekeyword() | |
544 |
|
566 | |||
545 |
|
567 | |||
546 | @templatekeyword('svnrev', requires={'ctx'}) |
|
568 | @templatekeyword(b'svnrev', requires={b'ctx'}) | |
547 | def kwsvnrev(context, mapping): |
|
569 | def kwsvnrev(context, mapping): | |
548 | """String. Converted subversion revision number.""" |
|
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 | def kwsvnpath(context, mapping): |
|
575 | def kwsvnpath(context, mapping): | |
554 | """String. Converted subversion revision project path.""" |
|
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 | def kwsvnuuid(context, mapping): |
|
581 | def kwsvnuuid(context, mapping): | |
560 | """String. Converted subversion revision repository identifier.""" |
|
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 | # tell hggettext to extract docstrings from these functions: |
|
586 | # tell hggettext to extract docstrings from these functions: |
@@ -17,7 +17,7 b' from . import common' | |||||
17 |
|
17 | |||
18 | # these do not work with demandimport, blacklist |
|
18 | # these do not work with demandimport, blacklist | |
19 | demandimport.IGNORES.update( |
|
19 | demandimport.IGNORES.update( | |
20 | ['bzrlib.transactions', 'bzrlib.urlutils', 'ElementPath',] |
|
20 | [b'bzrlib.transactions', b'bzrlib.urlutils', b'ElementPath',] | |
21 | ) |
|
21 | ) | |
22 |
|
22 | |||
23 | try: |
|
23 | try: | |
@@ -35,7 +35,7 b' try:' | |||||
35 | except ImportError: |
|
35 | except ImportError: | |
36 | pass |
|
36 | pass | |
37 |
|
37 | |||
38 | supportedkinds = ('file', 'symlink') |
|
38 | supportedkinds = (b'file', b'symlink') | |
39 |
|
39 | |||
40 |
|
40 | |||
41 | class bzr_source(common.converter_source): |
|
41 | class bzr_source(common.converter_source): | |
@@ -44,16 +44,16 b' class bzr_source(common.converter_source' | |||||
44 | def __init__(self, ui, repotype, path, revs=None): |
|
44 | def __init__(self, ui, repotype, path, revs=None): | |
45 | super(bzr_source, self).__init__(ui, repotype, path, revs=revs) |
|
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 | raise common.NoRepo( |
|
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 | try: |
|
52 | try: | |
53 | # access bzrlib stuff |
|
53 | # access bzrlib stuff | |
54 | bzrdir |
|
54 | bzrdir | |
55 | except NameError: |
|
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 | path = os.path.abspath(path) |
|
58 | path = os.path.abspath(path) | |
59 | self._checkrepotype(path) |
|
59 | self._checkrepotype(path) | |
@@ -61,10 +61,10 b' class bzr_source(common.converter_source' | |||||
61 | self.sourcerepo = bzrdir.BzrDir.open(path).open_repository() |
|
61 | self.sourcerepo = bzrdir.BzrDir.open(path).open_repository() | |
62 | except errors.NoRepositoryPresent: |
|
62 | except errors.NoRepositoryPresent: | |
63 | raise common.NoRepo( |
|
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 | self._parentids = {} |
|
66 | self._parentids = {} | |
67 | self._saverev = ui.configbool('convert', 'bzr.saverev') |
|
67 | self._saverev = ui.configbool(b'convert', b'bzr.saverev') | |
68 |
|
68 | |||
69 | def _checkrepotype(self, path): |
|
69 | def _checkrepotype(self, path): | |
70 | # Lightweight checkouts detection is informational but probably |
|
70 | # Lightweight checkouts detection is informational but probably | |
@@ -84,13 +84,13 b' class bzr_source(common.converter_source' | |||||
84 | ): |
|
84 | ): | |
85 | self.ui.warn( |
|
85 | self.ui.warn( | |
86 | _( |
|
86 | _( | |
87 | 'warning: lightweight checkouts may cause ' |
|
87 | b'warning: lightweight checkouts may cause ' | |
88 | 'conversion failures, try with a regular ' |
|
88 | b'conversion failures, try with a regular ' | |
89 | 'branch instead.\n' |
|
89 | b'branch instead.\n' | |
90 | ) |
|
90 | ) | |
91 | ) |
|
91 | ) | |
92 | except Exception: |
|
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 | def before(self): |
|
95 | def before(self): | |
96 | """Before the conversion begins, acquire a read lock |
|
96 | """Before the conversion begins, acquire a read lock | |
@@ -126,16 +126,16 b' class bzr_source(common.converter_source' | |||||
126 | revid = info.rev_id |
|
126 | revid = info.rev_id | |
127 | if revid is None: |
|
127 | if revid is None: | |
128 | raise error.Abort( |
|
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 | heads = [revid] |
|
131 | heads = [revid] | |
132 | # Empty repositories return 'null:', which cannot be retrieved |
|
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 | return heads |
|
134 | return heads | |
135 |
|
135 | |||
136 | def getfile(self, name, rev): |
|
136 | def getfile(self, name, rev): | |
137 | revtree = self.sourcerepo.revision_tree(rev) |
|
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 | kind = None |
|
139 | kind = None | |
140 | if fileid is not None: |
|
140 | if fileid is not None: | |
141 | kind = revtree.kind(fileid) |
|
141 | kind = revtree.kind(fileid) | |
@@ -143,11 +143,11 b' class bzr_source(common.converter_source' | |||||
143 | # the file is not available anymore - was deleted |
|
143 | # the file is not available anymore - was deleted | |
144 | return None, None |
|
144 | return None, None | |
145 | mode = self._modecache[(name, rev)] |
|
145 | mode = self._modecache[(name, rev)] | |
146 | if kind == 'symlink': |
|
146 | if kind == b'symlink': | |
147 | target = revtree.get_symlink_target(fileid) |
|
147 | target = revtree.get_symlink_target(fileid) | |
148 | if target is None: |
|
148 | if target is None: | |
149 | raise error.Abort( |
|
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 | return target, mode |
|
152 | return target, mode | |
153 | else: |
|
153 | else: | |
@@ -156,7 +156,7 b' class bzr_source(common.converter_source' | |||||
156 |
|
156 | |||
157 | def getchanges(self, version, full): |
|
157 | def getchanges(self, version, full): | |
158 | if full: |
|
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 | self._modecache = {} |
|
160 | self._modecache = {} | |
161 | self._revtree = self.sourcerepo.revision_tree(version) |
|
161 | self._revtree = self.sourcerepo.revision_tree(version) | |
162 | # get the parentids from the cache |
|
162 | # get the parentids from the cache | |
@@ -176,12 +176,12 b' class bzr_source(common.converter_source' | |||||
176 | parents = self._filterghosts(rev.parent_ids) |
|
176 | parents = self._filterghosts(rev.parent_ids) | |
177 | self._parentids[version] = parents |
|
177 | self._parentids[version] = parents | |
178 |
|
178 | |||
179 | branch = self.recode(rev.properties.get('branch-nick', u'default')) |
|
179 | branch = self.recode(rev.properties.get(b'branch-nick', u'default')) | |
180 | if branch == 'trunk': |
|
180 | if branch == b'trunk': | |
181 | branch = 'default' |
|
181 | branch = b'default' | |
182 | return common.commit( |
|
182 | return common.commit( | |
183 | parents=parents, |
|
183 | parents=parents, | |
184 | date='%d %d' % (rev.timestamp, -rev.timezone), |
|
184 | date=b'%d %d' % (rev.timestamp, -rev.timezone), | |
185 | author=self.recode(rev.committer), |
|
185 | author=self.recode(rev.committer), | |
186 | desc=self.recode(rev.message), |
|
186 | desc=self.recode(rev.message), | |
187 | branch=branch, |
|
187 | branch=branch, | |
@@ -248,13 +248,13 b' class bzr_source(common.converter_source' | |||||
248 |
|
248 | |||
249 | # bazaar tracks directories, mercurial does not, so |
|
249 | # bazaar tracks directories, mercurial does not, so | |
250 | # we have to rename the directory contents |
|
250 | # we have to rename the directory contents | |
251 | if kind[1] == 'directory': |
|
251 | if kind[1] == b'directory': | |
252 | if kind[0] not in (None, 'directory'): |
|
252 | if kind[0] not in (None, b'directory'): | |
253 | # Replacing 'something' with a directory, record it |
|
253 | # Replacing 'something' with a directory, record it | |
254 | # so it can be removed. |
|
254 | # so it can be removed. | |
255 | changes.append((self.recode(paths[0]), revid)) |
|
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 | renaming = paths[0] != paths[1] |
|
258 | renaming = paths[0] != paths[1] | |
259 | # neither an add nor an delete - a move |
|
259 | # neither an add nor an delete - a move | |
260 | # rename all directory contents manually |
|
260 | # rename all directory contents manually | |
@@ -262,9 +262,9 b' class bzr_source(common.converter_source' | |||||
262 | # get all child-entries of the directory |
|
262 | # get all child-entries of the directory | |
263 | for name, entry in inventory.iter_entries(subdir): |
|
263 | for name, entry in inventory.iter_entries(subdir): | |
264 | # hg does not track directory renames |
|
264 | # hg does not track directory renames | |
265 | if entry.kind == 'directory': |
|
265 | if entry.kind == b'directory': | |
266 | continue |
|
266 | continue | |
267 | frompath = self.recode(paths[0] + '/' + name) |
|
267 | frompath = self.recode(paths[0] + b'/' + name) | |
268 | if frompath in seen: |
|
268 | if frompath in seen: | |
269 | # Already handled by a more specific change entry |
|
269 | # Already handled by a more specific change entry | |
270 | # This is important when you have: |
|
270 | # This is important when you have: | |
@@ -275,15 +275,15 b' class bzr_source(common.converter_source' | |||||
275 | seen.add(frompath) |
|
275 | seen.add(frompath) | |
276 | if not renaming: |
|
276 | if not renaming: | |
277 | continue |
|
277 | continue | |
278 | topath = self.recode(paths[1] + '/' + name) |
|
278 | topath = self.recode(paths[1] + b'/' + name) | |
279 | # register the files as changed |
|
279 | # register the files as changed | |
280 | changes.append((frompath, revid)) |
|
280 | changes.append((frompath, revid)) | |
281 | changes.append((topath, revid)) |
|
281 | changes.append((topath, revid)) | |
282 | # add to mode cache |
|
282 | # add to mode cache | |
283 | mode = ( |
|
283 | mode = ( | |
284 | (entry.executable and 'x') |
|
284 | (entry.executable and b'x') | |
285 | or (entry.kind == 'symlink' and 's') |
|
285 | or (entry.kind == b'symlink' and b's') | |
286 | or '' |
|
286 | or b'' | |
287 | ) |
|
287 | ) | |
288 | self._modecache[(topath, revid)] = mode |
|
288 | self._modecache[(topath, revid)] = mode | |
289 | # register the change as move |
|
289 | # register the change as move | |
@@ -312,7 +312,7 b' class bzr_source(common.converter_source' | |||||
312 |
|
312 | |||
313 | # populate the mode cache |
|
313 | # populate the mode cache | |
314 | kind, executable = [e[1] for e in (kind, executable)] |
|
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 | self._modecache[(topath, revid)] = mode |
|
316 | self._modecache[(topath, revid)] = mode | |
317 | changes.append((topath, revid)) |
|
317 | changes.append((topath, revid)) | |
318 |
|
318 |
@@ -46,7 +46,7 b' class _shlexpy3proxy(object):' | |||||
46 |
|
46 | |||
47 | @property |
|
47 | @property | |
48 | def infile(self): |
|
48 | def infile(self): | |
49 | return self._l.infile or '<unknown>' |
|
49 | return self._l.infile or b'<unknown>' | |
50 |
|
50 | |||
51 | @property |
|
51 | @property | |
52 | def lineno(self): |
|
52 | def lineno(self): | |
@@ -56,13 +56,13 b' class _shlexpy3proxy(object):' | |||||
56 | def shlexer(data=None, filepath=None, wordchars=None, whitespace=None): |
|
56 | def shlexer(data=None, filepath=None, wordchars=None, whitespace=None): | |
57 | if data is None: |
|
57 | if data is None: | |
58 | if pycompat.ispy3: |
|
58 | if pycompat.ispy3: | |
59 | data = open(filepath, 'r', encoding=r'latin1') |
|
59 | data = open(filepath, b'r', encoding=r'latin1') | |
60 | else: |
|
60 | else: | |
61 | data = open(filepath, 'r') |
|
61 | data = open(filepath, b'r') | |
62 | else: |
|
62 | else: | |
63 | if filepath is not None: |
|
63 | if filepath is not None: | |
64 | raise error.ProgrammingError( |
|
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 | if pycompat.ispy3: |
|
67 | if pycompat.ispy3: | |
68 | data = data.decode('latin1') |
|
68 | data = data.decode('latin1') | |
@@ -87,7 +87,7 b' def encodeargs(args):' | |||||
87 | def encodearg(s): |
|
87 | def encodearg(s): | |
88 | lines = base64.encodestring(s) |
|
88 | lines = base64.encodestring(s) | |
89 | lines = [l.splitlines()[0] for l in lines] |
|
89 | lines = [l.splitlines()[0] for l in lines] | |
90 | return ''.join(lines) |
|
90 | return b''.join(lines) | |
91 |
|
91 | |||
92 | s = pickle.dumps(args) |
|
92 | s = pickle.dumps(args) | |
93 | return encodearg(s) |
|
93 | return encodearg(s) | |
@@ -109,14 +109,14 b' def checktool(exe, name=None, abort=True' | |||||
109 | exc = error.Abort |
|
109 | exc = error.Abort | |
110 | else: |
|
110 | else: | |
111 | exc = MissingTool |
|
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 | class NoRepo(Exception): |
|
115 | class NoRepo(Exception): | |
116 | pass |
|
116 | pass | |
117 |
|
117 | |||
118 |
|
118 | |||
119 | SKIPREV = 'SKIP' |
|
119 | SKIPREV = b'SKIP' | |
120 |
|
120 | |||
121 |
|
121 | |||
122 | class commit(object): |
|
122 | class commit(object): | |
@@ -135,8 +135,8 b' class commit(object):' | |||||
135 | optparents=None, |
|
135 | optparents=None, | |
136 | ctx=None, |
|
136 | ctx=None, | |
137 | ): |
|
137 | ): | |
138 | self.author = author or 'unknown' |
|
138 | self.author = author or b'unknown' | |
139 | self.date = date or '0 0' |
|
139 | self.date = date or b'0 0' | |
140 | self.desc = desc |
|
140 | self.desc = desc | |
141 | self.parents = parents # will be converted and used as parents |
|
141 | self.parents = parents # will be converted and used as parents | |
142 | self.optparents = optparents or [] # will be used if already converted |
|
142 | self.optparents = optparents or [] # will be used if already converted | |
@@ -160,15 +160,15 b' class converter_source(object):' | |||||
160 | self.revs = revs |
|
160 | self.revs = revs | |
161 | self.repotype = repotype |
|
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 | """ fails if revstr is not a 40 byte hex. mercurial and git both uses |
|
166 | """ fails if revstr is not a 40 byte hex. mercurial and git both uses | |
167 | such format for their revision numbering |
|
167 | such format for their revision numbering | |
168 | """ |
|
168 | """ | |
169 | if not re.match(br'[0-9a-fA-F]{40,40}$', revstr): |
|
169 | if not re.match(br'[0-9a-fA-F]{40,40}$', revstr): | |
170 | raise error.Abort( |
|
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 | % (mapname, revstr) |
|
172 | % (mapname, revstr) | |
173 | ) |
|
173 | ) | |
174 |
|
174 | |||
@@ -236,7 +236,7 b' class converter_source(object):' | |||||
236 |
|
236 | |||
237 | def recode(self, s, encoding=None): |
|
237 | def recode(self, s, encoding=None): | |
238 | if not encoding: |
|
238 | if not encoding: | |
239 | encoding = self.encoding or 'utf-8' |
|
239 | encoding = self.encoding or b'utf-8' | |
240 |
|
240 | |||
241 | if isinstance(s, pycompat.unicode): |
|
241 | if isinstance(s, pycompat.unicode): | |
242 | return s.encode("utf-8") |
|
242 | return s.encode("utf-8") | |
@@ -292,7 +292,7 b' class converter_source(object):' | |||||
292 | """ |
|
292 | """ | |
293 | return {} |
|
293 | return {} | |
294 |
|
294 | |||
295 | def checkrevformat(self, revstr, mapname='splicemap'): |
|
295 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
296 | """revstr is a string that describes a revision in the given |
|
296 | """revstr is a string that describes a revision in the given | |
297 | source control system. Return true if revstr has correct |
|
297 | source control system. Return true if revstr has correct | |
298 | format. |
|
298 | format. | |
@@ -412,20 +412,20 b' class commandline(object):' | |||||
412 | cmdline = [self.command, cmd] + list(args) |
|
412 | cmdline = [self.command, cmd] + list(args) | |
413 | for k, v in kwargs.iteritems(): |
|
413 | for k, v in kwargs.iteritems(): | |
414 | if len(k) == 1: |
|
414 | if len(k) == 1: | |
415 | cmdline.append('-' + k) |
|
415 | cmdline.append(b'-' + k) | |
416 | else: |
|
416 | else: | |
417 | cmdline.append('--' + k.replace('_', '-')) |
|
417 | cmdline.append(b'--' + k.replace(b'_', b'-')) | |
418 | try: |
|
418 | try: | |
419 | if len(k) == 1: |
|
419 | if len(k) == 1: | |
420 | cmdline.append('' + v) |
|
420 | cmdline.append(b'' + v) | |
421 | else: |
|
421 | else: | |
422 | cmdline[-1] += '=' + v |
|
422 | cmdline[-1] += b'=' + v | |
423 | except TypeError: |
|
423 | except TypeError: | |
424 | pass |
|
424 | pass | |
425 | cmdline = [procutil.shellquote(arg) for arg in cmdline] |
|
425 | cmdline = [procutil.shellquote(arg) for arg in cmdline] | |
426 | if not self.ui.debugflag: |
|
426 | if not self.ui.debugflag: | |
427 | cmdline += ['2>', pycompat.bytestr(os.devnull)] |
|
427 | cmdline += [b'2>', pycompat.bytestr(os.devnull)] | |
428 | cmdline = ' '.join(cmdline) |
|
428 | cmdline = b' '.join(cmdline) | |
429 | return cmdline |
|
429 | return cmdline | |
430 |
|
430 | |||
431 | def _run(self, cmd, *args, **kwargs): |
|
431 | def _run(self, cmd, *args, **kwargs): | |
@@ -449,7 +449,7 b' class commandline(object):' | |||||
449 |
|
449 | |||
450 | def _dorun(self, openfunc, cmd, *args, **kwargs): |
|
450 | def _dorun(self, openfunc, cmd, *args, **kwargs): | |
451 | cmdline = self._cmdline(cmd, *args, **kwargs) |
|
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 | self.prerun() |
|
453 | self.prerun() | |
454 | try: |
|
454 | try: | |
455 | return openfunc(cmdline) |
|
455 | return openfunc(cmdline) | |
@@ -466,16 +466,16 b' class commandline(object):' | |||||
466 | p = self._run(cmd, *args, **kwargs) |
|
466 | p = self._run(cmd, *args, **kwargs) | |
467 | output = p.stdout.readlines() |
|
467 | output = p.stdout.readlines() | |
468 | p.wait() |
|
468 | p.wait() | |
469 | self.ui.debug(''.join(output)) |
|
469 | self.ui.debug(b''.join(output)) | |
470 | return output, p.returncode |
|
470 | return output, p.returncode | |
471 |
|
471 | |||
472 | def checkexit(self, status, output=''): |
|
472 | def checkexit(self, status, output=b''): | |
473 | if status: |
|
473 | if status: | |
474 | if output: |
|
474 | if output: | |
475 | self.ui.warn(_('%s error:\n') % self.command) |
|
475 | self.ui.warn(_(b'%s error:\n') % self.command) | |
476 | self.ui.warn(output) |
|
476 | self.ui.warn(output) | |
477 | msg = procutil.explainexit(status) |
|
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 | def run0(self, cmd, *args, **kwargs): |
|
480 | def run0(self, cmd, *args, **kwargs): | |
481 | output, status = self.run(cmd, *args, **kwargs) |
|
481 | output, status = self.run(cmd, *args, **kwargs) | |
@@ -484,7 +484,7 b' class commandline(object):' | |||||
484 |
|
484 | |||
485 | def runlines0(self, cmd, *args, **kwargs): |
|
485 | def runlines0(self, cmd, *args, **kwargs): | |
486 | output, status = self.runlines(cmd, *args, **kwargs) |
|
486 | output, status = self.runlines(cmd, *args, **kwargs) | |
487 | self.checkexit(status, ''.join(output)) |
|
487 | self.checkexit(status, b''.join(output)) | |
488 | return output |
|
488 | return output | |
489 |
|
489 | |||
490 | @propertycache |
|
490 | @propertycache | |
@@ -540,7 +540,7 b' class mapfile(dict):' | |||||
540 | if not self.path: |
|
540 | if not self.path: | |
541 | return |
|
541 | return | |
542 | try: |
|
542 | try: | |
543 | fp = open(self.path, 'rb') |
|
543 | fp = open(self.path, b'rb') | |
544 | except IOError as err: |
|
544 | except IOError as err: | |
545 | if err.errno != errno.ENOENT: |
|
545 | if err.errno != errno.ENOENT: | |
546 | raise |
|
546 | raise | |
@@ -551,10 +551,10 b' class mapfile(dict):' | |||||
551 | # Ignore blank lines |
|
551 | # Ignore blank lines | |
552 | continue |
|
552 | continue | |
553 | try: |
|
553 | try: | |
554 | key, value = line.rsplit(' ', 1) |
|
554 | key, value = line.rsplit(b' ', 1) | |
555 | except ValueError: |
|
555 | except ValueError: | |
556 | raise error.Abort( |
|
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 | % (self.path, i + 1) |
|
558 | % (self.path, i + 1) | |
559 | ) |
|
559 | ) | |
560 | if key not in self: |
|
560 | if key not in self: | |
@@ -565,13 +565,13 b' class mapfile(dict):' | |||||
565 | def __setitem__(self, key, value): |
|
565 | def __setitem__(self, key, value): | |
566 | if self.fp is None: |
|
566 | if self.fp is None: | |
567 | try: |
|
567 | try: | |
568 | self.fp = open(self.path, 'ab') |
|
568 | self.fp = open(self.path, b'ab') | |
569 | except IOError as err: |
|
569 | except IOError as err: | |
570 | raise error.Abort( |
|
570 | raise error.Abort( | |
571 | _('could not open map file %r: %s') |
|
571 | _(b'could not open map file %r: %s') | |
572 | % (self.path, encoding.strtolocal(err.strerror)) |
|
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 | self.fp.flush() |
|
575 | self.fp.flush() | |
576 | super(mapfile, self).__setitem__(key, value) |
|
576 | super(mapfile, self).__setitem__(key, value) | |
577 |
|
577 |
@@ -52,7 +52,7 b' p4_source = p4.p4_source' | |||||
52 | svn_sink = subversion.svn_sink |
|
52 | svn_sink = subversion.svn_sink | |
53 | svn_source = subversion.svn_source |
|
53 | svn_source = subversion.svn_source | |
54 |
|
54 | |||
55 | orig_encoding = 'ascii' |
|
55 | orig_encoding = b'ascii' | |
56 |
|
56 | |||
57 |
|
57 | |||
58 | def recode(s): |
|
58 | def recode(s): | |
@@ -90,36 +90,36 b' def mapbranch(branch, branchmap):' | |||||
90 | # destination repository. For such commits, using a literal "default" |
|
90 | # destination repository. For such commits, using a literal "default" | |
91 | # in branchmap below allows the user to map "default" to an alternate |
|
91 | # in branchmap below allows the user to map "default" to an alternate | |
92 | # default branch in the destination repository. |
|
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 | # At some point we used "None" literal to denote the default branch, |
|
94 | # At some point we used "None" literal to denote the default branch, | |
95 | # attempt to use that for backward compatibility. |
|
95 | # attempt to use that for backward compatibility. | |
96 | if not branch: |
|
96 | if not branch: | |
97 | branch = branchmap.get('None', branch) |
|
97 | branch = branchmap.get(b'None', branch) | |
98 | return branch |
|
98 | return branch | |
99 |
|
99 | |||
100 |
|
100 | |||
101 | source_converters = [ |
|
101 | source_converters = [ | |
102 | ('cvs', convert_cvs, 'branchsort'), |
|
102 | (b'cvs', convert_cvs, b'branchsort'), | |
103 | ('git', convert_git, 'branchsort'), |
|
103 | (b'git', convert_git, b'branchsort'), | |
104 | ('svn', svn_source, 'branchsort'), |
|
104 | (b'svn', svn_source, b'branchsort'), | |
105 | ('hg', mercurial_source, 'sourcesort'), |
|
105 | (b'hg', mercurial_source, b'sourcesort'), | |
106 | ('darcs', darcs_source, 'branchsort'), |
|
106 | (b'darcs', darcs_source, b'branchsort'), | |
107 | ('mtn', monotone_source, 'branchsort'), |
|
107 | (b'mtn', monotone_source, b'branchsort'), | |
108 | ('gnuarch', gnuarch_source, 'branchsort'), |
|
108 | (b'gnuarch', gnuarch_source, b'branchsort'), | |
109 | ('bzr', bzr_source, 'branchsort'), |
|
109 | (b'bzr', bzr_source, b'branchsort'), | |
110 | ('p4', p4_source, 'branchsort'), |
|
110 | (b'p4', p4_source, b'branchsort'), | |
111 | ] |
|
111 | ] | |
112 |
|
112 | |||
113 | sink_converters = [ |
|
113 | sink_converters = [ | |
114 | ('hg', mercurial_sink), |
|
114 | (b'hg', mercurial_sink), | |
115 | ('svn', svn_sink), |
|
115 | (b'svn', svn_sink), | |
116 | ] |
|
116 | ] | |
117 |
|
117 | |||
118 |
|
118 | |||
119 | def convertsource(ui, path, type, revs): |
|
119 | def convertsource(ui, path, type, revs): | |
120 | exceptions = [] |
|
120 | exceptions = [] | |
121 | if type and type not in [s[0] for s in source_converters]: |
|
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 | for name, source, sortmode in source_converters: |
|
123 | for name, source, sortmode in source_converters: | |
124 | try: |
|
124 | try: | |
125 | if not type or name == type: |
|
125 | if not type or name == type: | |
@@ -128,22 +128,22 b' def convertsource(ui, path, type, revs):' | |||||
128 | exceptions.append(inst) |
|
128 | exceptions.append(inst) | |
129 | if not ui.quiet: |
|
129 | if not ui.quiet: | |
130 | for inst in exceptions: |
|
130 | for inst in exceptions: | |
131 | ui.write("%s\n" % pycompat.bytestr(inst.args[0])) |
|
131 | ui.write(b"%s\n" % pycompat.bytestr(inst.args[0])) | |
132 | raise error.Abort(_('%s: missing or unsupported repository') % path) |
|
132 | raise error.Abort(_(b'%s: missing or unsupported repository') % path) | |
133 |
|
133 | |||
134 |
|
134 | |||
135 | def convertsink(ui, path, type): |
|
135 | def convertsink(ui, path, type): | |
136 | if type and type not in [s[0] for s in sink_converters]: |
|
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 | for name, sink in sink_converters: |
|
138 | for name, sink in sink_converters: | |
139 | try: |
|
139 | try: | |
140 | if not type or name == type: |
|
140 | if not type or name == type: | |
141 | return sink(ui, name, path) |
|
141 | return sink(ui, name, path) | |
142 | except NoRepo as inst: |
|
142 | except NoRepo as inst: | |
143 | ui.note(_("convert: %s\n") % inst) |
|
143 | ui.note(_(b"convert: %s\n") % inst) | |
144 | except MissingTool as inst: |
|
144 | except MissingTool as inst: | |
145 | raise error.Abort('%s\n' % inst) |
|
145 | raise error.Abort(b'%s\n' % inst) | |
146 | raise error.Abort(_('%s: unknown repository type') % path) |
|
146 | raise error.Abort(_(b'%s: unknown repository type') % path) | |
147 |
|
147 | |||
148 |
|
148 | |||
149 | class progresssource(object): |
|
149 | class progresssource(object): | |
@@ -151,7 +151,7 b' class progresssource(object):' | |||||
151 | self.ui = ui |
|
151 | self.ui = ui | |
152 | self.source = source |
|
152 | self.source = source | |
153 | self.progress = ui.makeprogress( |
|
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 | def getfile(self, file, rev): |
|
157 | def getfile(self, file, rev): | |
@@ -189,12 +189,12 b' class converter(object):' | |||||
189 | if authorfile and os.path.exists(authorfile): |
|
189 | if authorfile and os.path.exists(authorfile): | |
190 | self.readauthormap(authorfile) |
|
190 | self.readauthormap(authorfile) | |
191 | # Extend/Override with new author map if necessary |
|
191 | # Extend/Override with new author map if necessary | |
192 | if opts.get('authormap'): |
|
192 | if opts.get(b'authormap'): | |
193 | self.readauthormap(opts.get('authormap')) |
|
193 | self.readauthormap(opts.get(b'authormap')) | |
194 | self.authorfile = self.dest.authorfile() |
|
194 | self.authorfile = self.dest.authorfile() | |
195 |
|
195 | |||
196 | self.splicemap = self.parsesplicemap(opts.get('splicemap')) |
|
196 | self.splicemap = self.parsesplicemap(opts.get(b'splicemap')) | |
197 | self.branchmap = mapfile(ui, opts.get('branchmap')) |
|
197 | self.branchmap = mapfile(ui, opts.get(b'branchmap')) | |
198 |
|
198 | |||
199 | def parsesplicemap(self, path): |
|
199 | def parsesplicemap(self, path): | |
200 | """ check and validate the splicemap format and |
|
200 | """ check and validate the splicemap format and | |
@@ -211,21 +211,21 b' class converter(object):' | |||||
211 | return {} |
|
211 | return {} | |
212 | m = {} |
|
212 | m = {} | |
213 | try: |
|
213 | try: | |
214 | fp = open(path, 'rb') |
|
214 | fp = open(path, b'rb') | |
215 | for i, line in enumerate(util.iterfile(fp)): |
|
215 | for i, line in enumerate(util.iterfile(fp)): | |
216 | line = line.splitlines()[0].rstrip() |
|
216 | line = line.splitlines()[0].rstrip() | |
217 | if not line: |
|
217 | if not line: | |
218 | # Ignore blank lines |
|
218 | # Ignore blank lines | |
219 | continue |
|
219 | continue | |
220 | # split line |
|
220 | # split line | |
221 | lex = common.shlexer(data=line, whitespace=',') |
|
221 | lex = common.shlexer(data=line, whitespace=b',') | |
222 | line = list(lex) |
|
222 | line = list(lex) | |
223 | # check number of parents |
|
223 | # check number of parents | |
224 | if not (2 <= len(line) <= 3): |
|
224 | if not (2 <= len(line) <= 3): | |
225 | raise error.Abort( |
|
225 | raise error.Abort( | |
226 | _( |
|
226 | _( | |
227 | 'syntax error in %s(%d): child parent1' |
|
227 | b'syntax error in %s(%d): child parent1' | |
228 | '[,parent2] expected' |
|
228 | b'[,parent2] expected' | |
229 | ) |
|
229 | ) | |
230 | % (path, i + 1) |
|
230 | % (path, i + 1) | |
231 | ) |
|
231 | ) | |
@@ -239,7 +239,7 b' class converter(object):' | |||||
239 | # if file does not exist or error reading, exit |
|
239 | # if file does not exist or error reading, exit | |
240 | except IOError: |
|
240 | except IOError: | |
241 | raise error.Abort( |
|
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 | return m |
|
244 | return m | |
245 |
|
245 | |||
@@ -251,7 +251,7 b' class converter(object):' | |||||
251 | parents = {} |
|
251 | parents = {} | |
252 | numcommits = self.source.numcommits() |
|
252 | numcommits = self.source.numcommits() | |
253 | progress = self.ui.makeprogress( |
|
253 | progress = self.ui.makeprogress( | |
254 | _('scanning'), unit=_('revisions'), total=numcommits |
|
254 | _(b'scanning'), unit=_(b'revisions'), total=numcommits | |
255 | ) |
|
255 | ) | |
256 | while visit: |
|
256 | while visit: | |
257 | n = visit.pop(0) |
|
257 | n = visit.pop(0) | |
@@ -283,8 +283,8 b' class converter(object):' | |||||
283 | # Could be in source but not converted during this run |
|
283 | # Could be in source but not converted during this run | |
284 | self.ui.warn( |
|
284 | self.ui.warn( | |
285 | _( |
|
285 | _( | |
286 | 'splice map revision %s is not being ' |
|
286 | b'splice map revision %s is not being ' | |
287 | 'converted, ignoring\n' |
|
287 | b'converted, ignoring\n' | |
288 | ) |
|
288 | ) | |
289 | % c |
|
289 | % c | |
290 | ) |
|
290 | ) | |
@@ -296,7 +296,7 b' class converter(object):' | |||||
296 | continue |
|
296 | continue | |
297 | # Parent is not in dest and not being converted, not good |
|
297 | # Parent is not in dest and not being converted, not good | |
298 | if p not in parents: |
|
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 | pc.append(p) |
|
300 | pc.append(p) | |
301 | parents[c] = pc |
|
301 | parents[c] = pc | |
302 |
|
302 | |||
@@ -369,7 +369,7 b' class converter(object):' | |||||
369 | def makeclosesorter(): |
|
369 | def makeclosesorter(): | |
370 | """Close order sort.""" |
|
370 | """Close order sort.""" | |
371 | keyfn = lambda n: ( |
|
371 | keyfn = lambda n: ( | |
372 | 'close' not in self.commitcache[n].extra, |
|
372 | b'close' not in self.commitcache[n].extra, | |
373 | self.commitcache[n].sortkey, |
|
373 | self.commitcache[n].sortkey, | |
374 | ) |
|
374 | ) | |
375 |
|
375 | |||
@@ -392,16 +392,16 b' class converter(object):' | |||||
392 |
|
392 | |||
393 | return picknext |
|
393 | return picknext | |
394 |
|
394 | |||
395 | if sortmode == 'branchsort': |
|
395 | if sortmode == b'branchsort': | |
396 | picknext = makebranchsorter() |
|
396 | picknext = makebranchsorter() | |
397 | elif sortmode == 'datesort': |
|
397 | elif sortmode == b'datesort': | |
398 | picknext = makedatesorter() |
|
398 | picknext = makedatesorter() | |
399 | elif sortmode == 'sourcesort': |
|
399 | elif sortmode == b'sourcesort': | |
400 | picknext = makesourcesorter() |
|
400 | picknext = makesourcesorter() | |
401 | elif sortmode == 'closesort': |
|
401 | elif sortmode == b'closesort': | |
402 | picknext = makeclosesorter() |
|
402 | picknext = makeclosesorter() | |
403 | else: |
|
403 | else: | |
404 | raise error.Abort(_('unknown sort mode: %s') % sortmode) |
|
404 | raise error.Abort(_(b'unknown sort mode: %s') % sortmode) | |
405 |
|
405 | |||
406 | children, actives = mapchildren(parents) |
|
406 | children, actives = mapchildren(parents) | |
407 |
|
407 | |||
@@ -420,7 +420,7 b' class converter(object):' | |||||
420 | pendings[c].remove(n) |
|
420 | pendings[c].remove(n) | |
421 | except ValueError: |
|
421 | except ValueError: | |
422 | raise error.Abort( |
|
422 | raise error.Abort( | |
423 | _('cycle detected between %s and %s') |
|
423 | _(b'cycle detected between %s and %s') | |
424 | % (recode(c), recode(n)) |
|
424 | % (recode(c), recode(n)) | |
425 | ) |
|
425 | ) | |
426 | if not pendings[c]: |
|
426 | if not pendings[c]: | |
@@ -429,45 +429,47 b' class converter(object):' | |||||
429 | pendings[c] = None |
|
429 | pendings[c] = None | |
430 |
|
430 | |||
431 | if len(s) != len(parents): |
|
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 | return s |
|
434 | return s | |
435 |
|
435 | |||
436 | def writeauthormap(self): |
|
436 | def writeauthormap(self): | |
437 | authorfile = self.authorfile |
|
437 | authorfile = self.authorfile | |
438 | if authorfile: |
|
438 | if authorfile: | |
439 | self.ui.status(_('writing author map file %s\n') % authorfile) |
|
439 | self.ui.status(_(b'writing author map file %s\n') % authorfile) | |
440 | ofile = open(authorfile, 'wb+') |
|
440 | ofile = open(authorfile, b'wb+') | |
441 | for author in self.authors: |
|
441 | for author in self.authors: | |
442 | ofile.write( |
|
442 | ofile.write( | |
443 |
util.tonativeeol( |
|
443 | util.tonativeeol( | |
|
444 | b"%s=%s\n" % (author, self.authors[author]) | |||
|
445 | ) | |||
444 | ) |
|
446 | ) | |
445 | ofile.close() |
|
447 | ofile.close() | |
446 |
|
448 | |||
447 | def readauthormap(self, authorfile): |
|
449 | def readauthormap(self, authorfile): | |
448 | afile = open(authorfile, 'rb') |
|
450 | afile = open(authorfile, b'rb') | |
449 | for line in afile: |
|
451 | for line in afile: | |
450 |
|
452 | |||
451 | line = line.strip() |
|
453 | line = line.strip() | |
452 | if not line or line.startswith('#'): |
|
454 | if not line or line.startswith(b'#'): | |
453 | continue |
|
455 | continue | |
454 |
|
456 | |||
455 | try: |
|
457 | try: | |
456 | srcauthor, dstauthor = line.split('=', 1) |
|
458 | srcauthor, dstauthor = line.split(b'=', 1) | |
457 | except ValueError: |
|
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 | self.ui.warn(msg % (authorfile, line.rstrip())) |
|
461 | self.ui.warn(msg % (authorfile, line.rstrip())) | |
460 | continue |
|
462 | continue | |
461 |
|
463 | |||
462 | srcauthor = srcauthor.strip() |
|
464 | srcauthor = srcauthor.strip() | |
463 | dstauthor = dstauthor.strip() |
|
465 | dstauthor = dstauthor.strip() | |
464 | if self.authors.get(srcauthor) in (None, dstauthor): |
|
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 | self.ui.debug(msg % (srcauthor, dstauthor)) |
|
468 | self.ui.debug(msg % (srcauthor, dstauthor)) | |
467 | self.authors[srcauthor] = dstauthor |
|
469 | self.authors[srcauthor] = dstauthor | |
468 | continue |
|
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 | self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor)) |
|
473 | self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor)) | |
472 |
|
474 | |||
473 | afile.close() |
|
475 | afile.close() | |
@@ -481,7 +483,7 b' class converter(object):' | |||||
481 |
|
483 | |||
482 | def copy(self, rev): |
|
484 | def copy(self, rev): | |
483 | commit = self.commitcache[rev] |
|
485 | commit = self.commitcache[rev] | |
484 | full = self.opts.get('full') |
|
486 | full = self.opts.get(b'full') | |
485 | changes = self.source.getchanges(rev, full) |
|
487 | changes = self.source.getchanges(rev, full) | |
486 | if isinstance(changes, bytes): |
|
488 | if isinstance(changes, bytes): | |
487 | if changes == SKIPREV: |
|
489 | if changes == SKIPREV: | |
@@ -503,8 +505,8 b' class converter(object):' | |||||
503 | try: |
|
505 | try: | |
504 | parents = self.splicemap[rev] |
|
506 | parents = self.splicemap[rev] | |
505 | self.ui.status( |
|
507 | self.ui.status( | |
506 | _('spliced in %s as parents of %s\n') |
|
508 | _(b'spliced in %s as parents of %s\n') | |
507 | % (_(' and ').join(parents), rev) |
|
509 | % (_(b' and ').join(parents), rev) | |
508 | ) |
|
510 | ) | |
509 | parents = [self.map.get(p, p) for p in parents] |
|
511 | parents = [self.map.get(p, p) for p in parents] | |
510 | except KeyError: |
|
512 | except KeyError: | |
@@ -536,34 +538,34 b' class converter(object):' | |||||
536 | self.source.before() |
|
538 | self.source.before() | |
537 | self.dest.before() |
|
539 | self.dest.before() | |
538 | self.source.setrevmap(self.map) |
|
540 | self.source.setrevmap(self.map) | |
539 | self.ui.status(_("scanning source...\n")) |
|
541 | self.ui.status(_(b"scanning source...\n")) | |
540 | heads = self.source.getheads() |
|
542 | heads = self.source.getheads() | |
541 | parents = self.walktree(heads) |
|
543 | parents = self.walktree(heads) | |
542 | self.mergesplicemap(parents, self.splicemap) |
|
544 | self.mergesplicemap(parents, self.splicemap) | |
543 | self.ui.status(_("sorting...\n")) |
|
545 | self.ui.status(_(b"sorting...\n")) | |
544 | t = self.toposort(parents, sortmode) |
|
546 | t = self.toposort(parents, sortmode) | |
545 | num = len(t) |
|
547 | num = len(t) | |
546 | c = None |
|
548 | c = None | |
547 |
|
549 | |||
548 | self.ui.status(_("converting...\n")) |
|
550 | self.ui.status(_(b"converting...\n")) | |
549 | progress = self.ui.makeprogress( |
|
551 | progress = self.ui.makeprogress( | |
550 | _('converting'), unit=_('revisions'), total=len(t) |
|
552 | _(b'converting'), unit=_(b'revisions'), total=len(t) | |
551 | ) |
|
553 | ) | |
552 | for i, c in enumerate(t): |
|
554 | for i, c in enumerate(t): | |
553 | num -= 1 |
|
555 | num -= 1 | |
554 | desc = self.commitcache[c].desc |
|
556 | desc = self.commitcache[c].desc | |
555 | if "\n" in desc: |
|
557 | if b"\n" in desc: | |
556 | desc = desc.splitlines()[0] |
|
558 | desc = desc.splitlines()[0] | |
557 | # convert log message to local encoding without using |
|
559 | # convert log message to local encoding without using | |
558 | # tolocal() because the encoding.encoding convert() |
|
560 | # tolocal() because the encoding.encoding convert() | |
559 | # uses is 'utf-8' |
|
561 | # uses is 'utf-8' | |
560 | self.ui.status("%d %s\n" % (num, recode(desc))) |
|
562 | self.ui.status(b"%d %s\n" % (num, recode(desc))) | |
561 | self.ui.note(_("source: %s\n") % recode(c)) |
|
563 | self.ui.note(_(b"source: %s\n") % recode(c)) | |
562 | progress.update(i) |
|
564 | progress.update(i) | |
563 | self.copy(c) |
|
565 | self.copy(c) | |
564 | progress.complete() |
|
566 | progress.complete() | |
565 |
|
567 | |||
566 | if not self.ui.configbool('convert', 'skiptags'): |
|
568 | if not self.ui.configbool(b'convert', b'skiptags'): | |
567 | tags = self.source.gettags() |
|
569 | tags = self.source.gettags() | |
568 | ctags = {} |
|
570 | ctags = {} | |
569 | for k in tags: |
|
571 | for k in tags: | |
@@ -610,45 +612,47 b' def convert(ui, src, dest=None, revmapfi' | |||||
610 | opts = pycompat.byteskwargs(opts) |
|
612 | opts = pycompat.byteskwargs(opts) | |
611 | global orig_encoding |
|
613 | global orig_encoding | |
612 | orig_encoding = encoding.encoding |
|
614 | orig_encoding = encoding.encoding | |
613 | encoding.encoding = 'UTF-8' |
|
615 | encoding.encoding = b'UTF-8' | |
614 |
|
616 | |||
615 | # support --authors as an alias for --authormap |
|
617 | # support --authors as an alias for --authormap | |
616 | if not opts.get('authormap'): |
|
618 | if not opts.get(b'authormap'): | |
617 | opts['authormap'] = opts.get('authors') |
|
619 | opts[b'authormap'] = opts.get(b'authors') | |
618 |
|
620 | |||
619 | if not dest: |
|
621 | if not dest: | |
620 | dest = hg.defaultdest(src) + "-hg" |
|
622 | dest = hg.defaultdest(src) + b"-hg" | |
621 | ui.status(_("assuming destination %s\n") % dest) |
|
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 | destc = scmutil.wrapconvertsink(destc) |
|
626 | destc = scmutil.wrapconvertsink(destc) | |
625 |
|
627 | |||
626 | try: |
|
628 | try: | |
627 | srcc, defaultsort = convertsource( |
|
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 | except Exception: |
|
632 | except Exception: | |
631 | for path in destc.created: |
|
633 | for path in destc.created: | |
632 | shutil.rmtree(path, True) |
|
634 | shutil.rmtree(path, True) | |
633 | raise |
|
635 | raise | |
634 |
|
636 | |||
635 | sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort') |
|
637 | sortmodes = (b'branchsort', b'datesort', b'sourcesort', b'closesort') | |
636 | sortmode = [m for m in sortmodes if opts.get(m)] |
|
638 | sortmode = [m for m in sortmodes if opts.get(m)] | |
637 | if len(sortmode) > 1: |
|
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 | if sortmode: |
|
641 | if sortmode: | |
640 | sortmode = sortmode[0] |
|
642 | sortmode = sortmode[0] | |
641 | else: |
|
643 | else: | |
642 | sortmode = defaultsort |
|
644 | sortmode = defaultsort | |
643 |
|
645 | |||
644 | if sortmode == 'sourcesort' and not srcc.hasnativeorder(): |
|
646 | if sortmode == b'sourcesort' and not srcc.hasnativeorder(): | |
645 | raise error.Abort( |
|
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(): |
|
650 | if sortmode == b'closesort' and not srcc.hasnativeclose(): | |
649 | raise error.Abort(_('--closesort is not supported by this data source')) |
|
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 | if fmap: |
|
656 | if fmap: | |
653 | srcc = filemap.filemap_source(ui, srcc, fmap) |
|
657 | srcc = filemap.filemap_source(ui, srcc, fmap) | |
654 | destc.setfilemapmode(True) |
|
658 | destc.setfilemapmode(True) |
@@ -39,19 +39,19 b' class convert_cvs(converter_source):' | |||||
39 | def __init__(self, ui, repotype, path, revs=None): |
|
39 | def __init__(self, ui, repotype, path, revs=None): | |
40 | super(convert_cvs, self).__init__(ui, repotype, path, revs=revs) |
|
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 | if not os.path.exists(cvs): |
|
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 | self.changeset = None |
|
48 | self.changeset = None | |
49 | self.files = {} |
|
49 | self.files = {} | |
50 | self.tags = {} |
|
50 | self.tags = {} | |
51 | self.lastbranch = {} |
|
51 | self.lastbranch = {} | |
52 | self.socket = None |
|
52 | self.socket = None | |
53 | self.cvsroot = open(os.path.join(cvs, "Root"), '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, "Repository"), 'rb').read()[:-1] |
|
54 | self.cvsrepo = open(os.path.join(cvs, b"Repository"), b'rb').read()[:-1] | |
55 | self.encoding = encoding.encoding |
|
55 | self.encoding = encoding.encoding | |
56 |
|
56 | |||
57 | self._connect() |
|
57 | self._connect() | |
@@ -65,7 +65,10 b' class convert_cvs(converter_source):' | |||||
65 | if self.revs: |
|
65 | if self.revs: | |
66 | if len(self.revs) > 1: |
|
66 | if len(self.revs) > 1: | |
67 | raise error.Abort( |
|
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 | # TODO: handle tags |
|
73 | # TODO: handle tags | |
71 | try: |
|
74 | try: | |
@@ -73,23 +76,23 b' class convert_cvs(converter_source):' | |||||
73 | maxrev = int(self.revs[0]) |
|
76 | maxrev = int(self.revs[0]) | |
74 | except ValueError: |
|
77 | except ValueError: | |
75 | raise error.Abort( |
|
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 | d = encoding.getcwd() |
|
82 | d = encoding.getcwd() | |
80 | try: |
|
83 | try: | |
81 | os.chdir(self.path) |
|
84 | os.chdir(self.path) | |
82 |
|
85 | |||
83 | cache = 'update' |
|
86 | cache = b'update' | |
84 | if not self.ui.configbool('convert', 'cvsps.cache'): |
|
87 | if not self.ui.configbool(b'convert', b'cvsps.cache'): | |
85 | cache = None |
|
88 | cache = None | |
86 | db = cvsps.createlog(self.ui, cache=cache) |
|
89 | db = cvsps.createlog(self.ui, cache=cache) | |
87 | db = cvsps.createchangeset( |
|
90 | db = cvsps.createchangeset( | |
88 | self.ui, |
|
91 | self.ui, | |
89 | db, |
|
92 | db, | |
90 | fuzz=int(self.ui.config('convert', 'cvsps.fuzz')), |
|
93 | fuzz=int(self.ui.config(b'convert', b'cvsps.fuzz')), | |
91 | mergeto=self.ui.config('convert', 'cvsps.mergeto'), |
|
94 | mergeto=self.ui.config(b'convert', b'cvsps.mergeto'), | |
92 | mergefrom=self.ui.config('convert', 'cvsps.mergefrom'), |
|
95 | mergefrom=self.ui.config(b'convert', b'cvsps.mergefrom'), | |
93 | ) |
|
96 | ) | |
94 |
|
97 | |||
95 | for cs in db: |
|
98 | for cs in db: | |
@@ -99,16 +102,16 b' class convert_cvs(converter_source):' | |||||
99 | cs.author = self.recode(cs.author) |
|
102 | cs.author = self.recode(cs.author) | |
100 | self.lastbranch[cs.branch] = id |
|
103 | self.lastbranch[cs.branch] = id | |
101 | cs.comment = self.recode(cs.comment) |
|
104 | cs.comment = self.recode(cs.comment) | |
102 | if self.ui.configbool('convert', 'localtimezone'): |
|
105 | if self.ui.configbool(b'convert', b'localtimezone'): | |
103 | cs.date = makedatetimestamp(cs.date[0]) |
|
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 | self.tags.update(dict.fromkeys(cs.tags, id)) |
|
108 | self.tags.update(dict.fromkeys(cs.tags, id)) | |
106 |
|
109 | |||
107 | files = {} |
|
110 | files = {} | |
108 | for f in cs.entries: |
|
111 | for f in cs.entries: | |
109 | files[f.file] = "%s%s" % ( |
|
112 | files[f.file] = b"%s%s" % ( | |
110 | '.'.join([(b"%d" % x) for x in f.revision]), |
|
113 | b'.'.join([(b"%d" % x) for x in f.revision]), | |
111 | ['', '(DEAD)'][f.dead], |
|
114 | [b'', b'(DEAD)'][f.dead], | |
112 | ) |
|
115 | ) | |
113 |
|
116 | |||
114 | # add current commit to set |
|
117 | # add current commit to set | |
@@ -117,7 +120,7 b' class convert_cvs(converter_source):' | |||||
117 | date=date, |
|
120 | date=date, | |
118 | parents=[(b"%d" % p.id) for p in cs.parents], |
|
121 | parents=[(b"%d" % p.id) for p in cs.parents], | |
119 | desc=cs.comment, |
|
122 | desc=cs.comment, | |
120 | branch=cs.branch or '', |
|
123 | branch=cs.branch or b'', | |
121 | ) |
|
124 | ) | |
122 | self.changeset[id] = c |
|
125 | self.changeset[id] = c | |
123 | self.files[id] = files |
|
126 | self.files[id] = files | |
@@ -130,38 +133,38 b' class convert_cvs(converter_source):' | |||||
130 | root = self.cvsroot |
|
133 | root = self.cvsroot | |
131 | conntype = None |
|
134 | conntype = None | |
132 | user, host = None, None |
|
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 | root = root[9:] |
|
141 | root = root[9:] | |
139 | m = re.match( |
|
142 | m = re.match( | |
140 | r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)', root |
|
143 | r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)', root | |
141 | ) |
|
144 | ) | |
142 | if m: |
|
145 | if m: | |
143 | conntype = "pserver" |
|
146 | conntype = b"pserver" | |
144 | user, passw, serv, port, root = m.groups() |
|
147 | user, passw, serv, port, root = m.groups() | |
145 | if not user: |
|
148 | if not user: | |
146 | user = "anonymous" |
|
149 | user = b"anonymous" | |
147 | if not port: |
|
150 | if not port: | |
148 | port = 2401 |
|
151 | port = 2401 | |
149 | else: |
|
152 | else: | |
150 | port = int(port) |
|
153 | port = int(port) | |
151 | format0 = ":pserver:%s@%s:%s" % (user, serv, root) |
|
154 | format0 = b":pserver:%s@%s:%s" % (user, serv, root) | |
152 | format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root) |
|
155 | format1 = b":pserver:%s@%s:%d%s" % (user, serv, port, root) | |
153 |
|
156 | |||
154 | if not passw: |
|
157 | if not passw: | |
155 | passw = "A" |
|
158 | passw = b"A" | |
156 | cvspass = os.path.expanduser("~/.cvspass") |
|
159 | cvspass = os.path.expanduser(b"~/.cvspass") | |
157 | try: |
|
160 | try: | |
158 | pf = open(cvspass, 'rb') |
|
161 | pf = open(cvspass, b'rb') | |
159 | for line in pf.read().splitlines(): |
|
162 | for line in pf.read().splitlines(): | |
160 | part1, part2 = line.split(' ', 1) |
|
163 | part1, part2 = line.split(b' ', 1) | |
161 | # /1 :pserver:user@example.com:2401/cvsroot/foo |
|
164 | # /1 :pserver:user@example.com:2401/cvsroot/foo | |
162 | # Ah<Z |
|
165 | # Ah<Z | |
163 | if part1 == '/1': |
|
166 | if part1 == b'/1': | |
164 | part1, part2 = part2.split(' ', 1) |
|
167 | part1, part2 = part2.split(b' ', 1) | |
165 | format = format1 |
|
168 | format = format1 | |
166 | # :pserver:user@example.com:/cvsroot/foo Ah<Z |
|
169 | # :pserver:user@example.com:/cvsroot/foo Ah<Z | |
167 | else: |
|
170 | else: | |
@@ -179,72 +182,72 b' class convert_cvs(converter_source):' | |||||
179 | sck = socket.socket() |
|
182 | sck = socket.socket() | |
180 | sck.connect((serv, port)) |
|
183 | sck.connect((serv, port)) | |
181 | sck.send( |
|
184 | sck.send( | |
182 | "\n".join( |
|
185 | b"\n".join( | |
183 | [ |
|
186 | [ | |
184 | "BEGIN AUTH REQUEST", |
|
187 | b"BEGIN AUTH REQUEST", | |
185 | root, |
|
188 | root, | |
186 | user, |
|
189 | user, | |
187 | passw, |
|
190 | passw, | |
188 | "END AUTH REQUEST", |
|
191 | b"END AUTH REQUEST", | |
189 | "", |
|
192 | b"", | |
190 | ] |
|
193 | ] | |
191 | ) |
|
194 | ) | |
192 | ) |
|
195 | ) | |
193 | if sck.recv(128) != "I LOVE YOU\n": |
|
196 | if sck.recv(128) != b"I LOVE YOU\n": | |
194 | raise error.Abort(_("CVS pserver authentication failed")) |
|
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:"): |
|
201 | if not conntype and root.startswith(b":local:"): | |
199 | conntype = "local" |
|
202 | conntype = b"local" | |
200 | root = root[7:] |
|
203 | root = root[7:] | |
201 |
|
204 | |||
202 | if not conntype: |
|
205 | if not conntype: | |
203 | # :ext:user@host/home/user/path/to/cvsroot |
|
206 | # :ext:user@host/home/user/path/to/cvsroot | |
204 | if root.startswith(":ext:"): |
|
207 | if root.startswith(b":ext:"): | |
205 | root = root[5:] |
|
208 | root = root[5:] | |
206 | m = re.match(br'(?:([^@:/]+)@)?([^:/]+):?(.*)', root) |
|
209 | m = re.match(br'(?:([^@:/]+)@)?([^:/]+):?(.*)', root) | |
207 | # Do not take Windows path "c:\foo\bar" for a connection strings |
|
210 | # Do not take Windows path "c:\foo\bar" for a connection strings | |
208 | if os.path.isdir(root) or not m: |
|
211 | if os.path.isdir(root) or not m: | |
209 | conntype = "local" |
|
212 | conntype = b"local" | |
210 | else: |
|
213 | else: | |
211 | conntype = "rsh" |
|
214 | conntype = b"rsh" | |
212 | user, host, root = m.group(1), m.group(2), m.group(3) |
|
215 | user, host, root = m.group(1), m.group(2), m.group(3) | |
213 |
|
216 | |||
214 | if conntype != "pserver": |
|
217 | if conntype != b"pserver": | |
215 | if conntype == "rsh": |
|
218 | if conntype == b"rsh": | |
216 | rsh = encoding.environ.get("CVS_RSH") or "ssh" |
|
219 | rsh = encoding.environ.get(b"CVS_RSH") or b"ssh" | |
217 | if user: |
|
220 | if user: | |
218 | cmd = [rsh, '-l', user, host] + cmd |
|
221 | cmd = [rsh, b'-l', user, host] + cmd | |
219 | else: |
|
222 | else: | |
220 | cmd = [rsh, host] + cmd |
|
223 | cmd = [rsh, host] + cmd | |
221 |
|
224 | |||
222 | # popen2 does not support argument lists under Windows |
|
225 | # popen2 does not support argument lists under Windows | |
223 | cmd = [procutil.shellquote(arg) for arg in cmd] |
|
226 | cmd = [procutil.shellquote(arg) for arg in cmd] | |
224 | cmd = procutil.quotecommand(' '.join(cmd)) |
|
227 | cmd = procutil.quotecommand(b' '.join(cmd)) | |
225 | self.writep, self.readp = procutil.popen2(cmd) |
|
228 | self.writep, self.readp = procutil.popen2(cmd) | |
226 |
|
229 | |||
227 | self.realroot = root |
|
230 | self.realroot = root | |
228 |
|
231 | |||
229 | self.writep.write("Root %s\n" % root) |
|
232 | self.writep.write(b"Root %s\n" % root) | |
230 | self.writep.write( |
|
233 | self.writep.write( | |
231 | "Valid-responses ok error Valid-requests Mode" |
|
234 | b"Valid-responses ok error Valid-requests Mode" | |
232 | " M Mbinary E Checked-in Created Updated" |
|
235 | b" M Mbinary E Checked-in Created Updated" | |
233 | " Merged Removed\n" |
|
236 | b" Merged Removed\n" | |
234 | ) |
|
237 | ) | |
235 | self.writep.write("valid-requests\n") |
|
238 | self.writep.write(b"valid-requests\n") | |
236 | self.writep.flush() |
|
239 | self.writep.flush() | |
237 | r = self.readp.readline() |
|
240 | r = self.readp.readline() | |
238 | if not r.startswith("Valid-requests"): |
|
241 | if not r.startswith(b"Valid-requests"): | |
239 | raise error.Abort( |
|
242 | raise error.Abort( | |
240 | _( |
|
243 | _( | |
241 | 'unexpected response from CVS server ' |
|
244 | b'unexpected response from CVS server ' | |
242 | '(expected "Valid-requests", but got %r)' |
|
245 | b'(expected "Valid-requests", but got %r)' | |
243 | ) |
|
246 | ) | |
244 | % r |
|
247 | % r | |
245 | ) |
|
248 | ) | |
246 | if "UseUnchanged" in r: |
|
249 | if b"UseUnchanged" in r: | |
247 | self.writep.write("UseUnchanged\n") |
|
250 | self.writep.write(b"UseUnchanged\n") | |
248 | self.writep.flush() |
|
251 | self.writep.flush() | |
249 | self.readp.readline() |
|
252 | self.readp.readline() | |
250 |
|
253 | |||
@@ -262,55 +265,55 b' class convert_cvs(converter_source):' | |||||
262 | data = fp.read(min(count, chunksize)) |
|
265 | data = fp.read(min(count, chunksize)) | |
263 | if not data: |
|
266 | if not data: | |
264 | raise error.Abort( |
|
267 | raise error.Abort( | |
265 | _("%d bytes missing from remote file") % count |
|
268 | _(b"%d bytes missing from remote file") % count | |
266 | ) |
|
269 | ) | |
267 | count -= len(data) |
|
270 | count -= len(data) | |
268 | output.write(data) |
|
271 | output.write(data) | |
269 | return output.getvalue() |
|
272 | return output.getvalue() | |
270 |
|
273 | |||
271 | self._parse() |
|
274 | self._parse() | |
272 | if rev.endswith("(DEAD)"): |
|
275 | if rev.endswith(b"(DEAD)"): | |
273 | return None, None |
|
276 | return None, None | |
274 |
|
277 | |||
275 | args = ("-N -P -kk -r %s --" % rev).split() |
|
278 | args = (b"-N -P -kk -r %s --" % rev).split() | |
276 | args.append(self.cvsrepo + '/' + name) |
|
279 | args.append(self.cvsrepo + b'/' + name) | |
277 | for x in args: |
|
280 | for x in args: | |
278 | self.writep.write("Argument %s\n" % x) |
|
281 | self.writep.write(b"Argument %s\n" % x) | |
279 | self.writep.write("Directory .\n%s\nco\n" % self.realroot) |
|
282 | self.writep.write(b"Directory .\n%s\nco\n" % self.realroot) | |
280 | self.writep.flush() |
|
283 | self.writep.flush() | |
281 |
|
284 | |||
282 | data = "" |
|
285 | data = b"" | |
283 | mode = None |
|
286 | mode = None | |
284 | while True: |
|
287 | while True: | |
285 | line = self.readp.readline() |
|
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 | self.readp.readline() # path |
|
290 | self.readp.readline() # path | |
288 | self.readp.readline() # entries |
|
291 | self.readp.readline() # entries | |
289 | mode = self.readp.readline()[:-1] |
|
292 | mode = self.readp.readline()[:-1] | |
290 | count = int(self.readp.readline()[:-1]) |
|
293 | count = int(self.readp.readline()[:-1]) | |
291 | data = chunkedread(self.readp, count) |
|
294 | data = chunkedread(self.readp, count) | |
292 | elif line.startswith(" "): |
|
295 | elif line.startswith(b" "): | |
293 | data += line[1:] |
|
296 | data += line[1:] | |
294 | elif line.startswith("M "): |
|
297 | elif line.startswith(b"M "): | |
295 | pass |
|
298 | pass | |
296 | elif line.startswith("Mbinary "): |
|
299 | elif line.startswith(b"Mbinary "): | |
297 | count = int(self.readp.readline()[:-1]) |
|
300 | count = int(self.readp.readline()[:-1]) | |
298 | data = chunkedread(self.readp, count) |
|
301 | data = chunkedread(self.readp, count) | |
299 | else: |
|
302 | else: | |
300 | if line == "ok\n": |
|
303 | if line == b"ok\n": | |
301 | if mode is None: |
|
304 | if mode is None: | |
302 | raise error.Abort(_('malformed response from CVS')) |
|
305 | raise error.Abort(_(b'malformed response from CVS')) | |
303 | return (data, "x" in mode and "x" or "") |
|
306 | return (data, b"x" in mode and b"x" or b"") | |
304 | elif line.startswith("E "): |
|
307 | elif line.startswith(b"E "): | |
305 | self.ui.warn(_("cvs server: %s\n") % line[2:]) |
|
308 | self.ui.warn(_(b"cvs server: %s\n") % line[2:]) | |
306 | elif line.startswith("Remove"): |
|
309 | elif line.startswith(b"Remove"): | |
307 | self.readp.readline() |
|
310 | self.readp.readline() | |
308 | else: |
|
311 | else: | |
309 | raise error.Abort(_("unknown CVS response: %s") % line) |
|
312 | raise error.Abort(_(b"unknown CVS response: %s") % line) | |
310 |
|
313 | |||
311 | def getchanges(self, rev, full): |
|
314 | def getchanges(self, rev, full): | |
312 | if full: |
|
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 | self._parse() |
|
317 | self._parse() | |
315 | return sorted(self.files[rev].iteritems()), {}, set() |
|
318 | return sorted(self.files[rev].iteritems()), {}, set() | |
316 |
|
319 |
@@ -92,18 +92,18 b' def getrepopath(cvspath):' | |||||
92 | # of the '/' char after the '@' is located. The solution is the rest of the |
|
92 | # of the '/' char after the '@' is located. The solution is the rest of the | |
93 | # string after that '/' sign including it |
|
93 | # string after that '/' sign including it | |
94 |
|
94 | |||
95 | parts = cvspath.split(':') |
|
95 | parts = cvspath.split(b':') | |
96 | atposition = parts[-1].find('@') |
|
96 | atposition = parts[-1].find(b'@') | |
97 | start = 0 |
|
97 | start = 0 | |
98 |
|
98 | |||
99 | if atposition != -1: |
|
99 | if atposition != -1: | |
100 | start = atposition |
|
100 | start = atposition | |
101 |
|
101 | |||
102 | repopath = parts[-1][parts[-1].find('/', start) :] |
|
102 | repopath = parts[-1][parts[-1].find(b'/', start) :] | |
103 | return repopath |
|
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 | '''Collect the CVS rlog''' |
|
107 | '''Collect the CVS rlog''' | |
108 |
|
108 | |||
109 | # Because we store many duplicate commit log messages, reusing strings |
|
109 | # Because we store many duplicate commit log messages, reusing strings | |
@@ -111,10 +111,10 b' def createlog(ui, directory=None, root="' | |||||
111 | _scache = {} |
|
111 | _scache = {} | |
112 |
|
112 | |||
113 | def scache(s): |
|
113 | def scache(s): | |
114 | "return a shared version of a string" |
|
114 | b"return a shared version of a string" | |
115 | return _scache.setdefault(s, s) |
|
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 | log = [] # list of logentry objects containing the CVS state |
|
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 | file_added_re = re.compile(br'file [^/]+ was (initially )?added on branch') |
|
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 | if directory is None: |
|
149 | if directory is None: | |
150 | # Current working directory |
|
150 | # Current working directory | |
151 |
|
151 | |||
152 | # Get the real directory in the repository |
|
152 | # Get the real directory in the repository | |
153 | try: |
|
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 | prefix = f.read().strip() |
|
155 | prefix = f.read().strip() | |
156 | directory = prefix |
|
156 | directory = prefix | |
157 | if prefix == ".": |
|
157 | if prefix == b".": | |
158 | prefix = "" |
|
158 | prefix = b"" | |
159 | except IOError: |
|
159 | except IOError: | |
160 | raise logerror(_('not a CVS sandbox')) |
|
160 | raise logerror(_(b'not a CVS sandbox')) | |
161 |
|
161 | |||
162 | if prefix and not prefix.endswith(pycompat.ossep): |
|
162 | if prefix and not prefix.endswith(pycompat.ossep): | |
163 | prefix += pycompat.ossep |
|
163 | prefix += pycompat.ossep | |
164 |
|
164 | |||
165 | # Use the Root file in the sandbox, if it exists |
|
165 | # Use the Root file in the sandbox, if it exists | |
166 | try: |
|
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 | except IOError: |
|
168 | except IOError: | |
169 | pass |
|
169 | pass | |
170 |
|
170 | |||
171 | if not root: |
|
171 | if not root: | |
172 | root = encoding.environ.get('CVSROOT', '') |
|
172 | root = encoding.environ.get(b'CVSROOT', b'') | |
173 |
|
173 | |||
174 | # read log cache if one exists |
|
174 | # read log cache if one exists | |
175 | oldlog = [] |
|
175 | oldlog = [] | |
176 | date = None |
|
176 | date = None | |
177 |
|
177 | |||
178 | if cache: |
|
178 | if cache: | |
179 | cachedir = os.path.expanduser('~/.hg.cvsps') |
|
179 | cachedir = os.path.expanduser(b'~/.hg.cvsps') | |
180 | if not os.path.exists(cachedir): |
|
180 | if not os.path.exists(cachedir): | |
181 | os.mkdir(cachedir) |
|
181 | os.mkdir(cachedir) | |
182 |
|
182 | |||
@@ -189,50 +189,50 b' def createlog(ui, directory=None, root="' | |||||
189 | # and |
|
189 | # and | |
190 | # /pserver/user/server/path |
|
190 | # /pserver/user/server/path | |
191 | # are mapped to different cache file names. |
|
191 | # are mapped to different cache file names. | |
192 | cachefile = root.split(":") + [directory, "cache"] |
|
192 | cachefile = root.split(b":") + [directory, b"cache"] | |
193 | cachefile = ['-'.join(re.findall(br'\w+', s)) for s in cachefile if s] |
|
193 | cachefile = [b'-'.join(re.findall(br'\w+', s)) for s in cachefile if s] | |
194 | cachefile = os.path.join( |
|
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 | try: |
|
199 | try: | |
200 | ui.note(_('reading cvs log cache %s\n') % cachefile) |
|
200 | ui.note(_(b'reading cvs log cache %s\n') % cachefile) | |
201 | oldlog = pickle.load(open(cachefile, 'rb')) |
|
201 | oldlog = pickle.load(open(cachefile, b'rb')) | |
202 | for e in oldlog: |
|
202 | for e in oldlog: | |
203 | if not ( |
|
203 | if not ( | |
204 | util.safehasattr(e, 'branchpoints') |
|
204 | util.safehasattr(e, b'branchpoints') | |
205 | and util.safehasattr(e, 'commitid') |
|
205 | and util.safehasattr(e, b'commitid') | |
206 | and util.safehasattr(e, 'mergepoint') |
|
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 | oldlog = [] |
|
209 | oldlog = [] | |
210 | break |
|
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 | except Exception as e: |
|
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 | if oldlog: |
|
216 | if oldlog: | |
217 | date = oldlog[-1].date # last commit date as a (time,tz) tuple |
|
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 | # build the CVS commandline |
|
220 | # build the CVS commandline | |
221 | cmd = ['cvs', '-q'] |
|
221 | cmd = [b'cvs', b'-q'] | |
222 | if root: |
|
222 | if root: | |
223 | cmd.append('-d%s' % root) |
|
223 | cmd.append(b'-d%s' % root) | |
224 | p = util.normpath(getrepopath(root)) |
|
224 | p = util.normpath(getrepopath(root)) | |
225 | if not p.endswith('/'): |
|
225 | if not p.endswith(b'/'): | |
226 | p += '/' |
|
226 | p += b'/' | |
227 | if prefix: |
|
227 | if prefix: | |
228 | # looks like normpath replaces "" by "." |
|
228 | # looks like normpath replaces "" by "." | |
229 | prefix = p + util.normpath(prefix) |
|
229 | prefix = p + util.normpath(prefix) | |
230 | else: |
|
230 | else: | |
231 | prefix = p |
|
231 | prefix = p | |
232 | cmd.append(['log', 'rlog'][rlog]) |
|
232 | cmd.append([b'log', b'rlog'][rlog]) | |
233 | if date: |
|
233 | if date: | |
234 | # no space between option and date string |
|
234 | # no space between option and date string | |
235 | cmd.append('-d>%s' % date) |
|
235 | cmd.append(b'-d>%s' % date) | |
236 | cmd.append(directory) |
|
236 | cmd.append(directory) | |
237 |
|
237 | |||
238 | # state machine begins here |
|
238 | # state machine begins here | |
@@ -243,17 +243,17 b' def createlog(ui, directory=None, root="' | |||||
243 | store = False # set when a new record can be appended |
|
243 | store = False # set when a new record can be appended | |
244 |
|
244 | |||
245 | cmd = [procutil.shellquote(arg) for arg in cmd] |
|
245 | cmd = [procutil.shellquote(arg) for arg in cmd] | |
246 | ui.note(_("running %s\n") % (' '.join(cmd))) |
|
246 | ui.note(_(b"running %s\n") % (b' '.join(cmd))) | |
247 | ui.debug("prefix=%r directory=%r root=%r\n" % (prefix, directory, root)) |
|
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 | peek = util.fromnativeeol(pfp.readline()) |
|
250 | peek = util.fromnativeeol(pfp.readline()) | |
251 | while True: |
|
251 | while True: | |
252 | line = peek |
|
252 | line = peek | |
253 | if line == '': |
|
253 | if line == b'': | |
254 | break |
|
254 | break | |
255 | peek = util.fromnativeeol(pfp.readline()) |
|
255 | peek = util.fromnativeeol(pfp.readline()) | |
256 | if line.endswith('\n'): |
|
256 | if line.endswith(b'\n'): | |
257 | line = line[:-1] |
|
257 | line = line[:-1] | |
258 | # ui.debug('state=%d line=%r\n' % (state, line)) |
|
258 | # ui.debug('state=%d line=%r\n' % (state, line)) | |
259 |
|
259 | |||
@@ -267,12 +267,12 b' def createlog(ui, directory=None, root="' | |||||
267 | filename = util.normpath(rcs[:-2]) |
|
267 | filename = util.normpath(rcs[:-2]) | |
268 | if filename.startswith(prefix): |
|
268 | if filename.startswith(prefix): | |
269 | filename = filename[len(prefix) :] |
|
269 | filename = filename[len(prefix) :] | |
270 | if filename.startswith('/'): |
|
270 | if filename.startswith(b'/'): | |
271 | filename = filename[1:] |
|
271 | filename = filename[1:] | |
272 | if filename.startswith('Attic/'): |
|
272 | if filename.startswith(b'Attic/'): | |
273 | filename = filename[6:] |
|
273 | filename = filename[6:] | |
274 | else: |
|
274 | else: | |
275 | filename = filename.replace('/Attic/', '/') |
|
275 | filename = filename.replace(b'/Attic/', b'/') | |
276 | state = 2 |
|
276 | state = 2 | |
277 | continue |
|
277 | continue | |
278 | state = 1 |
|
278 | state = 1 | |
@@ -289,7 +289,7 b' def createlog(ui, directory=None, root="' | |||||
289 | elif state == 1: |
|
289 | elif state == 1: | |
290 | # expect 'Working file' (only when using log instead of rlog) |
|
290 | # expect 'Working file' (only when using log instead of rlog) | |
291 | match = re_10.match(line) |
|
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 | filename = util.normpath(match.group(1)) |
|
293 | filename = util.normpath(match.group(1)) | |
294 | state = 2 |
|
294 | state = 2 | |
295 |
|
295 | |||
@@ -303,7 +303,7 b' def createlog(ui, directory=None, root="' | |||||
303 | # read the symbolic names and store as tags |
|
303 | # read the symbolic names and store as tags | |
304 | match = re_30.match(line) |
|
304 | match = re_30.match(line) | |
305 | if match: |
|
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 | # Convert magic branch number to an odd-numbered one |
|
308 | # Convert magic branch number to an odd-numbered one | |
309 | revn = len(rev) |
|
309 | revn = len(rev) | |
@@ -327,7 +327,7 b' def createlog(ui, directory=None, root="' | |||||
327 | state = 5 |
|
327 | state = 5 | |
328 | else: |
|
328 | else: | |
329 | assert not re_32.match(line), _( |
|
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 | elif state == 5: |
|
333 | elif state == 5: | |
@@ -335,11 +335,11 b' def createlog(ui, directory=None, root="' | |||||
335 | # we create the logentry here from values stored in states 0 to 4, |
|
335 | # we create the logentry here from values stored in states 0 to 4, | |
336 | # as this state is re-entered for subsequent revisions of a file. |
|
336 | # as this state is re-entered for subsequent revisions of a file. | |
337 | match = re_50.match(line) |
|
337 | match = re_50.match(line) | |
338 | assert match, _('expected revision number') |
|
338 | assert match, _(b'expected revision number') | |
339 | e = logentry( |
|
339 | e = logentry( | |
340 | rcs=scache(rcs), |
|
340 | rcs=scache(rcs), | |
341 | file=scache(filename), |
|
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 | branches=[], |
|
343 | branches=[], | |
344 | parent=None, |
|
344 | parent=None, | |
345 | commitid=None, |
|
345 | commitid=None, | |
@@ -352,21 +352,25 b' def createlog(ui, directory=None, root="' | |||||
352 | elif state == 6: |
|
352 | elif state == 6: | |
353 | # expecting date, author, state, lines changed |
|
353 | # expecting date, author, state, lines changed | |
354 | match = re_60.match(line) |
|
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 | d = match.group(1) |
|
356 | d = match.group(1) | |
357 | if d[2] == '/': |
|
357 | if d[2] == b'/': | |
358 | # Y2K |
|
358 | # Y2K | |
359 | d = '19' + d |
|
359 | d = b'19' + d | |
360 |
|
360 | |||
361 | if len(d.split()) != 3: |
|
361 | if len(d.split()) != 3: | |
362 | # cvs log dates always in GMT |
|
362 | # cvs log dates always in GMT | |
363 | d = d + ' UTC' |
|
363 | d = d + b' UTC' | |
364 | e.date = dateutil.parsedate( |
|
364 | e.date = dateutil.parsedate( | |
365 | d, |
|
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 | e.author = scache(match.group(2)) |
|
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 | if match.group(5): |
|
375 | if match.group(5): | |
372 | if match.group(6): |
|
376 | if match.group(6): | |
@@ -382,14 +386,14 b' def createlog(ui, directory=None, root="' | |||||
382 | e.commitid = match.group(8) |
|
386 | e.commitid = match.group(8) | |
383 |
|
387 | |||
384 | if match.group(9): # cvsnt mergepoint |
|
388 | if match.group(9): # cvsnt mergepoint | |
385 | myrev = match.group(10).split('.') |
|
389 | myrev = match.group(10).split(b'.') | |
386 | if len(myrev) == 2: # head |
|
390 | if len(myrev) == 2: # head | |
387 | e.mergepoint = 'HEAD' |
|
391 | e.mergepoint = b'HEAD' | |
388 | else: |
|
392 | else: | |
389 | myrev = '.'.join(myrev[:-2] + ['0', myrev[-2]]) |
|
393 | myrev = b'.'.join(myrev[:-2] + [b'0', myrev[-2]]) | |
390 | branches = [b for b in branchmap if branchmap[b] == myrev] |
|
394 | branches = [b for b in branchmap if branchmap[b] == myrev] | |
391 | assert len(branches) == 1, ( |
|
395 | assert len(branches) == 1, ( | |
392 | 'unknown branch: %s' % e.mergepoint |
|
396 | b'unknown branch: %s' % e.mergepoint | |
393 | ) |
|
397 | ) | |
394 | e.mergepoint = branches[0] |
|
398 | e.mergepoint = branches[0] | |
395 |
|
399 | |||
@@ -402,8 +406,8 b' def createlog(ui, directory=None, root="' | |||||
402 | m = re_70.match(line) |
|
406 | m = re_70.match(line) | |
403 | if m: |
|
407 | if m: | |
404 | e.branches = [ |
|
408 | e.branches = [ | |
405 | tuple([int(y) for y in x.strip().split('.')]) |
|
409 | tuple([int(y) for y in x.strip().split(b'.')]) | |
406 | for x in m.group(1).split(';') |
|
410 | for x in m.group(1).split(b';') | |
407 | ] |
|
411 | ] | |
408 | state = 8 |
|
412 | state = 8 | |
409 | elif re_31.match(line) and re_50.match(peek): |
|
413 | elif re_31.match(line) and re_50.match(peek): | |
@@ -419,7 +423,7 b' def createlog(ui, directory=None, root="' | |||||
419 | # store commit log message |
|
423 | # store commit log message | |
420 | if re_31.match(line): |
|
424 | if re_31.match(line): | |
421 | cpeek = peek |
|
425 | cpeek = peek | |
422 | if cpeek.endswith('\n'): |
|
426 | if cpeek.endswith(b'\n'): | |
423 | cpeek = cpeek[:-1] |
|
427 | cpeek = cpeek[:-1] | |
424 | if re_50.match(cpeek): |
|
428 | if re_50.match(cpeek): | |
425 | state = 5 |
|
429 | state = 5 | |
@@ -447,7 +451,7 b' def createlog(ui, directory=None, root="' | |||||
447 | and file_added_re.match(e.comment[0]) |
|
451 | and file_added_re.match(e.comment[0]) | |
448 | ): |
|
452 | ): | |
449 | ui.debug( |
|
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 | e.synthetic = True |
|
456 | e.synthetic = True | |
453 |
|
457 | |||
@@ -455,7 +459,7 b' def createlog(ui, directory=None, root="' | |||||
455 | # clean up the results and save in the log. |
|
459 | # clean up the results and save in the log. | |
456 | store = False |
|
460 | store = False | |
457 | e.tags = sorted([scache(x) for x in tags.get(e.revision, [])]) |
|
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 | revn = len(e.revision) |
|
464 | revn = len(e.revision) | |
461 | if revn > 3 and (revn % 2) == 0: |
|
465 | if revn > 3 and (revn % 2) == 0: | |
@@ -466,7 +470,7 b' def createlog(ui, directory=None, root="' | |||||
466 | # find the branches starting from this revision |
|
470 | # find the branches starting from this revision | |
467 | branchpoints = set() |
|
471 | branchpoints = set() | |
468 | for branch, revision in branchmap.iteritems(): |
|
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 | if len(revparts) < 2: # bad tags |
|
474 | if len(revparts) < 2: # bad tags | |
471 | continue |
|
475 | continue | |
472 | if revparts[-2] == 0 and revparts[-1] % 2 == 0: |
|
476 | if revparts[-2] == 0 and revparts[-1] % 2 == 0: | |
@@ -480,11 +484,12 b' def createlog(ui, directory=None, root="' | |||||
480 |
|
484 | |||
481 | log.append(e) |
|
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 | if len(log) % 100 == 0: |
|
489 | if len(log) % 100 == 0: | |
486 | ui.status( |
|
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 | log.sort(key=lambda x: (x.rcs, x.revision)) |
|
495 | log.sort(key=lambda x: (x.rcs, x.revision)) | |
@@ -492,7 +497,7 b' def createlog(ui, directory=None, root="' | |||||
492 | # find parent revisions of individual files |
|
497 | # find parent revisions of individual files | |
493 | versions = {} |
|
498 | versions = {} | |
494 | for e in sorted(oldlog, key=lambda x: (x.rcs, x.revision)): |
|
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 | if rcs in rcsmap: |
|
501 | if rcs in rcsmap: | |
497 | e.rcs = rcsmap[rcs] |
|
502 | e.rcs = rcsmap[rcs] | |
498 | branch = e.revision[:-1] |
|
503 | branch = e.revision[:-1] | |
@@ -515,28 +520,28 b' def createlog(ui, directory=None, root="' | |||||
515 | if oldlog and oldlog[-1].date >= log[0].date: |
|
520 | if oldlog and oldlog[-1].date >= log[0].date: | |
516 | raise logerror( |
|
521 | raise logerror( | |
517 | _( |
|
522 | _( | |
518 | 'log cache overlaps with new log entries,' |
|
523 | b'log cache overlaps with new log entries,' | |
519 | ' re-run without cache.' |
|
524 | b' re-run without cache.' | |
520 | ) |
|
525 | ) | |
521 | ) |
|
526 | ) | |
522 |
|
527 | |||
523 | log = oldlog + log |
|
528 | log = oldlog + log | |
524 |
|
529 | |||
525 | # write the new cachefile |
|
530 | # write the new cachefile | |
526 | ui.note(_('writing cvs log cache %s\n') % cachefile) |
|
531 | ui.note(_(b'writing cvs log cache %s\n') % cachefile) | |
527 | pickle.dump(log, open(cachefile, 'wb')) |
|
532 | pickle.dump(log, open(cachefile, b'wb')) | |
528 | else: |
|
533 | else: | |
529 | log = oldlog |
|
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 | if encodings: |
|
539 | if encodings: | |
535 |
|
540 | |||
536 | def revstr(r): |
|
541 | def revstr(r): | |
537 | # this is needed, because logentry.revision is a tuple of "int" |
|
542 | # this is needed, because logentry.revision is a tuple of "int" | |
538 | # (e.g. (1, 2) for "1.2") |
|
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 | for entry in log: |
|
546 | for entry in log: | |
542 | comment = entry.comment |
|
547 | comment = entry.comment | |
@@ -547,7 +552,7 b' def createlog(ui, directory=None, root="' | |||||
547 | ) |
|
552 | ) | |
548 | if ui.debugflag: |
|
553 | if ui.debugflag: | |
549 | ui.debug( |
|
554 | ui.debug( | |
550 | "transcoding by %s: %s of %s\n" |
|
555 | b"transcoding by %s: %s of %s\n" | |
551 | % (e, revstr(entry.revision), entry.file) |
|
556 | % (e, revstr(entry.revision), entry.file) | |
552 | ) |
|
557 | ) | |
553 | break |
|
558 | break | |
@@ -557,20 +562,22 b' def createlog(ui, directory=None, root="' | |||||
557 | raise error.Abort( |
|
562 | raise error.Abort( | |
558 | inst, |
|
563 | inst, | |
559 | hint=_( |
|
564 | hint=_( | |
560 | 'check convert.cvsps.logencoding' ' configuration' |
|
565 | b'check convert.cvsps.logencoding' b' configuration' | |
561 | ), |
|
566 | ), | |
562 | ) |
|
567 | ) | |
563 | else: |
|
568 | else: | |
564 | raise error.Abort( |
|
569 | raise error.Abort( | |
565 | _( |
|
570 | _( | |
566 | "no encoding can transcode" |
|
571 | b"no encoding can transcode" | |
567 | " CVS log message for %s of %s" |
|
572 | b" CVS log message for %s of %s" | |
568 | ) |
|
573 | ) | |
569 | % (revstr(entry.revision), entry.file), |
|
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 | return log |
|
582 | return log | |
576 |
|
583 | |||
@@ -597,14 +604,16 b' class changeset(object):' | |||||
597 | self.__dict__.update(entries) |
|
604 | self.__dict__.update(entries) | |
598 |
|
605 | |||
599 | def __repr__(self): |
|
606 | def __repr__(self): | |
600 | items = ("%s=%r" % (k, self.__dict__[k]) for k in sorted(self.__dict__)) |
|
607 | items = ( | |
601 | return "%s(%s)" % (type(self).__name__, ", ".join(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 | def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None): |
|
613 | def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None): | |
605 | '''Convert log into changesets.''' |
|
614 | '''Convert log into changesets.''' | |
606 |
|
615 | |||
607 | ui.status(_('creating changesets\n')) |
|
616 | ui.status(_(b'creating changesets\n')) | |
608 |
|
617 | |||
609 | # try to order commitids by date |
|
618 | # try to order commitids by date | |
610 | mindate = {} |
|
619 | mindate = {} | |
@@ -619,10 +628,10 b' def createchangeset(ui, log, fuzz=60, me' | |||||
619 | log.sort( |
|
628 | log.sort( | |
620 | key=lambda x: ( |
|
629 | key=lambda x: ( | |
621 | mindate.get(x.commitid, (-1, 0)), |
|
630 | mindate.get(x.commitid, (-1, 0)), | |
622 | x.commitid or '', |
|
631 | x.commitid or b'', | |
623 | x.comment, |
|
632 | x.comment, | |
624 | x.author, |
|
633 | x.author, | |
625 | x.branch or '', |
|
634 | x.branch or b'', | |
626 | x.date, |
|
635 | x.date, | |
627 | x.branchpoints, |
|
636 | x.branchpoints, | |
628 | ) |
|
637 | ) | |
@@ -682,8 +691,8 b' def createchangeset(ui, log, fuzz=60, me' | |||||
682 |
|
691 | |||
683 | files = set() |
|
692 | files = set() | |
684 | if len(changesets) % 100 == 0: |
|
693 | if len(changesets) % 100 == 0: | |
685 | t = '%d %s' % (len(changesets), repr(e.comment)[1:-1]) |
|
694 | t = b'%d %s' % (len(changesets), repr(e.comment)[1:-1]) | |
686 | ui.status(stringutil.ellipsis(t, 80) + '\n') |
|
695 | ui.status(stringutil.ellipsis(t, 80) + b'\n') | |
687 |
|
696 | |||
688 | c.entries.append(e) |
|
697 | c.entries.append(e) | |
689 | files.add(e.file) |
|
698 | files.add(e.file) | |
@@ -705,9 +714,9 b' def createchangeset(ui, log, fuzz=60, me' | |||||
705 | # Sort files in each changeset |
|
714 | # Sort files in each changeset | |
706 |
|
715 | |||
707 | def entitycompare(l, r): |
|
716 | def entitycompare(l, r): | |
708 | 'Mimic cvsps sorting order' |
|
717 | b'Mimic cvsps sorting order' | |
709 | l = l.file.split('/') |
|
718 | l = l.file.split(b'/') | |
710 | r = r.file.split('/') |
|
719 | r = r.file.split(b'/') | |
711 | nl = len(l) |
|
720 | nl = len(l) | |
712 | nr = len(r) |
|
721 | nr = len(r) | |
713 | n = min(nl, nr) |
|
722 | n = min(nl, nr) | |
@@ -842,7 +851,7 b' def createchangeset(ui, log, fuzz=60, me' | |||||
842 | # Ensure no changeset has a synthetic changeset as a parent. |
|
851 | # Ensure no changeset has a synthetic changeset as a parent. | |
843 | while p.synthetic: |
|
852 | while p.synthetic: | |
844 | assert len(p.parents) <= 1, _( |
|
853 | assert len(p.parents) <= 1, _( | |
845 | 'synthetic changeset cannot have multiple parents' |
|
854 | b'synthetic changeset cannot have multiple parents' | |
846 | ) |
|
855 | ) | |
847 | if p.parents: |
|
856 | if p.parents: | |
848 | p = p.parents[0] |
|
857 | p = p.parents[0] | |
@@ -854,7 +863,7 b' def createchangeset(ui, log, fuzz=60, me' | |||||
854 | c.parents.append(p) |
|
863 | c.parents.append(p) | |
855 |
|
864 | |||
856 | if c.mergepoint: |
|
865 | if c.mergepoint: | |
857 | if c.mergepoint == 'HEAD': |
|
866 | if c.mergepoint == b'HEAD': | |
858 | c.mergepoint = None |
|
867 | c.mergepoint = None | |
859 | c.parents.append(changesets[branches[c.mergepoint]]) |
|
868 | c.parents.append(changesets[branches[c.mergepoint]]) | |
860 |
|
869 | |||
@@ -862,15 +871,15 b' def createchangeset(ui, log, fuzz=60, me' | |||||
862 | m = mergefrom.search(c.comment) |
|
871 | m = mergefrom.search(c.comment) | |
863 | if m: |
|
872 | if m: | |
864 | m = m.group(1) |
|
873 | m = m.group(1) | |
865 | if m == 'HEAD': |
|
874 | if m == b'HEAD': | |
866 | m = None |
|
875 | m = None | |
867 | try: |
|
876 | try: | |
868 | candidate = changesets[branches[m]] |
|
877 | candidate = changesets[branches[m]] | |
869 | except KeyError: |
|
878 | except KeyError: | |
870 | ui.warn( |
|
879 | ui.warn( | |
871 | _( |
|
880 | _( | |
872 | "warning: CVS commit message references " |
|
881 | b"warning: CVS commit message references " | |
873 | "non-existent branch %r:\n%s\n" |
|
882 | b"non-existent branch %r:\n%s\n" | |
874 | ) |
|
883 | ) | |
875 | % (pycompat.bytestr(m), c.comment) |
|
884 | % (pycompat.bytestr(m), c.comment) | |
876 | ) |
|
885 | ) | |
@@ -882,7 +891,7 b' def createchangeset(ui, log, fuzz=60, me' | |||||
882 | if m: |
|
891 | if m: | |
883 | if m.groups(): |
|
892 | if m.groups(): | |
884 | m = m.group(1) |
|
893 | m = m.group(1) | |
885 | if m == 'HEAD': |
|
894 | if m == b'HEAD': | |
886 | m = None |
|
895 | m = None | |
887 | else: |
|
896 | else: | |
888 | m = None # if no group found then merge to HEAD |
|
897 | m = None # if no group found then merge to HEAD | |
@@ -892,7 +901,7 b' def createchangeset(ui, log, fuzz=60, me' | |||||
892 | author=c.author, |
|
901 | author=c.author, | |
893 | branch=m, |
|
902 | branch=m, | |
894 | date=c.date, |
|
903 | date=c.date, | |
895 | comment='convert-repo: CVS merge from branch %s' |
|
904 | comment=b'convert-repo: CVS merge from branch %s' | |
896 | % c.branch, |
|
905 | % c.branch, | |
897 | entries=[], |
|
906 | entries=[], | |
898 | tags=[], |
|
907 | tags=[], | |
@@ -927,13 +936,13 b' def createchangeset(ui, log, fuzz=60, me' | |||||
927 | for l, r in odd: |
|
936 | for l, r in odd: | |
928 | if l.id is not None and r.id is not None: |
|
937 | if l.id is not None and r.id is not None: | |
929 | ui.warn( |
|
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 | % (l.id, r.id) |
|
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 | return changesets |
|
947 | return changesets | |
939 |
|
948 | |||
@@ -944,27 +953,27 b' def debugcvsps(ui, *args, **opts):' | |||||
944 | commit log entries and dates. |
|
953 | commit log entries and dates. | |
945 | ''' |
|
954 | ''' | |
946 | opts = pycompat.byteskwargs(opts) |
|
955 | opts = pycompat.byteskwargs(opts) | |
947 | if opts["new_cache"]: |
|
956 | if opts[b"new_cache"]: | |
948 | cache = "write" |
|
957 | cache = b"write" | |
949 | elif opts["update_cache"]: |
|
958 | elif opts[b"update_cache"]: | |
950 | cache = "update" |
|
959 | cache = b"update" | |
951 | else: |
|
960 | else: | |
952 | cache = None |
|
961 | cache = None | |
953 |
|
962 | |||
954 | revisions = opts["revisions"] |
|
963 | revisions = opts[b"revisions"] | |
955 |
|
964 | |||
956 | try: |
|
965 | try: | |
957 | if args: |
|
966 | if args: | |
958 | log = [] |
|
967 | log = [] | |
959 | for d in args: |
|
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 | else: |
|
970 | else: | |
962 | log = createlog(ui, root=opts["root"], cache=cache) |
|
971 | log = createlog(ui, root=opts[b"root"], cache=cache) | |
963 | except logerror as e: |
|
972 | except logerror as e: | |
964 | ui.write("%r\n" % e) |
|
973 | ui.write(b"%r\n" % e) | |
965 | return |
|
974 | return | |
966 |
|
975 | |||
967 | changesets = createchangeset(ui, log, opts["fuzz"]) |
|
976 | changesets = createchangeset(ui, log, opts[b"fuzz"]) | |
968 | del log |
|
977 | del log | |
969 |
|
978 | |||
970 | # Print changesets (optionally filtered) |
|
979 | # Print changesets (optionally filtered) | |
@@ -974,7 +983,7 b' def debugcvsps(ui, *args, **opts):' | |||||
974 | ancestors = {} # parent branch |
|
983 | ancestors = {} # parent branch | |
975 | for cs in changesets: |
|
984 | for cs in changesets: | |
976 |
|
985 | |||
977 | if opts["ancestors"]: |
|
986 | if opts[b"ancestors"]: | |
978 | if cs.branch not in branches and cs.parents and cs.parents[0].id: |
|
987 | if cs.branch not in branches and cs.parents and cs.parents[0].id: | |
979 | ancestors[cs.branch] = ( |
|
988 | ancestors[cs.branch] = ( | |
980 | changesets[cs.parents[0].id - 1].branch, |
|
989 | changesets[cs.parents[0].id - 1].branch, | |
@@ -983,72 +992,75 b' def debugcvsps(ui, *args, **opts):' | |||||
983 | branches[cs.branch] = cs.id |
|
992 | branches[cs.branch] = cs.id | |
984 |
|
993 | |||
985 | # limit by branches |
|
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 | continue |
|
999 | continue | |
988 |
|
1000 | |||
989 | if not off: |
|
1001 | if not off: | |
990 | # Note: trailing spaces on several lines here are needed to have |
|
1002 | # Note: trailing spaces on several lines here are needed to have | |
991 | # bug-for-bug compatibility with cvsps. |
|
1003 | # bug-for-bug compatibility with cvsps. | |
992 | ui.write('---------------------\n') |
|
1004 | ui.write(b'---------------------\n') | |
993 | ui.write(('PatchSet %d \n' % cs.id)) |
|
1005 | ui.write((b'PatchSet %d \n' % cs.id)) | |
994 | ui.write( |
|
1006 | ui.write( | |
995 | ( |
|
1007 | ( | |
996 | 'Date: %s\n' |
|
1008 | b'Date: %s\n' | |
997 | % dateutil.datestr(cs.date, '%Y/%m/%d %H:%M:%S %1%2') |
|
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)) |
|
1012 | ui.write((b'Author: %s\n' % cs.author)) | |
1001 | ui.write(('Branch: %s\n' % (cs.branch or 'HEAD'))) |
|
1013 | ui.write((b'Branch: %s\n' % (cs.branch or b'HEAD'))) | |
1002 | ui.write( |
|
1014 | ui.write( | |
1003 | ( |
|
1015 | ( | |
1004 | 'Tag%s: %s \n' |
|
1016 | b'Tag%s: %s \n' | |
1005 | % ( |
|
1017 | % ( | |
1006 | ['', 's'][len(cs.tags) > 1], |
|
1018 | [b'', b's'][len(cs.tags) > 1], | |
1007 | ','.join(cs.tags) or '(none)', |
|
1019 | b','.join(cs.tags) or b'(none)', | |
1008 | ) |
|
1020 | ) | |
1009 | ) |
|
1021 | ) | |
1010 | ) |
|
1022 | ) | |
1011 | if cs.branchpoints: |
|
1023 | if cs.branchpoints: | |
1012 | ui.write( |
|
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 | if len(cs.parents) > 1: |
|
1028 | if len(cs.parents) > 1: | |
1017 | ui.write( |
|
1029 | ui.write( | |
1018 | ( |
|
1030 | ( | |
1019 | 'Parents: %s\n' |
|
1031 | b'Parents: %s\n' | |
1020 | % (','.join([(b"%d" % p.id) for p in cs.parents])) |
|
1032 | % (b','.join([(b"%d" % p.id) for p in cs.parents])) | |
1021 | ) |
|
1033 | ) | |
1022 | ) |
|
1034 | ) | |
1023 | else: |
|
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 | b = cs.branch |
|
1039 | b = cs.branch | |
1028 | r = [] |
|
1040 | r = [] | |
1029 | while b: |
|
1041 | while b: | |
1030 | b, c = ancestors[b] |
|
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 | if r: |
|
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') |
|
1047 | ui.write(b'Log:\n') | |
1036 | ui.write('%s\n\n' % cs.comment) |
|
1048 | ui.write(b'%s\n\n' % cs.comment) | |
1037 | ui.write('Members: \n') |
|
1049 | ui.write(b'Members: \n') | |
1038 | for f in cs.entries: |
|
1050 | for f in cs.entries: | |
1039 | fn = f.file |
|
1051 | fn = f.file | |
1040 | if fn.startswith(opts["prefix"]): |
|
1052 | if fn.startswith(opts[b"prefix"]): | |
1041 | fn = fn[len(opts["prefix"]) :] |
|
1053 | fn = fn[len(opts[b"prefix"]) :] | |
1042 | ui.write( |
|
1054 | ui.write( | |
1043 | '\t%s:%s->%s%s \n' |
|
1055 | b'\t%s:%s->%s%s \n' | |
1044 | % ( |
|
1056 | % ( | |
1045 | fn, |
|
1057 | fn, | |
1046 | '.'.join([b"%d" % x for x in f.parent]) or 'INITIAL', |
|
1058 | b'.'.join([b"%d" % x for x in f.parent]) or b'INITIAL', | |
1047 | '.'.join([(b"%d" % x) for x in f.revision]), |
|
1059 | b'.'.join([(b"%d" % x) for x in f.revision]), | |
1048 | ['', '(DEAD)'][f.dead], |
|
1060 | [b'', b'(DEAD)'][f.dead], | |
1049 | ) |
|
1061 | ) | |
1050 | ) |
|
1062 | ) | |
1051 | ui.write('\n') |
|
1063 | ui.write(b'\n') | |
1052 |
|
1064 | |||
1053 | # have we seen the start tag? |
|
1065 | # have we seen the start tag? | |
1054 | if revisions and off: |
|
1066 | if revisions and off: |
@@ -46,22 +46,22 b' except ImportError:' | |||||
46 | class darcs_source(common.converter_source, common.commandline): |
|
46 | class darcs_source(common.converter_source, common.commandline): | |
47 | def __init__(self, ui, repotype, path, revs=None): |
|
47 | def __init__(self, ui, repotype, path, revs=None): | |
48 | common.converter_source.__init__(self, ui, repotype, path, revs=revs) |
|
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 | # check for _darcs, ElementTree so that we can easily skip |
|
51 | # check for _darcs, ElementTree so that we can easily skip | |
52 | # test-convert-darcs if ElementTree is not around |
|
52 | # test-convert-darcs if ElementTree is not around | |
53 | if not os.path.exists(os.path.join(path, '_darcs')): |
|
53 | if not os.path.exists(os.path.join(path, b'_darcs')): | |
54 | raise NoRepo(_("%s does not look like a darcs repository") % path) |
|
54 | raise NoRepo(_(b"%s does not look like a darcs repository") % path) | |
55 |
|
55 | |||
56 | common.checktool('darcs') |
|
56 | common.checktool(b'darcs') | |
57 | version = self.run0('--version').splitlines()[0].strip() |
|
57 | version = self.run0(b'--version').splitlines()[0].strip() | |
58 | if version < '2.1': |
|
58 | if version < b'2.1': | |
59 | raise error.Abort( |
|
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(): |
|
63 | if b"ElementTree" not in globals(): | |
64 | raise error.Abort(_("Python ElementTree module is not available")) |
|
64 | raise error.Abort(_(b"Python ElementTree module is not available")) | |
65 |
|
65 | |||
66 | self.path = os.path.realpath(path) |
|
66 | self.path = os.path.realpath(path) | |
67 |
|
67 | |||
@@ -73,30 +73,33 b' class darcs_source(common.converter_sour' | |||||
73 | # Check darcs repository format |
|
73 | # Check darcs repository format | |
74 | format = self.format() |
|
74 | format = self.format() | |
75 | if format: |
|
75 | if format: | |
76 | if format in ('darcs-1.0', 'hashed'): |
|
76 | if format in (b'darcs-1.0', b'hashed'): | |
77 | raise NoRepo( |
|
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 | % format |
|
82 | % format | |
80 | ) |
|
83 | ) | |
81 | else: |
|
84 | else: | |
82 | self.ui.warn(_('failed to detect repository format!')) |
|
85 | self.ui.warn(_(b'failed to detect repository format!')) | |
83 |
|
86 | |||
84 | def before(self): |
|
87 | def before(self): | |
85 | self.tmppath = pycompat.mkdtemp( |
|
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 | self.checkexit(status) |
|
92 | self.checkexit(status) | |
90 |
|
93 | |||
91 | tree = self.xml( |
|
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 | tagname = None |
|
97 | tagname = None | |
95 | child = None |
|
98 | child = None | |
96 | for elt in tree.findall('patch'): |
|
99 | for elt in tree.findall(b'patch'): | |
97 | node = elt.get('hash') |
|
100 | node = elt.get(b'hash') | |
98 | name = elt.findtext('name', '') |
|
101 | name = elt.findtext(b'name', b'') | |
99 | if name.startswith('TAG '): |
|
102 | if name.startswith(b'TAG '): | |
100 | tagname = name[4:].strip() |
|
103 | tagname = name[4:].strip() | |
101 | elif tagname is not None: |
|
104 | elif tagname is not None: | |
102 | self.tags[tagname] = node |
|
105 | self.tags[tagname] = node | |
@@ -107,7 +110,7 b' class darcs_source(common.converter_sour' | |||||
107 | self.parents[child] = [] |
|
110 | self.parents[child] = [] | |
108 |
|
111 | |||
109 | def after(self): |
|
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 | shutil.rmtree(self.tmppath, ignore_errors=True) |
|
114 | shutil.rmtree(self.tmppath, ignore_errors=True) | |
112 |
|
115 | |||
113 | def recode(self, s, encoding=None): |
|
116 | def recode(self, s, encoding=None): | |
@@ -125,7 +128,7 b' class darcs_source(common.converter_sour' | |||||
125 | # While we are decoding the XML as latin-1 to be as liberal as |
|
128 | # While we are decoding the XML as latin-1 to be as liberal as | |
126 | # possible, etree will still raise an exception if any |
|
129 | # possible, etree will still raise an exception if any | |
127 | # non-printable characters are in the XML changelog. |
|
130 | # non-printable characters are in the XML changelog. | |
128 | parser = XMLParser(encoding='latin-1') |
|
131 | parser = XMLParser(encoding=b'latin-1') | |
129 | p = self._run(cmd, **kwargs) |
|
132 | p = self._run(cmd, **kwargs) | |
130 | etree.parse(p.stdout, parser=parser) |
|
133 | etree.parse(p.stdout, parser=parser) | |
131 | p.wait() |
|
134 | p.wait() | |
@@ -133,20 +136,20 b' class darcs_source(common.converter_sour' | |||||
133 | return etree.getroot() |
|
136 | return etree.getroot() | |
134 |
|
137 | |||
135 | def format(self): |
|
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 | self.checkexit(status) |
|
140 | self.checkexit(status) | |
138 | m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE) |
|
141 | m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE) | |
139 | if not m: |
|
142 | if not m: | |
140 | return None |
|
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 | def manifest(self): |
|
146 | def manifest(self): | |
144 | man = [] |
|
147 | man = [] | |
145 | output, status = self.run( |
|
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 | self.checkexit(status) |
|
151 | self.checkexit(status) | |
149 | for line in output.split('\n'): |
|
152 | for line in output.split(b'\n'): | |
150 | path = line[2:] |
|
153 | path = line[2:] | |
151 | if path: |
|
154 | if path: | |
152 | man.append(path) |
|
155 | man.append(path) | |
@@ -157,14 +160,14 b' class darcs_source(common.converter_sour' | |||||
157 |
|
160 | |||
158 | def getcommit(self, rev): |
|
161 | def getcommit(self, rev): | |
159 | elt = self.changes[rev] |
|
162 | elt = self.changes[rev] | |
160 | dateformat = '%a %b %d %H:%M:%S %Z %Y' |
|
163 | dateformat = b'%a %b %d %H:%M:%S %Z %Y' | |
161 | date = dateutil.strdate(elt.get('local_date'), dateformat) |
|
164 | date = dateutil.strdate(elt.get(b'local_date'), dateformat) | |
162 | desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') |
|
165 | desc = elt.findtext(b'name') + b'\n' + elt.findtext(b'comment', b'') | |
163 | # etree can return unicode objects for name, comment, and author, |
|
166 | # etree can return unicode objects for name, comment, and author, | |
164 | # so recode() is used to ensure str objects are emitted. |
|
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 | return common.commit( |
|
169 | return common.commit( | |
167 | author=self.recode(elt.get('author')), |
|
170 | author=self.recode(elt.get(b'author')), | |
168 | date=dateutil.datestr(date, newdateformat), |
|
171 | date=dateutil.datestr(date, newdateformat), | |
169 | desc=self.recode(desc).strip(), |
|
172 | desc=self.recode(desc).strip(), | |
170 | parents=self.parents[rev], |
|
173 | parents=self.parents[rev], | |
@@ -172,34 +175,34 b' class darcs_source(common.converter_sour' | |||||
172 |
|
175 | |||
173 | def pull(self, rev): |
|
176 | def pull(self, rev): | |
174 | output, status = self.run( |
|
177 | output, status = self.run( | |
175 | 'pull', |
|
178 | b'pull', | |
176 | self.path, |
|
179 | self.path, | |
177 | all=True, |
|
180 | all=True, | |
178 | match='hash %s' % rev, |
|
181 | match=b'hash %s' % rev, | |
179 | no_test=True, |
|
182 | no_test=True, | |
180 | no_posthook=True, |
|
183 | no_posthook=True, | |
181 | external_merge='/bin/false', |
|
184 | external_merge=b'/bin/false', | |
182 | repodir=self.tmppath, |
|
185 | repodir=self.tmppath, | |
183 | ) |
|
186 | ) | |
184 | if status: |
|
187 | if status: | |
185 | if output.find('We have conflicts in') == -1: |
|
188 | if output.find(b'We have conflicts in') == -1: | |
186 | self.checkexit(status, output) |
|
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 | self.checkexit(status, output) |
|
191 | self.checkexit(status, output) | |
189 |
|
192 | |||
190 | def getchanges(self, rev, full): |
|
193 | def getchanges(self, rev, full): | |
191 | if full: |
|
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 | copies = {} |
|
196 | copies = {} | |
194 | changes = [] |
|
197 | changes = [] | |
195 | man = None |
|
198 | man = None | |
196 | for elt in self.changes[rev].find('summary').getchildren(): |
|
199 | for elt in self.changes[rev].find(b'summary').getchildren(): | |
197 | if elt.tag in ('add_directory', 'remove_directory'): |
|
200 | if elt.tag in (b'add_directory', b'remove_directory'): | |
198 | continue |
|
201 | continue | |
199 | if elt.tag == 'move': |
|
202 | if elt.tag == b'move': | |
200 | if man is None: |
|
203 | if man is None: | |
201 | man = self.manifest() |
|
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 | if source in man: |
|
206 | if source in man: | |
204 | # File move |
|
207 | # File move | |
205 | changes.append((source, rev)) |
|
208 | changes.append((source, rev)) | |
@@ -207,11 +210,11 b' class darcs_source(common.converter_sour' | |||||
207 | copies[dest] = source |
|
210 | copies[dest] = source | |
208 | else: |
|
211 | else: | |
209 | # Directory move, deduce file moves from manifest |
|
212 | # Directory move, deduce file moves from manifest | |
210 | source = source + '/' |
|
213 | source = source + b'/' | |
211 | for f in man: |
|
214 | for f in man: | |
212 | if not f.startswith(source): |
|
215 | if not f.startswith(source): | |
213 | continue |
|
216 | continue | |
214 | fdest = dest + '/' + f[len(source) :] |
|
217 | fdest = dest + b'/' + f[len(source) :] | |
215 | changes.append((f, rev)) |
|
218 | changes.append((f, rev)) | |
216 | changes.append((fdest, rev)) |
|
219 | changes.append((fdest, rev)) | |
217 | copies[fdest] = f |
|
220 | copies[fdest] = f | |
@@ -223,7 +226,7 b' class darcs_source(common.converter_sour' | |||||
223 |
|
226 | |||
224 | def getfile(self, name, rev): |
|
227 | def getfile(self, name, rev): | |
225 | if rev != self.lastrev: |
|
228 | if rev != self.lastrev: | |
226 | raise error.Abort(_('internal calling inconsistency')) |
|
229 | raise error.Abort(_(b'internal calling inconsistency')) | |
227 | path = os.path.join(self.tmppath, name) |
|
230 | path = os.path.join(self.tmppath, name) | |
228 | try: |
|
231 | try: | |
229 | data = util.readfile(path) |
|
232 | data = util.readfile(path) | |
@@ -232,7 +235,7 b' class darcs_source(common.converter_sour' | |||||
232 | if inst.errno == errno.ENOENT: |
|
235 | if inst.errno == errno.ENOENT: | |
233 | return None, None |
|
236 | return None, None | |
234 | raise |
|
237 | raise | |
235 | mode = (mode & 0o111) and 'x' or '' |
|
238 | mode = (mode & 0o111) and b'x' or b'' | |
236 | return data, mode |
|
239 | return data, mode | |
237 |
|
240 | |||
238 | def gettags(self): |
|
241 | def gettags(self): |
@@ -30,8 +30,8 b' def rpairs(path):' | |||||
30 | i = len(path) |
|
30 | i = len(path) | |
31 | while i != -1: |
|
31 | while i != -1: | |
32 | yield path[:i], path[i + 1 :] |
|
32 | yield path[:i], path[i + 1 :] | |
33 | i = path.rfind('/', 0, i) |
|
33 | i = path.rfind(b'/', 0, i) | |
34 | yield '.', path |
|
34 | yield b'.', path | |
35 |
|
35 | |||
36 |
|
36 | |||
37 | def normalize(path): |
|
37 | def normalize(path): | |
@@ -55,7 +55,7 b' class filemapper(object):' | |||||
55 | self.targetprefixes = None |
|
55 | self.targetprefixes = None | |
56 | if path: |
|
56 | if path: | |
57 | if self.parse(path): |
|
57 | if self.parse(path): | |
58 | raise error.Abort(_('errors in filemap')) |
|
58 | raise error.Abort(_(b'errors in filemap')) | |
59 |
|
59 | |||
60 | def parse(self, path): |
|
60 | def parse(self, path): | |
61 | errs = 0 |
|
61 | errs = 0 | |
@@ -63,48 +63,48 b' class filemapper(object):' | |||||
63 | def check(name, mapping, listname): |
|
63 | def check(name, mapping, listname): | |
64 | if not name: |
|
64 | if not name: | |
65 | self.ui.warn( |
|
65 | self.ui.warn( | |
66 | _('%s:%d: path to %s is missing\n') |
|
66 | _(b'%s:%d: path to %s is missing\n') | |
67 | % (lex.infile, lex.lineno, listname) |
|
67 | % (lex.infile, lex.lineno, listname) | |
68 | ) |
|
68 | ) | |
69 | return 1 |
|
69 | return 1 | |
70 | if name in mapping: |
|
70 | if name in mapping: | |
71 | self.ui.warn( |
|
71 | self.ui.warn( | |
72 | _('%s:%d: %r already in %s list\n') |
|
72 | _(b'%s:%d: %r already in %s list\n') | |
73 | % (lex.infile, lex.lineno, name, listname) |
|
73 | % (lex.infile, lex.lineno, name, listname) | |
74 | ) |
|
74 | ) | |
75 | return 1 |
|
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 | self.ui.warn( |
|
77 | self.ui.warn( | |
78 | _('%s:%d: superfluous / in %s %r\n') |
|
78 | _(b'%s:%d: superfluous / in %s %r\n') | |
79 | % (lex.infile, lex.lineno, listname, pycompat.bytestr(name)) |
|
79 | % (lex.infile, lex.lineno, listname, pycompat.bytestr(name)) | |
80 | ) |
|
80 | ) | |
81 | return 1 |
|
81 | return 1 | |
82 | return 0 |
|
82 | return 0 | |
83 |
|
83 | |||
84 | lex = common.shlexer( |
|
84 | lex = common.shlexer( | |
85 | filepath=path, wordchars='!@#$%^&*()-=+[]{}|;:,./<>?' |
|
85 | filepath=path, wordchars=b'!@#$%^&*()-=+[]{}|;:,./<>?' | |
86 | ) |
|
86 | ) | |
87 | cmd = lex.get_token() |
|
87 | cmd = lex.get_token() | |
88 | while cmd: |
|
88 | while cmd: | |
89 | if cmd == 'include': |
|
89 | if cmd == b'include': | |
90 | name = normalize(lex.get_token()) |
|
90 | name = normalize(lex.get_token()) | |
91 | errs += check(name, self.exclude, 'exclude') |
|
91 | errs += check(name, self.exclude, b'exclude') | |
92 | self.include[name] = name |
|
92 | self.include[name] = name | |
93 | elif cmd == 'exclude': |
|
93 | elif cmd == b'exclude': | |
94 | name = normalize(lex.get_token()) |
|
94 | name = normalize(lex.get_token()) | |
95 | errs += check(name, self.include, 'include') |
|
95 | errs += check(name, self.include, b'include') | |
96 | errs += check(name, self.rename, 'rename') |
|
96 | errs += check(name, self.rename, b'rename') | |
97 | self.exclude[name] = name |
|
97 | self.exclude[name] = name | |
98 | elif cmd == 'rename': |
|
98 | elif cmd == b'rename': | |
99 | src = normalize(lex.get_token()) |
|
99 | src = normalize(lex.get_token()) | |
100 | dest = normalize(lex.get_token()) |
|
100 | dest = normalize(lex.get_token()) | |
101 | errs += check(src, self.exclude, 'exclude') |
|
101 | errs += check(src, self.exclude, b'exclude') | |
102 | self.rename[src] = dest |
|
102 | self.rename[src] = dest | |
103 | elif cmd == 'source': |
|
103 | elif cmd == b'source': | |
104 | errs += self.parse(normalize(lex.get_token())) |
|
104 | errs += self.parse(normalize(lex.get_token())) | |
105 | else: |
|
105 | else: | |
106 | self.ui.warn( |
|
106 | self.ui.warn( | |
107 | _('%s:%d: unknown directive %r\n') |
|
107 | _(b'%s:%d: unknown directive %r\n') | |
108 | % (lex.infile, lex.lineno, pycompat.bytestr(cmd)) |
|
108 | % (lex.infile, lex.lineno, pycompat.bytestr(cmd)) | |
109 | ) |
|
109 | ) | |
110 | errs += 1 |
|
110 | errs += 1 | |
@@ -118,7 +118,7 b' class filemapper(object):' | |||||
118 | return mapping[pre], pre, suf |
|
118 | return mapping[pre], pre, suf | |
119 | except KeyError: |
|
119 | except KeyError: | |
120 | pass |
|
120 | pass | |
121 | return '', name, '' |
|
121 | return b'', name, b'' | |
122 |
|
122 | |||
123 | def istargetfile(self, filename): |
|
123 | def istargetfile(self, filename): | |
124 | """Return true if the given target filename is covered as a destination |
|
124 | """Return true if the given target filename is covered as a destination | |
@@ -131,7 +131,7 b' class filemapper(object):' | |||||
131 |
|
131 | |||
132 | # If "." is a target, then all target files are considered from the |
|
132 | # If "." is a target, then all target files are considered from the | |
133 | # source. |
|
133 | # source. | |
134 | if not self.targetprefixes or '.' in self.targetprefixes: |
|
134 | if not self.targetprefixes or b'.' in self.targetprefixes: | |
135 | return True |
|
135 | return True | |
136 |
|
136 | |||
137 | filename = normalize(filename) |
|
137 | filename = normalize(filename) | |
@@ -152,17 +152,17 b' class filemapper(object):' | |||||
152 | if self.exclude: |
|
152 | if self.exclude: | |
153 | exc = self.lookup(name, self.exclude)[0] |
|
153 | exc = self.lookup(name, self.exclude)[0] | |
154 | else: |
|
154 | else: | |
155 | exc = '' |
|
155 | exc = b'' | |
156 | if (not self.include and exc) or (len(inc) <= len(exc)): |
|
156 | if (not self.include and exc) or (len(inc) <= len(exc)): | |
157 | return None |
|
157 | return None | |
158 | newpre, pre, suf = self.lookup(name, self.rename) |
|
158 | newpre, pre, suf = self.lookup(name, self.rename) | |
159 | if newpre: |
|
159 | if newpre: | |
160 | if newpre == '.': |
|
160 | if newpre == b'.': | |
161 | return suf |
|
161 | return suf | |
162 | if suf: |
|
162 | if suf: | |
163 | if newpre.endswith('/'): |
|
163 | if newpre.endswith(b'/'): | |
164 | return newpre + suf |
|
164 | return newpre + suf | |
165 | return newpre + '/' + suf |
|
165 | return newpre + b'/' + suf | |
166 | return newpre |
|
166 | return newpre | |
167 | return name |
|
167 | return name | |
168 |
|
168 | |||
@@ -204,7 +204,7 b' class filemap_source(common.converter_so' | |||||
204 | self.seenchildren = {} |
|
204 | self.seenchildren = {} | |
205 | # experimental config: convert.ignoreancestorcheck |
|
205 | # experimental config: convert.ignoreancestorcheck | |
206 | self.ignoreancestorcheck = self.ui.configbool( |
|
206 | self.ignoreancestorcheck = self.ui.configbool( | |
207 | 'convert', 'ignoreancestorcheck' |
|
207 | b'convert', b'ignoreancestorcheck' | |
208 | ) |
|
208 | ) | |
209 |
|
209 | |||
210 | def before(self): |
|
210 | def before(self): | |
@@ -256,7 +256,7 b' class filemap_source(common.converter_so' | |||||
256 | try: |
|
256 | try: | |
257 | self.origparents[rev] = self.getcommit(rev).parents |
|
257 | self.origparents[rev] = self.getcommit(rev).parents | |
258 | except error.RepoLookupError: |
|
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 | continue |
|
260 | continue | |
261 | if arg is not None: |
|
261 | if arg is not None: | |
262 | self.children[arg] = self.children.get(arg, 0) + 1 |
|
262 | self.children[arg] = self.children.get(arg, 0) + 1 | |
@@ -316,7 +316,7 b' class filemap_source(common.converter_so' | |||||
316 | try: |
|
316 | try: | |
317 | files = self.base.getchangedfiles(rev, i) |
|
317 | files = self.base.getchangedfiles(rev, i) | |
318 | except NotImplementedError: |
|
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 | for f in files: |
|
320 | for f in files: | |
321 | if self.filemapper(f): |
|
321 | if self.filemapper(f): | |
322 | return True |
|
322 | return True | |
@@ -331,7 +331,7 b' class filemap_source(common.converter_so' | |||||
331 | # close marker is significant (i.e. all of the branch ancestors weren't |
|
331 | # close marker is significant (i.e. all of the branch ancestors weren't | |
332 | # eliminated). Therefore if there *is* a close marker, getchanges() |
|
332 | # eliminated). Therefore if there *is* a close marker, getchanges() | |
333 | # doesn't consider it significant, and this revision should be dropped. |
|
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 | def mark_not_wanted(self, rev, p): |
|
336 | def mark_not_wanted(self, rev, p): | |
337 | # Mark rev as not interesting and update data structures. |
|
337 | # Mark rev as not interesting and update data structures. | |
@@ -363,7 +363,9 b' class filemap_source(common.converter_so' | |||||
363 | if p in self.wantedancestors: |
|
363 | if p in self.wantedancestors: | |
364 | wrev.update(self.wantedancestors[p]) |
|
364 | wrev.update(self.wantedancestors[p]) | |
365 | else: |
|
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 | wrev.add(rev) |
|
369 | wrev.add(rev) | |
368 | self.wantedancestors[rev] = wrev |
|
370 | self.wantedancestors[rev] = wrev | |
369 |
|
371 | |||
@@ -423,7 +425,7 b' class filemap_source(common.converter_so' | |||||
423 | self.origparents[rev] = parents |
|
425 | self.origparents[rev] = parents | |
424 |
|
426 | |||
425 | closed = False |
|
427 | closed = False | |
426 | if 'close' in self.commits[rev].extra: |
|
428 | if b'close' in self.commits[rev].extra: | |
427 | # A branch closing revision is only useful if one of its |
|
429 | # A branch closing revision is only useful if one of its | |
428 | # parents belong to the branch being closed |
|
430 | # parents belong to the branch being closed | |
429 | pbranches = [self._cachedcommit(p).branch for p in mparents] |
|
431 | pbranches = [self._cachedcommit(p).branch for p in mparents] |
@@ -26,22 +26,22 b' class submodule(object):' | |||||
26 | self.url = url |
|
26 | self.url = url | |
27 |
|
27 | |||
28 | def hgsub(self): |
|
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 | def hgsubstate(self): |
|
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 | # Keys in extra fields that should not be copied if the user requests. |
|
35 | # Keys in extra fields that should not be copied if the user requests. | |
36 | bannedextrakeys = { |
|
36 | bannedextrakeys = { | |
37 | # Git commit object built-ins. |
|
37 | # Git commit object built-ins. | |
38 | 'tree', |
|
38 | b'tree', | |
39 | 'parent', |
|
39 | b'parent', | |
40 | 'author', |
|
40 | b'author', | |
41 | 'committer', |
|
41 | b'committer', | |
42 | # Mercurial built-ins. |
|
42 | # Mercurial built-ins. | |
43 | 'branch', |
|
43 | b'branch', | |
44 | 'close', |
|
44 | b'close', | |
45 | } |
|
45 | } | |
46 |
|
46 | |||
47 |
|
47 | |||
@@ -51,7 +51,7 b' class convert_git(common.converter_sourc' | |||||
51 | # both issues. |
|
51 | # both issues. | |
52 |
|
52 | |||
53 | def _gitcmd(self, cmd, *args, **kwargs): |
|
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 | def gitrun0(self, *args, **kwargs): |
|
56 | def gitrun0(self, *args, **kwargs): | |
57 | return self._gitcmd(self.run0, *args, **kwargs) |
|
57 | return self._gitcmd(self.run0, *args, **kwargs) | |
@@ -70,100 +70,104 b' class convert_git(common.converter_sourc' | |||||
70 |
|
70 | |||
71 | def __init__(self, ui, repotype, path, revs=None): |
|
71 | def __init__(self, ui, repotype, path, revs=None): | |
72 | super(convert_git, self).__init__(ui, repotype, path, revs=revs) |
|
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 | # Pass an absolute path to git to prevent from ever being interpreted |
|
75 | # Pass an absolute path to git to prevent from ever being interpreted | |
76 | # as a URL |
|
76 | # as a URL | |
77 | path = os.path.abspath(path) |
|
77 | path = os.path.abspath(path) | |
78 |
|
78 | |||
79 | if os.path.isdir(path + "/.git"): |
|
79 | if os.path.isdir(path + b"/.git"): | |
80 | path += "/.git" |
|
80 | path += b"/.git" | |
81 | if not os.path.exists(path + "/objects"): |
|
81 | if not os.path.exists(path + b"/objects"): | |
82 | raise common.NoRepo( |
|
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 | # The default value (50) is based on the default for 'git diff'. |
|
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 | if similarity < 0 or similarity > 100: |
|
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 | if similarity > 0: |
|
90 | if similarity > 0: | |
91 | self.simopt = ['-C%d%%' % similarity] |
|
91 | self.simopt = [b'-C%d%%' % similarity] | |
92 |
findcopiesharder = ui.configbool( |
|
92 | findcopiesharder = ui.configbool( | |
|
93 | b'convert', b'git.findcopiesharder' | |||
|
94 | ) | |||
93 | if findcopiesharder: |
|
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') |
|
98 | renamelimit = ui.configint(b'convert', b'git.renamelimit') | |
97 | self.simopt.append('-l%d' % renamelimit) |
|
99 | self.simopt.append(b'-l%d' % renamelimit) | |
98 | else: |
|
100 | else: | |
99 | self.simopt = [] |
|
101 | self.simopt = [] | |
100 |
|
102 | |||
101 | common.checktool('git', 'git') |
|
103 | common.checktool(b'git', b'git') | |
102 |
|
104 | |||
103 | self.path = path |
|
105 | self.path = path | |
104 | self.submodules = [] |
|
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 | banned = set(self.copyextrakeys) & bannedextrakeys |
|
111 | banned = set(self.copyextrakeys) & bannedextrakeys | |
110 | if banned: |
|
112 | if banned: | |
111 | raise error.Abort( |
|
113 | raise error.Abort( | |
112 | _('copying of extra key is forbidden: %s') |
|
114 | _(b'copying of extra key is forbidden: %s') | |
113 | % _(', ').join(sorted(banned)) |
|
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 | messagedifferent = None |
|
122 | messagedifferent = None | |
119 | messagealways = None |
|
123 | messagealways = None | |
120 | for a in committeractions: |
|
124 | for a in committeractions: | |
121 | if a.startswith(('messagedifferent', 'messagealways')): |
|
125 | if a.startswith((b'messagedifferent', b'messagealways')): | |
122 | k = a |
|
126 | k = a | |
123 | v = None |
|
127 | v = None | |
124 | if '=' in a: |
|
128 | if b'=' in a: | |
125 | k, v = a.split('=', 1) |
|
129 | k, v = a.split(b'=', 1) | |
126 |
|
130 | |||
127 | if k == 'messagedifferent': |
|
131 | if k == b'messagedifferent': | |
128 | messagedifferent = v or 'committer:' |
|
132 | messagedifferent = v or b'committer:' | |
129 | elif k == 'messagealways': |
|
133 | elif k == b'messagealways': | |
130 | messagealways = v or 'committer:' |
|
134 | messagealways = v or b'committer:' | |
131 |
|
135 | |||
132 | if messagedifferent and messagealways: |
|
136 | if messagedifferent and messagealways: | |
133 | raise error.Abort( |
|
137 | raise error.Abort( | |
134 | _( |
|
138 | _( | |
135 | 'committeractions cannot define both ' |
|
139 | b'committeractions cannot define both ' | |
136 | 'messagedifferent and messagealways' |
|
140 | b'messagedifferent and messagealways' | |
137 | ) |
|
141 | ) | |
138 | ) |
|
142 | ) | |
139 |
|
143 | |||
140 | dropcommitter = 'dropcommitter' in committeractions |
|
144 | dropcommitter = b'dropcommitter' in committeractions | |
141 | replaceauthor = 'replaceauthor' in committeractions |
|
145 | replaceauthor = b'replaceauthor' in committeractions | |
142 |
|
146 | |||
143 | if dropcommitter and replaceauthor: |
|
147 | if dropcommitter and replaceauthor: | |
144 | raise error.Abort( |
|
148 | raise error.Abort( | |
145 | _( |
|
149 | _( | |
146 | 'committeractions cannot define both ' |
|
150 | b'committeractions cannot define both ' | |
147 | 'dropcommitter and replaceauthor' |
|
151 | b'dropcommitter and replaceauthor' | |
148 | ) |
|
152 | ) | |
149 | ) |
|
153 | ) | |
150 |
|
154 | |||
151 | if dropcommitter and messagealways: |
|
155 | if dropcommitter and messagealways: | |
152 | raise error.Abort( |
|
156 | raise error.Abort( | |
153 | _( |
|
157 | _( | |
154 | 'committeractions cannot define both ' |
|
158 | b'committeractions cannot define both ' | |
155 | 'dropcommitter and messagealways' |
|
159 | b'dropcommitter and messagealways' | |
156 | ) |
|
160 | ) | |
157 | ) |
|
161 | ) | |
158 |
|
162 | |||
159 | if not messagedifferent and not messagealways: |
|
163 | if not messagedifferent and not messagealways: | |
160 | messagedifferent = 'committer:' |
|
164 | messagedifferent = b'committer:' | |
161 |
|
165 | |||
162 | self.committeractions = { |
|
166 | self.committeractions = { | |
163 | 'dropcommitter': dropcommitter, |
|
167 | b'dropcommitter': dropcommitter, | |
164 | 'replaceauthor': replaceauthor, |
|
168 | b'replaceauthor': replaceauthor, | |
165 | 'messagedifferent': messagedifferent, |
|
169 | b'messagedifferent': messagedifferent, | |
166 | 'messagealways': messagealways, |
|
170 | b'messagealways': messagealways, | |
167 | } |
|
171 | } | |
168 |
|
172 | |||
169 | def after(self): |
|
173 | def after(self): | |
@@ -172,35 +176,38 b' class convert_git(common.converter_sourc' | |||||
172 |
|
176 | |||
173 | def getheads(self): |
|
177 | def getheads(self): | |
174 | if not self.revs: |
|
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 | heads = output.splitlines() |
|
182 | heads = output.splitlines() | |
177 | if status: |
|
183 | if status: | |
178 | raise error.Abort(_('cannot retrieve git heads')) |
|
184 | raise error.Abort(_(b'cannot retrieve git heads')) | |
179 | else: |
|
185 | else: | |
180 | heads = [] |
|
186 | heads = [] | |
181 | for rev in self.revs: |
|
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 | heads.append(rawhead[:-1]) |
|
189 | heads.append(rawhead[:-1]) | |
184 | if ret: |
|
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 | return heads |
|
192 | return heads | |
187 |
|
193 | |||
188 | def catfile(self, rev, ftype): |
|
194 | def catfile(self, rev, ftype): | |
189 | if rev == nodemod.nullhex: |
|
195 | if rev == nodemod.nullhex: | |
190 | raise IOError |
|
196 | raise IOError | |
191 | self.catfilepipe[0].write(rev + '\n') |
|
197 | self.catfilepipe[0].write(rev + b'\n') | |
192 | self.catfilepipe[0].flush() |
|
198 | self.catfilepipe[0].flush() | |
193 | info = self.catfilepipe[1].readline().split() |
|
199 | info = self.catfilepipe[1].readline().split() | |
194 | if info[1] != ftype: |
|
200 | if info[1] != ftype: | |
195 | raise error.Abort( |
|
201 | raise error.Abort( | |
196 | _('cannot read %r object at %s') |
|
202 | _(b'cannot read %r object at %s') | |
197 | % (pycompat.bytestr(ftype), rev) |
|
203 | % (pycompat.bytestr(ftype), rev) | |
198 | ) |
|
204 | ) | |
199 | size = int(info[2]) |
|
205 | size = int(info[2]) | |
200 | data = self.catfilepipe[1].read(size) |
|
206 | data = self.catfilepipe[1].read(size) | |
201 | if len(data) < size: |
|
207 | if len(data) < size: | |
202 | raise error.Abort( |
|
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 | # read the trailing newline |
|
212 | # read the trailing newline | |
206 | self.catfilepipe[1].read(1) |
|
213 | self.catfilepipe[1].read(1) | |
@@ -209,14 +216,14 b' class convert_git(common.converter_sourc' | |||||
209 | def getfile(self, name, rev): |
|
216 | def getfile(self, name, rev): | |
210 | if rev == nodemod.nullhex: |
|
217 | if rev == nodemod.nullhex: | |
211 | return None, None |
|
218 | return None, None | |
212 | if name == '.hgsub': |
|
219 | if name == b'.hgsub': | |
213 | data = '\n'.join([m.hgsub() for m in self.submoditer()]) |
|
220 | data = b'\n'.join([m.hgsub() for m in self.submoditer()]) | |
214 | mode = '' |
|
221 | mode = b'' | |
215 | elif name == '.hgsubstate': |
|
222 | elif name == b'.hgsubstate': | |
216 | data = '\n'.join([m.hgsubstate() for m in self.submoditer()]) |
|
223 | data = b'\n'.join([m.hgsubstate() for m in self.submoditer()]) | |
217 | mode = '' |
|
224 | mode = b'' | |
218 | else: |
|
225 | else: | |
219 | data = self.catfile(rev, "blob") |
|
226 | data = self.catfile(rev, b"blob") | |
220 | mode = self.modecache[(name, rev)] |
|
227 | mode = self.modecache[(name, rev)] | |
221 | return data, mode |
|
228 | return data, mode | |
222 |
|
229 | |||
@@ -236,21 +243,23 b' class convert_git(common.converter_sourc' | |||||
236 | c = config.config() |
|
243 | c = config.config() | |
237 | # Each item in .gitmodules starts with whitespace that cant be parsed |
|
244 | # Each item in .gitmodules starts with whitespace that cant be parsed | |
238 | c.parse( |
|
245 | c.parse( | |
239 | '.gitmodules', |
|
246 | b'.gitmodules', | |
240 | '\n'.join(line.strip() for line in content.split('\n')), |
|
247 | b'\n'.join(line.strip() for line in content.split(b'\n')), | |
241 | ) |
|
248 | ) | |
242 | for sec in c.sections(): |
|
249 | for sec in c.sections(): | |
243 | s = c[sec] |
|
250 | s = c[sec] | |
244 | if 'url' in s and 'path' in s: |
|
251 | if b'url' in s and b'path' in s: | |
245 | self.submodules.append(submodule(s['path'], '', s['url'])) |
|
252 | self.submodules.append(submodule(s[b'path'], b'', s[b'url'])) | |
246 |
|
253 | |||
247 | def retrievegitmodules(self, version): |
|
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 | if ret: |
|
258 | if ret: | |
250 | # This can happen if a file is in the repo that has permissions |
|
259 | # This can happen if a file is in the repo that has permissions | |
251 | # 160000, but there is no .gitmodules file. |
|
260 | # 160000, but there is no .gitmodules file. | |
252 | self.ui.warn( |
|
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 | % version |
|
263 | % version | |
255 | ) |
|
264 | ) | |
256 | return |
|
265 | return | |
@@ -259,74 +268,76 b' class convert_git(common.converter_sourc' | |||||
259 | self.parsegitmodules(modules) |
|
268 | self.parsegitmodules(modules) | |
260 | except error.ParseError: |
|
269 | except error.ParseError: | |
261 | self.ui.warn( |
|
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 | return |
|
273 | return | |
265 |
|
274 | |||
266 | for m in self.submodules: |
|
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 | if ret: |
|
277 | if ret: | |
269 | continue |
|
278 | continue | |
270 | m.node = node.strip() |
|
279 | m.node = node.strip() | |
271 |
|
280 | |||
272 | def getchanges(self, version, full): |
|
281 | def getchanges(self, version, full): | |
273 | if full: |
|
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 | self.modecache = {} |
|
284 | self.modecache = {} | |
276 | cmd = ( |
|
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 | output, status = self.gitrun(*cmd) |
|
290 | output, status = self.gitrun(*cmd) | |
280 | if status: |
|
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 | changes = [] |
|
293 | changes = [] | |
283 | copies = {} |
|
294 | copies = {} | |
284 | seen = set() |
|
295 | seen = set() | |
285 | entry = None |
|
296 | entry = None | |
286 | subexists = [False] |
|
297 | subexists = [False] | |
287 | subdeleted = [False] |
|
298 | subdeleted = [False] | |
288 | difftree = output.split('\x00') |
|
299 | difftree = output.split(b'\x00') | |
289 | lcount = len(difftree) |
|
300 | lcount = len(difftree) | |
290 | i = 0 |
|
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 | def add(entry, f, isdest): |
|
305 | def add(entry, f, isdest): | |
295 | seen.add(f) |
|
306 | seen.add(f) | |
296 | h = entry[3] |
|
307 | h = entry[3] | |
297 | p = entry[1] == "100755" |
|
308 | p = entry[1] == b"100755" | |
298 | s = entry[1] == "120000" |
|
309 | s = entry[1] == b"120000" | |
299 | renamesource = not isdest and entry[4][0] == 'R' |
|
310 | renamesource = not isdest and entry[4][0] == b'R' | |
300 |
|
311 | |||
301 | if f == '.gitmodules': |
|
312 | if f == b'.gitmodules': | |
302 | if skipsubmodules: |
|
313 | if skipsubmodules: | |
303 | return |
|
314 | return | |
304 |
|
315 | |||
305 | subexists[0] = True |
|
316 | subexists[0] = True | |
306 | if entry[4] == 'D' or renamesource: |
|
317 | if entry[4] == b'D' or renamesource: | |
307 | subdeleted[0] = True |
|
318 | subdeleted[0] = True | |
308 | changes.append(('.hgsub', nodemod.nullhex)) |
|
319 | changes.append((b'.hgsub', nodemod.nullhex)) | |
309 | else: |
|
320 | else: | |
310 | changes.append(('.hgsub', '')) |
|
321 | changes.append((b'.hgsub', b'')) | |
311 | elif entry[1] == '160000' or entry[0] == ':160000': |
|
322 | elif entry[1] == b'160000' or entry[0] == b':160000': | |
312 | if not skipsubmodules: |
|
323 | if not skipsubmodules: | |
313 | subexists[0] = True |
|
324 | subexists[0] = True | |
314 | else: |
|
325 | else: | |
315 | if renamesource: |
|
326 | if renamesource: | |
316 | h = nodemod.nullhex |
|
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 | changes.append((f, h)) |
|
329 | changes.append((f, h)) | |
319 |
|
330 | |||
320 | while i < lcount: |
|
331 | while i < lcount: | |
321 | l = difftree[i] |
|
332 | l = difftree[i] | |
322 | i += 1 |
|
333 | i += 1 | |
323 | if not entry: |
|
334 | if not entry: | |
324 | if not l.startswith(':'): |
|
335 | if not l.startswith(b':'): | |
325 | continue |
|
336 | continue | |
326 | entry = tuple(pycompat.bytestr(p) for p in l.split()) |
|
337 | entry = tuple(pycompat.bytestr(p) for p in l.split()) | |
327 | continue |
|
338 | continue | |
328 | f = l |
|
339 | f = l | |
329 | if entry[4][0] == 'C': |
|
340 | if entry[4][0] == b'C': | |
330 | copysrc = f |
|
341 | copysrc = f | |
331 | copydest = difftree[i] |
|
342 | copydest = difftree[i] | |
332 | i += 1 |
|
343 | i += 1 | |
@@ -336,7 +347,7 b' class convert_git(common.converter_sourc' | |||||
336 | add(entry, f, False) |
|
347 | add(entry, f, False) | |
337 | # A file can be copied multiple times, or modified and copied |
|
348 | # A file can be copied multiple times, or modified and copied | |
338 | # simultaneously. So f can be repeated even if fdest isn't. |
|
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 | # rename: next line is the destination |
|
351 | # rename: next line is the destination | |
341 | fdest = difftree[i] |
|
352 | fdest = difftree[i] | |
342 | i += 1 |
|
353 | i += 1 | |
@@ -344,21 +355,21 b' class convert_git(common.converter_sourc' | |||||
344 | add(entry, fdest, True) |
|
355 | add(entry, fdest, True) | |
345 | # .gitmodules isn't imported at all, so it being copied to |
|
356 | # .gitmodules isn't imported at all, so it being copied to | |
346 | # and fro doesn't really make sense |
|
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 | copies[fdest] = f |
|
359 | copies[fdest] = f | |
349 | entry = None |
|
360 | entry = None | |
350 |
|
361 | |||
351 | if subexists[0]: |
|
362 | if subexists[0]: | |
352 | if subdeleted[0]: |
|
363 | if subdeleted[0]: | |
353 | changes.append(('.hgsubstate', nodemod.nullhex)) |
|
364 | changes.append((b'.hgsubstate', nodemod.nullhex)) | |
354 | else: |
|
365 | else: | |
355 | self.retrievegitmodules(version) |
|
366 | self.retrievegitmodules(version) | |
356 | changes.append(('.hgsubstate', '')) |
|
367 | changes.append((b'.hgsubstate', b'')) | |
357 | return (changes, copies, set()) |
|
368 | return (changes, copies, set()) | |
358 |
|
369 | |||
359 | def getcommit(self, version): |
|
370 | def getcommit(self, version): | |
360 | c = self.catfile(version, "commit") # read the commit hash |
|
371 | c = self.catfile(version, b"commit") # read the commit hash | |
361 | end = c.find("\n\n") |
|
372 | end = c.find(b"\n\n") | |
362 | message = c[end + 2 :] |
|
373 | message = c[end + 2 :] | |
363 | message = self.recode(message) |
|
374 | message = self.recode(message) | |
364 | l = c[:end].splitlines() |
|
375 | l = c[:end].splitlines() | |
@@ -366,43 +377,43 b' class convert_git(common.converter_sourc' | |||||
366 | author = committer = None |
|
377 | author = committer = None | |
367 | extra = {} |
|
378 | extra = {} | |
368 | for e in l[1:]: |
|
379 | for e in l[1:]: | |
369 | n, v = e.split(" ", 1) |
|
380 | n, v = e.split(b" ", 1) | |
370 | if n == "author": |
|
381 | if n == b"author": | |
371 | p = v.split() |
|
382 | p = v.split() | |
372 | tm, tz = p[-2:] |
|
383 | tm, tz = p[-2:] | |
373 | author = " ".join(p[:-2]) |
|
384 | author = b" ".join(p[:-2]) | |
374 | if author[0] == "<": |
|
385 | if author[0] == b"<": | |
375 | author = author[1:-1] |
|
386 | author = author[1:-1] | |
376 | author = self.recode(author) |
|
387 | author = self.recode(author) | |
377 | if n == "committer": |
|
388 | if n == b"committer": | |
378 | p = v.split() |
|
389 | p = v.split() | |
379 | tm, tz = p[-2:] |
|
390 | tm, tz = p[-2:] | |
380 | committer = " ".join(p[:-2]) |
|
391 | committer = b" ".join(p[:-2]) | |
381 | if committer[0] == "<": |
|
392 | if committer[0] == b"<": | |
382 | committer = committer[1:-1] |
|
393 | committer = committer[1:-1] | |
383 | committer = self.recode(committer) |
|
394 | committer = self.recode(committer) | |
384 | if n == "parent": |
|
395 | if n == b"parent": | |
385 | parents.append(v) |
|
396 | parents.append(v) | |
386 | if n in self.copyextrakeys: |
|
397 | if n in self.copyextrakeys: | |
387 | extra[n] = v |
|
398 | extra[n] = v | |
388 |
|
399 | |||
389 | if self.committeractions['dropcommitter']: |
|
400 | if self.committeractions[b'dropcommitter']: | |
390 | committer = None |
|
401 | committer = None | |
391 | elif self.committeractions['replaceauthor']: |
|
402 | elif self.committeractions[b'replaceauthor']: | |
392 | author = committer |
|
403 | author = committer | |
393 |
|
404 | |||
394 | if committer: |
|
405 | if committer: | |
395 | messagealways = self.committeractions['messagealways'] |
|
406 | messagealways = self.committeractions[b'messagealways'] | |
396 | messagedifferent = self.committeractions['messagedifferent'] |
|
407 | messagedifferent = self.committeractions[b'messagedifferent'] | |
397 | if messagealways: |
|
408 | if messagealways: | |
398 | message += '\n%s %s\n' % (messagealways, committer) |
|
409 | message += b'\n%s %s\n' % (messagealways, committer) | |
399 | elif messagedifferent and author != committer: |
|
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 | tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) |
|
414 | tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) | |
404 | date = tm + " " + (b"%d" % tz) |
|
415 | date = tm + b" " + (b"%d" % tz) | |
405 | saverev = self.ui.configbool('convert', 'git.saverev') |
|
416 | saverev = self.ui.configbool(b'convert', b'git.saverev') | |
406 |
|
417 | |||
407 | c = common.commit( |
|
418 | c = common.commit( | |
408 | parents=parents, |
|
419 | parents=parents, | |
@@ -416,27 +427,27 b' class convert_git(common.converter_sourc' | |||||
416 | return c |
|
427 | return c | |
417 |
|
428 | |||
418 | def numcommits(self): |
|
429 | def numcommits(self): | |
419 | output, ret = self.gitrunlines('rev-list', '--all') |
|
430 | output, ret = self.gitrunlines(b'rev-list', b'--all') | |
420 | if ret: |
|
431 | if ret: | |
421 | raise error.Abort( |
|
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 | return len(output) |
|
435 | return len(output) | |
425 |
|
436 | |||
426 | def gettags(self): |
|
437 | def gettags(self): | |
427 | tags = {} |
|
438 | tags = {} | |
428 | alltags = {} |
|
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 | if status: |
|
442 | if status: | |
432 | raise error.Abort(_('cannot read tags from %s') % self.path) |
|
443 | raise error.Abort(_(b'cannot read tags from %s') % self.path) | |
433 | prefix = 'refs/tags/' |
|
444 | prefix = b'refs/tags/' | |
434 |
|
445 | |||
435 | # Build complete list of tags, both annotated and bare ones |
|
446 | # Build complete list of tags, both annotated and bare ones | |
436 | for line in output: |
|
447 | for line in output: | |
437 | line = line.strip() |
|
448 | line = line.strip() | |
438 | if line.startswith("error:") or line.startswith("fatal:"): |
|
449 | if line.startswith(b"error:") or line.startswith(b"fatal:"): | |
439 | raise error.Abort(_('cannot read tags from %s') % self.path) |
|
450 | raise error.Abort(_(b'cannot read tags from %s') % self.path) | |
440 | node, tag = line.split(None, 1) |
|
451 | node, tag = line.split(None, 1) | |
441 | if not tag.startswith(prefix): |
|
452 | if not tag.startswith(prefix): | |
442 | continue |
|
453 | continue | |
@@ -444,10 +455,10 b' class convert_git(common.converter_sourc' | |||||
444 |
|
455 | |||
445 | # Filter out tag objects for annotated tag refs |
|
456 | # Filter out tag objects for annotated tag refs | |
446 | for tag in alltags: |
|
457 | for tag in alltags: | |
447 | if tag.endswith('^{}'): |
|
458 | if tag.endswith(b'^{}'): | |
448 | tags[tag[:-3]] = alltags[tag] |
|
459 | tags[tag[:-3]] = alltags[tag] | |
449 | else: |
|
460 | else: | |
450 | if tag + '^{}' in alltags: |
|
461 | if tag + b'^{}' in alltags: | |
451 | continue |
|
462 | continue | |
452 | else: |
|
463 | else: | |
453 | tags[tag] = alltags[tag] |
|
464 | tags[tag] = alltags[tag] | |
@@ -458,28 +469,28 b' class convert_git(common.converter_sourc' | |||||
458 | changes = [] |
|
469 | changes = [] | |
459 | if i is None: |
|
470 | if i is None: | |
460 | output, status = self.gitrunlines( |
|
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 | if status: |
|
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 | for l in output: |
|
476 | for l in output: | |
466 | if "\t" not in l: |
|
477 | if b"\t" not in l: | |
467 | continue |
|
478 | continue | |
468 | m, f = l[:-1].split("\t") |
|
479 | m, f = l[:-1].split(b"\t") | |
469 | changes.append(f) |
|
480 | changes.append(f) | |
470 | else: |
|
481 | else: | |
471 | output, status = self.gitrunlines( |
|
482 | output, status = self.gitrunlines( | |
472 | 'diff-tree', |
|
483 | b'diff-tree', | |
473 | '--name-only', |
|
484 | b'--name-only', | |
474 | '--root', |
|
485 | b'--root', | |
475 | '-r', |
|
486 | b'-r', | |
476 | version, |
|
487 | version, | |
477 | '%s^%d' % (version, i + 1), |
|
488 | b'%s^%d' % (version, i + 1), | |
478 | '--', |
|
489 | b'--', | |
479 | ) |
|
490 | ) | |
480 | if status: |
|
491 | if status: | |
481 | raise error.Abort(_('cannot read changes in %s') % version) |
|
492 | raise error.Abort(_(b'cannot read changes in %s') % version) | |
482 | changes = [f.rstrip('\n') for f in output] |
|
493 | changes = [f.rstrip(b'\n') for f in output] | |
483 |
|
494 | |||
484 | return changes |
|
495 | return changes | |
485 |
|
496 | |||
@@ -487,19 +498,19 b' class convert_git(common.converter_sourc' | |||||
487 | bookmarks = {} |
|
498 | bookmarks = {} | |
488 |
|
499 | |||
489 | # Handle local and remote branches |
|
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 | reftypes = [ |
|
502 | reftypes = [ | |
492 | # (git prefix, hg prefix) |
|
503 | # (git prefix, hg prefix) | |
493 | ('refs/remotes/origin/', remoteprefix + '/'), |
|
504 | (b'refs/remotes/origin/', remoteprefix + b'/'), | |
494 | ('refs/heads/', ''), |
|
505 | (b'refs/heads/', b''), | |
495 | ] |
|
506 | ] | |
496 |
|
507 | |||
497 | exclude = { |
|
508 | exclude = { | |
498 | 'refs/remotes/origin/HEAD', |
|
509 | b'refs/remotes/origin/HEAD', | |
499 | } |
|
510 | } | |
500 |
|
511 | |||
501 | try: |
|
512 | try: | |
502 | output, status = self.gitrunlines('show-ref') |
|
513 | output, status = self.gitrunlines(b'show-ref') | |
503 | for line in output: |
|
514 | for line in output: | |
504 | line = line.strip() |
|
515 | line = line.strip() | |
505 | rev, name = line.split(None, 1) |
|
516 | rev, name = line.split(None, 1) | |
@@ -507,13 +518,13 b' class convert_git(common.converter_sourc' | |||||
507 | for gitprefix, hgprefix in reftypes: |
|
518 | for gitprefix, hgprefix in reftypes: | |
508 | if not name.startswith(gitprefix) or name in exclude: |
|
519 | if not name.startswith(gitprefix) or name in exclude: | |
509 | continue |
|
520 | continue | |
510 | name = '%s%s' % (hgprefix, name[len(gitprefix) :]) |
|
521 | name = b'%s%s' % (hgprefix, name[len(gitprefix) :]) | |
511 | bookmarks[name] = rev |
|
522 | bookmarks[name] = rev | |
512 | except Exception: |
|
523 | except Exception: | |
513 | pass |
|
524 | pass | |
514 |
|
525 | |||
515 | return bookmarks |
|
526 | return bookmarks | |
516 |
|
527 | |||
517 | def checkrevformat(self, revstr, mapname='splicemap'): |
|
528 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
518 | """ git revision string is a 40 byte hex """ |
|
529 | """ git revision string is a 40 byte hex """ | |
519 | self.checkhexformat(revstr, mapname) |
|
530 | self.checkhexformat(revstr, mapname) |
@@ -31,9 +31,9 b' class gnuarch_source(common.converter_so' | |||||
31 | class gnuarch_rev(object): |
|
31 | class gnuarch_rev(object): | |
32 | def __init__(self, rev): |
|
32 | def __init__(self, rev): | |
33 | self.rev = rev |
|
33 | self.rev = rev | |
34 | self.summary = '' |
|
34 | self.summary = b'' | |
35 | self.date = None |
|
35 | self.date = None | |
36 | self.author = '' |
|
36 | self.author = b'' | |
37 | self.continuationof = None |
|
37 | self.continuationof = None | |
38 | self.add_files = [] |
|
38 | self.add_files = [] | |
39 | self.mod_files = [] |
|
39 | self.mod_files = [] | |
@@ -44,20 +44,20 b' class gnuarch_source(common.converter_so' | |||||
44 | def __init__(self, ui, repotype, path, revs=None): |
|
44 | def __init__(self, ui, repotype, path, revs=None): | |
45 | super(gnuarch_source, self).__init__(ui, repotype, path, revs=revs) |
|
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 | raise common.NoRepo( |
|
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 | # Could use checktool, but we want to check for baz or tla. |
|
52 | # Could use checktool, but we want to check for baz or tla. | |
53 | self.execmd = None |
|
53 | self.execmd = None | |
54 | if procutil.findexe('baz'): |
|
54 | if procutil.findexe(b'baz'): | |
55 | self.execmd = 'baz' |
|
55 | self.execmd = b'baz' | |
56 | else: |
|
56 | else: | |
57 | if procutil.findexe('tla'): |
|
57 | if procutil.findexe(b'tla'): | |
58 | self.execmd = 'tla' |
|
58 | self.execmd = b'tla' | |
59 | else: |
|
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 | common.commandline.__init__(self, ui, self.execmd) |
|
62 | common.commandline.__init__(self, ui, self.execmd) | |
63 |
|
63 | |||
@@ -76,19 +76,19 b' class gnuarch_source(common.converter_so' | |||||
76 | def before(self): |
|
76 | def before(self): | |
77 | # Get registered archives |
|
77 | # Get registered archives | |
78 | self.archives = [ |
|
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': |
|
82 | if self.execmd == b'tla': | |
83 | output = self.run0('tree-version', self.path) |
|
83 | output = self.run0(b'tree-version', self.path) | |
84 | else: |
|
84 | else: | |
85 | output = self.run0('tree-version', '-d', self.path) |
|
85 | output = self.run0(b'tree-version', b'-d', self.path) | |
86 | self.treeversion = output.strip() |
|
86 | self.treeversion = output.strip() | |
87 |
|
87 | |||
88 | # Get name of temporary directory |
|
88 | # Get name of temporary directory | |
89 | version = self.treeversion.split('/') |
|
89 | version = self.treeversion.split(b'/') | |
90 | self.tmppath = os.path.join( |
|
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 | # Generate parents dictionary |
|
94 | # Generate parents dictionary | |
@@ -96,23 +96,25 b' class gnuarch_source(common.converter_so' | |||||
96 | treeversion = self.treeversion |
|
96 | treeversion = self.treeversion | |
97 | child = None |
|
97 | child = None | |
98 | while treeversion: |
|
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 | if archive not in self.archives: |
|
102 | if archive not in self.archives: | |
103 | self.ui.status( |
|
103 | self.ui.status( | |
104 | _( |
|
104 | _( | |
105 | 'tree analysis stopped because it points to ' |
|
105 | b'tree analysis stopped because it points to ' | |
106 | 'an unregistered archive %s...\n' |
|
106 | b'an unregistered archive %s...\n' | |
107 | ) |
|
107 | ) | |
108 | % archive |
|
108 | % archive | |
109 | ) |
|
109 | ) | |
110 | break |
|
110 | break | |
111 |
|
111 | |||
112 | # Get the complete list of revisions for that tree version |
|
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 | self.checkexit( |
|
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 | # No new iteration unless a revision has a continuation-of header |
|
120 | # No new iteration unless a revision has a continuation-of header | |
@@ -124,9 +126,9 b' class gnuarch_source(common.converter_so' | |||||
124 | self.parents[rev] = [] |
|
126 | self.parents[rev] = [] | |
125 |
|
127 | |||
126 | # Read author, date and summary |
|
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 | if status: |
|
130 | if status: | |
129 | catlog = self.run0('cat-archive-log', rev) |
|
131 | catlog = self.run0(b'cat-archive-log', rev) | |
130 | self._parsecatlog(catlog, rev) |
|
132 | self._parsecatlog(catlog, rev) | |
131 |
|
133 | |||
132 | # Populate the parents map |
|
134 | # Populate the parents map | |
@@ -140,18 +142,18 b' class gnuarch_source(common.converter_so' | |||||
140 | # or if we have to 'jump' to a different treeversion given |
|
142 | # or if we have to 'jump' to a different treeversion given | |
141 | # by the continuation-of header. |
|
143 | # by the continuation-of header. | |
142 | if self.changes[rev].continuationof: |
|
144 | if self.changes[rev].continuationof: | |
143 | treeversion = '--'.join( |
|
145 | treeversion = b'--'.join( | |
144 | self.changes[rev].continuationof.split('--')[:-1] |
|
146 | self.changes[rev].continuationof.split(b'--')[:-1] | |
145 | ) |
|
147 | ) | |
146 | break |
|
148 | break | |
147 |
|
149 | |||
148 | # If we reached a base-0 revision w/o any continuation-of |
|
150 | # If we reached a base-0 revision w/o any continuation-of | |
149 | # header, it means the tree history ends here. |
|
151 | # header, it means the tree history ends here. | |
150 | if rev[-6:] == 'base-0': |
|
152 | if rev[-6:] == b'base-0': | |
151 | break |
|
153 | break | |
152 |
|
154 | |||
153 | def after(self): |
|
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 | shutil.rmtree(self.tmppath, ignore_errors=True) |
|
157 | shutil.rmtree(self.tmppath, ignore_errors=True) | |
156 |
|
158 | |||
157 | def getheads(self): |
|
159 | def getheads(self): | |
@@ -159,7 +161,7 b' class gnuarch_source(common.converter_so' | |||||
159 |
|
161 | |||
160 | def getfile(self, name, rev): |
|
162 | def getfile(self, name, rev): | |
161 | if rev != self.lastrev: |
|
163 | if rev != self.lastrev: | |
162 | raise error.Abort(_('internal calling inconsistency')) |
|
164 | raise error.Abort(_(b'internal calling inconsistency')) | |
163 |
|
165 | |||
164 | if not os.path.lexists(os.path.join(self.tmppath, name)): |
|
166 | if not os.path.lexists(os.path.join(self.tmppath, name)): | |
165 | return None, None |
|
167 | return None, None | |
@@ -168,7 +170,7 b' class gnuarch_source(common.converter_so' | |||||
168 |
|
170 | |||
169 | def getchanges(self, rev, full): |
|
171 | def getchanges(self, rev, full): | |
170 | if full: |
|
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 | self._update(rev) |
|
174 | self._update(rev) | |
173 | changes = [] |
|
175 | changes = [] | |
174 | copies = {} |
|
176 | copies = {} | |
@@ -214,14 +216,14 b' class gnuarch_source(common.converter_so' | |||||
214 | cmdline = [self.execmd, cmd] |
|
216 | cmdline = [self.execmd, cmd] | |
215 | cmdline += args |
|
217 | cmdline += args | |
216 | cmdline = [procutil.shellquote(arg) for arg in cmdline] |
|
218 | cmdline = [procutil.shellquote(arg) for arg in cmdline] | |
217 | cmdline += ['>', os.devnull, '2>', os.devnull] |
|
219 | cmdline += [b'>', os.devnull, b'2>', os.devnull] | |
218 | cmdline = procutil.quotecommand(' '.join(cmdline)) |
|
220 | cmdline = procutil.quotecommand(b' '.join(cmdline)) | |
219 | self.ui.debug(cmdline, '\n') |
|
221 | self.ui.debug(cmdline, b'\n') | |
220 | return os.system(pycompat.rapply(procutil.tonativestr, cmdline)) |
|
222 | return os.system(pycompat.rapply(procutil.tonativestr, cmdline)) | |
221 |
|
223 | |||
222 | def _update(self, rev): |
|
224 | def _update(self, rev): | |
223 | self.ui.debug('applying revision %s...\n' % rev) |
|
225 | self.ui.debug(b'applying revision %s...\n' % rev) | |
224 | changeset, status = self.runlines('replay', '-d', self.tmppath, rev) |
|
226 | changeset, status = self.runlines(b'replay', b'-d', self.tmppath, rev) | |
225 | if status: |
|
227 | if status: | |
226 | # Something went wrong while merging (baz or tla |
|
228 | # Something went wrong while merging (baz or tla | |
227 | # issue?), get latest revision and try from there |
|
229 | # issue?), get latest revision and try from there | |
@@ -230,7 +232,7 b' class gnuarch_source(common.converter_so' | |||||
230 | else: |
|
232 | else: | |
231 | old_rev = self.parents[rev][0] |
|
233 | old_rev = self.parents[rev][0] | |
232 | self.ui.debug( |
|
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 | self._parsechangeset(changeset, rev) |
|
237 | self._parsechangeset(changeset, rev) | |
236 |
|
238 | |||
@@ -239,16 +241,16 b' class gnuarch_source(common.converter_so' | |||||
239 | if stat.S_ISLNK(mode): |
|
241 | if stat.S_ISLNK(mode): | |
240 | data = util.readlink(os.path.join(self.tmppath, name)) |
|
242 | data = util.readlink(os.path.join(self.tmppath, name)) | |
241 | if mode: |
|
243 | if mode: | |
242 | mode = 'l' |
|
244 | mode = b'l' | |
243 | else: |
|
245 | else: | |
244 | mode = '' |
|
246 | mode = b'' | |
245 | else: |
|
247 | else: | |
246 | data = util.readfile(os.path.join(self.tmppath, name)) |
|
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 | return data, mode |
|
250 | return data, mode | |
249 |
|
251 | |||
250 | def _exclude(self, name): |
|
252 | def _exclude(self, name): | |
251 | exclude = ['{arch}', '.arch-ids', '.arch-inventory'] |
|
253 | exclude = [b'{arch}', b'.arch-ids', b'.arch-inventory'] | |
252 | for exc in exclude: |
|
254 | for exc in exclude: | |
253 | if name.find(exc) != -1: |
|
255 | if name.find(exc) != -1: | |
254 | return True |
|
256 | return True | |
@@ -282,15 +284,15 b' class gnuarch_source(common.converter_so' | |||||
282 | return changes, copies |
|
284 | return changes, copies | |
283 |
|
285 | |||
284 | def _obtainrevision(self, rev): |
|
286 | def _obtainrevision(self, rev): | |
285 | self.ui.debug('obtaining revision %s...\n' % rev) |
|
287 | self.ui.debug(b'obtaining revision %s...\n' % rev) | |
286 | output = self._execute('get', rev, self.tmppath) |
|
288 | output = self._execute(b'get', rev, self.tmppath) | |
287 | self.checkexit(output) |
|
289 | self.checkexit(output) | |
288 | self.ui.debug('analyzing revision %s...\n' % rev) |
|
290 | self.ui.debug(b'analyzing revision %s...\n' % rev) | |
289 | files = self._readcontents(self.tmppath) |
|
291 | files = self._readcontents(self.tmppath) | |
290 | self.changes[rev].add_files += files |
|
292 | self.changes[rev].add_files += files | |
291 |
|
293 | |||
292 | def _stripbasepath(self, path): |
|
294 | def _stripbasepath(self, path): | |
293 | if path.startswith('./'): |
|
295 | if path.startswith(b'./'): | |
294 | return path[2:] |
|
296 | return path[2:] | |
295 | return path |
|
297 | return path | |
296 |
|
298 | |||
@@ -300,73 +302,73 b' class gnuarch_source(common.converter_so' | |||||
300 |
|
302 | |||
301 | # Commit date |
|
303 | # Commit date | |
302 | self.changes[rev].date = dateutil.datestr( |
|
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 | # Commit author |
|
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 | # Commit description |
|
311 | # Commit description | |
310 | self.changes[rev].summary = '\n\n'.join( |
|
312 | self.changes[rev].summary = b'\n\n'.join( | |
311 | (catlog['Summary'], catlog.get_payload()) |
|
313 | (catlog[b'Summary'], catlog.get_payload()) | |
312 | ) |
|
314 | ) | |
313 | self.changes[rev].summary = self.recode(self.changes[rev].summary) |
|
315 | self.changes[rev].summary = self.recode(self.changes[rev].summary) | |
314 |
|
316 | |||
315 | # Commit revision origin when dealing with a branch or tag |
|
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 | self.changes[rev].continuationof = self.recode( |
|
319 | self.changes[rev].continuationof = self.recode( | |
318 | catlog['Continuation-of'] |
|
320 | catlog[b'Continuation-of'] | |
319 | ) |
|
321 | ) | |
320 | except Exception: |
|
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 | def _parsechangeset(self, data, rev): |
|
325 | def _parsechangeset(self, data, rev): | |
324 | for l in data: |
|
326 | for l in data: | |
325 | l = l.strip() |
|
327 | l = l.strip() | |
326 | # Added file (ignore added directory) |
|
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 | file = self._stripbasepath(l[1:].strip()) |
|
330 | file = self._stripbasepath(l[1:].strip()) | |
329 | if not self._exclude(file): |
|
331 | if not self._exclude(file): | |
330 | self.changes[rev].add_files.append(file) |
|
332 | self.changes[rev].add_files.append(file) | |
331 | # Deleted file (ignore deleted directory) |
|
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 | file = self._stripbasepath(l[1:].strip()) |
|
335 | file = self._stripbasepath(l[1:].strip()) | |
334 | if not self._exclude(file): |
|
336 | if not self._exclude(file): | |
335 | self.changes[rev].del_files.append(file) |
|
337 | self.changes[rev].del_files.append(file) | |
336 | # Modified binary file |
|
338 | # Modified binary file | |
337 | elif l.startswith('Mb'): |
|
339 | elif l.startswith(b'Mb'): | |
338 | file = self._stripbasepath(l[2:].strip()) |
|
340 | file = self._stripbasepath(l[2:].strip()) | |
339 | if not self._exclude(file): |
|
341 | if not self._exclude(file): | |
340 | self.changes[rev].mod_files.append(file) |
|
342 | self.changes[rev].mod_files.append(file) | |
341 | # Modified link |
|
343 | # Modified link | |
342 | elif l.startswith('M->'): |
|
344 | elif l.startswith(b'M->'): | |
343 | file = self._stripbasepath(l[3:].strip()) |
|
345 | file = self._stripbasepath(l[3:].strip()) | |
344 | if not self._exclude(file): |
|
346 | if not self._exclude(file): | |
345 | self.changes[rev].mod_files.append(file) |
|
347 | self.changes[rev].mod_files.append(file) | |
346 | # Modified file |
|
348 | # Modified file | |
347 | elif l.startswith('M'): |
|
349 | elif l.startswith(b'M'): | |
348 | file = self._stripbasepath(l[1:].strip()) |
|
350 | file = self._stripbasepath(l[1:].strip()) | |
349 | if not self._exclude(file): |
|
351 | if not self._exclude(file): | |
350 | self.changes[rev].mod_files.append(file) |
|
352 | self.changes[rev].mod_files.append(file) | |
351 | # Renamed file (or link) |
|
353 | # Renamed file (or link) | |
352 | elif l.startswith('=>'): |
|
354 | elif l.startswith(b'=>'): | |
353 | files = l[2:].strip().split(' ') |
|
355 | files = l[2:].strip().split(b' ') | |
354 | if len(files) == 1: |
|
356 | if len(files) == 1: | |
355 | files = l[2:].strip().split('\t') |
|
357 | files = l[2:].strip().split(b'\t') | |
356 | src = self._stripbasepath(files[0]) |
|
358 | src = self._stripbasepath(files[0]) | |
357 | dst = self._stripbasepath(files[1]) |
|
359 | dst = self._stripbasepath(files[1]) | |
358 | if not self._exclude(src) and not self._exclude(dst): |
|
360 | if not self._exclude(src) and not self._exclude(dst): | |
359 | self.changes[rev].ren_files[src] = dst |
|
361 | self.changes[rev].ren_files[src] = dst | |
360 | # Conversion from file to link or from link to file (modified) |
|
362 | # Conversion from file to link or from link to file (modified) | |
361 | elif l.startswith('ch'): |
|
363 | elif l.startswith(b'ch'): | |
362 | file = self._stripbasepath(l[2:].strip()) |
|
364 | file = self._stripbasepath(l[2:].strip()) | |
363 | if not self._exclude(file): |
|
365 | if not self._exclude(file): | |
364 | self.changes[rev].mod_files.append(file) |
|
366 | self.changes[rev].mod_files.append(file) | |
365 | # Renamed directory |
|
367 | # Renamed directory | |
366 | elif l.startswith('/>'): |
|
368 | elif l.startswith(b'/>'): | |
367 | dirs = l[2:].strip().split(' ') |
|
369 | dirs = l[2:].strip().split(b' ') | |
368 | if len(dirs) == 1: |
|
370 | if len(dirs) == 1: | |
369 | dirs = l[2:].strip().split('\t') |
|
371 | dirs = l[2:].strip().split(b'\t') | |
370 | src = self._stripbasepath(dirs[0]) |
|
372 | src = self._stripbasepath(dirs[0]) | |
371 | dst = self._stripbasepath(dirs[1]) |
|
373 | dst = self._stripbasepath(dirs[1]) | |
372 | if not self._exclude(src) and not self._exclude(dst): |
|
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 | class mercurial_sink(common.converter_sink): |
|
51 | class mercurial_sink(common.converter_sink): | |
52 | def __init__(self, ui, repotype, path): |
|
52 | def __init__(self, ui, repotype, path): | |
53 | common.converter_sink.__init__(self, ui, repotype, path) |
|
53 | common.converter_sink.__init__(self, ui, repotype, path) | |
54 | self.branchnames = ui.configbool('convert', 'hg.usebranchnames') |
|
54 | self.branchnames = ui.configbool(b'convert', b'hg.usebranchnames') | |
55 | self.clonebranches = ui.configbool('convert', 'hg.clonebranches') |
|
55 | self.clonebranches = ui.configbool(b'convert', b'hg.clonebranches') | |
56 | self.tagsbranch = ui.config('convert', 'hg.tagsbranch') |
|
56 | self.tagsbranch = ui.config(b'convert', b'hg.tagsbranch') | |
57 | self.lastbranch = None |
|
57 | self.lastbranch = None | |
58 | if os.path.isdir(path) and len(os.listdir(path)) > 0: |
|
58 | if os.path.isdir(path) and len(os.listdir(path)) > 0: | |
59 | try: |
|
59 | try: | |
60 | self.repo = hg.repository(self.ui, path) |
|
60 | self.repo = hg.repository(self.ui, path) | |
61 | if not self.repo.local(): |
|
61 | if not self.repo.local(): | |
62 | raise NoRepo( |
|
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 | except error.RepoError as err: |
|
65 | except error.RepoError as err: | |
66 | ui.traceback() |
|
66 | ui.traceback() | |
67 | raise NoRepo(err.args[0]) |
|
67 | raise NoRepo(err.args[0]) | |
68 | else: |
|
68 | else: | |
69 | try: |
|
69 | try: | |
70 | ui.status(_('initializing destination %s repository\n') % path) |
|
70 | ui.status(_(b'initializing destination %s repository\n') % path) | |
71 | self.repo = hg.repository(self.ui, path, create=True) |
|
71 | self.repo = hg.repository(self.ui, path, create=True) | |
72 | if not self.repo.local(): |
|
72 | if not self.repo.local(): | |
73 | raise NoRepo( |
|
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 | self.created.append(path) |
|
76 | self.created.append(path) | |
77 | except error.RepoError: |
|
77 | except error.RepoError: | |
78 | ui.traceback() |
|
78 | ui.traceback() | |
79 | raise NoRepo( |
|
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 | self.lock = None |
|
82 | self.lock = None | |
83 | self.wlock = None |
|
83 | self.wlock = None | |
@@ -85,22 +85,22 b' class mercurial_sink(common.converter_si' | |||||
85 | self.subrevmaps = {} |
|
85 | self.subrevmaps = {} | |
86 |
|
86 | |||
87 | def before(self): |
|
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 | self.wlock = self.repo.wlock() |
|
89 | self.wlock = self.repo.wlock() | |
90 | self.lock = self.repo.lock() |
|
90 | self.lock = self.repo.lock() | |
91 |
|
91 | |||
92 | def after(self): |
|
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 | if self.lock: |
|
94 | if self.lock: | |
95 | self.lock.release() |
|
95 | self.lock.release() | |
96 | if self.wlock: |
|
96 | if self.wlock: | |
97 | self.wlock.release() |
|
97 | self.wlock.release() | |
98 |
|
98 | |||
99 | def revmapfile(self): |
|
99 | def revmapfile(self): | |
100 | return self.repo.vfs.join("shamap") |
|
100 | return self.repo.vfs.join(b"shamap") | |
101 |
|
101 | |||
102 | def authorfile(self): |
|
102 | def authorfile(self): | |
103 | return self.repo.vfs.join("authormap") |
|
103 | return self.repo.vfs.join(b"authormap") | |
104 |
|
104 | |||
105 | def setbranch(self, branch, pbranches): |
|
105 | def setbranch(self, branch, pbranches): | |
106 | if not self.clonebranches: |
|
106 | if not self.clonebranches: | |
@@ -109,8 +109,8 b' class mercurial_sink(common.converter_si' | |||||
109 | setbranch = branch != self.lastbranch |
|
109 | setbranch = branch != self.lastbranch | |
110 | self.lastbranch = branch |
|
110 | self.lastbranch = branch | |
111 | if not branch: |
|
111 | if not branch: | |
112 | branch = 'default' |
|
112 | branch = b'default' | |
113 | pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches] |
|
113 | pbranches = [(b[0], b[1] and b[1] or b'default') for b in pbranches] | |
114 |
|
114 | |||
115 | branchpath = os.path.join(self.path, branch) |
|
115 | branchpath = os.path.join(self.path, branch) | |
116 | if setbranch: |
|
116 | if setbranch: | |
@@ -135,7 +135,9 b' class mercurial_sink(common.converter_si' | |||||
135 | for pbranch, heads in sorted(missings.iteritems()): |
|
135 | for pbranch, heads in sorted(missings.iteritems()): | |
136 | pbranchpath = os.path.join(self.path, pbranch) |
|
136 | pbranchpath = os.path.join(self.path, pbranch) | |
137 | prepo = hg.peer(self.ui, {}, pbranchpath) |
|
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 | exchange.pull( |
|
141 | exchange.pull( | |
140 | self.repo, prepo, [prepo.lookup(h) for h in heads] |
|
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 | def _rewritetags(self, source, revmap, data): |
|
146 | def _rewritetags(self, source, revmap, data): | |
145 | fp = stringio() |
|
147 | fp = stringio() | |
146 | for line in data.splitlines(): |
|
148 | for line in data.splitlines(): | |
147 | s = line.split(' ', 1) |
|
149 | s = line.split(b' ', 1) | |
148 | if len(s) != 2: |
|
150 | if len(s) != 2: | |
149 | self.ui.warn(_('invalid tag entry: "%s"\n') % line) |
|
151 | self.ui.warn(_(b'invalid tag entry: "%s"\n') % line) | |
150 | fp.write('%s\n' % line) # Bogus, but keep for hash stability |
|
152 | fp.write(b'%s\n' % line) # Bogus, but keep for hash stability | |
151 | continue |
|
153 | continue | |
152 | revid = revmap.get(source.lookuprev(s[0])) |
|
154 | revid = revmap.get(source.lookuprev(s[0])) | |
153 | if not revid: |
|
155 | if not revid: | |
@@ -155,16 +157,16 b' class mercurial_sink(common.converter_si' | |||||
155 | revid = s[0] |
|
157 | revid = s[0] | |
156 | else: |
|
158 | else: | |
157 | # missing, but keep for hash stability |
|
159 | # missing, but keep for hash stability | |
158 | self.ui.warn(_('missing tag entry: "%s"\n') % line) |
|
160 | self.ui.warn(_(b'missing tag entry: "%s"\n') % line) | |
159 | fp.write('%s\n' % line) |
|
161 | fp.write(b'%s\n' % line) | |
160 | continue |
|
162 | continue | |
161 | fp.write('%s %s\n' % (revid, s[1])) |
|
163 | fp.write(b'%s %s\n' % (revid, s[1])) | |
162 | return fp.getvalue() |
|
164 | return fp.getvalue() | |
163 |
|
165 | |||
164 | def _rewritesubstate(self, source, data): |
|
166 | def _rewritesubstate(self, source, data): | |
165 | fp = stringio() |
|
167 | fp = stringio() | |
166 | for line in data.splitlines(): |
|
168 | for line in data.splitlines(): | |
167 | s = line.split(' ', 1) |
|
169 | s = line.split(b' ', 1) | |
168 | if len(s) != 2: |
|
170 | if len(s) != 2: | |
169 | continue |
|
171 | continue | |
170 |
|
172 | |||
@@ -174,7 +176,7 b' class mercurial_sink(common.converter_si' | |||||
174 | revmap = self.subrevmaps.get(subpath) |
|
176 | revmap = self.subrevmaps.get(subpath) | |
175 | if revmap is None: |
|
177 | if revmap is None: | |
176 | revmap = mapfile( |
|
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 | self.subrevmaps[subpath] = revmap |
|
181 | self.subrevmaps[subpath] = revmap | |
180 |
|
182 | |||
@@ -182,9 +184,9 b' class mercurial_sink(common.converter_si' | |||||
182 | # need to be converted, in which case they can be cloned |
|
184 | # need to be converted, in which case they can be cloned | |
183 | # into place instead of converted. Therefore, only warn |
|
185 | # into place instead of converted. Therefore, only warn | |
184 | # once. |
|
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 | if len(revmap) == 0: |
|
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 | if self.repo.wvfs.exists(sub): |
|
191 | if self.repo.wvfs.exists(sub): | |
190 | self.ui.warn(msg % subpath) |
|
192 | self.ui.warn(msg % subpath) | |
@@ -193,13 +195,13 b' class mercurial_sink(common.converter_si' | |||||
193 | if not newid: |
|
195 | if not newid: | |
194 | if len(revmap) > 0: |
|
196 | if len(revmap) > 0: | |
195 | self.ui.warn( |
|
197 | self.ui.warn( | |
196 | _("%s is missing from %s/.hg/shamap\n") |
|
198 | _(b"%s is missing from %s/.hg/shamap\n") | |
197 | % (revid, subpath) |
|
199 | % (revid, subpath) | |
198 | ) |
|
200 | ) | |
199 | else: |
|
201 | else: | |
200 | revid = newid |
|
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 | return fp.getvalue() |
|
206 | return fp.getvalue() | |
205 |
|
207 | |||
@@ -232,16 +234,16 b' class mercurial_sink(common.converter_si' | |||||
232 |
|
234 | |||
233 | # If the file requires actual merging, abort. We don't have enough |
|
235 | # If the file requires actual merging, abort. We don't have enough | |
234 | # context to resolve merges correctly. |
|
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 | raise error.Abort( |
|
238 | raise error.Abort( | |
237 | _( |
|
239 | _( | |
238 | "unable to convert merge commit " |
|
240 | b"unable to convert merge commit " | |
239 | "since target parents do not merge cleanly (file " |
|
241 | b"since target parents do not merge cleanly (file " | |
240 | "%s, parents %s and %s)" |
|
242 | b"%s, parents %s and %s)" | |
241 | ) |
|
243 | ) | |
242 | % (file, p1ctx, p2ctx) |
|
244 | % (file, p1ctx, p2ctx) | |
243 | ) |
|
245 | ) | |
244 | elif action == 'k': |
|
246 | elif action == b'k': | |
245 | # 'keep' means nothing changed from p1 |
|
247 | # 'keep' means nothing changed from p1 | |
246 | continue |
|
248 | continue | |
247 | else: |
|
249 | else: | |
@@ -255,7 +257,7 b' class mercurial_sink(common.converter_si' | |||||
255 |
|
257 | |||
256 | def getfilectx(repo, memctx, f): |
|
258 | def getfilectx(repo, memctx, f): | |
257 | if p2ctx and f in p2files and f not in copies: |
|
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 | try: |
|
261 | try: | |
260 | return p2ctx[f] |
|
262 | return p2ctx[f] | |
261 | except error.ManifestLookupError: |
|
263 | except error.ManifestLookupError: | |
@@ -269,17 +271,17 b' class mercurial_sink(common.converter_si' | |||||
269 | data, mode = source.getfile(f, v) |
|
271 | data, mode = source.getfile(f, v) | |
270 | if data is None: |
|
272 | if data is None: | |
271 | return None |
|
273 | return None | |
272 | if f == '.hgtags': |
|
274 | if f == b'.hgtags': | |
273 | data = self._rewritetags(source, revmap, data) |
|
275 | data = self._rewritetags(source, revmap, data) | |
274 | if f == '.hgsubstate': |
|
276 | if f == b'.hgsubstate': | |
275 | data = self._rewritesubstate(source, data) |
|
277 | data = self._rewritesubstate(source, data) | |
276 | return context.memfilectx( |
|
278 | return context.memfilectx( | |
277 | self.repo, |
|
279 | self.repo, | |
278 | memctx, |
|
280 | memctx, | |
279 | f, |
|
281 | f, | |
280 | data, |
|
282 | data, | |
281 | 'l' in mode, |
|
283 | b'l' in mode, | |
282 | 'x' in mode, |
|
284 | b'x' in mode, | |
283 | copies.get(f), |
|
285 | copies.get(f), | |
284 | ) |
|
286 | ) | |
285 |
|
287 | |||
@@ -310,15 +312,15 b' class mercurial_sink(common.converter_si' | |||||
310 |
|
312 | |||
311 | extra = commit.extra.copy() |
|
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 | if sourcename: |
|
316 | if sourcename: | |
315 | extra['convert_source'] = sourcename |
|
317 | extra[b'convert_source'] = sourcename | |
316 |
|
318 | |||
317 | for label in ( |
|
319 | for label in ( | |
318 | 'source', |
|
320 | b'source', | |
319 | 'transplant_source', |
|
321 | b'transplant_source', | |
320 | 'rebase_source', |
|
322 | b'rebase_source', | |
321 | 'intermediate-source', |
|
323 | b'intermediate-source', | |
322 | ): |
|
324 | ): | |
323 | node = extra.get(label) |
|
325 | node = extra.get(label) | |
324 |
|
326 | |||
@@ -326,20 +328,20 b' class mercurial_sink(common.converter_si' | |||||
326 | continue |
|
328 | continue | |
327 |
|
329 | |||
328 | # Only transplant stores its reference in binary |
|
330 | # Only transplant stores its reference in binary | |
329 | if label == 'transplant_source': |
|
331 | if label == b'transplant_source': | |
330 | node = nodemod.hex(node) |
|
332 | node = nodemod.hex(node) | |
331 |
|
333 | |||
332 | newrev = revmap.get(node) |
|
334 | newrev = revmap.get(node) | |
333 | if newrev is not None: |
|
335 | if newrev is not None: | |
334 | if label == 'transplant_source': |
|
336 | if label == b'transplant_source': | |
335 | newrev = nodemod.bin(newrev) |
|
337 | newrev = nodemod.bin(newrev) | |
336 |
|
338 | |||
337 | extra[label] = newrev |
|
339 | extra[label] = newrev | |
338 |
|
340 | |||
339 | if self.branchnames and commit.branch: |
|
341 | if self.branchnames and commit.branch: | |
340 | extra['branch'] = commit.branch |
|
342 | extra[b'branch'] = commit.branch | |
341 | if commit.rev and commit.saverev: |
|
343 | if commit.rev and commit.saverev: | |
342 | extra['convert_revision'] = commit.rev |
|
344 | extra[b'convert_revision'] = commit.rev | |
343 |
|
345 | |||
344 | while parents: |
|
346 | while parents: | |
345 | p1 = p2 |
|
347 | p1 = p2 | |
@@ -373,14 +375,14 b' class mercurial_sink(common.converter_si' | |||||
373 | # We won't know if the conversion changes the node until after the |
|
375 | # We won't know if the conversion changes the node until after the | |
374 | # commit, so copy the source's phase for now. |
|
376 | # commit, so copy the source's phase for now. | |
375 | self.repo.ui.setconfig( |
|
377 | self.repo.ui.setconfig( | |
376 | 'phases', |
|
378 | b'phases', | |
377 | 'new-commit', |
|
379 | b'new-commit', | |
378 | phases.phasenames[commit.phase], |
|
380 | phases.phasenames[commit.phase], | |
379 | 'convert', |
|
381 | b'convert', | |
380 | ) |
|
382 | ) | |
381 |
|
383 | |||
382 | with self.repo.transaction("convert") as tr: |
|
384 | with self.repo.transaction(b"convert") as tr: | |
383 | if self.repo.ui.config('convert', 'hg.preserve-hash'): |
|
385 | if self.repo.ui.config(b'convert', b'hg.preserve-hash'): | |
384 | origctx = commit.ctx |
|
386 | origctx = commit.ctx | |
385 | else: |
|
387 | else: | |
386 | origctx = None |
|
388 | origctx = None | |
@@ -396,15 +398,15 b' class mercurial_sink(common.converter_si' | |||||
396 | self.repo, tr, phases.draft, [ctx.node()] |
|
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 | p2 = node |
|
402 | p2 = node | |
401 |
|
403 | |||
402 | if self.filemapmode and nparents == 1: |
|
404 | if self.filemapmode and nparents == 1: | |
403 | man = self.repo.manifestlog.getstorage(b'') |
|
405 | man = self.repo.manifestlog.getstorage(b'') | |
404 | mnode = self.repo.changelog.read(nodemod.bin(p2))[0] |
|
406 | mnode = self.repo.changelog.read(nodemod.bin(p2))[0] | |
405 | closed = 'close' in commit.extra |
|
407 | closed = b'close' in commit.extra | |
406 | if not closed and not man.cmp(m1node, man.revision(mnode)): |
|
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 | self.repo.rollback(force=True) |
|
410 | self.repo.rollback(force=True) | |
409 | return parent |
|
411 | return parent | |
410 | return p2 |
|
412 | return p2 | |
@@ -416,13 +418,13 b' class mercurial_sink(common.converter_si' | |||||
416 | oldlines = set() |
|
418 | oldlines = set() | |
417 | for branch, heads in self.repo.branchmap().iteritems(): |
|
419 | for branch, heads in self.repo.branchmap().iteritems(): | |
418 | for h in heads: |
|
420 | for h in heads: | |
419 | if '.hgtags' in self.repo[h]: |
|
421 | if b'.hgtags' in self.repo[h]: | |
420 | oldlines.update( |
|
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 | oldlines = sorted(list(oldlines)) |
|
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 | if newlines == oldlines: |
|
428 | if newlines == oldlines: | |
427 | return None, None |
|
429 | return None, None | |
428 |
|
430 | |||
@@ -430,12 +432,12 b' class mercurial_sink(common.converter_si' | |||||
430 | oldtags = set() |
|
432 | oldtags = set() | |
431 | newtags = set() |
|
433 | newtags = set() | |
432 | for line in oldlines: |
|
434 | for line in oldlines: | |
433 | s = line.strip().split(' ', 1) |
|
435 | s = line.strip().split(b' ', 1) | |
434 | if len(s) != 2: |
|
436 | if len(s) != 2: | |
435 | continue |
|
437 | continue | |
436 | oldtags.add(s[1]) |
|
438 | oldtags.add(s[1]) | |
437 | for line in newlines: |
|
439 | for line in newlines: | |
438 | s = line.strip().split(' ', 1) |
|
440 | s = line.strip().split(b' ', 1) | |
439 | if len(s) != 2: |
|
441 | if len(s) != 2: | |
440 | continue |
|
442 | continue | |
441 | if s[1] not in oldtags: |
|
443 | if s[1] not in oldtags: | |
@@ -444,21 +446,21 b' class mercurial_sink(common.converter_si' | |||||
444 | if not newtags: |
|
446 | if not newtags: | |
445 | return None, None |
|
447 | return None, None | |
446 |
|
448 | |||
447 | data = "".join(newlines) |
|
449 | data = b"".join(newlines) | |
448 |
|
450 | |||
449 | def getfilectx(repo, memctx, f): |
|
451 | def getfilectx(repo, memctx, f): | |
450 | return context.memfilectx(repo, memctx, f, data, False, False, None) |
|
452 | return context.memfilectx(repo, memctx, f, data, False, False, None) | |
451 |
|
453 | |||
452 | self.ui.status(_("updating tags\n")) |
|
454 | self.ui.status(_(b"updating tags\n")) | |
453 | date = "%d 0" % int(time.mktime(time.gmtime())) |
|
455 | date = b"%d 0" % int(time.mktime(time.gmtime())) | |
454 | extra = {'branch': self.tagsbranch} |
|
456 | extra = {b'branch': self.tagsbranch} | |
455 | ctx = context.memctx( |
|
457 | ctx = context.memctx( | |
456 | self.repo, |
|
458 | self.repo, | |
457 | (tagparent, None), |
|
459 | (tagparent, None), | |
458 | "update tags", |
|
460 | b"update tags", | |
459 | [".hgtags"], |
|
461 | [b".hgtags"], | |
460 | getfilectx, |
|
462 | getfilectx, | |
461 | "convert-repo", |
|
463 | b"convert-repo", | |
462 | date, |
|
464 | date, | |
463 | extra, |
|
465 | extra, | |
464 | ) |
|
466 | ) | |
@@ -475,8 +477,8 b' class mercurial_sink(common.converter_si' | |||||
475 | try: |
|
477 | try: | |
476 | wlock = self.repo.wlock() |
|
478 | wlock = self.repo.wlock() | |
477 | lock = self.repo.lock() |
|
479 | lock = self.repo.lock() | |
478 | tr = self.repo.transaction('bookmark') |
|
480 | tr = self.repo.transaction(b'bookmark') | |
479 | self.ui.status(_("updating bookmarks\n")) |
|
481 | self.ui.status(_(b"updating bookmarks\n")) | |
480 | destmarks = self.repo._bookmarks |
|
482 | destmarks = self.repo._bookmarks | |
481 | changes = [ |
|
483 | changes = [ | |
482 | (bookmark, nodemod.bin(updatedbookmark[bookmark])) |
|
484 | (bookmark, nodemod.bin(updatedbookmark[bookmark])) | |
@@ -495,9 +497,9 b' class mercurial_sink(common.converter_si' | |||||
495 | if rev not in self.repo and self.clonebranches: |
|
497 | if rev not in self.repo and self.clonebranches: | |
496 | raise error.Abort( |
|
498 | raise error.Abort( | |
497 | _( |
|
499 | _( | |
498 | 'revision %s not found in destination ' |
|
500 | b'revision %s not found in destination ' | |
499 | 'repository (lookups with clonebranches=true ' |
|
501 | b'repository (lookups with clonebranches=true ' | |
500 | 'are not implemented)' |
|
502 | b'are not implemented)' | |
501 | ) |
|
503 | ) | |
502 | % rev |
|
504 | % rev | |
503 | ) |
|
505 | ) | |
@@ -507,9 +509,9 b' class mercurial_sink(common.converter_si' | |||||
507 | class mercurial_source(common.converter_source): |
|
509 | class mercurial_source(common.converter_source): | |
508 | def __init__(self, ui, repotype, path, revs=None): |
|
510 | def __init__(self, ui, repotype, path, revs=None): | |
509 | common.converter_source.__init__(self, ui, repotype, path, revs) |
|
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 | self.ignored = set() |
|
513 | self.ignored = set() | |
512 | self.saverev = ui.configbool('convert', 'hg.saverev') |
|
514 | self.saverev = ui.configbool(b'convert', b'hg.saverev') | |
513 | try: |
|
515 | try: | |
514 | self.repo = hg.repository(self.ui, path) |
|
516 | self.repo = hg.repository(self.ui, path) | |
515 | # try to provoke an exception if this isn't really a hg |
|
517 | # try to provoke an exception if this isn't really a hg | |
@@ -518,21 +520,21 b' class mercurial_source(common.converter_' | |||||
518 | raise error.RepoError |
|
520 | raise error.RepoError | |
519 | except error.RepoError: |
|
521 | except error.RepoError: | |
520 | ui.traceback() |
|
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 | self.lastrev = None |
|
524 | self.lastrev = None | |
523 | self.lastctx = None |
|
525 | self.lastctx = None | |
524 | self._changescache = None, None |
|
526 | self._changescache = None, None | |
525 | self.convertfp = None |
|
527 | self.convertfp = None | |
526 | # Restrict converted revisions to startrev descendants |
|
528 | # Restrict converted revisions to startrev descendants | |
527 | startnode = ui.config('convert', 'hg.startrev') |
|
529 | startnode = ui.config(b'convert', b'hg.startrev') | |
528 | hgrevs = ui.config('convert', 'hg.revs') |
|
530 | hgrevs = ui.config(b'convert', b'hg.revs') | |
529 | if hgrevs is None: |
|
531 | if hgrevs is None: | |
530 | if startnode is not None: |
|
532 | if startnode is not None: | |
531 | try: |
|
533 | try: | |
532 | startnode = self.repo.lookup(startnode) |
|
534 | startnode = self.repo.lookup(startnode) | |
533 | except error.RepoError: |
|
535 | except error.RepoError: | |
534 | raise error.Abort( |
|
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 | startrev = self.repo.changelog.rev(startnode) |
|
539 | startrev = self.repo.changelog.rev(startnode) | |
538 | children = {startnode: 1} |
|
540 | children = {startnode: 1} | |
@@ -548,7 +550,10 b' class mercurial_source(common.converter_' | |||||
548 | else: |
|
550 | else: | |
549 | if revs or startnode is not None: |
|
551 | if revs or startnode is not None: | |
550 | raise error.Abort( |
|
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 | nodes = set() |
|
558 | nodes = set() | |
554 | parents = set() |
|
559 | parents = set() | |
@@ -635,7 +640,7 b' class mercurial_source(common.converter_' | |||||
635 | if not self.ignoreerrors: |
|
640 | if not self.ignoreerrors: | |
636 | raise |
|
641 | raise | |
637 | self.ignored.add(name) |
|
642 | self.ignored.add(name) | |
638 | self.ui.warn(_('ignoring: %s\n') % e) |
|
643 | self.ui.warn(_(b'ignoring: %s\n') % e) | |
639 | return copies |
|
644 | return copies | |
640 |
|
645 | |||
641 | def getcommit(self, rev): |
|
646 | def getcommit(self, rev): | |
@@ -647,7 +652,7 b' class mercurial_source(common.converter_' | |||||
647 |
|
652 | |||
648 | return common.commit( |
|
653 | return common.commit( | |
649 | author=ctx.user(), |
|
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 | desc=ctx.description(), |
|
656 | desc=ctx.description(), | |
652 | rev=crev, |
|
657 | rev=crev, | |
653 | parents=parents, |
|
658 | parents=parents, | |
@@ -668,7 +673,7 b' class mercurial_source(common.converter_' | |||||
668 | tags = [ |
|
673 | tags = [ | |
669 | t |
|
674 | t | |
670 | for t in self.repo.tagslist() |
|
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 | return dict( |
|
678 | return dict( | |
674 | [ |
|
679 | [ | |
@@ -696,15 +701,15 b' class mercurial_source(common.converter_' | |||||
696 |
|
701 | |||
697 | def converted(self, rev, destrev): |
|
702 | def converted(self, rev, destrev): | |
698 | if self.convertfp is None: |
|
703 | if self.convertfp is None: | |
699 | self.convertfp = open(self.repo.vfs.join('shamap'), 'ab') |
|
704 | self.convertfp = open(self.repo.vfs.join(b'shamap'), b'ab') | |
700 | self.convertfp.write(util.tonativeeol('%s %s\n' % (destrev, rev))) |
|
705 | self.convertfp.write(util.tonativeeol(b'%s %s\n' % (destrev, rev))) | |
701 | self.convertfp.flush() |
|
706 | self.convertfp.flush() | |
702 |
|
707 | |||
703 | def before(self): |
|
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 | def after(self): |
|
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 | def hasnativeorder(self): |
|
714 | def hasnativeorder(self): | |
710 | return True |
|
715 | return True | |
@@ -721,6 +726,6 b' class mercurial_source(common.converter_' | |||||
721 | def getbookmarks(self): |
|
726 | def getbookmarks(self): | |
722 | return bookmarks.listbookmarks(self.repo) |
|
727 | return bookmarks.listbookmarks(self.repo) | |
723 |
|
728 | |||
724 | def checkrevformat(self, revstr, mapname='splicemap'): |
|
729 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
725 | """ Mercurial, revision string is a 40 byte hex """ |
|
730 | """ Mercurial, revision string is a 40 byte hex """ | |
726 | self.checkhexformat(revstr, mapname) |
|
731 | self.checkhexformat(revstr, mapname) |
@@ -26,11 +26,11 b' class monotone_source(common.converter_s' | |||||
26 | if revs and len(revs) > 1: |
|
26 | if revs and len(revs) > 1: | |
27 | raise error.Abort( |
|
27 | raise error.Abort( | |
28 | _( |
|
28 | _( | |
29 | 'monotone source does not support specifying ' |
|
29 | b'monotone source does not support specifying ' | |
30 | 'multiple revs' |
|
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 | self.ui = ui |
|
35 | self.ui = ui | |
36 | self.path = path |
|
36 | self.path = path | |
@@ -38,17 +38,17 b' class monotone_source(common.converter_s' | |||||
38 | self.revs = revs |
|
38 | self.revs = revs | |
39 |
|
39 | |||
40 | norepo = common.NoRepo( |
|
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 | # Could be a monotone repository (SQLite db file) |
|
44 | # Could be a monotone repository (SQLite db file) | |
45 | try: |
|
45 | try: | |
46 | f = open(path, 'rb') |
|
46 | f = open(path, b'rb') | |
47 | header = f.read(16) |
|
47 | header = f.read(16) | |
48 | f.close() |
|
48 | f.close() | |
49 | except IOError: |
|
49 | except IOError: | |
50 | header = '' |
|
50 | header = b'' | |
51 | if header != 'SQLite format 3\x00': |
|
51 | if header != b'SQLite format 3\x00': | |
52 | raise norepo |
|
52 | raise norepo | |
53 |
|
53 | |||
54 | # regular expressions for parsing monotone output |
|
54 | # regular expressions for parsing monotone output | |
@@ -58,24 +58,26 b' class monotone_source(common.converter_s' | |||||
58 | revision = br'\s+\[(\w+)\]\s*' |
|
58 | revision = br'\s+\[(\w+)\]\s*' | |
59 | lines = br'(?:.|\n)+' |
|
59 | lines = br'(?:.|\n)+' | |
60 |
|
60 | |||
61 | self.dir_re = re.compile(space + "dir" + name) |
|
61 | self.dir_re = re.compile(space + b"dir" + name) | |
62 |
self.file_re = re.compile( |
|
62 | self.file_re = re.compile( | |
|
63 | space + b"file" + name + b"content" + revision | |||
|
64 | ) | |||
63 | self.add_file_re = re.compile( |
|
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 | self.patch_re = re.compile( |
|
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) |
|
71 | self.rename_re = re.compile(space + b"rename" + name + b"to" + name) | |
70 | self.delete_re = re.compile(space + "delete" + name) |
|
72 | self.delete_re = re.compile(space + b"delete" + name) | |
71 | self.tag_re = re.compile(space + "tag" + name + "revision" + revision) |
|
73 | self.tag_re = re.compile(space + b"tag" + name + b"revision" + revision) | |
72 | self.cert_re = re.compile( |
|
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 | self.attr_execute_re = re.compile( |
|
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 | # cached data |
|
83 | # cached data | |
@@ -84,7 +86,7 b' class monotone_source(common.converter_s' | |||||
84 | self.files = None |
|
86 | self.files = None | |
85 | self.dirs = None |
|
87 | self.dirs = None | |
86 |
|
88 | |||
87 | common.checktool('mtn', abort=False) |
|
89 | common.checktool(b'mtn', abort=False) | |
88 |
|
90 | |||
89 | def mtnrun(self, *args, **kwargs): |
|
91 | def mtnrun(self, *args, **kwargs): | |
90 | if self.automatestdio: |
|
92 | if self.automatestdio: | |
@@ -94,27 +96,27 b' class monotone_source(common.converter_s' | |||||
94 |
|
96 | |||
95 | def mtnrunsingle(self, *args, **kwargs): |
|
97 | def mtnrunsingle(self, *args, **kwargs): | |
96 | kwargs[r'd'] = self.path |
|
98 | kwargs[r'd'] = self.path | |
97 | return self.run0('automate', *args, **kwargs) |
|
99 | return self.run0(b'automate', *args, **kwargs) | |
98 |
|
100 | |||
99 | def mtnrunstdio(self, *args, **kwargs): |
|
101 | def mtnrunstdio(self, *args, **kwargs): | |
100 | # Prepare the command in automate stdio format |
|
102 | # Prepare the command in automate stdio format | |
101 | kwargs = pycompat.byteskwargs(kwargs) |
|
103 | kwargs = pycompat.byteskwargs(kwargs) | |
102 | command = [] |
|
104 | command = [] | |
103 | for k, v in kwargs.iteritems(): |
|
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 | if v: |
|
107 | if v: | |
106 | command.append("%d:%s" % (len(v), v)) |
|
108 | command.append(b"%d:%s" % (len(v), v)) | |
107 | if command: |
|
109 | if command: | |
108 | command.insert(0, 'o') |
|
110 | command.insert(0, b'o') | |
109 | command.append('e') |
|
111 | command.append(b'e') | |
110 |
|
112 | |||
111 | command.append('l') |
|
113 | command.append(b'l') | |
112 | for arg in args: |
|
114 | for arg in args: | |
113 | command.append("%d:%s" % (len(arg), arg)) |
|
115 | command.append(b"%d:%s" % (len(arg), arg)) | |
114 | command.append('e') |
|
116 | command.append(b'e') | |
115 | command = ''.join(command) |
|
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 | self.mtnwritefp.write(command) |
|
120 | self.mtnwritefp.write(command) | |
119 | self.mtnwritefp.flush() |
|
121 | self.mtnwritefp.flush() | |
120 |
|
122 | |||
@@ -122,42 +124,44 b' class monotone_source(common.converter_s' | |||||
122 |
|
124 | |||
123 | def mtnstdioreadpacket(self): |
|
125 | def mtnstdioreadpacket(self): | |
124 | read = None |
|
126 | read = None | |
125 | commandnbr = '' |
|
127 | commandnbr = b'' | |
126 | while read != ':': |
|
128 | while read != b':': | |
127 | read = self.mtnreadfp.read(1) |
|
129 | read = self.mtnreadfp.read(1) | |
128 | if not read: |
|
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 | commandnbr += read |
|
132 | commandnbr += read | |
131 | commandnbr = commandnbr[:-1] |
|
133 | commandnbr = commandnbr[:-1] | |
132 |
|
134 | |||
133 | stream = self.mtnreadfp.read(1) |
|
135 | stream = self.mtnreadfp.read(1) | |
134 | if stream not in 'mewptl': |
|
136 | if stream not in b'mewptl': | |
135 | raise error.Abort(_('bad mtn packet - bad stream type %s') % stream) |
|
137 | raise error.Abort( | |
|
138 | _(b'bad mtn packet - bad stream type %s') % stream | |||
|
139 | ) | |||
136 |
|
140 | |||
137 | read = self.mtnreadfp.read(1) |
|
141 | read = self.mtnreadfp.read(1) | |
138 | if read != ':': |
|
142 | if read != b':': | |
139 | raise error.Abort(_('bad mtn packet - no divider before size')) |
|
143 | raise error.Abort(_(b'bad mtn packet - no divider before size')) | |
140 |
|
144 | |||
141 | read = None |
|
145 | read = None | |
142 | lengthstr = '' |
|
146 | lengthstr = b'' | |
143 | while read != ':': |
|
147 | while read != b':': | |
144 | read = self.mtnreadfp.read(1) |
|
148 | read = self.mtnreadfp.read(1) | |
145 | if not read: |
|
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 | lengthstr += read |
|
151 | lengthstr += read | |
148 | try: |
|
152 | try: | |
149 | length = pycompat.long(lengthstr[:-1]) |
|
153 | length = pycompat.long(lengthstr[:-1]) | |
150 | except TypeError: |
|
154 | except TypeError: | |
151 | raise error.Abort( |
|
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 | read = self.mtnreadfp.read(length) |
|
159 | read = self.mtnreadfp.read(length) | |
156 | if len(read) != length: |
|
160 | if len(read) != length: | |
157 | raise error.Abort( |
|
161 | raise error.Abort( | |
158 | _( |
|
162 | _( | |
159 | "bad mtn packet - unable to read full packet " |
|
163 | b"bad mtn packet - unable to read full packet " | |
160 | "read %s of %s" |
|
164 | b"read %s of %s" | |
161 | ) |
|
165 | ) | |
162 | % (len(read), length) |
|
166 | % (len(read), length) | |
163 | ) |
|
167 | ) | |
@@ -169,33 +173,33 b' class monotone_source(common.converter_s' | |||||
169 | while True: |
|
173 | while True: | |
170 | commandnbr, stream, length, output = self.mtnstdioreadpacket() |
|
174 | commandnbr, stream, length, output = self.mtnstdioreadpacket() | |
171 | self.ui.debug( |
|
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 | # End of command |
|
180 | # End of command | |
177 | if output != '0': |
|
181 | if output != b'0': | |
178 | raise error.Abort( |
|
182 | raise error.Abort( | |
179 | _("mtn command '%s' returned %s") % (command, output) |
|
183 | _(b"mtn command '%s' returned %s") % (command, output) | |
180 | ) |
|
184 | ) | |
181 | break |
|
185 | break | |
182 | elif stream in 'ew': |
|
186 | elif stream in b'ew': | |
183 | # Error, warning output |
|
187 | # Error, warning output | |
184 | self.ui.warn(_('%s error:\n') % self.command) |
|
188 | self.ui.warn(_(b'%s error:\n') % self.command) | |
185 | self.ui.warn(output) |
|
189 | self.ui.warn(output) | |
186 | elif stream == 'p': |
|
190 | elif stream == b'p': | |
187 | # Progress messages |
|
191 | # Progress messages | |
188 | self.ui.debug('mtn: ' + output) |
|
192 | self.ui.debug(b'mtn: ' + output) | |
189 | elif stream == 'm': |
|
193 | elif stream == b'm': | |
190 | # Main stream - command output |
|
194 | # Main stream - command output | |
191 | retval.append(output) |
|
195 | retval.append(output) | |
192 |
|
196 | |||
193 | return ''.join(retval) |
|
197 | return b''.join(retval) | |
194 |
|
198 | |||
195 | def mtnloadmanifest(self, rev): |
|
199 | def mtnloadmanifest(self, rev): | |
196 | if self.manifest_rev == rev: |
|
200 | if self.manifest_rev == rev: | |
197 | return |
|
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 | self.manifest_rev = rev |
|
203 | self.manifest_rev = rev | |
200 | self.files = {} |
|
204 | self.files = {} | |
201 | self.dirs = {} |
|
205 | self.dirs = {} | |
@@ -203,11 +207,11 b' class monotone_source(common.converter_s' | |||||
203 | for e in self.manifest: |
|
207 | for e in self.manifest: | |
204 | m = self.file_re.match(e) |
|
208 | m = self.file_re.match(e) | |
205 | if m: |
|
209 | if m: | |
206 | attr = "" |
|
210 | attr = b"" | |
207 | name = m.group(1) |
|
211 | name = m.group(1) | |
208 | node = m.group(2) |
|
212 | node = m.group(2) | |
209 | if self.attr_execute_re.match(e): |
|
213 | if self.attr_execute_re.match(e): | |
210 | attr += "x" |
|
214 | attr += b"x" | |
211 | self.files[name] = (node, attr) |
|
215 | self.files[name] = (node, attr) | |
212 | m = self.dir_re.match(e) |
|
216 | m = self.dir_re.match(e) | |
213 | if m: |
|
217 | if m: | |
@@ -224,12 +228,12 b' class monotone_source(common.converter_s' | |||||
224 |
|
228 | |||
225 | def mtngetcerts(self, rev): |
|
229 | def mtngetcerts(self, rev): | |
226 | certs = { |
|
230 | certs = { | |
227 | "author": "<missing>", |
|
231 | b"author": b"<missing>", | |
228 | "date": "<missing>", |
|
232 | b"date": b"<missing>", | |
229 | "changelog": "<missing>", |
|
233 | b"changelog": b"<missing>", | |
230 | "branch": "<missing>", |
|
234 | b"branch": b"<missing>", | |
231 | } |
|
235 | } | |
232 | certlist = self.mtnrun("certs", rev) |
|
236 | certlist = self.mtnrun(b"certs", rev) | |
233 | # mtn < 0.45: |
|
237 | # mtn < 0.45: | |
234 | # key "test@selenic.com" |
|
238 | # key "test@selenic.com" | |
235 | # mtn >= 0.45: |
|
239 | # mtn >= 0.45: | |
@@ -239,28 +243,28 b' class monotone_source(common.converter_s' | |||||
239 | m = self.cert_re.match(e) |
|
243 | m = self.cert_re.match(e) | |
240 | if m: |
|
244 | if m: | |
241 | name, value = m.groups() |
|
245 | name, value = m.groups() | |
242 | value = value.replace(br'\"', '"') |
|
246 | value = value.replace(br'\"', b'"') | |
243 | value = value.replace(br'\\', '\\') |
|
247 | value = value.replace(br'\\', b'\\') | |
244 | certs[name] = value |
|
248 | certs[name] = value | |
245 | # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306 |
|
249 | # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306 | |
246 | # and all times are stored in UTC |
|
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 | return certs |
|
252 | return certs | |
249 |
|
253 | |||
250 | # implement the converter_source interface: |
|
254 | # implement the converter_source interface: | |
251 |
|
255 | |||
252 | def getheads(self): |
|
256 | def getheads(self): | |
253 | if not self.revs: |
|
257 | if not self.revs: | |
254 | return self.mtnrun("leaves").splitlines() |
|
258 | return self.mtnrun(b"leaves").splitlines() | |
255 | else: |
|
259 | else: | |
256 | return self.revs |
|
260 | return self.revs | |
257 |
|
261 | |||
258 | def getchanges(self, rev, full): |
|
262 | def getchanges(self, rev, full): | |
259 | if full: |
|
263 | if full: | |
260 | raise error.Abort( |
|
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 | files = {} |
|
268 | files = {} | |
265 | ignoremove = {} |
|
269 | ignoremove = {} | |
266 | renameddirs = [] |
|
270 | renameddirs = [] | |
@@ -298,7 +302,7 b' class monotone_source(common.converter_s' | |||||
298 | for tofile in self.files: |
|
302 | for tofile in self.files: | |
299 | if tofile in ignoremove: |
|
303 | if tofile in ignoremove: | |
300 | continue |
|
304 | continue | |
301 | if tofile.startswith(todir + '/'): |
|
305 | if tofile.startswith(todir + b'/'): | |
302 | renamed[tofile] = fromdir + tofile[len(todir) :] |
|
306 | renamed[tofile] = fromdir + tofile[len(todir) :] | |
303 | # Avoid chained moves like: |
|
307 | # Avoid chained moves like: | |
304 | # d1(/a) => d3/d1(/a) |
|
308 | # d1(/a) => d3/d1(/a) | |
@@ -306,9 +310,9 b' class monotone_source(common.converter_s' | |||||
306 | ignoremove[tofile] = 1 |
|
310 | ignoremove[tofile] = 1 | |
307 | for tofile, fromfile in renamed.items(): |
|
311 | for tofile, fromfile in renamed.items(): | |
308 | self.ui.debug( |
|
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 | % (fromfile, tofile), |
|
314 | % (fromfile, tofile), | |
311 | '\n', |
|
315 | b'\n', | |
312 | ) |
|
316 | ) | |
313 | files[tofile] = rev |
|
317 | files[tofile] = rev | |
314 | copies[tofile] = fromfile |
|
318 | copies[tofile] = fromfile | |
@@ -321,32 +325,32 b' class monotone_source(common.converter_s' | |||||
321 | if not self.mtnisfile(name, rev): |
|
325 | if not self.mtnisfile(name, rev): | |
322 | return None, None |
|
326 | return None, None | |
323 | try: |
|
327 | try: | |
324 | data = self.mtnrun("get_file_of", name, r=rev) |
|
328 | data = self.mtnrun(b"get_file_of", name, r=rev) | |
325 | except Exception: |
|
329 | except Exception: | |
326 | return None, None |
|
330 | return None, None | |
327 | self.mtnloadmanifest(rev) |
|
331 | self.mtnloadmanifest(rev) | |
328 | node, attr = self.files.get(name, (None, "")) |
|
332 | node, attr = self.files.get(name, (None, b"")) | |
329 | return data, attr |
|
333 | return data, attr | |
330 |
|
334 | |||
331 | def getcommit(self, rev): |
|
335 | def getcommit(self, rev): | |
332 | extra = {} |
|
336 | extra = {} | |
333 | certs = self.mtngetcerts(rev) |
|
337 | certs = self.mtngetcerts(rev) | |
334 | if certs.get('suspend') == certs["branch"]: |
|
338 | if certs.get(b'suspend') == certs[b"branch"]: | |
335 | extra['close'] = 1 |
|
339 | extra[b'close'] = 1 | |
336 | dateformat = "%Y-%m-%dT%H:%M:%S" |
|
340 | dateformat = b"%Y-%m-%dT%H:%M:%S" | |
337 | return common.commit( |
|
341 | return common.commit( | |
338 | author=certs["author"], |
|
342 | author=certs[b"author"], | |
339 | date=dateutil.datestr(dateutil.strdate(certs["date"], dateformat)), |
|
343 | date=dateutil.datestr(dateutil.strdate(certs[b"date"], dateformat)), | |
340 | desc=certs["changelog"], |
|
344 | desc=certs[b"changelog"], | |
341 | rev=rev, |
|
345 | rev=rev, | |
342 | parents=self.mtnrun("parents", rev).splitlines(), |
|
346 | parents=self.mtnrun(b"parents", rev).splitlines(), | |
343 | branch=certs["branch"], |
|
347 | branch=certs[b"branch"], | |
344 | extra=extra, |
|
348 | extra=extra, | |
345 | ) |
|
349 | ) | |
346 |
|
350 | |||
347 | def gettags(self): |
|
351 | def gettags(self): | |
348 | tags = {} |
|
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 | m = self.tag_re.match(e) |
|
354 | m = self.tag_re.match(e) | |
351 | if m: |
|
355 | if m: | |
352 | tags[m.group(1)] = m.group(2) |
|
356 | tags[m.group(1)] = m.group(2) | |
@@ -360,42 +364,42 b' class monotone_source(common.converter_s' | |||||
360 | def before(self): |
|
364 | def before(self): | |
361 | # Check if we have a new enough version to use automate stdio |
|
365 | # Check if we have a new enough version to use automate stdio | |
362 | try: |
|
366 | try: | |
363 | versionstr = self.mtnrunsingle("interface_version") |
|
367 | versionstr = self.mtnrunsingle(b"interface_version") | |
364 | version = float(versionstr) |
|
368 | version = float(versionstr) | |
365 | except Exception: |
|
369 | except Exception: | |
366 | raise error.Abort( |
|
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 | if version >= 12.0: |
|
374 | if version >= 12.0: | |
371 | self.automatestdio = True |
|
375 | self.automatestdio = True | |
372 | self.ui.debug( |
|
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 | # launch the long-running automate stdio process |
|
380 | # launch the long-running automate stdio process | |
377 | self.mtnwritefp, self.mtnreadfp = self._run2( |
|
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 | # read the headers |
|
384 | # read the headers | |
381 | read = self.mtnreadfp.readline() |
|
385 | read = self.mtnreadfp.readline() | |
382 | if read != 'format-version: 2\n': |
|
386 | if read != b'format-version: 2\n': | |
383 | raise error.Abort( |
|
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 | read = self.mtnreadfp.readline() |
|
391 | read = self.mtnreadfp.readline() | |
388 | if not read: |
|
392 | if not read: | |
389 | raise error.Abort( |
|
393 | raise error.Abort( | |
390 | _( |
|
394 | _( | |
391 | "failed to reach end of mtn automate " |
|
395 | b"failed to reach end of mtn automate " | |
392 | "stdio headers" |
|
396 | b"stdio headers" | |
393 | ) |
|
397 | ) | |
394 | ) |
|
398 | ) | |
395 | else: |
|
399 | else: | |
396 | self.ui.debug( |
|
400 | self.ui.debug( | |
397 | "mtn automate version %s - not using automate stdio " |
|
401 | b"mtn automate version %s - not using automate stdio " | |
398 | "(automate >= 12.0 - mtn >= 0.46 is needed)\n" % version |
|
402 | b"(automate >= 12.0 - mtn >= 0.46 is needed)\n" % version | |
399 | ) |
|
403 | ) | |
400 |
|
404 | |||
401 | def after(self): |
|
405 | def after(self): |
@@ -24,7 +24,7 b' from . import common' | |||||
24 |
|
24 | |||
25 |
|
25 | |||
26 | def loaditer(f): |
|
26 | def loaditer(f): | |
27 | "Yield the dictionary objects generated by p4" |
|
27 | b"Yield the dictionary objects generated by p4" | |
28 | try: |
|
28 | try: | |
29 | while True: |
|
29 | while True: | |
30 | d = marshal.load(f) |
|
30 | d = marshal.load(f) | |
@@ -44,7 +44,12 b' def decodefilename(filename):' | |||||
44 | >>> decodefilename(b'//Depot/Directory/%2525/%2523/%23%40.%2A') |
|
44 | >>> decodefilename(b'//Depot/Directory/%2525/%2523/%23%40.%2A') | |
45 | '//Depot/Directory/%25/%23/#@.*' |
|
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 | for k, v in replacements: |
|
53 | for k, v in replacements: | |
49 | filename = filename.replace(k, v) |
|
54 | filename = filename.replace(k, v) | |
50 | return filename |
|
55 | return filename | |
@@ -57,16 +62,16 b' class p4_source(common.converter_source)' | |||||
57 |
|
62 | |||
58 | super(p4_source, self).__init__(ui, repotype, path, revs=revs) |
|
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 | raise common.NoRepo( |
|
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 | self.revmap = {} |
|
72 | self.revmap = {} | |
68 | self.encoding = self.ui.config( |
|
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 | self.re_type = re.compile( |
|
76 | self.re_type = re.compile( | |
72 | br"([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)" |
|
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 | if revs and len(revs) > 1: |
|
86 | if revs and len(revs) > 1: | |
82 | raise error.Abort( |
|
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 | def setrevmap(self, revmap): |
|
94 | def setrevmap(self, revmap): | |
@@ -97,18 +105,18 b' class p4_source(common.converter_source)' | |||||
97 | self.revmap = revmap |
|
105 | self.revmap = revmap | |
98 |
|
106 | |||
99 | def _parse_view(self, path): |
|
107 | def _parse_view(self, path): | |
100 | "Read changes affecting the path" |
|
108 | b"Read changes affecting the path" | |
101 | cmd = 'p4 -G changes -s submitted %s' % procutil.shellquote(path) |
|
109 | cmd = b'p4 -G changes -s submitted %s' % procutil.shellquote(path) | |
102 | stdout = procutil.popen(cmd, mode='rb') |
|
110 | stdout = procutil.popen(cmd, mode=b'rb') | |
103 | p4changes = {} |
|
111 | p4changes = {} | |
104 | for d in loaditer(stdout): |
|
112 | for d in loaditer(stdout): | |
105 | c = d.get("change", None) |
|
113 | c = d.get(b"change", None) | |
106 | if c: |
|
114 | if c: | |
107 | p4changes[c] = True |
|
115 | p4changes[c] = True | |
108 | return p4changes |
|
116 | return p4changes | |
109 |
|
117 | |||
110 | def _parse(self, ui, path): |
|
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 | p4changes = {} |
|
120 | p4changes = {} | |
113 | changeset = {} |
|
121 | changeset = {} | |
114 | files_map = {} |
|
122 | files_map = {} | |
@@ -117,29 +125,29 b' class p4_source(common.converter_source)' | |||||
117 | depotname = {} |
|
125 | depotname = {} | |
118 | heads = [] |
|
126 | heads = [] | |
119 |
|
127 | |||
120 | ui.status(_('reading p4 views\n')) |
|
128 | ui.status(_(b'reading p4 views\n')) | |
121 |
|
129 | |||
122 | # read client spec or view |
|
130 | # read client spec or view | |
123 | if "/" in path: |
|
131 | if b"/" in path: | |
124 | p4changes.update(self._parse_view(path)) |
|
132 | p4changes.update(self._parse_view(path)) | |
125 | if path.startswith("//") and path.endswith("/..."): |
|
133 | if path.startswith(b"//") and path.endswith(b"/..."): | |
126 | views = {path[:-3]: ""} |
|
134 | views = {path[:-3]: b""} | |
127 | else: |
|
135 | else: | |
128 | views = {"//": ""} |
|
136 | views = {b"//": b""} | |
129 | else: |
|
137 | else: | |
130 | cmd = 'p4 -G client -o %s' % procutil.shellquote(path) |
|
138 | cmd = b'p4 -G client -o %s' % procutil.shellquote(path) | |
131 | clientspec = marshal.load(procutil.popen(cmd, mode='rb')) |
|
139 | clientspec = marshal.load(procutil.popen(cmd, mode=b'rb')) | |
132 |
|
140 | |||
133 | views = {} |
|
141 | views = {} | |
134 | for client in clientspec: |
|
142 | for client in clientspec: | |
135 | if client.startswith("View"): |
|
143 | if client.startswith(b"View"): | |
136 | sview, cview = clientspec[client].split() |
|
144 | sview, cview = clientspec[client].split() | |
137 | p4changes.update(self._parse_view(sview)) |
|
145 | p4changes.update(self._parse_view(sview)) | |
138 | if sview.endswith("...") and cview.endswith("..."): |
|
146 | if sview.endswith(b"...") and cview.endswith(b"..."): | |
139 | sview = sview[:-3] |
|
147 | sview = sview[:-3] | |
140 | cview = cview[:-3] |
|
148 | cview = cview[:-3] | |
141 | cview = cview[2:] |
|
149 | cview = cview[2:] | |
142 | cview = cview[cview.find("/") + 1 :] |
|
150 | cview = cview[cview.find(b"/") + 1 :] | |
143 | views[sview] = cview |
|
151 | views[sview] = cview | |
144 |
|
152 | |||
145 | # list of changes that affect our source files |
|
153 | # list of changes that affect our source files | |
@@ -151,10 +159,10 b' class p4_source(common.converter_source)' | |||||
151 | vieworder.sort(key=len, reverse=True) |
|
159 | vieworder.sort(key=len, reverse=True) | |
152 |
|
160 | |||
153 | # handle revision limiting |
|
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 | # now read the full changelists to get the list of file revisions |
|
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 | lastid = None |
|
166 | lastid = None | |
159 | for change in p4changes: |
|
167 | for change in p4changes: | |
160 | if startrev and int(change) < int(startrev): |
|
168 | if startrev and int(change) < int(startrev): | |
@@ -176,28 +184,28 b' class p4_source(common.converter_source)' | |||||
176 |
|
184 | |||
177 | descarr = c.desc.splitlines(True) |
|
185 | descarr = c.desc.splitlines(True) | |
178 | if len(descarr) > 0: |
|
186 | if len(descarr) > 0: | |
179 | shortdesc = descarr[0].rstrip('\r\n') |
|
187 | shortdesc = descarr[0].rstrip(b'\r\n') | |
180 | else: |
|
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]) |
|
191 | t = b'%s %s' % (c.rev, repr(shortdesc)[1:-1]) | |
184 | ui.status(stringutil.ellipsis(t, 80) + '\n') |
|
192 | ui.status(stringutil.ellipsis(t, 80) + b'\n') | |
185 |
|
193 | |||
186 | files = [] |
|
194 | files = [] | |
187 | copies = {} |
|
195 | copies = {} | |
188 | copiedfiles = [] |
|
196 | copiedfiles = [] | |
189 | i = 0 |
|
197 | i = 0 | |
190 | while ("depotFile%d" % i) in d and ("rev%d" % i) in d: |
|
198 | while (b"depotFile%d" % i) in d and (b"rev%d" % i) in d: | |
191 | oldname = d["depotFile%d" % i] |
|
199 | oldname = d[b"depotFile%d" % i] | |
192 | filename = None |
|
200 | filename = None | |
193 | for v in vieworder: |
|
201 | for v in vieworder: | |
194 | if oldname.lower().startswith(v.lower()): |
|
202 | if oldname.lower().startswith(v.lower()): | |
195 | filename = decodefilename(views[v] + oldname[len(v) :]) |
|
203 | filename = decodefilename(views[v] + oldname[len(v) :]) | |
196 | break |
|
204 | break | |
197 | if filename: |
|
205 | if filename: | |
198 | files.append((filename, d["rev%d" % i])) |
|
206 | files.append((filename, d[b"rev%d" % i])) | |
199 | depotname[filename] = oldname |
|
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 | copiedfiles.append(filename) |
|
209 | copiedfiles.append(filename) | |
202 | localname[oldname] = filename |
|
210 | localname[oldname] = filename | |
203 | i += 1 |
|
211 | i += 1 | |
@@ -206,23 +214,23 b' class p4_source(common.converter_source)' | |||||
206 | for filename in copiedfiles: |
|
214 | for filename in copiedfiles: | |
207 | oldname = depotname[filename] |
|
215 | oldname = depotname[filename] | |
208 |
|
216 | |||
209 | flcmd = 'p4 -G filelog %s' % procutil.shellquote(oldname) |
|
217 | flcmd = b'p4 -G filelog %s' % procutil.shellquote(oldname) | |
210 | flstdout = procutil.popen(flcmd, mode='rb') |
|
218 | flstdout = procutil.popen(flcmd, mode=b'rb') | |
211 |
|
219 | |||
212 | copiedfilename = None |
|
220 | copiedfilename = None | |
213 | for d in loaditer(flstdout): |
|
221 | for d in loaditer(flstdout): | |
214 | copiedoldname = None |
|
222 | copiedoldname = None | |
215 |
|
223 | |||
216 | i = 0 |
|
224 | i = 0 | |
217 | while ("change%d" % i) in d: |
|
225 | while (b"change%d" % i) in d: | |
218 | if ( |
|
226 | if ( | |
219 | d["change%d" % i] == change |
|
227 | d[b"change%d" % i] == change | |
220 | and d["action%d" % i] == "move/add" |
|
228 | and d[b"action%d" % i] == b"move/add" | |
221 | ): |
|
229 | ): | |
222 | j = 0 |
|
230 | j = 0 | |
223 | while ("file%d,%d" % (i, j)) in d: |
|
231 | while (b"file%d,%d" % (i, j)) in d: | |
224 | if d["how%d,%d" % (i, j)] == "moved from": |
|
232 | if d[b"how%d,%d" % (i, j)] == b"moved from": | |
225 | copiedoldname = d["file%d,%d" % (i, j)] |
|
233 | copiedoldname = d[b"file%d,%d" % (i, j)] | |
226 | break |
|
234 | break | |
227 | j += 1 |
|
235 | j += 1 | |
228 | i += 1 |
|
236 | i += 1 | |
@@ -235,7 +243,7 b' class p4_source(common.converter_source)' | |||||
235 | copies[filename] = copiedfilename |
|
243 | copies[filename] = copiedfilename | |
236 | else: |
|
244 | else: | |
237 | ui.warn( |
|
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 | % (filename, change) |
|
247 | % (filename, change) | |
240 | ) |
|
248 | ) | |
241 |
|
249 | |||
@@ -248,11 +256,11 b' class p4_source(common.converter_source)' | |||||
248 | heads = [lastid] |
|
256 | heads = [lastid] | |
249 |
|
257 | |||
250 | return { |
|
258 | return { | |
251 | 'changeset': changeset, |
|
259 | b'changeset': changeset, | |
252 | 'files': files_map, |
|
260 | b'files': files_map, | |
253 | 'copies': copies_map, |
|
261 | b'copies': copies_map, | |
254 | 'heads': heads, |
|
262 | b'heads': heads, | |
255 | 'depotname': depotname, |
|
263 | b'depotname': depotname, | |
256 | } |
|
264 | } | |
257 |
|
265 | |||
258 | @util.propertycache |
|
266 | @util.propertycache | |
@@ -261,74 +269,74 b' class p4_source(common.converter_source)' | |||||
261 |
|
269 | |||
262 | @util.propertycache |
|
270 | @util.propertycache | |
263 | def copies(self): |
|
271 | def copies(self): | |
264 | return self._parse_once['copies'] |
|
272 | return self._parse_once[b'copies'] | |
265 |
|
273 | |||
266 | @util.propertycache |
|
274 | @util.propertycache | |
267 | def files(self): |
|
275 | def files(self): | |
268 | return self._parse_once['files'] |
|
276 | return self._parse_once[b'files'] | |
269 |
|
277 | |||
270 | @util.propertycache |
|
278 | @util.propertycache | |
271 | def changeset(self): |
|
279 | def changeset(self): | |
272 | return self._parse_once['changeset'] |
|
280 | return self._parse_once[b'changeset'] | |
273 |
|
281 | |||
274 | @util.propertycache |
|
282 | @util.propertycache | |
275 | def heads(self): |
|
283 | def heads(self): | |
276 | return self._parse_once['heads'] |
|
284 | return self._parse_once[b'heads'] | |
277 |
|
285 | |||
278 | @util.propertycache |
|
286 | @util.propertycache | |
279 | def depotname(self): |
|
287 | def depotname(self): | |
280 | return self._parse_once['depotname'] |
|
288 | return self._parse_once[b'depotname'] | |
281 |
|
289 | |||
282 | def getheads(self): |
|
290 | def getheads(self): | |
283 | return self.heads |
|
291 | return self.heads | |
284 |
|
292 | |||
285 | def getfile(self, name, rev): |
|
293 | def getfile(self, name, rev): | |
286 | cmd = 'p4 -G print %s' % procutil.shellquote( |
|
294 | cmd = b'p4 -G print %s' % procutil.shellquote( | |
287 | "%s#%s" % (self.depotname[name], rev) |
|
295 | b"%s#%s" % (self.depotname[name], rev) | |
288 | ) |
|
296 | ) | |
289 |
|
297 | |||
290 | lasterror = None |
|
298 | lasterror = None | |
291 | while True: |
|
299 | while True: | |
292 | stdout = procutil.popen(cmd, mode='rb') |
|
300 | stdout = procutil.popen(cmd, mode=b'rb') | |
293 |
|
301 | |||
294 | mode = None |
|
302 | mode = None | |
295 | contents = [] |
|
303 | contents = [] | |
296 | keywords = None |
|
304 | keywords = None | |
297 |
|
305 | |||
298 | for d in loaditer(stdout): |
|
306 | for d in loaditer(stdout): | |
299 | code = d["code"] |
|
307 | code = d[b"code"] | |
300 | data = d.get("data") |
|
308 | data = d.get(b"data") | |
301 |
|
309 | |||
302 | if code == "error": |
|
310 | if code == b"error": | |
303 | # if this is the first time error happened |
|
311 | # if this is the first time error happened | |
304 | # re-attempt getting the file |
|
312 | # re-attempt getting the file | |
305 | if not lasterror: |
|
313 | if not lasterror: | |
306 | lasterror = IOError(d["generic"], data) |
|
314 | lasterror = IOError(d[b"generic"], data) | |
307 | # this will exit inner-most for-loop |
|
315 | # this will exit inner-most for-loop | |
308 | break |
|
316 | break | |
309 | else: |
|
317 | else: | |
310 | raise lasterror |
|
318 | raise lasterror | |
311 |
|
319 | |||
312 | elif code == "stat": |
|
320 | elif code == b"stat": | |
313 | action = d.get("action") |
|
321 | action = d.get(b"action") | |
314 | if action in ["purge", "delete", "move/delete"]: |
|
322 | if action in [b"purge", b"delete", b"move/delete"]: | |
315 | return None, None |
|
323 | return None, None | |
316 | p4type = self.re_type.match(d["type"]) |
|
324 | p4type = self.re_type.match(d[b"type"]) | |
317 | if p4type: |
|
325 | if p4type: | |
318 | mode = "" |
|
326 | mode = b"" | |
319 | flags = (p4type.group(1) or "") + ( |
|
327 | flags = (p4type.group(1) or b"") + ( | |
320 | p4type.group(3) or "" |
|
328 | p4type.group(3) or b"" | |
321 | ) |
|
329 | ) | |
322 | if "x" in flags: |
|
330 | if b"x" in flags: | |
323 | mode = "x" |
|
331 | mode = b"x" | |
324 | if p4type.group(2) == "symlink": |
|
332 | if p4type.group(2) == b"symlink": | |
325 | mode = "l" |
|
333 | mode = b"l" | |
326 | if "ko" in flags: |
|
334 | if b"ko" in flags: | |
327 | keywords = self.re_keywords_old |
|
335 | keywords = self.re_keywords_old | |
328 | elif "k" in flags: |
|
336 | elif b"k" in flags: | |
329 | keywords = self.re_keywords |
|
337 | keywords = self.re_keywords | |
330 |
|
338 | |||
331 | elif code == "text" or code == "binary": |
|
339 | elif code == b"text" or code == b"binary": | |
332 | contents.append(data) |
|
340 | contents.append(data) | |
333 |
|
341 | |||
334 | lasterror = None |
|
342 | lasterror = None | |
@@ -339,18 +347,18 b' class p4_source(common.converter_source)' | |||||
339 | if mode is None: |
|
347 | if mode is None: | |
340 | return None, None |
|
348 | return None, None | |
341 |
|
349 | |||
342 | contents = ''.join(contents) |
|
350 | contents = b''.join(contents) | |
343 |
|
351 | |||
344 | if keywords: |
|
352 | if keywords: | |
345 | contents = keywords.sub("$\\1$", contents) |
|
353 | contents = keywords.sub(b"$\\1$", contents) | |
346 | if mode == "l" and contents.endswith("\n"): |
|
354 | if mode == b"l" and contents.endswith(b"\n"): | |
347 | contents = contents[:-1] |
|
355 | contents = contents[:-1] | |
348 |
|
356 | |||
349 | return contents, mode |
|
357 | return contents, mode | |
350 |
|
358 | |||
351 | def getchanges(self, rev, full): |
|
359 | def getchanges(self, rev, full): | |
352 | if full: |
|
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 | return self.files[rev], self.copies[rev], set() |
|
362 | return self.files[rev], self.copies[rev], set() | |
355 |
|
363 | |||
356 | def _construct_commit(self, obj, parents=None): |
|
364 | def _construct_commit(self, obj, parents=None): | |
@@ -358,26 +366,26 b' class p4_source(common.converter_source)' | |||||
358 | Constructs a common.commit object from an unmarshalled |
|
366 | Constructs a common.commit object from an unmarshalled | |
359 | `p4 describe` output |
|
367 | `p4 describe` output | |
360 | """ |
|
368 | """ | |
361 | desc = self.recode(obj.get("desc", "")) |
|
369 | desc = self.recode(obj.get(b"desc", b"")) | |
362 | date = (int(obj["time"]), 0) # timezone not set |
|
370 | date = (int(obj[b"time"]), 0) # timezone not set | |
363 | if parents is None: |
|
371 | if parents is None: | |
364 | parents = [] |
|
372 | parents = [] | |
365 |
|
373 | |||
366 | return common.commit( |
|
374 | return common.commit( | |
367 | author=self.recode(obj["user"]), |
|
375 | author=self.recode(obj[b"user"]), | |
368 | date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), |
|
376 | date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'), | |
369 | parents=parents, |
|
377 | parents=parents, | |
370 | desc=desc, |
|
378 | desc=desc, | |
371 | branch=None, |
|
379 | branch=None, | |
372 | rev=obj['change'], |
|
380 | rev=obj[b'change'], | |
373 | extra={"p4": obj['change'], "convert_revision": obj['change']}, |
|
381 | extra={b"p4": obj[b'change'], b"convert_revision": obj[b'change']}, | |
374 | ) |
|
382 | ) | |
375 |
|
383 | |||
376 | def _fetch_revision(self, rev): |
|
384 | def _fetch_revision(self, rev): | |
377 | """Return an output of `p4 describe` including author, commit date as |
|
385 | """Return an output of `p4 describe` including author, commit date as | |
378 | a dictionary.""" |
|
386 | a dictionary.""" | |
379 | cmd = "p4 -G describe -s %s" % rev |
|
387 | cmd = b"p4 -G describe -s %s" % rev | |
380 | stdout = procutil.popen(cmd, mode='rb') |
|
388 | stdout = procutil.popen(cmd, mode=b'rb') | |
381 | return marshal.load(stdout) |
|
389 | return marshal.load(stdout) | |
382 |
|
390 | |||
383 | def getcommit(self, rev): |
|
391 | def getcommit(self, rev): | |
@@ -387,7 +395,7 b' class p4_source(common.converter_source)' | |||||
387 | d = self._fetch_revision(rev) |
|
395 | d = self._fetch_revision(rev) | |
388 | return self._construct_commit(d, parents=None) |
|
396 | return self._construct_commit(d, parents=None) | |
389 | raise error.Abort( |
|
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 | def gettags(self): |
|
401 | def gettags(self): |
@@ -54,7 +54,7 b' try:' | |||||
54 | import warnings |
|
54 | import warnings | |
55 |
|
55 | |||
56 | warnings.filterwarnings( |
|
56 | warnings.filterwarnings( | |
57 | 'ignore', module='svn.core', category=DeprecationWarning |
|
57 | b'ignore', module=b'svn.core', category=DeprecationWarning | |
58 | ) |
|
58 | ) | |
59 | svn.core.SubversionException # trigger import to catch error |
|
59 | svn.core.SubversionException # trigger import to catch error | |
60 |
|
60 | |||
@@ -80,16 +80,16 b' def revsplit(rev):' | |||||
80 | >>> revsplit(b'bad') |
|
80 | >>> revsplit(b'bad') | |
81 | ('', '', 0) |
|
81 | ('', '', 0) | |
82 | """ |
|
82 | """ | |
83 | parts = rev.rsplit('@', 1) |
|
83 | parts = rev.rsplit(b'@', 1) | |
84 | revnum = 0 |
|
84 | revnum = 0 | |
85 | if len(parts) > 1: |
|
85 | if len(parts) > 1: | |
86 | revnum = int(parts[1]) |
|
86 | revnum = int(parts[1]) | |
87 | parts = parts[0].split('/', 1) |
|
87 | parts = parts[0].split(b'/', 1) | |
88 | uuid = '' |
|
88 | uuid = b'' | |
89 | mod = '' |
|
89 | mod = b'' | |
90 | if len(parts) > 1 and parts[0].startswith('svn:'): |
|
90 | if len(parts) > 1 and parts[0].startswith(b'svn:'): | |
91 | uuid = parts[0][4:] |
|
91 | uuid = parts[0][4:] | |
92 | mod = '/' + parts[1] |
|
92 | mod = b'/' + parts[1] | |
93 | return uuid, mod, revnum |
|
93 | return uuid, mod, revnum | |
94 |
|
94 | |||
95 |
|
95 | |||
@@ -101,7 +101,7 b' def quote(s):' | |||||
101 | # so we can extend it safely with new components. The "safe" |
|
101 | # so we can extend it safely with new components. The "safe" | |
102 | # characters were taken from the "svn_uri__char_validity" table in |
|
102 | # characters were taken from the "svn_uri__char_validity" table in | |
103 | # libsvn_subr/path.c. |
|
103 | # libsvn_subr/path.c. | |
104 | return urlreq.quote(s, "!$&'()*+,-./:=@_~") |
|
104 | return urlreq.quote(s, b"!$&'()*+,-./:=@_~") | |
105 |
|
105 | |||
106 |
|
106 | |||
107 | def geturl(path): |
|
107 | def geturl(path): | |
@@ -113,11 +113,11 b' def geturl(path):' | |||||
113 | if os.path.isdir(path): |
|
113 | if os.path.isdir(path): | |
114 | path = os.path.normpath(os.path.abspath(path)) |
|
114 | path = os.path.normpath(os.path.abspath(path)) | |
115 | if pycompat.iswindows: |
|
115 | if pycompat.iswindows: | |
116 | path = '/' + util.normpath(path) |
|
116 | path = b'/' + util.normpath(path) | |
117 | # Module URL is later compared with the repository URL returned |
|
117 | # Module URL is later compared with the repository URL returned | |
118 | # by svn API, which is UTF-8. |
|
118 | # by svn API, which is UTF-8. | |
119 | path = encoding.tolocal(path) |
|
119 | path = encoding.tolocal(path) | |
120 | path = 'file://%s' % quote(path) |
|
120 | path = b'file://%s' % quote(path) | |
121 | return svn.core.svn_path_canonicalize(path) |
|
121 | return svn.core.svn_path_canonicalize(path) | |
122 |
|
122 | |||
123 |
|
123 | |||
@@ -188,7 +188,7 b' def debugsvnlog(ui, **opts):' | |||||
188 | """ |
|
188 | """ | |
189 | if svn is None: |
|
189 | if svn is None: | |
190 | raise error.Abort( |
|
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 | args = decodeargs(ui.fin.read()) |
|
194 | args = decodeargs(ui.fin.read()) | |
@@ -208,8 +208,8 b' class logstream(object):' | |||||
208 | except EOFError: |
|
208 | except EOFError: | |
209 | raise error.Abort( |
|
209 | raise error.Abort( | |
210 | _( |
|
210 | _( | |
211 | 'Mercurial failed to run itself, check' |
|
211 | b'Mercurial failed to run itself, check' | |
212 | ' hg executable is in PATH' |
|
212 | b' hg executable is in PATH' | |
213 | ) |
|
213 | ) | |
214 | ) |
|
214 | ) | |
215 | try: |
|
215 | try: | |
@@ -217,7 +217,7 b' class logstream(object):' | |||||
217 | except (TypeError, ValueError): |
|
217 | except (TypeError, ValueError): | |
218 | if entry is None: |
|
218 | if entry is None: | |
219 | break |
|
219 | break | |
220 | raise error.Abort(_("log stream exception '%s'") % entry) |
|
220 | raise error.Abort(_(b"log stream exception '%s'") % entry) | |
221 | yield entry |
|
221 | yield entry | |
222 |
|
222 | |||
223 | def close(self): |
|
223 | def close(self): | |
@@ -270,7 +270,7 b' class directlogstream(list):' | |||||
270 | # looking for several svn-specific files and directories in the given |
|
270 | # looking for several svn-specific files and directories in the given | |
271 | # directory. |
|
271 | # directory. | |
272 | def filecheck(ui, path, proto): |
|
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 | if not os.path.exists(os.path.join(path, x)): |
|
274 | if not os.path.exists(os.path.join(path, x)): | |
275 | return False |
|
275 | return False | |
276 | return True |
|
276 | return True | |
@@ -282,16 +282,16 b' def filecheck(ui, path, proto):' | |||||
282 | def httpcheck(ui, path, proto): |
|
282 | def httpcheck(ui, path, proto): | |
283 | try: |
|
283 | try: | |
284 | opener = urlreq.buildopener() |
|
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 | data = rsp.read() |
|
286 | data = rsp.read() | |
287 | except urlerr.httperror as inst: |
|
287 | except urlerr.httperror as inst: | |
288 | if inst.code != 404: |
|
288 | if inst.code != 404: | |
289 | # Except for 404 we cannot know for sure this is not an svn repo |
|
289 | # Except for 404 we cannot know for sure this is not an svn repo | |
290 | ui.warn( |
|
290 | ui.warn( | |
291 | _( |
|
291 | _( | |
292 | 'svn: cannot probe remote repository, assume it could ' |
|
292 | b'svn: cannot probe remote repository, assume it could ' | |
293 | 'be a subversion repository. Use --source-type if you ' |
|
293 | b'be a subversion repository. Use --source-type if you ' | |
294 | 'know better.\n' |
|
294 | b'know better.\n' | |
295 | ) |
|
295 | ) | |
296 | ) |
|
296 | ) | |
297 | return True |
|
297 | return True | |
@@ -299,38 +299,38 b' def httpcheck(ui, path, proto):' | |||||
299 | except Exception: |
|
299 | except Exception: | |
300 | # Could be urlerr.urlerror if the URL is invalid or anything else. |
|
300 | # Could be urlerr.urlerror if the URL is invalid or anything else. | |
301 | return False |
|
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 | protomap = { |
|
305 | protomap = { | |
306 | 'http': httpcheck, |
|
306 | b'http': httpcheck, | |
307 | 'https': httpcheck, |
|
307 | b'https': httpcheck, | |
308 | 'file': filecheck, |
|
308 | b'file': filecheck, | |
309 | } |
|
309 | } | |
310 |
|
310 | |||
311 |
|
311 | |||
312 | def issvnurl(ui, url): |
|
312 | def issvnurl(ui, url): | |
313 | try: |
|
313 | try: | |
314 | proto, path = url.split('://', 1) |
|
314 | proto, path = url.split(b'://', 1) | |
315 | if proto == 'file': |
|
315 | if proto == b'file': | |
316 | if ( |
|
316 | if ( | |
317 | pycompat.iswindows |
|
317 | pycompat.iswindows | |
318 | and path[:1] == '/' |
|
318 | and path[:1] == b'/' | |
319 | and path[1:2].isalpha() |
|
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 | path = urlreq.url2pathname(path) |
|
323 | path = urlreq.url2pathname(path) | |
324 | except ValueError: |
|
324 | except ValueError: | |
325 | proto = 'file' |
|
325 | proto = b'file' | |
326 | path = os.path.abspath(url) |
|
326 | path = os.path.abspath(url) | |
327 | if proto == 'file': |
|
327 | if proto == b'file': | |
328 | path = util.pconvert(path) |
|
328 | path = util.pconvert(path) | |
329 | check = protomap.get(proto, lambda *args: False) |
|
329 | check = protomap.get(proto, lambda *args: False) | |
330 | while '/' in path: |
|
330 | while b'/' in path: | |
331 | if check(ui, path, proto): |
|
331 | if check(ui, path, proto): | |
332 | return True |
|
332 | return True | |
333 | path = path.rsplit('/', 1)[0] |
|
333 | path = path.rsplit(b'/', 1)[0] | |
334 | return False |
|
334 | return False | |
335 |
|
335 | |||
336 |
|
336 | |||
@@ -353,35 +353,35 b' class svn_source(converter_source):' | |||||
353 | super(svn_source, self).__init__(ui, repotype, url, revs=revs) |
|
353 | super(svn_source, self).__init__(ui, repotype, url, revs=revs) | |
354 |
|
354 | |||
355 | if not ( |
|
355 | if not ( | |
356 | url.startswith('svn://') |
|
356 | url.startswith(b'svn://') | |
357 | or url.startswith('svn+ssh://') |
|
357 | or url.startswith(b'svn+ssh://') | |
358 | or ( |
|
358 | or ( | |
359 | os.path.exists(url) |
|
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 | or issvnurl(ui, url) |
|
362 | or issvnurl(ui, url) | |
363 | ): |
|
363 | ): | |
364 | raise NoRepo( |
|
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 | if svn is None: |
|
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 | try: |
|
370 | try: | |
371 | version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR |
|
371 | version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR | |
372 | if version < (1, 4): |
|
372 | if version < (1, 4): | |
373 | raise MissingTool( |
|
373 | raise MissingTool( | |
374 | _( |
|
374 | _( | |
375 | 'Subversion python bindings %d.%d found, ' |
|
375 | b'Subversion python bindings %d.%d found, ' | |
376 | '1.4 or later required' |
|
376 | b'1.4 or later required' | |
377 | ) |
|
377 | ) | |
378 | % version |
|
378 | % version | |
379 | ) |
|
379 | ) | |
380 | except AttributeError: |
|
380 | except AttributeError: | |
381 | raise MissingTool( |
|
381 | raise MissingTool( | |
382 | _( |
|
382 | _( | |
383 | 'Subversion python bindings are too old, 1.4 ' |
|
383 | b'Subversion python bindings are too old, 1.4 ' | |
384 | 'or later required' |
|
384 | b'or later required' | |
385 | ) |
|
385 | ) | |
386 | ) |
|
386 | ) | |
387 |
|
387 | |||
@@ -391,14 +391,14 b' class svn_source(converter_source):' | |||||
391 | try: |
|
391 | try: | |
392 | # Support file://path@rev syntax. Useful e.g. to convert |
|
392 | # Support file://path@rev syntax. Useful e.g. to convert | |
393 | # deleted branches. |
|
393 | # deleted branches. | |
394 | at = url.rfind('@') |
|
394 | at = url.rfind(b'@') | |
395 | if at >= 0: |
|
395 | if at >= 0: | |
396 | latest = int(url[at + 1 :]) |
|
396 | latest = int(url[at + 1 :]) | |
397 | url = url[:at] |
|
397 | url = url[:at] | |
398 | except ValueError: |
|
398 | except ValueError: | |
399 | pass |
|
399 | pass | |
400 | self.url = geturl(url) |
|
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 | try: |
|
402 | try: | |
403 | self.transport = transport.SvnRaTransport(url=self.url) |
|
403 | self.transport = transport.SvnRaTransport(url=self.url) | |
404 | self.ra = self.transport.ra |
|
404 | self.ra = self.transport.ra | |
@@ -414,15 +414,15 b' class svn_source(converter_source):' | |||||
414 | self.uuid = svn.ra.get_uuid(self.ra) |
|
414 | self.uuid = svn.ra.get_uuid(self.ra) | |
415 | except svn.core.SubversionException: |
|
415 | except svn.core.SubversionException: | |
416 | ui.traceback() |
|
416 | ui.traceback() | |
417 | svnversion = '%d.%d.%d' % ( |
|
417 | svnversion = b'%d.%d.%d' % ( | |
418 | svn.core.SVN_VER_MAJOR, |
|
418 | svn.core.SVN_VER_MAJOR, | |
419 | svn.core.SVN_VER_MINOR, |
|
419 | svn.core.SVN_VER_MINOR, | |
420 | svn.core.SVN_VER_MICRO, |
|
420 | svn.core.SVN_VER_MICRO, | |
421 | ) |
|
421 | ) | |
422 | raise NoRepo( |
|
422 | raise NoRepo( | |
423 | _( |
|
423 | _( | |
424 | "%s does not look like a Subversion repository " |
|
424 | b"%s does not look like a Subversion repository " | |
425 | "to libsvn version %s" |
|
425 | b"to libsvn version %s" | |
426 | ) |
|
426 | ) | |
427 | % (self.url, svnversion) |
|
427 | % (self.url, svnversion) | |
428 | ) |
|
428 | ) | |
@@ -431,29 +431,29 b' class svn_source(converter_source):' | |||||
431 | if len(revs) > 1: |
|
431 | if len(revs) > 1: | |
432 | raise error.Abort( |
|
432 | raise error.Abort( | |
433 | _( |
|
433 | _( | |
434 | 'subversion source does not support ' |
|
434 | b'subversion source does not support ' | |
435 | 'specifying multiple revisions' |
|
435 | b'specifying multiple revisions' | |
436 | ) |
|
436 | ) | |
437 | ) |
|
437 | ) | |
438 | try: |
|
438 | try: | |
439 | latest = int(revs[0]) |
|
439 | latest = int(revs[0]) | |
440 | except ValueError: |
|
440 | except ValueError: | |
441 | raise error.Abort( |
|
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 | if trunkcfg is None: |
|
446 | if trunkcfg is None: | |
447 | trunkcfg = 'trunk' |
|
447 | trunkcfg = b'trunk' | |
448 | self.trunkname = trunkcfg.strip('/') |
|
448 | self.trunkname = trunkcfg.strip(b'/') | |
449 | self.startrev = self.ui.config('convert', 'svn.startrev') |
|
449 | self.startrev = self.ui.config(b'convert', b'svn.startrev') | |
450 | try: |
|
450 | try: | |
451 | self.startrev = int(self.startrev) |
|
451 | self.startrev = int(self.startrev) | |
452 | if self.startrev < 0: |
|
452 | if self.startrev < 0: | |
453 | self.startrev = 0 |
|
453 | self.startrev = 0 | |
454 | except ValueError: |
|
454 | except ValueError: | |
455 | raise error.Abort( |
|
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 | try: |
|
459 | try: | |
@@ -461,12 +461,14 b' class svn_source(converter_source):' | |||||
461 | except SvnPathNotFound: |
|
461 | except SvnPathNotFound: | |
462 | self.head = None |
|
462 | self.head = None | |
463 | if not self.head: |
|
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 | self.last_changed = self.revnum(self.head) |
|
467 | self.last_changed = self.revnum(self.head) | |
466 |
|
468 | |||
467 | self._changescache = (None, None) |
|
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 | self.wc = url |
|
472 | self.wc = url | |
471 | else: |
|
473 | else: | |
472 | self.wc = None |
|
474 | self.wc = None | |
@@ -484,7 +486,7 b' class svn_source(converter_source):' | |||||
484 | def exists(self, path, optrev): |
|
486 | def exists(self, path, optrev): | |
485 | try: |
|
487 | try: | |
486 | svn.client.ls( |
|
488 | svn.client.ls( | |
487 | self.url.rstrip('/') + '/' + quote(path), |
|
489 | self.url.rstrip(b'/') + b'/' + quote(path), | |
488 | optrev, |
|
490 | optrev, | |
489 | False, |
|
491 | False, | |
490 | self.ctx, |
|
492 | self.ctx, | |
@@ -499,61 +501,62 b' class svn_source(converter_source):' | |||||
499 | return kind == svn.core.svn_node_dir |
|
501 | return kind == svn.core.svn_node_dir | |
500 |
|
502 | |||
501 | def getcfgpath(name, rev): |
|
503 | def getcfgpath(name, rev): | |
502 | cfgpath = self.ui.config('convert', 'svn.' + name) |
|
504 | cfgpath = self.ui.config(b'convert', b'svn.' + name) | |
503 | if cfgpath is not None and cfgpath.strip() == '': |
|
505 | if cfgpath is not None and cfgpath.strip() == b'': | |
504 | return None |
|
506 | return None | |
505 | path = (cfgpath or name).strip('/') |
|
507 | path = (cfgpath or name).strip(b'/') | |
506 | if not self.exists(path, rev): |
|
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 | # we are converting from inside this directory |
|
510 | # we are converting from inside this directory | |
509 | return None |
|
511 | return None | |
510 | if cfgpath: |
|
512 | if cfgpath: | |
511 | raise error.Abort( |
|
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 | % (name, path) |
|
515 | % (name, path) | |
514 | ) |
|
516 | ) | |
515 | return None |
|
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 | return path |
|
519 | return path | |
518 |
|
520 | |||
519 | rev = optrev(self.last_changed) |
|
521 | rev = optrev(self.last_changed) | |
520 | oldmodule = '' |
|
522 | oldmodule = b'' | |
521 | trunk = getcfgpath('trunk', rev) |
|
523 | trunk = getcfgpath(b'trunk', rev) | |
522 | self.tags = getcfgpath('tags', rev) |
|
524 | self.tags = getcfgpath(b'tags', rev) | |
523 | branches = getcfgpath('branches', rev) |
|
525 | branches = getcfgpath(b'branches', rev) | |
524 |
|
526 | |||
525 | # If the project has a trunk or branches, we will extract heads |
|
527 | # If the project has a trunk or branches, we will extract heads | |
526 | # from them. We keep the project root otherwise. |
|
528 | # from them. We keep the project root otherwise. | |
527 | if trunk: |
|
529 | if trunk: | |
528 | oldmodule = self.module or '' |
|
530 | oldmodule = self.module or b'' | |
529 | self.module += '/' + trunk |
|
531 | self.module += b'/' + trunk | |
530 | self.head = self.latest(self.module, self.last_changed) |
|
532 | self.head = self.latest(self.module, self.last_changed) | |
531 | if not self.head: |
|
533 | if not self.head: | |
532 | raise error.Abort( |
|
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 | # First head in the list is the module's head |
|
538 | # First head in the list is the module's head | |
537 | self.heads = [self.head] |
|
539 | self.heads = [self.head] | |
538 | if self.tags is not None: |
|
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 | # Check if branches bring a few more heads to the list |
|
543 | # Check if branches bring a few more heads to the list | |
542 | if branches: |
|
544 | if branches: | |
543 | rpath = self.url.strip('/') |
|
545 | rpath = self.url.strip(b'/') | |
544 | branchnames = svn.client.ls( |
|
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 | for branch in sorted(branchnames): |
|
549 | for branch in sorted(branchnames): | |
548 | module = '%s/%s/%s' % (oldmodule, branches, branch) |
|
550 | module = b'%s/%s/%s' % (oldmodule, branches, branch) | |
549 | if not isdir(module, self.last_changed): |
|
551 | if not isdir(module, self.last_changed): | |
550 | continue |
|
552 | continue | |
551 | brevid = self.latest(module, self.last_changed) |
|
553 | brevid = self.latest(module, self.last_changed) | |
552 | if not brevid: |
|
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 | continue |
|
556 | continue | |
555 | self.ui.note( |
|
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 | self.heads.append(brevid) |
|
561 | self.heads.append(brevid) | |
559 |
|
562 | |||
@@ -561,14 +564,14 b' class svn_source(converter_source):' | |||||
561 | if len(self.heads) > 1: |
|
564 | if len(self.heads) > 1: | |
562 | raise error.Abort( |
|
565 | raise error.Abort( | |
563 | _( |
|
566 | _( | |
564 | 'svn: start revision is not supported ' |
|
567 | b'svn: start revision is not supported ' | |
565 | 'with more than one branch' |
|
568 | b'with more than one branch' | |
566 | ) |
|
569 | ) | |
567 | ) |
|
570 | ) | |
568 | revnum = self.revnum(self.heads[0]) |
|
571 | revnum = self.revnum(self.heads[0]) | |
569 | if revnum < self.startrev: |
|
572 | if revnum < self.startrev: | |
570 | raise error.Abort( |
|
573 | raise error.Abort( | |
571 | _('svn: no revision found after start revision %d') |
|
574 | _(b'svn: no revision found after start revision %d') | |
572 | % self.startrev |
|
575 | % self.startrev | |
573 | ) |
|
576 | ) | |
574 |
|
577 | |||
@@ -628,13 +631,13 b' class svn_source(converter_source):' | |||||
628 | stop = revnum + 1 |
|
631 | stop = revnum + 1 | |
629 | self._fetch_revisions(revnum, stop) |
|
632 | self._fetch_revisions(revnum, stop) | |
630 | if rev not in self.commits: |
|
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 | revcommit = self.commits[rev] |
|
635 | revcommit = self.commits[rev] | |
633 | # caller caches the result, so free it here to release memory |
|
636 | # caller caches the result, so free it here to release memory | |
634 | del self.commits[rev] |
|
637 | del self.commits[rev] | |
635 | return revcommit |
|
638 | return revcommit | |
636 |
|
639 | |||
637 | def checkrevformat(self, revstr, mapname='splicemap'): |
|
640 | def checkrevformat(self, revstr, mapname=b'splicemap'): | |
638 | """ fails if revision format does not match the correct format""" |
|
641 | """ fails if revision format does not match the correct format""" | |
639 | if not re.match( |
|
642 | if not re.match( | |
640 | r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' |
|
643 | r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' | |
@@ -643,12 +646,12 b' class svn_source(converter_source):' | |||||
643 | revstr, |
|
646 | revstr, | |
644 | ): |
|
647 | ): | |
645 | raise error.Abort( |
|
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 | % (mapname, revstr) |
|
650 | % (mapname, revstr) | |
648 | ) |
|
651 | ) | |
649 |
|
652 | |||
650 | def numcommits(self): |
|
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 | def gettags(self): |
|
656 | def gettags(self): | |
654 | tags = {} |
|
657 | tags = {} | |
@@ -689,7 +692,7 b' class svn_source(converter_source):' | |||||
689 | srctagspath = copies.pop()[0] |
|
692 | srctagspath = copies.pop()[0] | |
690 |
|
693 | |||
691 | for source, sourcerev, dest in copies: |
|
694 | for source, sourcerev, dest in copies: | |
692 | if not dest.startswith(tagspath + '/'): |
|
695 | if not dest.startswith(tagspath + b'/'): | |
693 | continue |
|
696 | continue | |
694 | for tag in pendings: |
|
697 | for tag in pendings: | |
695 | if tag[0].startswith(dest): |
|
698 | if tag[0].startswith(dest): | |
@@ -709,14 +712,14 b' class svn_source(converter_source):' | |||||
709 | addeds = dict( |
|
712 | addeds = dict( | |
710 | (p, e.copyfrom_path) |
|
713 | (p, e.copyfrom_path) | |
711 | for p, e in origpaths.iteritems() |
|
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 | badroots = set() |
|
717 | badroots = set() | |
715 | for destroot in addeds: |
|
718 | for destroot in addeds: | |
716 | for source, sourcerev, dest in pendings: |
|
719 | for source, sourcerev, dest in pendings: | |
717 | if not dest.startswith( |
|
720 | if not dest.startswith( | |
718 | destroot + '/' |
|
721 | destroot + b'/' | |
719 | ) or source.startswith(addeds[destroot] + '/'): |
|
722 | ) or source.startswith(addeds[destroot] + b'/'): | |
720 | continue |
|
723 | continue | |
721 | badroots.add(destroot) |
|
724 | badroots.add(destroot) | |
722 | break |
|
725 | break | |
@@ -726,13 +729,13 b' class svn_source(converter_source):' | |||||
726 | p |
|
729 | p | |
727 | for p in pendings |
|
730 | for p in pendings | |
728 | if p[2] != badroot |
|
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 | # Tell tag renamings from tag creations |
|
735 | # Tell tag renamings from tag creations | |
733 | renamings = [] |
|
736 | renamings = [] | |
734 | for source, sourcerev, dest in pendings: |
|
737 | for source, sourcerev, dest in pendings: | |
735 | tagname = dest.split('/')[-1] |
|
738 | tagname = dest.split(b'/')[-1] | |
736 | if source.startswith(srctagspath): |
|
739 | if source.startswith(srctagspath): | |
737 | renamings.append([source, sourcerev, tagname]) |
|
740 | renamings.append([source, sourcerev, tagname]) | |
738 | continue |
|
741 | continue | |
@@ -761,18 +764,18 b' class svn_source(converter_source):' | |||||
761 | return |
|
764 | return | |
762 | if self.convertfp is None: |
|
765 | if self.convertfp is None: | |
763 | self.convertfp = open( |
|
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 | self.convertfp.write( |
|
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 | self.convertfp.flush() |
|
772 | self.convertfp.flush() | |
770 |
|
773 | |||
771 | def revid(self, revnum, module=None): |
|
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 | def revnum(self, rev): |
|
777 | def revnum(self, rev): | |
775 | return int(rev.split('@')[-1]) |
|
778 | return int(rev.split(b'@')[-1]) | |
776 |
|
779 | |||
777 | def latest(self, path, stop=None): |
|
780 | def latest(self, path, stop=None): | |
778 | """Find the latest revid affecting path, up to stop revision |
|
781 | """Find the latest revid affecting path, up to stop revision | |
@@ -800,7 +803,7 b' class svn_source(converter_source):' | |||||
800 | continue |
|
803 | continue | |
801 | newpath = paths[p].copyfrom_path + path[len(p) :] |
|
804 | newpath = paths[p].copyfrom_path + path[len(p) :] | |
802 | self.ui.debug( |
|
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 | % (path, newpath, revnum) |
|
807 | % (path, newpath, revnum) | |
805 | ) |
|
808 | ) | |
806 | path = newpath |
|
809 | path = newpath | |
@@ -813,20 +816,20 b' class svn_source(converter_source):' | |||||
813 |
|
816 | |||
814 | if not path.startswith(self.rootmodule): |
|
817 | if not path.startswith(self.rootmodule): | |
815 | # Requests on foreign branches may be forbidden at server level |
|
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 | return None |
|
820 | return None | |
818 |
|
821 | |||
819 | if stop is None: |
|
822 | if stop is None: | |
820 | stop = svn.ra.get_latest_revnum(self.ra) |
|
823 | stop = svn.ra.get_latest_revnum(self.ra) | |
821 | try: |
|
824 | try: | |
822 | prevmodule = self.reparent('') |
|
825 | prevmodule = self.reparent(b'') | |
823 | dirent = svn.ra.stat(self.ra, path.strip('/'), stop) |
|
826 | dirent = svn.ra.stat(self.ra, path.strip(b'/'), stop) | |
824 | self.reparent(prevmodule) |
|
827 | self.reparent(prevmodule) | |
825 | except svn.core.SubversionException: |
|
828 | except svn.core.SubversionException: | |
826 | dirent = None |
|
829 | dirent = None | |
827 | if not dirent: |
|
830 | if not dirent: | |
828 | raise SvnPathNotFound( |
|
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 | # stat() gives us the previous revision on this line of |
|
835 | # stat() gives us the previous revision on this line of | |
@@ -843,11 +846,11 b' class svn_source(converter_source):' | |||||
843 | # the whole history. |
|
846 | # the whole history. | |
844 | revnum, realpath = findchanges(path, stop) |
|
847 | revnum, realpath = findchanges(path, stop) | |
845 | if revnum is None: |
|
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 | return None |
|
850 | return None | |
848 |
|
851 | |||
849 | if not realpath.startswith(self.rootmodule): |
|
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 | return None |
|
854 | return None | |
852 | return self.revid(revnum, realpath) |
|
855 | return self.revid(revnum, realpath) | |
853 |
|
856 | |||
@@ -858,8 +861,8 b' class svn_source(converter_source):' | |||||
858 | svnurl = self.baseurl + quote(module) |
|
861 | svnurl = self.baseurl + quote(module) | |
859 | prevmodule = self.prevmodule |
|
862 | prevmodule = self.prevmodule | |
860 | if prevmodule is None: |
|
863 | if prevmodule is None: | |
861 | prevmodule = '' |
|
864 | prevmodule = b'' | |
862 | self.ui.debug("reparent to %s\n" % svnurl) |
|
865 | self.ui.debug(b"reparent to %s\n" % svnurl) | |
863 | svn.ra.reparent(self.ra, svnurl) |
|
866 | svn.ra.reparent(self.ra, svnurl) | |
864 | self.prevmodule = module |
|
867 | self.prevmodule = module | |
865 | return prevmodule |
|
868 | return prevmodule | |
@@ -874,7 +877,7 b' class svn_source(converter_source):' | |||||
874 | self.reparent(self.module) |
|
877 | self.reparent(self.module) | |
875 |
|
878 | |||
876 | progress = self.ui.makeprogress( |
|
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 | for i, (path, ent) in enumerate(paths): |
|
882 | for i, (path, ent) in enumerate(paths): | |
880 | progress.update(i, item=path) |
|
883 | progress.update(i, item=path) | |
@@ -894,37 +897,37 b' class svn_source(converter_source):' | |||||
894 | if not copyfrom_path: |
|
897 | if not copyfrom_path: | |
895 | continue |
|
898 | continue | |
896 | self.ui.debug( |
|
899 | self.ui.debug( | |
897 | "copied to %s from %s@%s\n" |
|
900 | b"copied to %s from %s@%s\n" | |
898 | % (entrypath, copyfrom_path, ent.copyfrom_rev) |
|
901 | % (entrypath, copyfrom_path, ent.copyfrom_rev) | |
899 | ) |
|
902 | ) | |
900 | copies[self.recode(entrypath)] = self.recode(copyfrom_path) |
|
903 | copies[self.recode(entrypath)] = self.recode(copyfrom_path) | |
901 | elif kind == 0: # gone, but had better be a deleted *file* |
|
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 | pmodule, prevnum = revsplit(parents[0])[1:] |
|
906 | pmodule, prevnum = revsplit(parents[0])[1:] | |
904 | parentpath = pmodule + "/" + entrypath |
|
907 | parentpath = pmodule + b"/" + entrypath | |
905 | fromkind = self._checkpath(entrypath, prevnum, pmodule) |
|
908 | fromkind = self._checkpath(entrypath, prevnum, pmodule) | |
906 |
|
909 | |||
907 | if fromkind == svn.core.svn_node_file: |
|
910 | if fromkind == svn.core.svn_node_file: | |
908 | removed.add(self.recode(entrypath)) |
|
911 | removed.add(self.recode(entrypath)) | |
909 | elif fromkind == svn.core.svn_node_dir: |
|
912 | elif fromkind == svn.core.svn_node_dir: | |
910 | oroot = parentpath.strip('/') |
|
913 | oroot = parentpath.strip(b'/') | |
911 | nroot = path.strip('/') |
|
914 | nroot = path.strip(b'/') | |
912 | children = self._iterfiles(oroot, prevnum) |
|
915 | children = self._iterfiles(oroot, prevnum) | |
913 | for childpath in children: |
|
916 | for childpath in children: | |
914 | childpath = childpath.replace(oroot, nroot) |
|
917 | childpath = childpath.replace(oroot, nroot) | |
915 | childpath = self.getrelpath("/" + childpath, pmodule) |
|
918 | childpath = self.getrelpath(b"/" + childpath, pmodule) | |
916 | if childpath: |
|
919 | if childpath: | |
917 | removed.add(self.recode(childpath)) |
|
920 | removed.add(self.recode(childpath)) | |
918 | else: |
|
921 | else: | |
919 | self.ui.debug( |
|
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 | elif kind == svn.core.svn_node_dir: |
|
925 | elif kind == svn.core.svn_node_dir: | |
923 | if ent.action == 'M': |
|
926 | if ent.action == b'M': | |
924 | # If the directory just had a prop change, |
|
927 | # If the directory just had a prop change, | |
925 | # then we shouldn't need to look for its children. |
|
928 | # then we shouldn't need to look for its children. | |
926 | continue |
|
929 | continue | |
927 | if ent.action == 'R' and parents: |
|
930 | if ent.action == b'R' and parents: | |
928 | # If a directory is replacing a file, mark the previous |
|
931 | # If a directory is replacing a file, mark the previous | |
929 | # file as deleted |
|
932 | # file as deleted | |
930 | pmodule, prevnum = revsplit(parents[0])[1:] |
|
933 | pmodule, prevnum = revsplit(parents[0])[1:] | |
@@ -935,12 +938,12 b' class svn_source(converter_source):' | |||||
935 | # We do not know what files were kept or removed, |
|
938 | # We do not know what files were kept or removed, | |
936 | # mark them all as changed. |
|
939 | # mark them all as changed. | |
937 | for childpath in self._iterfiles(pmodule, prevnum): |
|
940 | for childpath in self._iterfiles(pmodule, prevnum): | |
938 | childpath = self.getrelpath("/" + childpath) |
|
941 | childpath = self.getrelpath(b"/" + childpath) | |
939 | if childpath: |
|
942 | if childpath: | |
940 | changed.add(self.recode(childpath)) |
|
943 | changed.add(self.recode(childpath)) | |
941 |
|
944 | |||
942 | for childpath in self._iterfiles(path, revnum): |
|
945 | for childpath in self._iterfiles(path, revnum): | |
943 | childpath = self.getrelpath("/" + childpath) |
|
946 | childpath = self.getrelpath(b"/" + childpath) | |
944 | if childpath: |
|
947 | if childpath: | |
945 | changed.add(self.recode(childpath)) |
|
948 | changed.add(self.recode(childpath)) | |
946 |
|
949 | |||
@@ -956,12 +959,12 b' class svn_source(converter_source):' | |||||
956 | if not copyfrompath: |
|
959 | if not copyfrompath: | |
957 | continue |
|
960 | continue | |
958 | self.ui.debug( |
|
961 | self.ui.debug( | |
959 | "mark %s came from %s:%d\n" |
|
962 | b"mark %s came from %s:%d\n" | |
960 | % (path, copyfrompath, ent.copyfrom_rev) |
|
963 | % (path, copyfrompath, ent.copyfrom_rev) | |
961 | ) |
|
964 | ) | |
962 | children = self._iterfiles(ent.copyfrom_path, ent.copyfrom_rev) |
|
965 | children = self._iterfiles(ent.copyfrom_path, ent.copyfrom_rev) | |
963 | for childpath in children: |
|
966 | for childpath in children: | |
964 | childpath = self.getrelpath("/" + childpath, pmodule) |
|
967 | childpath = self.getrelpath(b"/" + childpath, pmodule) | |
965 | if not childpath: |
|
968 | if not childpath: | |
966 | continue |
|
969 | continue | |
967 | copytopath = path + childpath[len(copyfrompath) :] |
|
970 | copytopath = path + childpath[len(copyfrompath) :] | |
@@ -983,7 +986,8 b' class svn_source(converter_source):' | |||||
983 | the revision is a branch root. |
|
986 | the revision is a branch root. | |
984 | """ |
|
987 | """ | |
985 | self.ui.debug( |
|
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 | branched = False |
|
993 | branched = False | |
@@ -1012,11 +1016,11 b' class svn_source(converter_source):' | |||||
1012 | if prevnum >= self.startrev: |
|
1016 | if prevnum >= self.startrev: | |
1013 | parents = [previd] |
|
1017 | parents = [previd] | |
1014 | self.ui.note( |
|
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 | % (self.module, prevnum, prevmodule) |
|
1020 | % (self.module, prevnum, prevmodule) | |
1017 | ) |
|
1021 | ) | |
1018 | else: |
|
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 | paths = [] |
|
1025 | paths = [] | |
1022 | # filter out unrelated paths |
|
1026 | # filter out unrelated paths | |
@@ -1028,22 +1032,24 b' class svn_source(converter_source):' | |||||
1028 | # Example SVN datetime. Includes microseconds. |
|
1032 | # Example SVN datetime. Includes microseconds. | |
1029 | # ISO-8601 conformant |
|
1033 | # ISO-8601 conformant | |
1030 | # '2007-01-04T17:35:00.902377Z' |
|
1034 | # '2007-01-04T17:35:00.902377Z' | |
1031 |
date = dateutil.parsedate( |
|
1035 | date = dateutil.parsedate( | |
1032 | if self.ui.configbool('convert', 'localtimezone'): |
|
1036 | date[:19] + b" UTC", [b"%Y-%m-%dT%H:%M:%S"] | |
|
1037 | ) | |||
|
1038 | if self.ui.configbool(b'convert', b'localtimezone'): | |||
1033 | date = makedatetimestamp(date[0]) |
|
1039 | date = makedatetimestamp(date[0]) | |
1034 |
|
1040 | |||
1035 | if message: |
|
1041 | if message: | |
1036 | log = self.recode(message) |
|
1042 | log = self.recode(message) | |
1037 | else: |
|
1043 | else: | |
1038 | log = '' |
|
1044 | log = b'' | |
1039 |
|
1045 | |||
1040 | if author: |
|
1046 | if author: | |
1041 | author = self.recode(author) |
|
1047 | author = self.recode(author) | |
1042 | else: |
|
1048 | else: | |
1043 | author = '' |
|
1049 | author = b'' | |
1044 |
|
1050 | |||
1045 | try: |
|
1051 | try: | |
1046 | branch = self.module.split("/")[-1] |
|
1052 | branch = self.module.split(b"/")[-1] | |
1047 | if branch == self.trunkname: |
|
1053 | if branch == self.trunkname: | |
1048 | branch = None |
|
1054 | branch = None | |
1049 | except IndexError: |
|
1055 | except IndexError: | |
@@ -1051,7 +1057,7 b' class svn_source(converter_source):' | |||||
1051 |
|
1057 | |||
1052 | cset = commit( |
|
1058 | cset = commit( | |
1053 | author=author, |
|
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 | desc=log, |
|
1061 | desc=log, | |
1056 | parents=parents, |
|
1062 | parents=parents, | |
1057 | branch=branch, |
|
1063 | branch=branch, | |
@@ -1068,7 +1074,7 b' class svn_source(converter_source):' | |||||
1068 | return cset, branched |
|
1074 | return cset, branched | |
1069 |
|
1075 | |||
1070 | self.ui.note( |
|
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 | % (self.module, from_revnum, to_revnum) |
|
1078 | % (self.module, from_revnum, to_revnum) | |
1073 | ) |
|
1079 | ) | |
1074 |
|
1080 | |||
@@ -1083,7 +1089,7 b' class svn_source(converter_source):' | |||||
1083 | lastonbranch = True |
|
1089 | lastonbranch = True | |
1084 | break |
|
1090 | break | |
1085 | if not paths: |
|
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 | # If we ever leave the loop on an empty |
|
1093 | # If we ever leave the loop on an empty | |
1088 | # revision, do not try to get a parent branch |
|
1094 | # revision, do not try to get a parent branch | |
1089 | lastonbranch = lastonbranch or revnum == 0 |
|
1095 | lastonbranch = lastonbranch or revnum == 0 | |
@@ -1114,7 +1120,7 b' class svn_source(converter_source):' | |||||
1114 | (inst, num) = xxx_todo_changeme.args |
|
1120 | (inst, num) = xxx_todo_changeme.args | |
1115 | if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: |
|
1121 | if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: | |
1116 | raise error.Abort( |
|
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 | raise |
|
1125 | raise | |
1120 |
|
1126 | |||
@@ -1135,8 +1141,8 b' class svn_source(converter_source):' | |||||
1135 | io.close() |
|
1141 | io.close() | |
1136 | if isinstance(info, list): |
|
1142 | if isinstance(info, list): | |
1137 | info = info[-1] |
|
1143 | info = info[-1] | |
1138 | mode = ("svn:executable" in info) and 'x' or '' |
|
1144 | mode = (b"svn:executable" in info) and b'x' or b'' | |
1139 | mode = ("svn:special" in info) and 'l' or mode |
|
1145 | mode = (b"svn:special" in info) and b'l' or mode | |
1140 | except svn.core.SubversionException as e: |
|
1146 | except svn.core.SubversionException as e: | |
1141 | notfound = ( |
|
1147 | notfound = ( | |
1142 | svn.core.SVN_ERR_FS_NOT_FOUND, |
|
1148 | svn.core.SVN_ERR_FS_NOT_FOUND, | |
@@ -1145,20 +1151,20 b' class svn_source(converter_source):' | |||||
1145 | if e.apr_err in notfound: # File not found |
|
1151 | if e.apr_err in notfound: # File not found | |
1146 | return None, None |
|
1152 | return None, None | |
1147 | raise |
|
1153 | raise | |
1148 | if mode == 'l': |
|
1154 | if mode == b'l': | |
1149 | link_prefix = "link " |
|
1155 | link_prefix = b"link " | |
1150 | if data.startswith(link_prefix): |
|
1156 | if data.startswith(link_prefix): | |
1151 | data = data[len(link_prefix) :] |
|
1157 | data = data[len(link_prefix) :] | |
1152 | return data, mode |
|
1158 | return data, mode | |
1153 |
|
1159 | |||
1154 | def _iterfiles(self, path, revnum): |
|
1160 | def _iterfiles(self, path, revnum): | |
1155 | """Enumerate all files in path at revnum, recursively.""" |
|
1161 | """Enumerate all files in path at revnum, recursively.""" | |
1156 | path = path.strip('/') |
|
1162 | path = path.strip(b'/') | |
1157 | pool = svn.core.Pool() |
|
1163 | pool = svn.core.Pool() | |
1158 | rpath = '/'.join([self.baseurl, quote(path)]).strip('/') |
|
1164 | rpath = b'/'.join([self.baseurl, quote(path)]).strip(b'/') | |
1159 | entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool) |
|
1165 | entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool) | |
1160 | if path: |
|
1166 | if path: | |
1161 | path += '/' |
|
1167 | path += b'/' | |
1162 | return ( |
|
1168 | return ( | |
1163 | (path + p) |
|
1169 | (path + p) | |
1164 | for p, e in entries.iteritems() |
|
1170 | for p, e in entries.iteritems() | |
@@ -1175,24 +1181,24 b' class svn_source(converter_source):' | |||||
1175 | # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py" |
|
1181 | # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py" | |
1176 | # that is to say "tests/PloneTestCase.py" |
|
1182 | # that is to say "tests/PloneTestCase.py" | |
1177 | if path.startswith(module): |
|
1183 | if path.startswith(module): | |
1178 | relative = path.rstrip('/')[len(module) :] |
|
1184 | relative = path.rstrip(b'/')[len(module) :] | |
1179 | if relative.startswith('/'): |
|
1185 | if relative.startswith(b'/'): | |
1180 | return relative[1:] |
|
1186 | return relative[1:] | |
1181 | elif relative == '': |
|
1187 | elif relative == b'': | |
1182 | return relative |
|
1188 | return relative | |
1183 |
|
1189 | |||
1184 | # The path is outside our tracked tree... |
|
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 | return None |
|
1192 | return None | |
1187 |
|
1193 | |||
1188 | def _checkpath(self, path, revnum, module=None): |
|
1194 | def _checkpath(self, path, revnum, module=None): | |
1189 | if module is not None: |
|
1195 | if module is not None: | |
1190 | prevmodule = self.reparent('') |
|
1196 | prevmodule = self.reparent(b'') | |
1191 | path = module + '/' + path |
|
1197 | path = module + b'/' + path | |
1192 | try: |
|
1198 | try: | |
1193 | # ra.check_path does not like leading slashes very much, it leads |
|
1199 | # ra.check_path does not like leading slashes very much, it leads | |
1194 | # to PROPFIND subversion errors |
|
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 | finally: |
|
1202 | finally: | |
1197 | if module is not None: |
|
1203 | if module is not None: | |
1198 | self.reparent(prevmodule) |
|
1204 | self.reparent(prevmodule) | |
@@ -1210,9 +1216,9 b' class svn_source(converter_source):' | |||||
1210 | # supplied URL |
|
1216 | # supplied URL | |
1211 | relpaths = [] |
|
1217 | relpaths = [] | |
1212 | for p in paths: |
|
1218 | for p in paths: | |
1213 | if not p.startswith('/'): |
|
1219 | if not p.startswith(b'/'): | |
1214 | p = self.module + '/' + p |
|
1220 | p = self.module + b'/' + p | |
1215 | relpaths.append(p.strip('/')) |
|
1221 | relpaths.append(p.strip(b'/')) | |
1216 | args = [ |
|
1222 | args = [ | |
1217 | self.baseurl, |
|
1223 | self.baseurl, | |
1218 | relpaths, |
|
1224 | relpaths, | |
@@ -1223,11 +1229,11 b' class svn_source(converter_source):' | |||||
1223 | strict_node_history, |
|
1229 | strict_node_history, | |
1224 | ] |
|
1230 | ] | |
1225 | # developer config: convert.svn.debugsvnlog |
|
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 | return directlogstream(*args) |
|
1233 | return directlogstream(*args) | |
1228 | arg = encodeargs(args) |
|
1234 | arg = encodeargs(args) | |
1229 | hgexe = procutil.hgexecutable() |
|
1235 | hgexe = procutil.hgexecutable() | |
1230 | cmd = '%s debugsvnlog' % procutil.shellquote(hgexe) |
|
1236 | cmd = b'%s debugsvnlog' % procutil.shellquote(hgexe) | |
1231 | stdin, stdout = procutil.popen2(procutil.quotecommand(cmd)) |
|
1237 | stdin, stdout = procutil.popen2(procutil.quotecommand(cmd)) | |
1232 | stdin.write(arg) |
|
1238 | stdin.write(arg) | |
1233 | try: |
|
1239 | try: | |
@@ -1235,8 +1241,8 b' class svn_source(converter_source):' | |||||
1235 | except IOError: |
|
1241 | except IOError: | |
1236 | raise error.Abort( |
|
1242 | raise error.Abort( | |
1237 | _( |
|
1243 | _( | |
1238 | 'Mercurial failed to run itself, check' |
|
1244 | b'Mercurial failed to run itself, check' | |
1239 | ' hg executable is in PATH' |
|
1245 | b' hg executable is in PATH' | |
1240 | ) |
|
1246 | ) | |
1241 | ) |
|
1247 | ) | |
1242 | return logstream(stdout) |
|
1248 | return logstream(stdout) | |
@@ -1272,18 +1278,18 b' class svn_sink(converter_sink, commandli' | |||||
1272 | os.chdir(self.cwd) |
|
1278 | os.chdir(self.cwd) | |
1273 |
|
1279 | |||
1274 | def join(self, name): |
|
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 | def revmapfile(self): |
|
1283 | def revmapfile(self): | |
1278 | return self.join('hg-shamap') |
|
1284 | return self.join(b'hg-shamap') | |
1279 |
|
1285 | |||
1280 | def authorfile(self): |
|
1286 | def authorfile(self): | |
1281 | return self.join('hg-authormap') |
|
1287 | return self.join(b'hg-authormap') | |
1282 |
|
1288 | |||
1283 | def __init__(self, ui, repotype, path): |
|
1289 | def __init__(self, ui, repotype, path): | |
1284 |
|
1290 | |||
1285 | converter_sink.__init__(self, ui, repotype, path) |
|
1291 | converter_sink.__init__(self, ui, repotype, path) | |
1286 | commandline.__init__(self, ui, 'svn') |
|
1292 | commandline.__init__(self, ui, b'svn') | |
1287 | self.delete = [] |
|
1293 | self.delete = [] | |
1288 | self.setexec = [] |
|
1294 | self.setexec = [] | |
1289 | self.delexec = [] |
|
1295 | self.delexec = [] | |
@@ -1292,51 +1298,53 b' class svn_sink(converter_sink, commandli' | |||||
1292 | self.cwd = encoding.getcwd() |
|
1298 | self.cwd = encoding.getcwd() | |
1293 |
|
1299 | |||
1294 | created = False |
|
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 | self.wc = os.path.realpath(path) |
|
1302 | self.wc = os.path.realpath(path) | |
1297 | self.run0('update') |
|
1303 | self.run0(b'update') | |
1298 | else: |
|
1304 | else: | |
1299 | if not re.search(br'^(file|http|https|svn|svn\+ssh)\://', path): |
|
1305 | if not re.search(br'^(file|http|https|svn|svn\+ssh)\://', path): | |
1300 | path = os.path.realpath(path) |
|
1306 | path = os.path.realpath(path) | |
1301 | if os.path.isdir(os.path.dirname(path)): |
|
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 | ui.status( |
|
1311 | ui.status( | |
1304 | _("initializing svn repository '%s'\n") |
|
1312 | _(b"initializing svn repository '%s'\n") | |
1305 | % os.path.basename(path) |
|
1313 | % os.path.basename(path) | |
1306 | ) |
|
1314 | ) | |
1307 | commandline(ui, 'svnadmin').run0('create', path) |
|
1315 | commandline(ui, b'svnadmin').run0(b'create', path) | |
1308 | created = path |
|
1316 | created = path | |
1309 | path = util.normpath(path) |
|
1317 | path = util.normpath(path) | |
1310 | if not path.startswith('/'): |
|
1318 | if not path.startswith(b'/'): | |
1311 | path = '/' + path |
|
1319 | path = b'/' + path | |
1312 | path = 'file://' + path |
|
1320 | path = b'file://' + path | |
1313 |
|
1321 | |||
1314 | wcpath = os.path.join( |
|
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 | ui.status( |
|
1325 | ui.status( | |
1318 | _("initializing svn working copy '%s'\n") |
|
1326 | _(b"initializing svn working copy '%s'\n") | |
1319 | % os.path.basename(wcpath) |
|
1327 | % os.path.basename(wcpath) | |
1320 | ) |
|
1328 | ) | |
1321 | self.run0('checkout', path, wcpath) |
|
1329 | self.run0(b'checkout', path, wcpath) | |
1322 |
|
1330 | |||
1323 | self.wc = wcpath |
|
1331 | self.wc = wcpath | |
1324 | self.opener = vfsmod.vfs(self.wc) |
|
1332 | self.opener = vfsmod.vfs(self.wc) | |
1325 | self.wopener = vfsmod.vfs(self.wc) |
|
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 | if util.checkexec(self.wc): |
|
1335 | if util.checkexec(self.wc): | |
1328 | self.is_exec = util.isexec |
|
1336 | self.is_exec = util.isexec | |
1329 | else: |
|
1337 | else: | |
1330 | self.is_exec = None |
|
1338 | self.is_exec = None | |
1331 |
|
1339 | |||
1332 | if created: |
|
1340 | if created: | |
1333 | hook = os.path.join(created, 'hooks', 'pre-revprop-change') |
|
1341 | hook = os.path.join(created, b'hooks', b'pre-revprop-change') | |
1334 | fp = open(hook, 'wb') |
|
1342 | fp = open(hook, b'wb') | |
1335 | fp.write(pre_revprop_change) |
|
1343 | fp.write(pre_revprop_change) | |
1336 | fp.close() |
|
1344 | fp.close() | |
1337 | util.setflags(hook, False, True) |
|
1345 | util.setflags(hook, False, True) | |
1338 |
|
1346 | |||
1339 | output = self.run0('info') |
|
1347 | output = self.run0(b'info') | |
1340 | self.uuid = self.uuid_re.search(output).group(1).strip() |
|
1348 | self.uuid = self.uuid_re.search(output).group(1).strip() | |
1341 |
|
1349 | |||
1342 | def wjoin(self, *names): |
|
1350 | def wjoin(self, *names): | |
@@ -1348,7 +1356,7 b' class svn_sink(converter_sink, commandli' | |||||
1348 | # already tracked entries, so we have to track and filter them |
|
1356 | # already tracked entries, so we have to track and filter them | |
1349 | # ourselves. |
|
1357 | # ourselves. | |
1350 | m = set() |
|
1358 | m = set() | |
1351 | output = self.run0('ls', recursive=True, xml=True) |
|
1359 | output = self.run0(b'ls', recursive=True, xml=True) | |
1352 | doc = xml.dom.minidom.parseString(output) |
|
1360 | doc = xml.dom.minidom.parseString(output) | |
1353 | for e in doc.getElementsByTagName(r'entry'): |
|
1361 | for e in doc.getElementsByTagName(r'entry'): | |
1354 | for n in e.childNodes: |
|
1362 | for n in e.childNodes: | |
@@ -1367,7 +1375,7 b' class svn_sink(converter_sink, commandli' | |||||
1367 | return m |
|
1375 | return m | |
1368 |
|
1376 | |||
1369 | def putfile(self, filename, flags, data): |
|
1377 | def putfile(self, filename, flags, data): | |
1370 | if 'l' in flags: |
|
1378 | if b'l' in flags: | |
1371 | self.wopener.symlink(data, filename) |
|
1379 | self.wopener.symlink(data, filename) | |
1372 | else: |
|
1380 | else: | |
1373 | try: |
|
1381 | try: | |
@@ -1387,12 +1395,12 b' class svn_sink(converter_sink, commandli' | |||||
1387 |
|
1395 | |||
1388 | if self.is_exec: |
|
1396 | if self.is_exec: | |
1389 | if wasexec: |
|
1397 | if wasexec: | |
1390 | if 'x' not in flags: |
|
1398 | if b'x' not in flags: | |
1391 | self.delexec.append(filename) |
|
1399 | self.delexec.append(filename) | |
1392 | else: |
|
1400 | else: | |
1393 | if 'x' in flags: |
|
1401 | if b'x' in flags: | |
1394 | self.setexec.append(filename) |
|
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 | def _copyfile(self, source, dest): |
|
1405 | def _copyfile(self, source, dest): | |
1398 | # SVN's copy command pukes if the destination file exists, but |
|
1406 | # SVN's copy command pukes if the destination file exists, but | |
@@ -1402,13 +1410,13 b' class svn_sink(converter_sink, commandli' | |||||
1402 | exists = os.path.lexists(wdest) |
|
1410 | exists = os.path.lexists(wdest) | |
1403 | if exists: |
|
1411 | if exists: | |
1404 | fd, tempname = pycompat.mkstemp( |
|
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 | os.close(fd) |
|
1415 | os.close(fd) | |
1408 | os.unlink(tempname) |
|
1416 | os.unlink(tempname) | |
1409 | os.rename(wdest, tempname) |
|
1417 | os.rename(wdest, tempname) | |
1410 | try: |
|
1418 | try: | |
1411 | self.run0('copy', source, dest) |
|
1419 | self.run0(b'copy', source, dest) | |
1412 | finally: |
|
1420 | finally: | |
1413 | self.manifest.add(dest) |
|
1421 | self.manifest.add(dest) | |
1414 | if exists: |
|
1422 | if exists: | |
@@ -1424,7 +1432,7 b' class svn_sink(converter_sink, commandli' | |||||
1424 | if os.path.isdir(self.wjoin(f)): |
|
1432 | if os.path.isdir(self.wjoin(f)): | |
1425 | dirs.add(f) |
|
1433 | dirs.add(f) | |
1426 | i = len(f) |
|
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 | dirs.add(f[:i]) |
|
1436 | dirs.add(f[:i]) | |
1429 | return dirs |
|
1437 | return dirs | |
1430 |
|
1438 | |||
@@ -1434,21 +1442,21 b' class svn_sink(converter_sink, commandli' | |||||
1434 | ] |
|
1442 | ] | |
1435 | if add_dirs: |
|
1443 | if add_dirs: | |
1436 | self.manifest.update(add_dirs) |
|
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 | return add_dirs |
|
1446 | return add_dirs | |
1439 |
|
1447 | |||
1440 | def add_files(self, files): |
|
1448 | def add_files(self, files): | |
1441 | files = [f for f in files if f not in self.manifest] |
|
1449 | files = [f for f in files if f not in self.manifest] | |
1442 | if files: |
|
1450 | if files: | |
1443 | self.manifest.update(files) |
|
1451 | self.manifest.update(files) | |
1444 | self.xargs(files, 'add', quiet=True) |
|
1452 | self.xargs(files, b'add', quiet=True) | |
1445 | return files |
|
1453 | return files | |
1446 |
|
1454 | |||
1447 | def addchild(self, parent, child): |
|
1455 | def addchild(self, parent, child): | |
1448 | self.childmap[parent] = child |
|
1456 | self.childmap[parent] = child | |
1449 |
|
1457 | |||
1450 | def revid(self, rev): |
|
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 | def putcommit( |
|
1461 | def putcommit( | |
1454 | self, files, copies, parents, commit, source, revmap, full, cleanp2 |
|
1462 | self, files, copies, parents, commit, source, revmap, full, cleanp2 | |
@@ -1480,49 +1488,49 b' class svn_sink(converter_sink, commandli' | |||||
1480 | self._copyfile(s, d) |
|
1488 | self._copyfile(s, d) | |
1481 | self.copies = [] |
|
1489 | self.copies = [] | |
1482 | if self.delete: |
|
1490 | if self.delete: | |
1483 | self.xargs(self.delete, 'delete') |
|
1491 | self.xargs(self.delete, b'delete') | |
1484 | for f in self.delete: |
|
1492 | for f in self.delete: | |
1485 | self.manifest.remove(f) |
|
1493 | self.manifest.remove(f) | |
1486 | self.delete = [] |
|
1494 | self.delete = [] | |
1487 | entries.update(self.add_files(files.difference(entries))) |
|
1495 | entries.update(self.add_files(files.difference(entries))) | |
1488 | if self.delexec: |
|
1496 | if self.delexec: | |
1489 | self.xargs(self.delexec, 'propdel', 'svn:executable') |
|
1497 | self.xargs(self.delexec, b'propdel', b'svn:executable') | |
1490 | self.delexec = [] |
|
1498 | self.delexec = [] | |
1491 | if self.setexec: |
|
1499 | if self.setexec: | |
1492 | self.xargs(self.setexec, 'propset', 'svn:executable', '*') |
|
1500 | self.xargs(self.setexec, b'propset', b'svn:executable', b'*') | |
1493 | self.setexec = [] |
|
1501 | self.setexec = [] | |
1494 |
|
1502 | |||
1495 | fd, messagefile = pycompat.mkstemp(prefix='hg-convert-') |
|
1503 | fd, messagefile = pycompat.mkstemp(prefix=b'hg-convert-') | |
1496 | fp = os.fdopen(fd, r'wb') |
|
1504 | fp = os.fdopen(fd, r'wb') | |
1497 | fp.write(util.tonativeeol(commit.desc)) |
|
1505 | fp.write(util.tonativeeol(commit.desc)) | |
1498 | fp.close() |
|
1506 | fp.close() | |
1499 | try: |
|
1507 | try: | |
1500 | output = self.run0( |
|
1508 | output = self.run0( | |
1501 | 'commit', |
|
1509 | b'commit', | |
1502 | username=stringutil.shortuser(commit.author), |
|
1510 | username=stringutil.shortuser(commit.author), | |
1503 | file=messagefile, |
|
1511 | file=messagefile, | |
1504 | encoding='utf-8', |
|
1512 | encoding=b'utf-8', | |
1505 | ) |
|
1513 | ) | |
1506 | try: |
|
1514 | try: | |
1507 | rev = self.commit_re.search(output).group(1) |
|
1515 | rev = self.commit_re.search(output).group(1) | |
1508 | except AttributeError: |
|
1516 | except AttributeError: | |
1509 | if not files: |
|
1517 | if not files: | |
1510 | return parents[0] if parents else 'None' |
|
1518 | return parents[0] if parents else b'None' | |
1511 | self.ui.warn(_('unexpected svn output:\n')) |
|
1519 | self.ui.warn(_(b'unexpected svn output:\n')) | |
1512 | self.ui.warn(output) |
|
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 | if commit.rev: |
|
1522 | if commit.rev: | |
1515 | self.run( |
|
1523 | self.run( | |
1516 | 'propset', |
|
1524 | b'propset', | |
1517 | 'hg:convert-rev', |
|
1525 | b'hg:convert-rev', | |
1518 | commit.rev, |
|
1526 | commit.rev, | |
1519 | revprop=True, |
|
1527 | revprop=True, | |
1520 | revision=rev, |
|
1528 | revision=rev, | |
1521 | ) |
|
1529 | ) | |
1522 | if commit.branch and commit.branch != 'default': |
|
1530 | if commit.branch and commit.branch != b'default': | |
1523 | self.run( |
|
1531 | self.run( | |
1524 | 'propset', |
|
1532 | b'propset', | |
1525 | 'hg:convert-branch', |
|
1533 | b'hg:convert-branch', | |
1526 | commit.branch, |
|
1534 | commit.branch, | |
1527 | revprop=True, |
|
1535 | revprop=True, | |
1528 | revision=rev, |
|
1536 | revision=rev, | |
@@ -1534,7 +1542,7 b' class svn_sink(converter_sink, commandli' | |||||
1534 | os.unlink(messagefile) |
|
1542 | os.unlink(messagefile) | |
1535 |
|
1543 | |||
1536 | def puttags(self, tags): |
|
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 | return None, None |
|
1546 | return None, None | |
1539 |
|
1547 | |||
1540 | def hascommitfrommap(self, rev): |
|
1548 | def hascommitfrommap(self, rev): | |
@@ -1549,8 +1557,8 b' class svn_sink(converter_sink, commandli' | |||||
1549 | return True |
|
1557 | return True | |
1550 | raise error.Abort( |
|
1558 | raise error.Abort( | |
1551 | _( |
|
1559 | _( | |
1552 | 'splice map revision %s not found in subversion ' |
|
1560 | b'splice map revision %s not found in subversion ' | |
1553 | 'child map (revision lookups are not implemented)' |
|
1561 | b'child map (revision lookups are not implemented)' | |
1554 | ) |
|
1562 | ) | |
1555 | % rev |
|
1563 | % rev | |
1556 | ) |
|
1564 | ) |
@@ -54,13 +54,13 b' def _create_auth_baton(pool):' | |||||
54 | ) |
|
54 | ) | |
55 | if getprovider: |
|
55 | if getprovider: | |
56 | # Available in svn >= 1.6 |
|
56 | # Available in svn >= 1.6 | |
57 | for name in ('gnome_keyring', 'keychain', 'kwallet', 'windows'): |
|
57 | for name in (b'gnome_keyring', b'keychain', b'kwallet', b'windows'): | |
58 | for type in ('simple', 'ssl_client_cert_pw', 'ssl_server_trust'): |
|
58 | for type in (b'simple', b'ssl_client_cert_pw', b'ssl_server_trust'): | |
59 | p = getprovider(name, type, pool) |
|
59 | p = getprovider(name, type, pool) | |
60 | if p: |
|
60 | if p: | |
61 | providers.append(p) |
|
61 | providers.append(p) | |
62 | else: |
|
62 | else: | |
63 | if util.safehasattr(svn.client, 'get_windows_simple_provider'): |
|
63 | if util.safehasattr(svn.client, b'get_windows_simple_provider'): | |
64 | providers.append(svn.client.get_windows_simple_provider(pool)) |
|
64 | providers.append(svn.client.get_windows_simple_provider(pool)) | |
65 |
|
65 | |||
66 | return svn.core.svn_auth_open(providers, pool) |
|
66 | return svn.core.svn_auth_open(providers, pool) | |
@@ -75,14 +75,14 b' class SvnRaTransport(object):' | |||||
75 | Open an ra connection to a Subversion repository. |
|
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 | self.pool = Pool() |
|
79 | self.pool = Pool() | |
80 | self.svn_url = url |
|
80 | self.svn_url = url | |
81 | self.username = '' |
|
81 | self.username = b'' | |
82 | self.password = '' |
|
82 | self.password = b'' | |
83 |
|
83 | |||
84 | # Only Subversion 1.4 has reparent() |
|
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 | self.client = svn.client.create_context(self.pool) |
|
86 | self.client = svn.client.create_context(self.pool) | |
87 | ab = _create_auth_baton(self.pool) |
|
87 | ab = _create_auth_baton(self.pool) | |
88 | self.client.auth_baton = ab |
|
88 | self.client.auth_baton = ab |
@@ -112,41 +112,41 b' from mercurial.utils import stringutil' | |||||
112 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
112 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
113 | # be specifying the version(s) of Mercurial they are tested with, or |
|
113 | # be specifying the version(s) of Mercurial they are tested with, or | |
114 | # leave the attribute unspecified. |
|
114 | # leave the attribute unspecified. | |
115 | testedwith = 'ships-with-hg-core' |
|
115 | testedwith = b'ships-with-hg-core' | |
116 |
|
116 | |||
117 | configtable = {} |
|
117 | configtable = {} | |
118 | configitem = registrar.configitem(configtable) |
|
118 | configitem = registrar.configitem(configtable) | |
119 |
|
119 | |||
120 | configitem( |
|
120 | configitem( | |
121 | 'eol', 'fix-trailing-newline', default=False, |
|
121 | b'eol', b'fix-trailing-newline', default=False, | |
122 | ) |
|
122 | ) | |
123 | configitem( |
|
123 | configitem( | |
124 | 'eol', 'native', default=pycompat.oslinesep, |
|
124 | b'eol', b'native', default=pycompat.oslinesep, | |
125 | ) |
|
125 | ) | |
126 | configitem( |
|
126 | configitem( | |
127 | 'eol', 'only-consistent', default=True, |
|
127 | b'eol', b'only-consistent', default=True, | |
128 | ) |
|
128 | ) | |
129 |
|
129 | |||
130 | # Matches a lone LF, i.e., one that is not part of CRLF. |
|
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 | def inconsistenteol(data): |
|
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 | def tolf(s, params, ui, **kwargs): |
|
138 | def tolf(s, params, ui, **kwargs): | |
139 | """Filter to convert to LF EOLs.""" |
|
139 | """Filter to convert to LF EOLs.""" | |
140 | if stringutil.binary(s): |
|
140 | if stringutil.binary(s): | |
141 | return s |
|
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 | return s |
|
143 | return s | |
144 | if ( |
|
144 | if ( | |
145 | ui.configbool('eol', 'fix-trailing-newline') |
|
145 | ui.configbool(b'eol', b'fix-trailing-newline') | |
146 | and s |
|
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 | return util.tolf(s) |
|
150 | return util.tolf(s) | |
151 |
|
151 | |||
152 |
|
152 | |||
@@ -154,14 +154,14 b' def tocrlf(s, params, ui, **kwargs):' | |||||
154 | """Filter to convert to CRLF EOLs.""" |
|
154 | """Filter to convert to CRLF EOLs.""" | |
155 | if stringutil.binary(s): |
|
155 | if stringutil.binary(s): | |
156 | return s |
|
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 | return s |
|
158 | return s | |
159 | if ( |
|
159 | if ( | |
160 | ui.configbool('eol', 'fix-trailing-newline') |
|
160 | ui.configbool(b'eol', b'fix-trailing-newline') | |
161 | and s |
|
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 | return util.tocrlf(s) |
|
165 | return util.tocrlf(s) | |
166 |
|
166 | |||
167 |
|
167 | |||
@@ -171,60 +171,68 b' def isbinary(s, params):' | |||||
171 |
|
171 | |||
172 |
|
172 | |||
173 | filters = { |
|
173 | filters = { | |
174 | 'to-lf': tolf, |
|
174 | b'to-lf': tolf, | |
175 | 'to-crlf': tocrlf, |
|
175 | b'to-crlf': tocrlf, | |
176 | 'is-binary': isbinary, |
|
176 | b'is-binary': isbinary, | |
177 | # The following provide backwards compatibility with win32text |
|
177 | # The following provide backwards compatibility with win32text | |
178 | 'cleverencode:': tolf, |
|
178 | b'cleverencode:': tolf, | |
179 | 'cleverdecode:': tocrlf, |
|
179 | b'cleverdecode:': tocrlf, | |
180 | } |
|
180 | } | |
181 |
|
181 | |||
182 |
|
182 | |||
183 | class eolfile(object): |
|
183 | class eolfile(object): | |
184 | def __init__(self, ui, root, data): |
|
184 | def __init__(self, ui, root, data): | |
185 | self._decode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} |
|
185 | self._decode = { | |
186 | self._encode = {'LF': 'to-lf', 'CRLF': 'to-crlf', 'BIN': 'is-binary'} |
|
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 | self.cfg = config.config() |
|
196 | self.cfg = config.config() | |
189 | # Our files should not be touched. The pattern must be |
|
197 | # Our files should not be touched. The pattern must be | |
190 | # inserted first override a '** = native' pattern. |
|
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 | # We can then parse the user's patterns. |
|
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' |
|
203 | isrepolf = self.cfg.get(b'repository', b'native') != b'CRLF' | |
196 | self._encode['NATIVE'] = isrepolf and 'to-lf' or 'to-crlf' |
|
204 | self._encode[b'NATIVE'] = isrepolf and b'to-lf' or b'to-crlf' | |
197 | iswdlf = ui.config('eol', 'native') in ('LF', '\n') |
|
205 | iswdlf = ui.config(b'eol', b'native') in (b'LF', b'\n') | |
198 | self._decode['NATIVE'] = iswdlf and 'to-lf' or 'to-crlf' |
|
206 | self._decode[b'NATIVE'] = iswdlf and b'to-lf' or b'to-crlf' | |
199 |
|
207 | |||
200 | include = [] |
|
208 | include = [] | |
201 | exclude = [] |
|
209 | exclude = [] | |
202 | self.patterns = [] |
|
210 | self.patterns = [] | |
203 | for pattern, style in self.cfg.items('patterns'): |
|
211 | for pattern, style in self.cfg.items(b'patterns'): | |
204 | key = style.upper() |
|
212 | key = style.upper() | |
205 | if key == 'BIN': |
|
213 | if key == b'BIN': | |
206 | exclude.append(pattern) |
|
214 | exclude.append(pattern) | |
207 | else: |
|
215 | else: | |
208 | include.append(pattern) |
|
216 | include.append(pattern) | |
209 | m = match.match(root, '', [pattern]) |
|
217 | m = match.match(root, b'', [pattern]) | |
210 | self.patterns.append((pattern, key, m)) |
|
218 | self.patterns.append((pattern, key, m)) | |
211 | # This will match the files for which we need to care |
|
219 | # This will match the files for which we need to care | |
212 | # about inconsistent newlines. |
|
220 | # about inconsistent newlines. | |
213 | self.match = match.match(root, '', [], include, exclude) |
|
221 | self.match = match.match(root, b'', [], include, exclude) | |
214 |
|
222 | |||
215 | def copytoui(self, ui): |
|
223 | def copytoui(self, ui): | |
216 | for pattern, key, m in self.patterns: |
|
224 | for pattern, key, m in self.patterns: | |
217 | try: |
|
225 | try: | |
218 | ui.setconfig('decode', pattern, self._decode[key], 'eol') |
|
226 | ui.setconfig(b'decode', pattern, self._decode[key], b'eol') | |
219 | ui.setconfig('encode', pattern, self._encode[key], 'eol') |
|
227 | ui.setconfig(b'encode', pattern, self._encode[key], b'eol') | |
220 | except KeyError: |
|
228 | except KeyError: | |
221 | ui.warn( |
|
229 | ui.warn( | |
222 | _("ignoring unknown EOL style '%s' from %s\n") |
|
230 | _(b"ignoring unknown EOL style '%s' from %s\n") | |
223 | % (key, self.cfg.source('patterns', pattern)) |
|
231 | % (key, self.cfg.source(b'patterns', pattern)) | |
224 | ) |
|
232 | ) | |
225 | # eol.only-consistent can be specified in ~/.hgrc or .hgeol |
|
233 | # eol.only-consistent can be specified in ~/.hgrc or .hgeol | |
226 | for k, v in self.cfg.items('eol'): |
|
234 | for k, v in self.cfg.items(b'eol'): | |
227 | ui.setconfig('eol', k, v, 'eol') |
|
235 | ui.setconfig(b'eol', k, v, b'eol') | |
228 |
|
236 | |||
229 | def checkrev(self, repo, ctx, files): |
|
237 | def checkrev(self, repo, ctx, files): | |
230 | failed = [] |
|
238 | failed = [] | |
@@ -237,9 +245,9 b' class eolfile(object):' | |||||
237 | target = self._encode[key] |
|
245 | target = self._encode[key] | |
238 | data = ctx[f].data() |
|
246 | data = ctx[f].data() | |
239 | if ( |
|
247 | if ( | |
240 | target == "to-lf" |
|
248 | target == b"to-lf" | |
241 | and "\r\n" in data |
|
249 | and b"\r\n" in data | |
242 | or target == "to-crlf" |
|
250 | or target == b"to-crlf" | |
243 | and singlelf.search(data) |
|
251 | and singlelf.search(data) | |
244 | ): |
|
252 | ): | |
245 | failed.append((f, target, bytes(ctx))) |
|
253 | failed.append((f, target, bytes(ctx))) | |
@@ -254,15 +262,18 b' def parseeol(ui, repo, nodes):' | |||||
254 | if node is None: |
|
262 | if node is None: | |
255 | # Cannot use workingctx.data() since it would load |
|
263 | # Cannot use workingctx.data() since it would load | |
256 | # and cache the filters before we configure them. |
|
264 | # and cache the filters before we configure them. | |
257 | data = repo.wvfs('.hgeol').read() |
|
265 | data = repo.wvfs(b'.hgeol').read() | |
258 | else: |
|
266 | else: | |
259 | data = repo[node]['.hgeol'].data() |
|
267 | data = repo[node][b'.hgeol'].data() | |
260 | return eolfile(ui, repo.root, data) |
|
268 | return eolfile(ui, repo.root, data) | |
261 | except (IOError, LookupError): |
|
269 | except (IOError, LookupError): | |
262 | pass |
|
270 | pass | |
263 | except errormod.ParseError as inst: |
|
271 | except errormod.ParseError as inst: | |
264 | ui.warn( |
|
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 | % (inst.args[1], inst.args[0]) |
|
277 | % (inst.args[1], inst.args[0]) | |
267 | ) |
|
278 | ) | |
268 | return None |
|
279 | return None | |
@@ -276,10 +287,10 b' def ensureenabled(ui):' | |||||
276 | never loaded. This function ensure the extension is enabled when running |
|
287 | never loaded. This function ensure the extension is enabled when running | |
277 | hooks. |
|
288 | hooks. | |
278 | """ |
|
289 | """ | |
279 | if 'eol' in ui._knownconfig: |
|
290 | if b'eol' in ui._knownconfig: | |
280 | return |
|
291 | return | |
281 | ui.setconfig('extensions', 'eol', '', source='internal') |
|
292 | ui.setconfig(b'extensions', b'eol', b'', source=b'internal') | |
282 | extensions.loadall(ui, ['eol']) |
|
293 | extensions.loadall(ui, [b'eol']) | |
283 |
|
294 | |||
284 |
|
295 | |||
285 | def _checkhook(ui, repo, node, headsonly): |
|
296 | def _checkhook(ui, repo, node, headsonly): | |
@@ -302,14 +313,16 b' def _checkhook(ui, repo, node, headsonly' | |||||
302 | failed.extend(eol.checkrev(repo, ctx, files)) |
|
313 | failed.extend(eol.checkrev(repo, ctx, files)) | |
303 |
|
314 | |||
304 | if failed: |
|
315 | if failed: | |
305 | eols = {'to-lf': 'CRLF', 'to-crlf': 'LF'} |
|
316 | eols = {b'to-lf': b'CRLF', b'to-crlf': b'LF'} | |
306 | msgs = [] |
|
317 | msgs = [] | |
307 | for f, target, node in sorted(failed): |
|
318 | for f, target, node in sorted(failed): | |
308 | msgs.append( |
|
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 | % (f, node, eols[target]) |
|
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 | def checkallhook(ui, repo, node, hooktype, **kwargs): |
|
328 | def checkallhook(ui, repo, node, hooktype, **kwargs): | |
@@ -333,16 +346,16 b' def preupdate(ui, repo, hooktype, parent' | |||||
333 |
|
346 | |||
334 |
|
347 | |||
335 | def uisetup(ui): |
|
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 | def extsetup(ui): |
|
352 | def extsetup(ui): | |
340 | try: |
|
353 | try: | |
341 | extensions.find('win32text') |
|
354 | extensions.find(b'win32text') | |
342 | ui.warn( |
|
355 | ui.warn( | |
343 | _( |
|
356 | _( | |
344 | "the eol extension is incompatible with the " |
|
357 | b"the eol extension is incompatible with the " | |
345 | "win32text extension\n" |
|
358 | b"win32text extension\n" | |
346 | ) |
|
359 | ) | |
347 | ) |
|
360 | ) | |
348 | except KeyError: |
|
361 | except KeyError: | |
@@ -357,7 +370,7 b' def reposetup(ui, repo):' | |||||
357 | for name, fn in filters.iteritems(): |
|
370 | for name, fn in filters.iteritems(): | |
358 | repo.adddatafilter(name, fn) |
|
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 | class eolrepo(repo.__class__): |
|
375 | class eolrepo(repo.__class__): | |
363 | def loadeol(self, nodes): |
|
376 | def loadeol(self, nodes): | |
@@ -368,37 +381,37 b' def reposetup(ui, repo):' | |||||
368 | return eol.match |
|
381 | return eol.match | |
369 |
|
382 | |||
370 | def _hgcleardirstate(self): |
|
383 | def _hgcleardirstate(self): | |
371 | self._eolmatch = self.loadeol([None, 'tip']) |
|
384 | self._eolmatch = self.loadeol([None, b'tip']) | |
372 | if not self._eolmatch: |
|
385 | if not self._eolmatch: | |
373 | self._eolmatch = util.never |
|
386 | self._eolmatch = util.never | |
374 | return |
|
387 | return | |
375 |
|
388 | |||
376 | oldeol = None |
|
389 | oldeol = None | |
377 | try: |
|
390 | try: | |
378 | cachemtime = os.path.getmtime(self.vfs.join("eol.cache")) |
|
391 | cachemtime = os.path.getmtime(self.vfs.join(b"eol.cache")) | |
379 | except OSError: |
|
392 | except OSError: | |
380 | cachemtime = 0 |
|
393 | cachemtime = 0 | |
381 | else: |
|
394 | else: | |
382 | olddata = self.vfs.read("eol.cache") |
|
395 | olddata = self.vfs.read(b"eol.cache") | |
383 | if olddata: |
|
396 | if olddata: | |
384 | oldeol = eolfile(self.ui, self.root, olddata) |
|
397 | oldeol = eolfile(self.ui, self.root, olddata) | |
385 |
|
398 | |||
386 | try: |
|
399 | try: | |
387 | eolmtime = os.path.getmtime(self.wjoin(".hgeol")) |
|
400 | eolmtime = os.path.getmtime(self.wjoin(b".hgeol")) | |
388 | except OSError: |
|
401 | except OSError: | |
389 | eolmtime = 0 |
|
402 | eolmtime = 0 | |
390 |
|
403 | |||
391 | if eolmtime > cachemtime: |
|
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 | neweol = eolfile(self.ui, self.root, hgeoldata) |
|
408 | neweol = eolfile(self.ui, self.root, hgeoldata) | |
396 |
|
409 | |||
397 | wlock = None |
|
410 | wlock = None | |
398 | try: |
|
411 | try: | |
399 | wlock = self.wlock() |
|
412 | wlock = self.wlock() | |
400 | for f in self.dirstate: |
|
413 | for f in self.dirstate: | |
401 | if self.dirstate[f] != 'n': |
|
414 | if self.dirstate[f] != b'n': | |
402 | continue |
|
415 | continue | |
403 | if oldeol is not None: |
|
416 | if oldeol is not None: | |
404 | if not oldeol.match(f) and not neweol.match(f): |
|
417 | if not oldeol.match(f) and not neweol.match(f): | |
@@ -419,7 +432,7 b' def reposetup(ui, repo):' | |||||
419 | # the new .hgeol file specify a different filter |
|
432 | # the new .hgeol file specify a different filter | |
420 | self.dirstate.normallookup(f) |
|
433 | self.dirstate.normallookup(f) | |
421 | # Write the cache to update mtime and cache .hgeol |
|
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 | f.write(hgeoldata) |
|
436 | f.write(hgeoldata) | |
424 | except errormod.LockUnavailable: |
|
437 | except errormod.LockUnavailable: | |
425 | # If we cannot lock the repository and clear the |
|
438 | # If we cannot lock the repository and clear the | |
@@ -447,7 +460,7 b' def reposetup(ui, repo):' | |||||
447 | continue |
|
460 | continue | |
448 | if inconsistenteol(data): |
|
461 | if inconsistenteol(data): | |
449 | raise errormod.Abort( |
|
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 | return super(eolrepo, self).commitctx(ctx, error, origctx) |
|
465 | return super(eolrepo, self).commitctx(ctx, error, origctx) | |
453 |
|
466 |
@@ -118,26 +118,26 b' configtable = {}' | |||||
118 | configitem = registrar.configitem(configtable) |
|
118 | configitem = registrar.configitem(configtable) | |
119 |
|
119 | |||
120 | configitem( |
|
120 | configitem( | |
121 | 'extdiff', br'opts\..*', default='', generic=True, |
|
121 | b'extdiff', br'opts\..*', default=b'', generic=True, | |
122 | ) |
|
122 | ) | |
123 |
|
123 | |||
124 | configitem( |
|
124 | configitem( | |
125 | 'extdiff', br'gui\..*', generic=True, |
|
125 | b'extdiff', br'gui\..*', generic=True, | |
126 | ) |
|
126 | ) | |
127 |
|
127 | |||
128 | configitem( |
|
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 | configitem( |
|
132 | configitem( | |
133 | 'diff-tools', br'.*\.gui$', generic=True, |
|
133 | b'diff-tools', br'.*\.gui$', generic=True, | |
134 | ) |
|
134 | ) | |
135 |
|
135 | |||
136 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for |
|
136 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | |
137 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
137 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
138 | # be specifying the version(s) of Mercurial they are tested with, or |
|
138 | # be specifying the version(s) of Mercurial they are tested with, or | |
139 | # leave the attribute unspecified. |
|
139 | # leave the attribute unspecified. | |
140 | testedwith = 'ships-with-hg-core' |
|
140 | testedwith = b'ships-with-hg-core' | |
141 |
|
141 | |||
142 |
|
142 | |||
143 | def snapshot(ui, repo, files, node, tmproot, listsubrepos): |
|
143 | def snapshot(ui, repo, files, node, tmproot, listsubrepos): | |
@@ -145,40 +145,40 b' def snapshot(ui, repo, files, node, tmpr' | |||||
145 | if not using snapshot, -I/-X does not work and recursive diff |
|
145 | if not using snapshot, -I/-X does not work and recursive diff | |
146 | in tools like kdiff3 and meld displays too many files.''' |
|
146 | in tools like kdiff3 and meld displays too many files.''' | |
147 | dirname = os.path.basename(repo.root) |
|
147 | dirname = os.path.basename(repo.root) | |
148 | if dirname == "": |
|
148 | if dirname == b"": | |
149 | dirname = "root" |
|
149 | dirname = b"root" | |
150 | if node is not None: |
|
150 | if node is not None: | |
151 | dirname = '%s.%s' % (dirname, short(node)) |
|
151 | dirname = b'%s.%s' % (dirname, short(node)) | |
152 | base = os.path.join(tmproot, dirname) |
|
152 | base = os.path.join(tmproot, dirname) | |
153 | os.mkdir(base) |
|
153 | os.mkdir(base) | |
154 | fnsandstat = [] |
|
154 | fnsandstat = [] | |
155 |
|
155 | |||
156 | if node is not None: |
|
156 | if node is not None: | |
157 | ui.note( |
|
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 | % (len(files), short(node)) |
|
159 | % (len(files), short(node)) | |
160 | ) |
|
160 | ) | |
161 | else: |
|
161 | else: | |
162 | ui.note( |
|
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 | % (len(files)) |
|
164 | % (len(files)) | |
165 | ) |
|
165 | ) | |
166 |
|
166 | |||
167 | if files: |
|
167 | if files: | |
168 | repo.ui.setconfig("ui", "archivemeta", False) |
|
168 | repo.ui.setconfig(b"ui", b"archivemeta", False) | |
169 |
|
169 | |||
170 | archival.archive( |
|
170 | archival.archive( | |
171 | repo, |
|
171 | repo, | |
172 | base, |
|
172 | base, | |
173 | node, |
|
173 | node, | |
174 | 'files', |
|
174 | b'files', | |
175 | match=scmutil.matchfiles(repo, files), |
|
175 | match=scmutil.matchfiles(repo, files), | |
176 | subrepos=listsubrepos, |
|
176 | subrepos=listsubrepos, | |
177 | ) |
|
177 | ) | |
178 |
|
178 | |||
179 | for fn in sorted(files): |
|
179 | for fn in sorted(files): | |
180 | wfn = util.pconvert(fn) |
|
180 | wfn = util.pconvert(fn) | |
181 | ui.note(' %s\n' % wfn) |
|
181 | ui.note(b' %s\n' % wfn) | |
182 |
|
182 | |||
183 | if node is None: |
|
183 | if node is None: | |
184 | dest = os.path.join(base, wfn) |
|
184 | dest = os.path.join(base, wfn) | |
@@ -202,20 +202,20 b' def formatcmdline(' | |||||
202 | # When not operating in 3-way mode, an empty string is |
|
202 | # When not operating in 3-way mode, an empty string is | |
203 | # returned for parent2 |
|
203 | # returned for parent2 | |
204 | replace = { |
|
204 | replace = { | |
205 | 'parent': parent1, |
|
205 | b'parent': parent1, | |
206 | 'parent1': parent1, |
|
206 | b'parent1': parent1, | |
207 | 'parent2': parent2, |
|
207 | b'parent2': parent2, | |
208 | 'plabel1': plabel1, |
|
208 | b'plabel1': plabel1, | |
209 | 'plabel2': plabel2, |
|
209 | b'plabel2': plabel2, | |
210 | 'child': child, |
|
210 | b'child': child, | |
211 | 'clabel': clabel, |
|
211 | b'clabel': clabel, | |
212 | 'root': repo_root, |
|
212 | b'root': repo_root, | |
213 | } |
|
213 | } | |
214 |
|
214 | |||
215 | def quote(match): |
|
215 | def quote(match): | |
216 | pre = match.group(2) |
|
216 | pre = match.group(2) | |
217 | key = match.group(3) |
|
217 | key = match.group(3) | |
218 | if not do3way and key == 'parent2': |
|
218 | if not do3way and key == b'parent2': | |
219 | return pre |
|
219 | return pre | |
220 | return pre + procutil.shellquote(replace[key]) |
|
220 | return pre + procutil.shellquote(replace[key]) | |
221 |
|
221 | |||
@@ -225,7 +225,7 b' def formatcmdline(' | |||||
225 | br'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1' |
|
225 | br'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1' | |
226 | ) |
|
226 | ) | |
227 | if not do3way and not re.search(regex, cmdline): |
|
227 | if not do3way and not re.search(regex, cmdline): | |
228 | cmdline += ' $parent1 $child' |
|
228 | cmdline += b' $parent1 $child' | |
229 | return re.sub(regex, quote, cmdline) |
|
229 | return re.sub(regex, quote, cmdline) | |
230 |
|
230 | |||
231 |
|
231 | |||
@@ -273,8 +273,8 b' def _runperfilediff(' | |||||
273 | if not os.path.isfile(path1a): |
|
273 | if not os.path.isfile(path1a): | |
274 | path1a = os.devnull |
|
274 | path1a = os.devnull | |
275 |
|
275 | |||
276 | path1b = '' |
|
276 | path1b = b'' | |
277 | label1b = '' |
|
277 | label1b = b'' | |
278 | if do3way: |
|
278 | if do3way: | |
279 | path1b = os.path.join(tmproot, dir1b, commonfile) |
|
279 | path1b = os.path.join(tmproot, dir1b, commonfile) | |
280 | label1b = commonfile + rev1b |
|
280 | label1b = commonfile + rev1b | |
@@ -286,24 +286,24 b' def _runperfilediff(' | |||||
286 |
|
286 | |||
287 | if confirm: |
|
287 | if confirm: | |
288 | # Prompt before showing this diff |
|
288 | # Prompt before showing this diff | |
289 | difffiles = _('diff %s (%d of %d)') % ( |
|
289 | difffiles = _(b'diff %s (%d of %d)') % ( | |
290 | commonfile, |
|
290 | commonfile, | |
291 | idx + 1, |
|
291 | idx + 1, | |
292 | totalfiles, |
|
292 | totalfiles, | |
293 | ) |
|
293 | ) | |
294 | responses = _( |
|
294 | responses = _( | |
295 | '[Yns?]' |
|
295 | b'[Yns?]' | |
296 | '$$ &Yes, show diff' |
|
296 | b'$$ &Yes, show diff' | |
297 | '$$ &No, skip this diff' |
|
297 | b'$$ &No, skip this diff' | |
298 | '$$ &Skip remaining diffs' |
|
298 | b'$$ &Skip remaining diffs' | |
299 | '$$ &? (display help)' |
|
299 | b'$$ &? (display help)' | |
300 | ) |
|
300 | ) | |
301 | r = ui.promptchoice('%s %s' % (difffiles, responses)) |
|
301 | r = ui.promptchoice(b'%s %s' % (difffiles, responses)) | |
302 | if r == 3: # ? |
|
302 | if r == 3: # ? | |
303 | while r == 3: |
|
303 | while r == 3: | |
304 | for c, t in ui.extractchoices(responses)[1]: |
|
304 | for c, t in ui.extractchoices(responses)[1]: | |
305 | ui.write('%s - %s\n' % (c, encoding.lower(t))) |
|
305 | ui.write(b'%s - %s\n' % (c, encoding.lower(t))) | |
306 | r = ui.promptchoice('%s %s' % (difffiles, responses)) |
|
306 | r = ui.promptchoice(b'%s %s' % (difffiles, responses)) | |
307 | if r == 0: # yes |
|
307 | if r == 0: # yes | |
308 | pass |
|
308 | pass | |
309 | elif r == 1: # no |
|
309 | elif r == 1: # no | |
@@ -331,22 +331,22 b' def _runperfilediff(' | |||||
331 | # as we know, the tool doesn't have a GUI, in which case |
|
331 | # as we know, the tool doesn't have a GUI, in which case | |
332 | # we can't run multiple CLI programs at the same time. |
|
332 | # we can't run multiple CLI programs at the same time. | |
333 | ui.debug( |
|
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 | else: |
|
337 | else: | |
338 | # Run the comparison program but don't wait, as we're |
|
338 | # Run the comparison program but don't wait, as we're | |
339 | # going to rapid-fire each file diff and then wait on |
|
339 | # going to rapid-fire each file diff and then wait on | |
340 | # the whole group. |
|
340 | # the whole group. | |
341 | ui.debug( |
|
341 | ui.debug( | |
342 | 'running %r in %s (backgrounded)\n' |
|
342 | b'running %r in %s (backgrounded)\n' | |
343 | % (pycompat.bytestr(curcmdline), tmproot) |
|
343 | % (pycompat.bytestr(curcmdline), tmproot) | |
344 | ) |
|
344 | ) | |
345 | proc = _systembackground(curcmdline, cwd=tmproot) |
|
345 | proc = _systembackground(curcmdline, cwd=tmproot) | |
346 | waitprocs.append(proc) |
|
346 | waitprocs.append(proc) | |
347 |
|
347 | |||
348 | if waitprocs: |
|
348 | if waitprocs: | |
349 | with ui.timeblockedsection('extdiff'): |
|
349 | with ui.timeblockedsection(b'extdiff'): | |
350 | for proc in waitprocs: |
|
350 | for proc in waitprocs: | |
351 | proc.wait() |
|
351 | proc.wait() | |
352 |
|
352 | |||
@@ -360,12 +360,12 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
360 | - just invoke the diff for a single file in the working dir |
|
360 | - just invoke the diff for a single file in the working dir | |
361 | ''' |
|
361 | ''' | |
362 |
|
362 | |||
363 | revs = opts.get('rev') |
|
363 | revs = opts.get(b'rev') | |
364 | change = opts.get('change') |
|
364 | change = opts.get(b'change') | |
365 | do3way = '$parent2' in cmdline |
|
365 | do3way = b'$parent2' in cmdline | |
366 |
|
366 | |||
367 | if revs and change: |
|
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 | raise error.Abort(msg) |
|
369 | raise error.Abort(msg) | |
370 | elif change: |
|
370 | elif change: | |
371 | ctx2 = scmutil.revsingle(repo, change, None) |
|
371 | ctx2 = scmutil.revsingle(repo, change, None) | |
@@ -377,8 +377,8 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
377 | else: |
|
377 | else: | |
378 | ctx1b = repo[nullid] |
|
378 | ctx1b = repo[nullid] | |
379 |
|
379 | |||
380 | perfile = opts.get('per_file') |
|
380 | perfile = opts.get(b'per_file') | |
381 | confirm = opts.get('confirm') |
|
381 | confirm = opts.get(b'confirm') | |
382 |
|
382 | |||
383 | node1a = ctx1a.node() |
|
383 | node1a = ctx1a.node() | |
384 | node1b = ctx1b.node() |
|
384 | node1b = ctx1b.node() | |
@@ -389,17 +389,17 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
389 | if node1b == nullid: |
|
389 | if node1b == nullid: | |
390 | do3way = False |
|
390 | do3way = False | |
391 |
|
391 | |||
392 | subrepos = opts.get('subrepos') |
|
392 | subrepos = opts.get(b'subrepos') | |
393 |
|
393 | |||
394 | matcher = scmutil.match(repo[node2], pats, opts) |
|
394 | matcher = scmutil.match(repo[node2], pats, opts) | |
395 |
|
395 | |||
396 | if opts.get('patch'): |
|
396 | if opts.get(b'patch'): | |
397 | if subrepos: |
|
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 | if perfile: |
|
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 | if node2 is None: |
|
401 | if node2 is None: | |
402 | raise error.Abort(_('--patch requires two revisions')) |
|
402 | raise error.Abort(_(b'--patch requires two revisions')) | |
403 | else: |
|
403 | else: | |
404 | mod_a, add_a, rem_a = map( |
|
404 | mod_a, add_a, rem_a = map( | |
405 | set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3] |
|
405 | set, repo.status(node1a, node2, matcher, listsubrepos=subrepos)[:3] | |
@@ -416,33 +416,33 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
416 | if not common: |
|
416 | if not common: | |
417 | return 0 |
|
417 | return 0 | |
418 |
|
418 | |||
419 | tmproot = pycompat.mkdtemp(prefix='extdiff.') |
|
419 | tmproot = pycompat.mkdtemp(prefix=b'extdiff.') | |
420 | try: |
|
420 | try: | |
421 | if not opts.get('patch'): |
|
421 | if not opts.get(b'patch'): | |
422 | # Always make a copy of node1a (and node1b, if applicable) |
|
422 | # Always make a copy of node1a (and node1b, if applicable) | |
423 | dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) |
|
423 | dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) | |
424 | dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[ |
|
424 | dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[ | |
425 | 0 |
|
425 | 0 | |
426 | ] |
|
426 | ] | |
427 | rev1a = '@%d' % repo[node1a].rev() |
|
427 | rev1a = b'@%d' % repo[node1a].rev() | |
428 | if do3way: |
|
428 | if do3way: | |
429 | dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) |
|
429 | dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) | |
430 | dir1b = snapshot( |
|
430 | dir1b = snapshot( | |
431 | ui, repo, dir1b_files, node1b, tmproot, subrepos |
|
431 | ui, repo, dir1b_files, node1b, tmproot, subrepos | |
432 | )[0] |
|
432 | )[0] | |
433 | rev1b = '@%d' % repo[node1b].rev() |
|
433 | rev1b = b'@%d' % repo[node1b].rev() | |
434 | else: |
|
434 | else: | |
435 | dir1b = None |
|
435 | dir1b = None | |
436 | rev1b = '' |
|
436 | rev1b = b'' | |
437 |
|
437 | |||
438 | fnsandstat = [] |
|
438 | fnsandstat = [] | |
439 |
|
439 | |||
440 | # If node2 in not the wc or there is >1 change, copy it |
|
440 | # If node2 in not the wc or there is >1 change, copy it | |
441 | dir2root = '' |
|
441 | dir2root = b'' | |
442 | rev2 = '' |
|
442 | rev2 = b'' | |
443 | if node2: |
|
443 | if node2: | |
444 | dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] |
|
444 | dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] | |
445 | rev2 = '@%d' % repo[node2].rev() |
|
445 | rev2 = b'@%d' % repo[node2].rev() | |
446 | elif len(common) > 1: |
|
446 | elif len(common) > 1: | |
447 | # we only actually need to get the files to copy back to |
|
447 | # we only actually need to get the files to copy back to | |
448 | # the working dir in this case (because the other cases |
|
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 | else: |
|
454 | else: | |
455 | # This lets the diff tool open the changed file directly |
|
455 | # This lets the diff tool open the changed file directly | |
456 | dir2 = '' |
|
456 | dir2 = b'' | |
457 | dir2root = repo.root |
|
457 | dir2root = repo.root | |
458 |
|
458 | |||
459 | label1a = rev1a |
|
459 | label1a = rev1a | |
@@ -476,8 +476,8 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
476 | dir2 = os.path.join(dir2root, dir2, common_file) |
|
476 | dir2 = os.path.join(dir2root, dir2, common_file) | |
477 | label2 = common_file + rev2 |
|
477 | label2 = common_file + rev2 | |
478 | else: |
|
478 | else: | |
479 | template = 'hg-%h.patch' |
|
479 | template = b'hg-%h.patch' | |
480 | with formatter.nullformatter(ui, 'extdiff', {}) as fm: |
|
480 | with formatter.nullformatter(ui, b'extdiff', {}) as fm: | |
481 | cmdutil.export( |
|
481 | cmdutil.export( | |
482 | repo, |
|
482 | repo, | |
483 | [repo[node1a].rev(), repo[node2].rev()], |
|
483 | [repo[node1a].rev(), repo[node2].rev()], | |
@@ -507,9 +507,9 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
507 | clabel=label2, |
|
507 | clabel=label2, | |
508 | ) |
|
508 | ) | |
509 | ui.debug( |
|
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 | else: |
|
513 | else: | |
514 | # Run the external tool once for each pair of files |
|
514 | # Run the external tool once for each pair of files | |
515 | _runperfilediff( |
|
515 | _runperfilediff( | |
@@ -545,35 +545,41 b' def dodiff(ui, repo, cmdline, pats, opts' | |||||
545 | or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100) |
|
545 | or (cpstat.st_mode & 0o100) != (st.st_mode & 0o100) | |
546 | ): |
|
546 | ): | |
547 | ui.debug( |
|
547 | ui.debug( | |
548 | 'file changed while diffing. ' |
|
548 | b'file changed while diffing. ' | |
549 | 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn) |
|
549 | b'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn) | |
550 | ) |
|
550 | ) | |
551 | util.copyfile(copy_fn, working_fn) |
|
551 | util.copyfile(copy_fn, working_fn) | |
552 |
|
552 | |||
553 | return 1 |
|
553 | return 1 | |
554 | finally: |
|
554 | finally: | |
555 | ui.note(_('cleaning up temp directory\n')) |
|
555 | ui.note(_(b'cleaning up temp directory\n')) | |
556 | shutil.rmtree(tmproot) |
|
556 | shutil.rmtree(tmproot) | |
557 |
|
557 | |||
558 |
|
558 | |||
559 | extdiffopts = ( |
|
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 | '', |
|
562 | b'o', | |
566 |
' |
|
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 | False, |
|
573 | False, | |
568 | _('compare each file instead of revision snapshots'), |
|
574 | _(b'compare each file instead of revision snapshots'), | |
569 | ), |
|
575 | ), | |
570 | ( |
|
576 | ( | |
571 | '', |
|
577 | b'', | |
572 | 'confirm', |
|
578 | b'confirm', | |
573 | False, |
|
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 | + cmdutil.walkopts |
|
584 | + cmdutil.walkopts | |
579 | + cmdutil.subrepoopts |
|
585 | + cmdutil.subrepoopts | |
@@ -581,10 +587,10 b' extdiffopts = (' | |||||
581 |
|
587 | |||
582 |
|
588 | |||
583 | @command( |
|
589 | @command( | |
584 | 'extdiff', |
|
590 | b'extdiff', | |
585 | [('p', 'program', '', _('comparison program to run'), _('CMD')),] |
|
591 | [(b'p', b'program', b'', _(b'comparison program to run'), _(b'CMD')),] | |
586 | + extdiffopts, |
|
592 | + extdiffopts, | |
587 | _('hg extdiff [OPT]... [FILE]...'), |
|
593 | _(b'hg extdiff [OPT]... [FILE]...'), | |
588 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
594 | helpcategory=command.CATEGORY_FILE_CONTENTS, | |
589 | inferrepo=True, |
|
595 | inferrepo=True, | |
590 | ) |
|
596 | ) | |
@@ -620,12 +626,12 b' def extdiff(ui, repo, *pats, **opts):' | |||||
620 | the external program. It is ignored if --per-file isn't specified. |
|
626 | the external program. It is ignored if --per-file isn't specified. | |
621 | ''' |
|
627 | ''' | |
622 | opts = pycompat.byteskwargs(opts) |
|
628 | opts = pycompat.byteskwargs(opts) | |
623 | program = opts.get('program') |
|
629 | program = opts.get(b'program') | |
624 | option = opts.get('option') |
|
630 | option = opts.get(b'option') | |
625 | if not program: |
|
631 | if not program: | |
626 | program = 'diff' |
|
632 | program = b'diff' | |
627 | option = option or ['-Npru'] |
|
633 | option = option or [b'-Npru'] | |
628 | cmdline = ' '.join(map(procutil.shellquote, [program] + option)) |
|
634 | cmdline = b' '.join(map(procutil.shellquote, [program] + option)) | |
629 | return dodiff(ui, repo, cmdline, pats, opts) |
|
635 | return dodiff(ui, repo, cmdline, pats, opts) | |
630 |
|
636 | |||
631 |
|
637 | |||
@@ -655,29 +661,29 b' class savedcmd(object):' | |||||
655 |
|
661 | |||
656 | def __call__(self, ui, repo, *pats, **opts): |
|
662 | def __call__(self, ui, repo, *pats, **opts): | |
657 | opts = pycompat.byteskwargs(opts) |
|
663 | opts = pycompat.byteskwargs(opts) | |
658 | options = ' '.join(map(procutil.shellquote, opts['option'])) |
|
664 | options = b' '.join(map(procutil.shellquote, opts[b'option'])) | |
659 | if options: |
|
665 | if options: | |
660 | options = ' ' + options |
|
666 | options = b' ' + options | |
661 | return dodiff( |
|
667 | return dodiff( | |
662 | ui, repo, self._cmdline + options, pats, opts, guitool=self._isgui |
|
668 | ui, repo, self._cmdline + options, pats, opts, guitool=self._isgui | |
663 | ) |
|
669 | ) | |
664 |
|
670 | |||
665 |
|
671 | |||
666 | def uisetup(ui): |
|
672 | def uisetup(ui): | |
667 | for cmd, path in ui.configitems('extdiff'): |
|
673 | for cmd, path in ui.configitems(b'extdiff'): | |
668 | path = util.expandpath(path) |
|
674 | path = util.expandpath(path) | |
669 | if cmd.startswith('cmd.'): |
|
675 | if cmd.startswith(b'cmd.'): | |
670 | cmd = cmd[4:] |
|
676 | cmd = cmd[4:] | |
671 | if not path: |
|
677 | if not path: | |
672 | path = procutil.findexe(cmd) |
|
678 | path = procutil.findexe(cmd) | |
673 | if path is None: |
|
679 | if path is None: | |
674 | path = filemerge.findexternaltool(ui, cmd) or cmd |
|
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 | cmdline = procutil.shellquote(path) |
|
682 | cmdline = procutil.shellquote(path) | |
677 | if diffopts: |
|
683 | if diffopts: | |
678 | cmdline += ' ' + diffopts |
|
684 | cmdline += b' ' + diffopts | |
679 | isgui = ui.configbool('extdiff', 'gui.' + cmd) |
|
685 | isgui = ui.configbool(b'extdiff', b'gui.' + cmd) | |
680 | elif cmd.startswith('opts.') or cmd.startswith('gui.'): |
|
686 | elif cmd.startswith(b'opts.') or cmd.startswith(b'gui.'): | |
681 | continue |
|
687 | continue | |
682 | else: |
|
688 | else: | |
683 | if path: |
|
689 | if path: | |
@@ -691,21 +697,21 b' def uisetup(ui):' | |||||
691 | path = filemerge.findexternaltool(ui, cmd) or cmd |
|
697 | path = filemerge.findexternaltool(ui, cmd) or cmd | |
692 | cmdline = procutil.shellquote(path) |
|
698 | cmdline = procutil.shellquote(path) | |
693 | diffopts = False |
|
699 | diffopts = False | |
694 | isgui = ui.configbool('extdiff', 'gui.' + cmd) |
|
700 | isgui = ui.configbool(b'extdiff', b'gui.' + cmd) | |
695 | # look for diff arguments in [diff-tools] then [merge-tools] |
|
701 | # look for diff arguments in [diff-tools] then [merge-tools] | |
696 | if not diffopts: |
|
702 | if not diffopts: | |
697 | key = cmd + '.diffargs' |
|
703 | key = cmd + b'.diffargs' | |
698 | for section in ('diff-tools', 'merge-tools'): |
|
704 | for section in (b'diff-tools', b'merge-tools'): | |
699 | args = ui.config(section, key) |
|
705 | args = ui.config(section, key) | |
700 | if args: |
|
706 | if args: | |
701 | cmdline += ' ' + args |
|
707 | cmdline += b' ' + args | |
702 | if isgui is None: |
|
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 | break |
|
710 | break | |
705 | command( |
|
711 | command( | |
706 | cmd, |
|
712 | cmd, | |
707 | extdiffopts[:], |
|
713 | extdiffopts[:], | |
708 | _('hg %s [OPTION]... [FILE]...') % cmd, |
|
714 | _(b'hg %s [OPTION]... [FILE]...') % cmd, | |
709 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
715 | helpcategory=command.CATEGORY_FILE_CONTENTS, | |
710 | inferrepo=True, |
|
716 | inferrepo=True, | |
711 | )(savedcmd(path, cmdline, isgui)) |
|
717 | )(savedcmd(path, cmdline, isgui)) |
@@ -69,44 +69,44 b' configtable = {}' | |||||
69 | configitem = registrar.configitem(configtable) |
|
69 | configitem = registrar.configitem(configtable) | |
70 |
|
70 | |||
71 | configitem( |
|
71 | configitem( | |
72 | 'factotum', 'executable', default='/bin/auth/factotum', |
|
72 | b'factotum', b'executable', default=b'/bin/auth/factotum', | |
73 | ) |
|
73 | ) | |
74 | configitem( |
|
74 | configitem( | |
75 | 'factotum', 'mountpoint', default='/mnt/factotum', |
|
75 | b'factotum', b'mountpoint', default=b'/mnt/factotum', | |
76 | ) |
|
76 | ) | |
77 | configitem( |
|
77 | configitem( | |
78 | 'factotum', 'service', default='hg', |
|
78 | b'factotum', b'service', default=b'hg', | |
79 | ) |
|
79 | ) | |
80 |
|
80 | |||
81 |
|
81 | |||
82 | def auth_getkey(self, params): |
|
82 | def auth_getkey(self, params): | |
83 | if not self.ui.interactive(): |
|
83 | if not self.ui.interactive(): | |
84 | raise error.Abort(_('factotum not interactive')) |
|
84 | raise error.Abort(_(b'factotum not interactive')) | |
85 | if 'user=' not in params: |
|
85 | if b'user=' not in params: | |
86 | params = '%s user?' % params |
|
86 | params = b'%s user?' % params | |
87 | params = '%s !password?' % params |
|
87 | params = b'%s !password?' % params | |
88 | os.system(procutil.tonativestr("%s -g '%s'" % (_executable, params))) |
|
88 | os.system(procutil.tonativestr(b"%s -g '%s'" % (_executable, params))) | |
89 |
|
89 | |||
90 |
|
90 | |||
91 | def auth_getuserpasswd(self, getkey, params): |
|
91 | def auth_getuserpasswd(self, getkey, params): | |
92 | params = 'proto=pass %s' % params |
|
92 | params = b'proto=pass %s' % params | |
93 | while True: |
|
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 | try: |
|
95 | try: | |
96 | os.write(fd, 'start %s' % params) |
|
96 | os.write(fd, b'start %s' % params) | |
97 | l = os.read(fd, ERRMAX).split() |
|
97 | l = os.read(fd, ERRMAX).split() | |
98 | if l[0] == 'ok': |
|
98 | if l[0] == b'ok': | |
99 | os.write(fd, 'read') |
|
99 | os.write(fd, b'read') | |
100 | status, user, passwd = os.read(fd, ERRMAX).split(None, 2) |
|
100 | status, user, passwd = os.read(fd, ERRMAX).split(None, 2) | |
101 | if status == 'ok': |
|
101 | if status == b'ok': | |
102 | if passwd.startswith("'"): |
|
102 | if passwd.startswith(b"'"): | |
103 | if passwd.endswith("'"): |
|
103 | if passwd.endswith(b"'"): | |
104 | passwd = passwd[1:-1].replace("''", "'") |
|
104 | passwd = passwd[1:-1].replace(b"''", b"'") | |
105 | else: |
|
105 | else: | |
106 | raise error.Abort(_('malformed password string')) |
|
106 | raise error.Abort(_(b'malformed password string')) | |
107 | return (user, passwd) |
|
107 | return (user, passwd) | |
108 | except (OSError, IOError): |
|
108 | except (OSError, IOError): | |
109 | raise error.Abort(_('factotum not responding')) |
|
109 | raise error.Abort(_(b'factotum not responding')) | |
110 | finally: |
|
110 | finally: | |
111 | os.close(fd) |
|
111 | os.close(fd) | |
112 | getkey(self, params) |
|
112 | getkey(self, params) | |
@@ -127,18 +127,18 b' def find_user_password(self, realm, auth' | |||||
127 | self._writedebug(user, passwd) |
|
127 | self._writedebug(user, passwd) | |
128 | return (user, passwd) |
|
128 | return (user, passwd) | |
129 |
|
129 | |||
130 | prefix = '' |
|
130 | prefix = b'' | |
131 | res = httpconnection.readauthforuri(self.ui, authuri, user) |
|
131 | res = httpconnection.readauthforuri(self.ui, authuri, user) | |
132 | if res: |
|
132 | if res: | |
133 | _, auth = res |
|
133 | _, auth = res | |
134 | prefix = auth.get('prefix') |
|
134 | prefix = auth.get(b'prefix') | |
135 | user, passwd = auth.get('username'), auth.get('password') |
|
135 | user, passwd = auth.get(b'username'), auth.get(b'password') | |
136 | if not user or not passwd: |
|
136 | if not user or not passwd: | |
137 | if not prefix: |
|
137 | if not prefix: | |
138 | prefix = realm.split(' ')[0].lower() |
|
138 | prefix = realm.split(b' ')[0].lower() | |
139 | params = 'service=%s prefix=%s' % (_service, prefix) |
|
139 | params = b'service=%s prefix=%s' % (_service, prefix) | |
140 | if user: |
|
140 | if user: | |
141 | params = '%s user=%s' % (params, user) |
|
141 | params = b'%s user=%s' % (params, user) | |
142 | user, passwd = auth_getuserpasswd(self, auth_getkey, params) |
|
142 | user, passwd = auth_getuserpasswd(self, auth_getkey, params) | |
143 |
|
143 | |||
144 | self.add_password(realm, authuri, user, passwd) |
|
144 | self.add_password(realm, authuri, user, passwd) | |
@@ -148,8 +148,8 b' def find_user_password(self, realm, auth' | |||||
148 |
|
148 | |||
149 | def uisetup(ui): |
|
149 | def uisetup(ui): | |
150 | global _executable |
|
150 | global _executable | |
151 | _executable = ui.config('factotum', 'executable') |
|
151 | _executable = ui.config(b'factotum', b'executable') | |
152 | global _mountpoint |
|
152 | global _mountpoint | |
153 | _mountpoint = ui.config('factotum', 'mountpoint') |
|
153 | _mountpoint = ui.config(b'factotum', b'mountpoint') | |
154 | global _service |
|
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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
119 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
120 | # be specifying the version(s) of Mercurial they are tested with, or |
|
120 | # be specifying the version(s) of Mercurial they are tested with, or | |
121 | # leave the attribute unspecified. |
|
121 | # leave the attribute unspecified. | |
122 | testedwith = 'ships-with-hg-core' |
|
122 | testedwith = b'ships-with-hg-core' | |
123 |
|
123 | |||
124 | cmdtable = commands.cmdtable |
|
124 | cmdtable = commands.cmdtable | |
125 |
|
125 | |||
126 | configtable = {} |
|
126 | configtable = {} | |
127 | configitem = registrar.configitem(configtable) |
|
127 | configitem = registrar.configitem(configtable) | |
128 |
|
128 | |||
129 | configitem('fastannotate', 'modes', default=['fastannotate']) |
|
129 | configitem(b'fastannotate', b'modes', default=[b'fastannotate']) | |
130 | configitem('fastannotate', 'server', default=False) |
|
130 | configitem(b'fastannotate', b'server', default=False) | |
131 | configitem('fastannotate', 'client', default=False) |
|
131 | configitem(b'fastannotate', b'client', default=False) | |
132 | configitem('fastannotate', 'unfilteredrepo', default=True) |
|
132 | configitem(b'fastannotate', b'unfilteredrepo', default=True) | |
133 | configitem('fastannotate', 'defaultformat', default=['number']) |
|
133 | configitem(b'fastannotate', b'defaultformat', default=[b'number']) | |
134 | configitem('fastannotate', 'perfhack', default=False) |
|
134 | configitem(b'fastannotate', b'perfhack', default=False) | |
135 | configitem('fastannotate', 'mainbranch') |
|
135 | configitem(b'fastannotate', b'mainbranch') | |
136 | configitem('fastannotate', 'forcetext', default=True) |
|
136 | configitem(b'fastannotate', b'forcetext', default=True) | |
137 | configitem('fastannotate', 'forcefollow', default=True) |
|
137 | configitem(b'fastannotate', b'forcefollow', default=True) | |
138 | configitem('fastannotate', 'clientfetchthreshold', default=10) |
|
138 | configitem(b'fastannotate', b'clientfetchthreshold', default=10) | |
139 | configitem('fastannotate', 'serverbuildondemand', default=True) |
|
139 | configitem(b'fastannotate', b'serverbuildondemand', default=True) | |
140 | configitem('fastannotate', 'remotepath', default='default') |
|
140 | configitem(b'fastannotate', b'remotepath', default=b'default') | |
141 |
|
141 | |||
142 |
|
142 | |||
143 | def uisetup(ui): |
|
143 | def uisetup(ui): | |
144 | modes = set(ui.configlist('fastannotate', 'modes')) |
|
144 | modes = set(ui.configlist(b'fastannotate', b'modes')) | |
145 | if 'fctx' in modes: |
|
145 | if b'fctx' in modes: | |
146 | modes.discard('hgweb') |
|
146 | modes.discard(b'hgweb') | |
147 | for name in modes: |
|
147 | for name in modes: | |
148 | if name == 'fastannotate': |
|
148 | if name == b'fastannotate': | |
149 | commands.registercommand() |
|
149 | commands.registercommand() | |
150 | elif name == 'hgweb': |
|
150 | elif name == b'hgweb': | |
151 | from . import support |
|
151 | from . import support | |
152 |
|
152 | |||
153 | support.replacehgwebannotate() |
|
153 | support.replacehgwebannotate() | |
154 | elif name == 'fctx': |
|
154 | elif name == b'fctx': | |
155 | from . import support |
|
155 | from . import support | |
156 |
|
156 | |||
157 | support.replacefctxannotate() |
|
157 | support.replacefctxannotate() | |
158 | commands.wrapdefault() |
|
158 | commands.wrapdefault() | |
159 | else: |
|
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 | protocol.serveruisetup(ui) |
|
163 | protocol.serveruisetup(ui) | |
164 |
|
164 | |||
165 |
|
165 | |||
166 | def extsetup(ui): |
|
166 | def extsetup(ui): | |
167 | # fastannotate has its own locking, without depending on repo lock |
|
167 | # fastannotate has its own locking, without depending on repo lock | |
168 | # TODO: avoid mutating this unless the specific repo has it enabled |
|
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 | def reposetup(ui, repo): |
|
172 | def reposetup(ui, repo): | |
173 | if ui.configbool('fastannotate', 'client'): |
|
173 | if ui.configbool(b'fastannotate', b'client'): | |
174 | protocol.clientreposetup(ui, repo) |
|
174 | protocol.clientreposetup(ui, repo) |
@@ -34,7 +34,7 b' command = registrar.command(cmdtable)' | |||||
34 |
|
34 | |||
35 | def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts): |
|
35 | def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts): | |
36 | """generate paths matching given patterns""" |
|
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 | # disable perfhack if: |
|
39 | # disable perfhack if: | |
40 | # a) any walkopt is used |
|
40 | # a) any walkopt is used | |
@@ -44,8 +44,8 b' def _matchpaths(repo, rev, pats, opts, a' | |||||
44 | # cwd related to reporoot |
|
44 | # cwd related to reporoot | |
45 | reporoot = os.path.dirname(repo.path) |
|
45 | reporoot = os.path.dirname(repo.path) | |
46 | reldir = os.path.relpath(encoding.getcwd(), reporoot) |
|
46 | reldir = os.path.relpath(encoding.getcwd(), reporoot) | |
47 | if reldir == '.': |
|
47 | if reldir == b'.': | |
48 | reldir = '' |
|
48 | reldir = b'' | |
49 | if any(opts.get(o[1]) for o in commands.walkopts): # a) |
|
49 | if any(opts.get(o[1]) for o in commands.walkopts): # a) | |
50 | perfhack = False |
|
50 | perfhack = False | |
51 | else: # b) |
|
51 | else: # b) | |
@@ -56,7 +56,7 b' def _matchpaths(repo, rev, pats, opts, a' | |||||
56 | # disable perfhack on '..' since it allows escaping from the repo |
|
56 | # disable perfhack on '..' since it allows escaping from the repo | |
57 | if any( |
|
57 | if any( | |
58 | ( |
|
58 | ( | |
59 | '..' in f |
|
59 | b'..' in f | |
60 | or not os.path.isfile( |
|
60 | or not os.path.isfile( | |
61 | facontext.pathhelper(repo, f, aopts).linelogpath |
|
61 | facontext.pathhelper(repo, f, aopts).linelogpath | |
62 | ) |
|
62 | ) | |
@@ -73,7 +73,7 b' def _matchpaths(repo, rev, pats, opts, a' | |||||
73 | else: |
|
73 | else: | |
74 |
|
74 | |||
75 | def bad(x, y): |
|
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 | ctx = scmutil.revsingle(repo, rev) |
|
78 | ctx = scmutil.revsingle(repo, rev) | |
79 | m = scmutil.match(ctx, pats, opts, badfn=bad) |
|
79 | m = scmutil.match(ctx, pats, opts, badfn=bad) | |
@@ -83,42 +83,57 b' def _matchpaths(repo, rev, pats, opts, a' | |||||
83 |
|
83 | |||
84 | fastannotatecommandargs = { |
|
84 | fastannotatecommandargs = { | |
85 | r'options': [ |
|
85 | r'options': [ | |
86 | ('r', 'rev', '.', _('annotate the specified revision'), _('REV')), |
|
86 | (b'r', b'rev', b'.', _(b'annotate the specified revision'), _(b'REV')), | |
87 | ('u', 'user', None, _('list the author (long with -v)')), |
|
87 | (b'u', b'user', None, _(b'list the author (long with -v)')), | |
88 | ('f', 'file', None, _('list the filename')), |
|
88 | (b'f', b'file', None, _(b'list the filename')), | |
89 | ('d', 'date', None, _('list the date (short with -q)')), |
|
89 | (b'd', b'date', None, _(b'list the date (short with -q)')), | |
90 | ('n', 'number', None, _('list the revision number (default)')), |
|
90 | (b'n', b'number', None, _(b'list the revision number (default)')), | |
91 | ('c', 'changeset', None, _('list the changeset')), |
|
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 |
' |
|
99 | b'e', | |
94 |
' |
|
100 | b'deleted', | |
95 | None, |
|
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 | '', |
|
105 | b'', | |
103 |
' |
|
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 | None, |
|
114 | None, | |
105 | _( |
|
115 | _( | |
106 | 'enforce linear history, ignore second parent ' |
|
116 | b'enforce linear history, ignore second parent ' | |
107 | 'of merges (EXPERIMENTAL)' |
|
117 | b'of merges (EXPERIMENTAL)' | |
108 | ), |
|
118 | ), | |
109 | ), |
|
119 | ), | |
110 | ('', 'long-hash', None, _('show long changeset hash (EXPERIMENTAL)')), |
|
|||
111 | ( |
|
120 | ( | |
112 | '', |
|
121 | b'', | |
113 |
' |
|
122 | b'long-hash', | |
114 | None, |
|
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 | + commands.diffwsopts |
|
133 | + commands.diffwsopts | |
119 | + commands.walkopts |
|
134 | + commands.walkopts | |
120 | + commands.formatteropts, |
|
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 | r'inferrepo': True, |
|
137 | r'inferrepo': True, | |
123 | } |
|
138 | } | |
124 |
|
139 | |||
@@ -155,52 +170,55 b' def fastannotate(ui, repo, *pats, **opts' | |||||
155 | affecting results are used. |
|
170 | affecting results are used. | |
156 | """ |
|
171 | """ | |
157 | if not pats: |
|
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 | # performance hack: filtered repo can be slow. unfilter by default. |
|
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 | repo = repo.unfiltered() |
|
177 | repo = repo.unfiltered() | |
163 |
|
178 | |||
164 | opts = pycompat.byteskwargs(opts) |
|
179 | opts = pycompat.byteskwargs(opts) | |
165 |
|
180 | |||
166 | rev = opts.get('rev', '.') |
|
181 | rev = opts.get(b'rev', b'.') | |
167 | rebuild = opts.get('rebuild', False) |
|
182 | rebuild = opts.get(b'rebuild', False) | |
168 |
|
183 | |||
169 | diffopts = patch.difffeatureopts( |
|
184 | diffopts = patch.difffeatureopts( | |
170 | ui, opts, section='annotate', whitespace=True |
|
185 | ui, opts, section=b'annotate', whitespace=True | |
171 | ) |
|
186 | ) | |
172 | aopts = facontext.annotateopts( |
|
187 | aopts = facontext.annotateopts( | |
173 | diffopts=diffopts, |
|
188 | diffopts=diffopts, | |
174 | followmerge=not opts.get('linear', False), |
|
189 | followmerge=not opts.get(b'linear', False), | |
175 | followrename=not opts.get('no_follow', False), |
|
190 | followrename=not opts.get(b'no_follow', False), | |
176 | ) |
|
191 | ) | |
177 |
|
192 | |||
178 | if not any( |
|
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 | # default 'number' for compatibility. but fastannotate is more |
|
197 | # default 'number' for compatibility. but fastannotate is more | |
182 | # efficient with "changeset", "line-number" and "no-content". |
|
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 | opts[name] = True |
|
202 | opts[name] = True | |
185 |
|
203 | |||
186 | ui.pager('fastannotate') |
|
204 | ui.pager(b'fastannotate') | |
187 | template = opts.get('template') |
|
205 | template = opts.get(b'template') | |
188 | if template == 'json': |
|
206 | if template == b'json': | |
189 | formatter = faformatter.jsonformatter(ui, repo, opts) |
|
207 | formatter = faformatter.jsonformatter(ui, repo, opts) | |
190 | else: |
|
208 | else: | |
191 | formatter = faformatter.defaultformatter(ui, repo, opts) |
|
209 | formatter = faformatter.defaultformatter(ui, repo, opts) | |
192 | showdeleted = opts.get('deleted', False) |
|
210 | showdeleted = opts.get(b'deleted', False) | |
193 | showlines = not bool(opts.get('no_content')) |
|
211 | showlines = not bool(opts.get(b'no_content')) | |
194 | showpath = opts.get('file', False) |
|
212 | showpath = opts.get(b'file', False) | |
195 |
|
213 | |||
196 | # find the head of the main (master) branch |
|
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 | # paths will be used for prefetching and the real annotating |
|
217 | # paths will be used for prefetching and the real annotating | |
200 | paths = list(_matchpaths(repo, rev, pats, opts, aopts)) |
|
218 | paths = list(_matchpaths(repo, rev, pats, opts, aopts)) | |
201 |
|
219 | |||
202 | # for client, prefetch from the server |
|
220 | # for client, prefetch from the server | |
203 | if util.safehasattr(repo, 'prefetchfastannotate'): |
|
221 | if util.safehasattr(repo, b'prefetchfastannotate'): | |
204 | repo.prefetchfastannotate(paths) |
|
222 | repo.prefetchfastannotate(paths) | |
205 |
|
223 | |||
206 | for path in paths: |
|
224 | for path in paths: | |
@@ -238,7 +256,7 b' def fastannotate(ui, repo, *pats, **opts' | |||||
238 |
|
256 | |||
239 | _newopts = set() |
|
257 | _newopts = set() | |
240 | _knownopts = { |
|
258 | _knownopts = { | |
241 | opt[1].replace('-', '_') |
|
259 | opt[1].replace(b'-', b'_') | |
242 | for opt in (fastannotatecommandargs[r'options'] + commands.globalopts) |
|
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 | def _annotatewrapper(orig, ui, repo, *pats, **opts): |
|
264 | def _annotatewrapper(orig, ui, repo, *pats, **opts): | |
247 | """used by wrapdefault""" |
|
265 | """used by wrapdefault""" | |
248 | # we need this hack until the obsstore has 0.0 seconds perf impact |
|
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 | repo = repo.unfiltered() |
|
268 | repo = repo.unfiltered() | |
251 |
|
269 | |||
252 | # treat the file as text (skip the isbinary check) |
|
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 | opts[r'text'] = True |
|
272 | opts[r'text'] = True | |
255 |
|
273 | |||
256 | # check if we need to do prefetch (client-side) |
|
274 | # check if we need to do prefetch (client-side) | |
257 | rev = opts.get(r'rev') |
|
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 | paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) |
|
277 | paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) | |
260 | repo.prefetchfastannotate(paths) |
|
278 | repo.prefetchfastannotate(paths) | |
261 |
|
279 | |||
@@ -264,20 +282,20 b' def _annotatewrapper(orig, ui, repo, *pa' | |||||
264 |
|
282 | |||
265 | def registercommand(): |
|
283 | def registercommand(): | |
266 | """register the fastannotate command""" |
|
284 | """register the fastannotate command""" | |
267 | name = 'fastannotate|fastblame|fa' |
|
285 | name = b'fastannotate|fastblame|fa' | |
268 | command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate) |
|
286 | command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate) | |
269 |
|
287 | |||
270 |
|
288 | |||
271 | def wrapdefault(): |
|
289 | def wrapdefault(): | |
272 | """wrap the default annotate command, to be aware of the protocol""" |
|
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 | @command( |
|
294 | @command( | |
277 | 'debugbuildannotatecache', |
|
295 | b'debugbuildannotatecache', | |
278 | [('r', 'rev', '', _('build up to the specific revision'), _('REV'))] |
|
296 | [(b'r', b'rev', b'', _(b'build up to the specific revision'), _(b'REV'))] | |
279 | + commands.walkopts, |
|
297 | + commands.walkopts, | |
280 | _('[-r REV] FILE...'), |
|
298 | _(b'[-r REV] FILE...'), | |
281 | ) |
|
299 | ) | |
282 | def debugbuildannotatecache(ui, repo, *pats, **opts): |
|
300 | def debugbuildannotatecache(ui, repo, *pats, **opts): | |
283 | """incrementally build fastannotate cache up to REV for specified files |
|
301 | """incrementally build fastannotate cache up to REV for specified files | |
@@ -291,25 +309,25 b' def debugbuildannotatecache(ui, repo, *p' | |||||
291 | options and lives in '.hg/fastannotate/default'. |
|
309 | options and lives in '.hg/fastannotate/default'. | |
292 | """ |
|
310 | """ | |
293 | opts = pycompat.byteskwargs(opts) |
|
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 | if not rev: |
|
313 | if not rev: | |
296 | raise error.Abort( |
|
314 | raise error.Abort( | |
297 | _('you need to provide a revision'), |
|
315 | _(b'you need to provide a revision'), | |
298 | hint=_('set fastannotate.mainbranch or use --rev'), |
|
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 | repo = repo.unfiltered() |
|
319 | repo = repo.unfiltered() | |
302 | ctx = scmutil.revsingle(repo, rev) |
|
320 | ctx = scmutil.revsingle(repo, rev) | |
303 | m = scmutil.match(ctx, pats, opts) |
|
321 | m = scmutil.match(ctx, pats, opts) | |
304 | paths = list(ctx.walk(m)) |
|
322 | paths = list(ctx.walk(m)) | |
305 | if util.safehasattr(repo, 'prefetchfastannotate'): |
|
323 | if util.safehasattr(repo, b'prefetchfastannotate'): | |
306 | # client |
|
324 | # client | |
307 | if opts.get('REV'): |
|
325 | if opts.get(b'REV'): | |
308 | raise error.Abort(_('--rev cannot be used for client')) |
|
326 | raise error.Abort(_(b'--rev cannot be used for client')) | |
309 | repo.prefetchfastannotate(paths) |
|
327 | repo.prefetchfastannotate(paths) | |
310 | else: |
|
328 | else: | |
311 | # server, or full repo |
|
329 | # server, or full repo | |
312 | progress = ui.makeprogress(_('building'), total=len(paths)) |
|
330 | progress = ui.makeprogress(_(b'building'), total=len(paths)) | |
313 | for i, path in enumerate(paths): |
|
331 | for i, path in enumerate(paths): | |
314 | progress.update(i) |
|
332 | progress.update(i) | |
315 | with facontext.annotatecontext(repo, path) as actx: |
|
333 | with facontext.annotatecontext(repo, path) as actx: | |
@@ -321,7 +339,7 b' def debugbuildannotatecache(ui, repo, *p' | |||||
321 | # the cache is broken (could happen with renaming so the |
|
339 | # the cache is broken (could happen with renaming so the | |
322 | # file history gets invalidated). rebuild and try again. |
|
340 | # file history gets invalidated). rebuild and try again. | |
323 | ui.debug( |
|
341 | ui.debug( | |
324 | 'fastannotate: %s: rebuilding broken cache\n' % path |
|
342 | b'fastannotate: %s: rebuilding broken cache\n' % path | |
325 | ) |
|
343 | ) | |
326 | actx.rebuild() |
|
344 | actx.rebuild() | |
327 | try: |
|
345 | try: | |
@@ -331,8 +349,8 b' def debugbuildannotatecache(ui, repo, *p' | |||||
331 | # cache for other files. |
|
349 | # cache for other files. | |
332 | ui.warn( |
|
350 | ui.warn( | |
333 | _( |
|
351 | _( | |
334 | 'fastannotate: %s: failed to ' |
|
352 | b'fastannotate: %s: failed to ' | |
335 | 'build cache: %r\n' |
|
353 | b'build cache: %r\n' | |
336 | ) |
|
354 | ) | |
337 | % (path, ex) |
|
355 | % (path, ex) | |
338 | ) |
|
356 | ) |
@@ -52,7 +52,7 b' def _parents(f, follow=True):' | |||||
52 | # renamed filectx won't have a filelog yet, so set it |
|
52 | # renamed filectx won't have a filelog yet, so set it | |
53 | # from the cache to save time |
|
53 | # from the cache to save time | |
54 | for p in pl: |
|
54 | for p in pl: | |
55 | if not '_filelog' in p.__dict__: |
|
55 | if not b'_filelog' in p.__dict__: | |
56 | p._filelog = _getflog(f._repo, p.path()) |
|
56 | p._filelog = _getflog(f._repo, p.path()) | |
57 |
|
57 | |||
58 | return pl |
|
58 | return pl | |
@@ -62,8 +62,8 b' def _parents(f, follow=True):' | |||||
62 | # so it takes a fctx instead of a pair of text and fctx. |
|
62 | # so it takes a fctx instead of a pair of text and fctx. | |
63 | def _decorate(fctx): |
|
63 | def _decorate(fctx): | |
64 | text = fctx.data() |
|
64 | text = fctx.data() | |
65 | linecount = text.count('\n') |
|
65 | linecount = text.count(b'\n') | |
66 | if text and not text.endswith('\n'): |
|
66 | if text and not text.endswith(b'\n'): | |
67 | linecount += 1 |
|
67 | linecount += 1 | |
68 | return ([(fctx, i) for i in pycompat.xrange(linecount)], text) |
|
68 | return ([(fctx, i) for i in pycompat.xrange(linecount)], text) | |
69 |
|
69 | |||
@@ -75,7 +75,7 b' def _pair(parent, child, blocks):' | |||||
75 | for (a1, a2, b1, b2), t in blocks: |
|
75 | for (a1, a2, b1, b2), t in blocks: | |
76 | # Changed blocks ('!') or blocks made only of blank lines ('~') |
|
76 | # Changed blocks ('!') or blocks made only of blank lines ('~') | |
77 | # belong to the child. |
|
77 | # belong to the child. | |
78 | if t == '=': |
|
78 | if t == b'=': | |
79 | child[0][b1:b2] = parent[0][a1:a2] |
|
79 | child[0][b1:b2] = parent[0][a1:a2] | |
80 | return child |
|
80 | return child | |
81 |
|
81 | |||
@@ -119,7 +119,7 b' def resolvefctx(repo, rev, path, resolve' | |||||
119 | fctx = repo.filectx(path, changeid=ctx.rev()) |
|
119 | fctx = repo.filectx(path, changeid=ctx.rev()) | |
120 | else: |
|
120 | else: | |
121 | fctx = ctx[path] |
|
121 | fctx = ctx[path] | |
122 | if adjustctx == 'linkrev': |
|
122 | if adjustctx == b'linkrev': | |
123 | introrev = fctx.linkrev() |
|
123 | introrev = fctx.linkrev() | |
124 | else: |
|
124 | else: | |
125 | introrev = fctx.introrev() |
|
125 | introrev = fctx.introrev() | |
@@ -132,10 +132,10 b' def resolvefctx(repo, rev, path, resolve' | |||||
132 | # like mercurial.store.encodedir, but use linelog suffixes: .m, .l, .lock |
|
132 | # like mercurial.store.encodedir, but use linelog suffixes: .m, .l, .lock | |
133 | def encodedir(path): |
|
133 | def encodedir(path): | |
134 | return ( |
|
134 | return ( | |
135 | path.replace('.hg/', '.hg.hg/') |
|
135 | path.replace(b'.hg/', b'.hg.hg/') | |
136 | .replace('.l/', '.l.hg/') |
|
136 | .replace(b'.l/', b'.l.hg/') | |
137 | .replace('.m/', '.m.hg/') |
|
137 | .replace(b'.m/', b'.m.hg/') | |
138 | .replace('.lock/', '.lock.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 | defaults = { |
|
159 | defaults = { | |
160 | 'diffopts': None, |
|
160 | b'diffopts': None, | |
161 | 'followrename': True, |
|
161 | b'followrename': True, | |
162 | 'followmerge': True, |
|
162 | b'followmerge': True, | |
163 | } |
|
163 | } | |
164 |
|
164 | |||
165 | def __init__(self, **opts): |
|
165 | def __init__(self, **opts): | |
@@ -170,17 +170,17 b' class annotateopts(object):' | |||||
170 | @util.propertycache |
|
170 | @util.propertycache | |
171 | def shortstr(self): |
|
171 | def shortstr(self): | |
172 | """represent opts in a short string, suitable for a directory name""" |
|
172 | """represent opts in a short string, suitable for a directory name""" | |
173 | result = '' |
|
173 | result = b'' | |
174 | if not self.followrename: |
|
174 | if not self.followrename: | |
175 | result += 'r0' |
|
175 | result += b'r0' | |
176 | if not self.followmerge: |
|
176 | if not self.followmerge: | |
177 | result += 'm0' |
|
177 | result += b'm0' | |
178 | if self.diffopts is not None: |
|
178 | if self.diffopts is not None: | |
179 | assert isinstance(self.diffopts, mdiff.diffopts) |
|
179 | assert isinstance(self.diffopts, mdiff.diffopts) | |
180 | diffopthash = hashdiffopts(self.diffopts) |
|
180 | diffopthash = hashdiffopts(self.diffopts) | |
181 | if diffopthash != _defaultdiffopthash: |
|
181 | if diffopthash != _defaultdiffopthash: | |
182 | result += 'i' + diffopthash |
|
182 | result += b'i' + diffopthash | |
183 | return result or 'default' |
|
183 | return result or b'default' | |
184 |
|
184 | |||
185 |
|
185 | |||
186 | defaultopts = annotateopts() |
|
186 | defaultopts = annotateopts() | |
@@ -206,7 +206,7 b' class _annotatecontext(object):' | |||||
206 | def linelog(self): |
|
206 | def linelog(self): | |
207 | if self._linelog is None: |
|
207 | if self._linelog is None: | |
208 | if os.path.exists(self.linelogpath): |
|
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 | try: |
|
210 | try: | |
211 | self._linelog = linelogmod.linelog.fromdata(f.read()) |
|
211 | self._linelog = linelogmod.linelog.fromdata(f.read()) | |
212 | except linelogmod.LineLogError: |
|
212 | except linelogmod.LineLogError: | |
@@ -226,7 +226,7 b' class _annotatecontext(object):' | |||||
226 | self._revmap.flush() |
|
226 | self._revmap.flush() | |
227 | self._revmap = None |
|
227 | self._revmap = None | |
228 | if self._linelog is not None: |
|
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 | f.write(self._linelog.encode()) |
|
230 | f.write(self._linelog.encode()) | |
231 | self._linelog = None |
|
231 | self._linelog = None | |
232 |
|
232 | |||
@@ -308,11 +308,11 b' class _annotatecontext(object):' | |||||
308 | if directly: |
|
308 | if directly: | |
309 | if self.ui.debugflag: |
|
309 | if self.ui.debugflag: | |
310 | self.ui.debug( |
|
310 | self.ui.debug( | |
311 | 'fastannotate: %s: using fast path ' |
|
311 | b'fastannotate: %s: using fast path ' | |
312 | '(resolved fctx: %s)\n' |
|
312 | b'(resolved fctx: %s)\n' | |
313 | % ( |
|
313 | % ( | |
314 | self.path, |
|
314 | self.path, | |
315 | stringutil.pprint(util.safehasattr(revfctx, 'node')), |
|
315 | stringutil.pprint(util.safehasattr(revfctx, b'node')), | |
316 | ) |
|
316 | ) | |
317 | ) |
|
317 | ) | |
318 | return self.annotatedirectly(revfctx, showpath, showlines) |
|
318 | return self.annotatedirectly(revfctx, showpath, showlines) | |
@@ -356,8 +356,8 b' class _annotatecontext(object):' | |||||
356 | if masterfctx: |
|
356 | if masterfctx: | |
357 | if masterfctx.rev() is None: |
|
357 | if masterfctx.rev() is None: | |
358 | raise error.Abort( |
|
358 | raise error.Abort( | |
359 | _('cannot update linelog to wdir()'), |
|
359 | _(b'cannot update linelog to wdir()'), | |
360 | hint=_('set fastannotate.mainbranch'), |
|
360 | hint=_(b'set fastannotate.mainbranch'), | |
361 | ) |
|
361 | ) | |
362 | initvisit.append(masterfctx) |
|
362 | initvisit.append(masterfctx) | |
363 | visit = initvisit[:] |
|
363 | visit = initvisit[:] | |
@@ -403,13 +403,13 b' class _annotatecontext(object):' | |||||
403 | if self.ui.debugflag: |
|
403 | if self.ui.debugflag: | |
404 | if newmainbranch: |
|
404 | if newmainbranch: | |
405 | self.ui.debug( |
|
405 | self.ui.debug( | |
406 | 'fastannotate: %s: %d new changesets in the main' |
|
406 | b'fastannotate: %s: %d new changesets in the main' | |
407 | ' branch\n' % (self.path, len(newmainbranch)) |
|
407 | b' branch\n' % (self.path, len(newmainbranch)) | |
408 | ) |
|
408 | ) | |
409 | elif not hist: # no joints, no updates |
|
409 | elif not hist: # no joints, no updates | |
410 | self.ui.debug( |
|
410 | self.ui.debug( | |
411 | 'fastannotate: %s: linelog cannot help in ' |
|
411 | b'fastannotate: %s: linelog cannot help in ' | |
412 | 'annotating this revision\n' % self.path |
|
412 | b'annotating this revision\n' % self.path | |
413 | ) |
|
413 | ) | |
414 |
|
414 | |||
415 | # prepare annotateresult so we can update linelog incrementally |
|
415 | # prepare annotateresult so we can update linelog incrementally | |
@@ -418,7 +418,7 b' class _annotatecontext(object):' | |||||
418 | # 3rd DFS does the actual annotate |
|
418 | # 3rd DFS does the actual annotate | |
419 | visit = initvisit[:] |
|
419 | visit = initvisit[:] | |
420 | progress = self.ui.makeprogress( |
|
420 | progress = self.ui.makeprogress( | |
421 | 'building cache', total=len(newmainbranch) |
|
421 | b'building cache', total=len(newmainbranch) | |
422 | ) |
|
422 | ) | |
423 | while visit: |
|
423 | while visit: | |
424 | f = visit[-1] |
|
424 | f = visit[-1] | |
@@ -463,7 +463,7 b' class _annotatecontext(object):' | |||||
463 | if len(pl) == 2 and self.opts.followmerge: # merge |
|
463 | if len(pl) == 2 and self.opts.followmerge: # merge | |
464 | bannotated = curr[0] |
|
464 | bannotated = curr[0] | |
465 | if blocks is None: # no parents, add an empty one |
|
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 | self._appendrev(f, blocks, bannotated) |
|
467 | self._appendrev(f, blocks, bannotated) | |
468 | elif showpath: # not append linelog, but we need to record path |
|
468 | elif showpath: # not append linelog, but we need to record path | |
469 | self._node2path[f.node()] = f.path() |
|
469 | self._node2path[f.node()] = f.path() | |
@@ -490,7 +490,7 b' class _annotatecontext(object):' | |||||
490 | if hsh is not None and (hsh, self.path) in self.revmap: |
|
490 | if hsh is not None and (hsh, self.path) in self.revmap: | |
491 | f = hsh |
|
491 | f = hsh | |
492 | if f is None: |
|
492 | if f is None: | |
493 | adjustctx = 'linkrev' if self._perfhack else True |
|
493 | adjustctx = b'linkrev' if self._perfhack else True | |
494 | f = self._resolvefctx(rev, adjustctx=adjustctx, resolverev=True) |
|
494 | f = self._resolvefctx(rev, adjustctx=adjustctx, resolverev=True) | |
495 | result = f in self.revmap |
|
495 | result = f in self.revmap | |
496 | if not result and self._perfhack: |
|
496 | if not result and self._perfhack: | |
@@ -511,7 +511,7 b' class _annotatecontext(object):' | |||||
511 | # find a chain from rev to anything in the mainbranch |
|
511 | # find a chain from rev to anything in the mainbranch | |
512 | if revfctx not in self.revmap: |
|
512 | if revfctx not in self.revmap: | |
513 | chain = [revfctx] |
|
513 | chain = [revfctx] | |
514 | a = '' |
|
514 | a = b'' | |
515 | while True: |
|
515 | while True: | |
516 | f = chain[-1] |
|
516 | f = chain[-1] | |
517 | pl = self._parentfunc(f) |
|
517 | pl = self._parentfunc(f) | |
@@ -589,8 +589,8 b' class _annotatecontext(object):' | |||||
589 | hsh = annotateresult[idxs[0]][0] |
|
589 | hsh = annotateresult[idxs[0]][0] | |
590 | if self.ui.debugflag: |
|
590 | if self.ui.debugflag: | |
591 | self.ui.debug( |
|
591 | self.ui.debug( | |
592 | 'fastannotate: reading %s line #%d ' |
|
592 | b'fastannotate: reading %s line #%d ' | |
593 | 'to resolve lines %r\n' |
|
593 | b'to resolve lines %r\n' | |
594 | % (node.short(hsh), linenum, idxs) |
|
594 | % (node.short(hsh), linenum, idxs) | |
595 | ) |
|
595 | ) | |
596 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
|
596 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) | |
@@ -603,14 +603,15 b' class _annotatecontext(object):' | |||||
603 |
|
603 | |||
604 | # run the annotate and the lines should match to the file content |
|
604 | # run the annotate and the lines should match to the file content | |
605 | self.ui.debug( |
|
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 | linelog.annotate(rev) |
|
609 | linelog.annotate(rev) | |
609 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) |
|
610 | fctx = self._resolvefctx(hsh, revmap.rev2path(rev)) | |
610 | annotated = linelog.annotateresult |
|
611 | annotated = linelog.annotateresult | |
611 | lines = mdiff.splitnewlines(fctx.data()) |
|
612 | lines = mdiff.splitnewlines(fctx.data()) | |
612 | if len(lines) != len(annotated): |
|
613 | if len(lines) != len(annotated): | |
613 | raise faerror.CorruptedFileError('unexpected annotated lines') |
|
614 | raise faerror.CorruptedFileError(b'unexpected annotated lines') | |
614 | # resolve lines from the annotate result |
|
615 | # resolve lines from the annotate result | |
615 | for i, line in enumerate(lines): |
|
616 | for i, line in enumerate(lines): | |
616 | k = annotated[i] |
|
617 | k = annotated[i] | |
@@ -633,11 +634,11 b' class _annotatecontext(object):' | |||||
633 | llrev = self.revmap.hsh2rev(hsh) |
|
634 | llrev = self.revmap.hsh2rev(hsh) | |
634 | if not llrev: |
|
635 | if not llrev: | |
635 | raise faerror.CorruptedFileError( |
|
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 | if (self.revmap.rev2flag(llrev) & revmapmod.sidebranchflag) != 0: |
|
639 | if (self.revmap.rev2flag(llrev) & revmapmod.sidebranchflag) != 0: | |
639 | raise faerror.CorruptedFileError( |
|
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 | self.linelog.annotate(llrev) |
|
643 | self.linelog.annotate(llrev) | |
643 | result = [ |
|
644 | result = [ | |
@@ -677,7 +678,7 b' class _annotatecontext(object):' | |||||
677 | """(fctx) -> int""" |
|
678 | """(fctx) -> int""" | |
678 | # f should not be a linelog revision |
|
679 | # f should not be a linelog revision | |
679 | if isinstance(f, int): |
|
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 | # f is a fctx, allocate linelog rev on demand |
|
682 | # f is a fctx, allocate linelog rev on demand | |
682 | hsh = f.node() |
|
683 | hsh = f.node() | |
683 | rev = revmap.hsh2rev(hsh) |
|
684 | rev = revmap.hsh2rev(hsh) | |
@@ -690,7 +691,7 b' class _annotatecontext(object):' | |||||
690 | siderevmap = {} # node: int |
|
691 | siderevmap = {} # node: int | |
691 | if bannotated is not None: |
|
692 | if bannotated is not None: | |
692 | for (a1, a2, b1, b2), op in blocks: |
|
693 | for (a1, a2, b1, b2), op in blocks: | |
693 | if op != '=': |
|
694 | if op != b'=': | |
694 | # f could be either linelong rev, or fctx. |
|
695 | # f could be either linelong rev, or fctx. | |
695 | siderevs += [ |
|
696 | siderevs += [ | |
696 | f |
|
697 | f | |
@@ -708,7 +709,7 b' class _annotatecontext(object):' | |||||
708 | siderevmap[fctx] = llrev |
|
709 | siderevmap[fctx] = llrev | |
709 |
|
710 | |||
710 | for (a1, a2, b1, b2), op in reversed(blocks): |
|
711 | for (a1, a2, b1, b2), op in reversed(blocks): | |
711 | if op == '=': |
|
712 | if op == b'=': | |
712 | continue |
|
713 | continue | |
713 | if bannotated is None: |
|
714 | if bannotated is None: | |
714 | linelog.replacelines(llrev, a1, a2, b1, b2) |
|
715 | linelog.replacelines(llrev, a1, a2, b1, b2) | |
@@ -760,7 +761,7 b' class _annotatecontext(object):' | |||||
760 |
|
761 | |||
761 | @util.propertycache |
|
762 | @util.propertycache | |
762 | def _perfhack(self): |
|
763 | def _perfhack(self): | |
763 | return self.ui.configbool('fastannotate', 'perfhack') |
|
764 | return self.ui.configbool(b'fastannotate', b'perfhack') | |
764 |
|
765 | |||
765 | def _resolvefctx(self, rev, path=None, **kwds): |
|
766 | def _resolvefctx(self, rev, path=None, **kwds): | |
766 | return resolvefctx(self.repo, rev, (path or self.path), **kwds) |
|
767 | return resolvefctx(self.repo, rev, (path or self.path), **kwds) | |
@@ -781,7 +782,7 b' class pathhelper(object):' | |||||
781 | def __init__(self, repo, path, opts=defaultopts): |
|
782 | def __init__(self, repo, path, opts=defaultopts): | |
782 | # different options use different directories |
|
783 | # different options use different directories | |
783 | self._vfspath = os.path.join( |
|
784 | self._vfspath = os.path.join( | |
784 | 'fastannotate', opts.shortstr, encodedir(path) |
|
785 | b'fastannotate', opts.shortstr, encodedir(path) | |
785 | ) |
|
786 | ) | |
786 | self._repo = repo |
|
787 | self._repo = repo | |
787 |
|
788 | |||
@@ -791,14 +792,14 b' class pathhelper(object):' | |||||
791 |
|
792 | |||
792 | @property |
|
793 | @property | |
793 | def linelogpath(self): |
|
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 | def lock(self): |
|
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 | @property |
|
800 | @property | |
800 | def revmappath(self): |
|
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 | @contextlib.contextmanager |
|
805 | @contextlib.contextmanager | |
@@ -831,7 +832,7 b' def annotatecontext(repo, path, opts=def' | |||||
831 | except Exception: |
|
832 | except Exception: | |
832 | if actx is not None: |
|
833 | if actx is not None: | |
833 | actx.rebuild() |
|
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 | raise |
|
836 | raise | |
836 | finally: |
|
837 | finally: | |
837 | if actx is not None: |
|
838 | if actx is not None: | |
@@ -844,7 +845,7 b' def fctxannotatecontext(fctx, follow=Tru' | |||||
844 | """ |
|
845 | """ | |
845 | repo = fctx._repo |
|
846 | repo = fctx._repo | |
846 | path = fctx._path |
|
847 | path = fctx._path | |
847 | if repo.ui.configbool('fastannotate', 'forcefollow', True): |
|
848 | if repo.ui.configbool(b'fastannotate', b'forcefollow', True): | |
848 | follow = True |
|
849 | follow = True | |
849 | aopts = annotateopts(diffopts=diffopts, followrename=follow) |
|
850 | aopts = annotateopts(diffopts=diffopts, followrename=follow) | |
850 | return annotatecontext(repo, path, aopts, rebuild) |
|
851 | return annotatecontext(repo, path, aopts, rebuild) |
@@ -33,35 +33,35 b' class defaultformatter(object):' | |||||
33 | hexfunc = self._hexfunc |
|
33 | hexfunc = self._hexfunc | |
34 |
|
34 | |||
35 | # special handling working copy "changeset" and "rev" functions |
|
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 | orig = hexfunc |
|
37 | orig = hexfunc | |
38 | hexfunc = lambda x: None if x is None else orig(x) |
|
38 | hexfunc = lambda x: None if x is None else orig(x) | |
39 | wnode = hexfunc(repo['.'].node()) + '+' |
|
39 | wnode = hexfunc(repo[b'.'].node()) + b'+' | |
40 | wrev = '%d' % repo['.'].rev() |
|
40 | wrev = b'%d' % repo[b'.'].rev() | |
41 | wrevpad = '' |
|
41 | wrevpad = b'' | |
42 | if not opts.get('changeset'): # only show + if changeset is hidden |
|
42 | if not opts.get(b'changeset'): # only show + if changeset is hidden | |
43 | wrev += '+' |
|
43 | wrev += b'+' | |
44 | wrevpad = ' ' |
|
44 | wrevpad = b' ' | |
45 | revenc = lambda x: wrev if x is None else ('%d' % x) + wrevpad |
|
45 | revenc = lambda x: wrev if x is None else (b'%d' % x) + wrevpad | |
46 |
|
46 | |||
47 | def csetenc(x): |
|
47 | def csetenc(x): | |
48 | if x is None: |
|
48 | if x is None: | |
49 | return wnode |
|
49 | return wnode | |
50 | return pycompat.bytestr(x) + ' ' |
|
50 | return pycompat.bytestr(x) + b' ' | |
51 |
|
51 | |||
52 | else: |
|
52 | else: | |
53 | revenc = csetenc = pycompat.bytestr |
|
53 | revenc = csetenc = pycompat.bytestr | |
54 |
|
54 | |||
55 | # opt name, separator, raw value (for json/plain), encoder (for plain) |
|
55 | # opt name, separator, raw value (for json/plain), encoder (for plain) | |
56 | opmap = [ |
|
56 | opmap = [ | |
57 | ('user', ' ', lambda x: getctx(x).user(), ui.shortuser), |
|
57 | (b'user', b' ', lambda x: getctx(x).user(), ui.shortuser), | |
58 | ('number', ' ', lambda x: getctx(x).rev(), revenc), |
|
58 | (b'number', b' ', lambda x: getctx(x).rev(), revenc), | |
59 | ('changeset', ' ', lambda x: hexfunc(x[0]), csetenc), |
|
59 | (b'changeset', b' ', lambda x: hexfunc(x[0]), csetenc), | |
60 | ('date', ' ', lambda x: getctx(x).date(), datefunc), |
|
60 | (b'date', b' ', lambda x: getctx(x).date(), datefunc), | |
61 | ('file', ' ', lambda x: x[2], pycompat.bytestr), |
|
61 | (b'file', b' ', lambda x: x[2], pycompat.bytestr), | |
62 | ('line_number', ':', lambda x: x[1] + 1, 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 | funcmap = [ |
|
65 | funcmap = [ | |
66 | (get, sep, fieldnamemap.get(op, op), enc) |
|
66 | (get, sep, fieldnamemap.get(op, op), enc) | |
67 | for op, sep, get, enc in opmap |
|
67 | for op, sep, get, enc in opmap | |
@@ -69,7 +69,7 b' class defaultformatter(object):' | |||||
69 | ] |
|
69 | ] | |
70 | # no separator for first column |
|
70 | # no separator for first column | |
71 | funcmap[0] = list(funcmap[0]) |
|
71 | funcmap[0] = list(funcmap[0]) | |
72 | funcmap[0][1] = '' |
|
72 | funcmap[0][1] = b'' | |
73 | self.funcmap = funcmap |
|
73 | self.funcmap = funcmap | |
74 |
|
74 | |||
75 | def write(self, annotatedresult, lines=None, existinglines=None): |
|
75 | def write(self, annotatedresult, lines=None, existinglines=None): | |
@@ -83,39 +83,39 b' class defaultformatter(object):' | |||||
83 | for f, sep, name, enc in self.funcmap: |
|
83 | for f, sep, name, enc in self.funcmap: | |
84 | l = [enc(f(x)) for x in annotatedresult] |
|
84 | l = [enc(f(x)) for x in annotatedresult] | |
85 | pieces.append(l) |
|
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 | l = l[:1] |
|
87 | l = l[:1] | |
88 | widths = pycompat.maplist(encoding.colwidth, set(l)) |
|
88 | widths = pycompat.maplist(encoding.colwidth, set(l)) | |
89 | maxwidth = max(widths) if widths else 0 |
|
89 | maxwidth = max(widths) if widths else 0 | |
90 | maxwidths.append(maxwidth) |
|
90 | maxwidths.append(maxwidth) | |
91 |
|
91 | |||
92 | # buffered output |
|
92 | # buffered output | |
93 | result = '' |
|
93 | result = b'' | |
94 | for i in pycompat.xrange(len(annotatedresult)): |
|
94 | for i in pycompat.xrange(len(annotatedresult)): | |
95 | for j, p in enumerate(pieces): |
|
95 | for j, p in enumerate(pieces): | |
96 | sep = self.funcmap[j][1] |
|
96 | sep = self.funcmap[j][1] | |
97 | padding = ' ' * (maxwidths[j] - len(p[i])) |
|
97 | padding = b' ' * (maxwidths[j] - len(p[i])) | |
98 | result += sep + padding + p[i] |
|
98 | result += sep + padding + p[i] | |
99 | if lines: |
|
99 | if lines: | |
100 | if existinglines is None: |
|
100 | if existinglines is None: | |
101 | result += ': ' + lines[i] |
|
101 | result += b': ' + lines[i] | |
102 | else: # extra formatting showing whether a line exists |
|
102 | else: # extra formatting showing whether a line exists | |
103 | key = (annotatedresult[i][0], annotatedresult[i][1]) |
|
103 | key = (annotatedresult[i][0], annotatedresult[i][1]) | |
104 | if key in existinglines: |
|
104 | if key in existinglines: | |
105 | result += ': ' + lines[i] |
|
105 | result += b': ' + lines[i] | |
106 | else: |
|
106 | else: | |
107 | result += ': ' + self.ui.label( |
|
107 | result += b': ' + self.ui.label( | |
108 | '-' + lines[i], 'diff.deleted' |
|
108 | b'-' + lines[i], b'diff.deleted' | |
109 | ) |
|
109 | ) | |
110 |
|
110 | |||
111 | if result[-1:] != '\n': |
|
111 | if result[-1:] != b'\n': | |
112 | result += '\n' |
|
112 | result += b'\n' | |
113 |
|
113 | |||
114 | self.ui.write(result) |
|
114 | self.ui.write(result) | |
115 |
|
115 | |||
116 | @util.propertycache |
|
116 | @util.propertycache | |
117 | def _hexfunc(self): |
|
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 | return node.hex |
|
119 | return node.hex | |
120 | else: |
|
120 | else: | |
121 | return node.short |
|
121 | return node.short | |
@@ -127,7 +127,7 b' class defaultformatter(object):' | |||||
127 | class jsonformatter(defaultformatter): |
|
127 | class jsonformatter(defaultformatter): | |
128 | def __init__(self, ui, repo, opts): |
|
128 | def __init__(self, ui, repo, opts): | |
129 | super(jsonformatter, self).__init__(ui, repo, opts) |
|
129 | super(jsonformatter, self).__init__(ui, repo, opts) | |
130 | self.ui.write('[') |
|
130 | self.ui.write(b'[') | |
131 | self.needcomma = False |
|
131 | self.needcomma = False | |
132 |
|
132 | |||
133 | def write(self, annotatedresult, lines=None, existinglines=None): |
|
133 | def write(self, annotatedresult, lines=None, existinglines=None): | |
@@ -139,23 +139,23 b' class jsonformatter(defaultformatter):' | |||||
139 | for f, sep, name, enc in self.funcmap |
|
139 | for f, sep, name, enc in self.funcmap | |
140 | ] |
|
140 | ] | |
141 | if lines is not None: |
|
141 | if lines is not None: | |
142 | pieces.append(('line', lines)) |
|
142 | pieces.append((b'line', lines)) | |
143 | pieces.sort() |
|
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 | lasti = len(annotatedresult) - 1 |
|
148 | lasti = len(annotatedresult) - 1 | |
149 | for i in pycompat.xrange(len(annotatedresult)): |
|
149 | for i in pycompat.xrange(len(annotatedresult)): | |
150 | result += '\n {\n' |
|
150 | result += b'\n {\n' | |
151 | for j, p in enumerate(pieces): |
|
151 | for j, p in enumerate(pieces): | |
152 | k, vs = p |
|
152 | k, vs = p | |
153 | result += ' "%s": %s%s\n' % ( |
|
153 | result += b' "%s": %s%s\n' % ( | |
154 | k, |
|
154 | k, | |
155 | templatefilters.json(vs[i], paranoid=False), |
|
155 | templatefilters.json(vs[i], paranoid=False), | |
156 | seps[j], |
|
156 | seps[j], | |
157 | ) |
|
157 | ) | |
158 | result += ' }%s' % ('' if i == lasti else ',') |
|
158 | result += b' }%s' % (b'' if i == lasti else b',') | |
159 | if lasti >= 0: |
|
159 | if lasti >= 0: | |
160 | self.needcomma = True |
|
160 | self.needcomma = True | |
161 |
|
161 | |||
@@ -163,7 +163,7 b' class jsonformatter(defaultformatter):' | |||||
163 |
|
163 | |||
164 | def _writecomma(self): |
|
164 | def _writecomma(self): | |
165 | if self.needcomma: |
|
165 | if self.needcomma: | |
166 | self.ui.write(',') |
|
166 | self.ui.write(b',') | |
167 | self.needcomma = False |
|
167 | self.needcomma = False | |
168 |
|
168 | |||
169 | @util.propertycache |
|
169 | @util.propertycache | |
@@ -171,4 +171,4 b' class jsonformatter(defaultformatter):' | |||||
171 | return node.hex |
|
171 | return node.hex | |
172 |
|
172 | |||
173 | def end(self): |
|
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 | def _getmaster(ui): |
|
26 | def _getmaster(ui): | |
27 | """get the mainbranch, and enforce it is set""" |
|
27 | """get the mainbranch, and enforce it is set""" | |
28 | master = ui.config('fastannotate', 'mainbranch') |
|
28 | master = ui.config(b'fastannotate', b'mainbranch') | |
29 | if not master: |
|
29 | if not master: | |
30 | raise error.Abort( |
|
30 | raise error.Abort( | |
31 | _( |
|
31 | _( | |
32 | 'fastannotate.mainbranch is required ' |
|
32 | b'fastannotate.mainbranch is required ' | |
33 | 'for both the client and the server' |
|
33 | b'for both the client and the server' | |
34 | ) |
|
34 | ) | |
35 | ) |
|
35 | ) | |
36 | return master |
|
36 | return master | |
@@ -41,7 +41,7 b' def _getmaster(ui):' | |||||
41 |
|
41 | |||
42 | def _capabilities(orig, repo, proto): |
|
42 | def _capabilities(orig, repo, proto): | |
43 | result = orig(repo, proto) |
|
43 | result = orig(repo, proto) | |
44 | result.append('getannotate') |
|
44 | result.append(b'getannotate') | |
45 | return result |
|
45 | return result | |
46 |
|
46 | |||
47 |
|
47 | |||
@@ -49,9 +49,9 b' def _getannotate(repo, proto, path, last' | |||||
49 | # output: |
|
49 | # output: | |
50 | # FILE := vfspath + '\0' + str(size) + '\0' + content |
|
50 | # FILE := vfspath + '\0' + str(size) + '\0' + content | |
51 | # OUTPUT := '' | FILE + OUTPUT |
|
51 | # OUTPUT := '' | FILE + OUTPUT | |
52 | result = '' |
|
52 | result = b'' | |
53 | buildondemand = repo.ui.configbool( |
|
53 | buildondemand = repo.ui.configbool( | |
54 | 'fastannotate', 'serverbuildondemand', True |
|
54 | b'fastannotate', b'serverbuildondemand', True | |
55 | ) |
|
55 | ) | |
56 | with context.annotatecontext(repo, path) as actx: |
|
56 | with context.annotatecontext(repo, path) as actx: | |
57 | if buildondemand: |
|
57 | if buildondemand: | |
@@ -80,25 +80,25 b' def _getannotate(repo, proto, path, last' | |||||
80 | for p in [actx.revmappath, actx.linelogpath]: |
|
80 | for p in [actx.revmappath, actx.linelogpath]: | |
81 | if not os.path.exists(p): |
|
81 | if not os.path.exists(p): | |
82 | continue |
|
82 | continue | |
83 | with open(p, 'rb') as f: |
|
83 | with open(p, b'rb') as f: | |
84 | content = f.read() |
|
84 | content = f.read() | |
85 | vfsbaselen = len(repo.vfs.base + '/') |
|
85 | vfsbaselen = len(repo.vfs.base + b'/') | |
86 | relpath = p[vfsbaselen:] |
|
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 | return result |
|
88 | return result | |
89 |
|
89 | |||
90 |
|
90 | |||
91 | def _registerwireprotocommand(): |
|
91 | def _registerwireprotocommand(): | |
92 | if 'getannotate' in wireprotov1server.commands: |
|
92 | if b'getannotate' in wireprotov1server.commands: | |
93 | return |
|
93 | return | |
94 | wireprotov1server.wireprotocommand('getannotate', 'path lastnode')( |
|
94 | wireprotov1server.wireprotocommand(b'getannotate', b'path lastnode')( | |
95 | _getannotate |
|
95 | _getannotate | |
96 | ) |
|
96 | ) | |
97 |
|
97 | |||
98 |
|
98 | |||
99 | def serveruisetup(ui): |
|
99 | def serveruisetup(ui): | |
100 | _registerwireprotocommand() |
|
100 | _registerwireprotocommand() | |
101 | extensions.wrapfunction(wireprotov1server, '_capabilities', _capabilities) |
|
101 | extensions.wrapfunction(wireprotov1server, b'_capabilities', _capabilities) | |
102 |
|
102 | |||
103 |
|
103 | |||
104 | # client-side |
|
104 | # client-side | |
@@ -109,15 +109,15 b' def _parseresponse(payload):' | |||||
109 | i = 0 |
|
109 | i = 0 | |
110 | l = len(payload) - 1 |
|
110 | l = len(payload) - 1 | |
111 | state = 0 # 0: vfspath, 1: size |
|
111 | state = 0 # 0: vfspath, 1: size | |
112 | vfspath = size = '' |
|
112 | vfspath = size = b'' | |
113 | while i < l: |
|
113 | while i < l: | |
114 | ch = payload[i : i + 1] |
|
114 | ch = payload[i : i + 1] | |
115 | if ch == '\0': |
|
115 | if ch == b'\0': | |
116 | if state == 1: |
|
116 | if state == 1: | |
117 | result[vfspath] = payload[i + 1 : i + 1 + int(size)] |
|
117 | result[vfspath] = payload[i + 1 : i + 1 + int(size)] | |
118 | i += int(size) |
|
118 | i += int(size) | |
119 | state = 0 |
|
119 | state = 0 | |
120 | vfspath = size = '' |
|
120 | vfspath = size = b'' | |
121 | elif state == 0: |
|
121 | elif state == 0: | |
122 | state = 1 |
|
122 | state = 1 | |
123 | else: |
|
123 | else: | |
@@ -133,11 +133,11 b' def peersetup(ui, peer):' | |||||
133 | class fastannotatepeer(peer.__class__): |
|
133 | class fastannotatepeer(peer.__class__): | |
134 | @wireprotov1peer.batchable |
|
134 | @wireprotov1peer.batchable | |
135 | def getannotate(self, path, lastnode=None): |
|
135 | def getannotate(self, path, lastnode=None): | |
136 | if not self.capable('getannotate'): |
|
136 | if not self.capable(b'getannotate'): | |
137 | ui.warn(_('remote peer cannot provide annotate cache\n')) |
|
137 | ui.warn(_(b'remote peer cannot provide annotate cache\n')) | |
138 | yield None, None |
|
138 | yield None, None | |
139 | else: |
|
139 | else: | |
140 | args = {'path': path, 'lastnode': lastnode or ''} |
|
140 | args = {b'path': path, b'lastnode': lastnode or b''} | |
141 | f = wireprotov1peer.future() |
|
141 | f = wireprotov1peer.future() | |
142 | yield args, f |
|
142 | yield args, f | |
143 | yield _parseresponse(f.value) |
|
143 | yield _parseresponse(f.value) | |
@@ -150,7 +150,7 b' def annotatepeer(repo):' | |||||
150 | ui = repo.ui |
|
150 | ui = repo.ui | |
151 |
|
151 | |||
152 | remotepath = ui.expandpath( |
|
152 | remotepath = ui.expandpath( | |
153 | ui.config('fastannotate', 'remotepath', 'default') |
|
153 | ui.config(b'fastannotate', b'remotepath', b'default') | |
154 | ) |
|
154 | ) | |
155 | peer = hg.peer(ui, {}, remotepath) |
|
155 | peer = hg.peer(ui, {}, remotepath) | |
156 |
|
156 | |||
@@ -175,11 +175,12 b' def clientfetch(repo, paths, lastnodemap' | |||||
175 | ui = repo.ui |
|
175 | ui = repo.ui | |
176 | results = [] |
|
176 | results = [] | |
177 | with peer.commandexecutor() as batcher: |
|
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 | for p in paths: |
|
179 | for p in paths: | |
180 | results.append( |
|
180 | results.append( | |
181 | batcher.callcommand( |
|
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 | r = {util.pconvert(p): v for p, v in r.iteritems()} |
|
190 | r = {util.pconvert(p): v for p, v in r.iteritems()} | |
190 | for path in sorted(r): |
|
191 | for path in sorted(r): | |
191 | # ignore malicious paths |
|
192 | # ignore malicious paths | |
192 | if not path.startswith('fastannotate/') or '/../' in ( |
|
193 | if not path.startswith(b'fastannotate/') or b'/../' in ( | |
193 | path + '/' |
|
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 | continue |
|
199 | continue | |
197 | content = r[path] |
|
200 | content = r[path] | |
198 | if ui.debugflag: |
|
201 | if ui.debugflag: | |
199 | ui.debug( |
|
202 | ui.debug( | |
200 | 'fastannotate: writing %d bytes to %s\n' |
|
203 | b'fastannotate: writing %d bytes to %s\n' | |
201 | % (len(content), path) |
|
204 | % (len(content), path) | |
202 | ) |
|
205 | ) | |
203 | repo.vfs.makedirs(os.path.dirname(path)) |
|
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 | f.write(content) |
|
208 | f.write(content) | |
206 |
|
209 | |||
207 |
|
210 | |||
@@ -209,7 +212,7 b' def _filterfetchpaths(repo, paths):' | |||||
209 | """return a subset of paths whose history is long and need to fetch linelog |
|
212 | """return a subset of paths whose history is long and need to fetch linelog | |
210 | from the server. works with remotefilelog and non-remotefilelog repos. |
|
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 | if threshold <= 0: |
|
216 | if threshold <= 0: | |
214 | return paths |
|
217 | return paths | |
215 |
|
218 | |||
@@ -240,7 +243,7 b' def localreposetup(ui, repo):' | |||||
240 | clientfetch(self, needupdatepaths, lastnodemap, peer) |
|
243 | clientfetch(self, needupdatepaths, lastnodemap, peer) | |
241 | except Exception as ex: |
|
244 | except Exception as ex: | |
242 | # could be directory not writable or so, not fatal |
|
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 | repo.__class__ = fastannotaterepo |
|
248 | repo.__class__ = fastannotaterepo | |
246 |
|
249 |
@@ -70,7 +70,7 b' class revmap(object):' | |||||
70 | # since rename does not happen frequently, do not store path for every |
|
70 | # since rename does not happen frequently, do not store path for every | |
71 | # revision. self._renamerevs can be used for bisecting. |
|
71 | # revision. self._renamerevs can be used for bisecting. | |
72 | self._renamerevs = [0] |
|
72 | self._renamerevs = [0] | |
73 | self._renamepaths = [''] |
|
73 | self._renamepaths = [b''] | |
74 | self._lastmaxrev = -1 |
|
74 | self._lastmaxrev = -1 | |
75 | if path: |
|
75 | if path: | |
76 | if os.path.exists(path): |
|
76 | if os.path.exists(path): | |
@@ -98,9 +98,13 b' class revmap(object):' | |||||
98 | if flush is True, incrementally update the file. |
|
98 | if flush is True, incrementally update the file. | |
99 | """ |
|
99 | """ | |
100 | if hsh in self._hsh2rev: |
|
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 | if len(hsh) != _hshlen: |
|
104 | if len(hsh) != _hshlen: | |
103 |
raise hgerror.ProgrammingError( |
|
105 | raise hgerror.ProgrammingError( | |
|
106 | b'hsh must be %d-char long' % _hshlen | |||
|
107 | ) | |||
104 | idx = len(self._rev2hsh) |
|
108 | idx = len(self._rev2hsh) | |
105 | flag = 0 |
|
109 | flag = 0 | |
106 | if sidebranch: |
|
110 | if sidebranch: | |
@@ -149,7 +153,7 b' class revmap(object):' | |||||
149 | self._rev2hsh = [None] |
|
153 | self._rev2hsh = [None] | |
150 | self._rev2flag = [None] |
|
154 | self._rev2flag = [None] | |
151 | self._hsh2rev = {} |
|
155 | self._hsh2rev = {} | |
152 | self._rev2path = [''] |
|
156 | self._rev2path = [b''] | |
153 | self._lastmaxrev = -1 |
|
157 | self._lastmaxrev = -1 | |
154 | if flush: |
|
158 | if flush: | |
155 | self.flush() |
|
159 | self.flush() | |
@@ -159,12 +163,12 b' class revmap(object):' | |||||
159 | if not self.path: |
|
163 | if not self.path: | |
160 | return |
|
164 | return | |
161 | if self._lastmaxrev == -1: # write the entire file |
|
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 | f.write(self.HEADER) |
|
167 | f.write(self.HEADER) | |
164 | for i in pycompat.xrange(1, len(self._rev2hsh)): |
|
168 | for i in pycompat.xrange(1, len(self._rev2hsh)): | |
165 | self._writerev(i, f) |
|
169 | self._writerev(i, f) | |
166 | else: # append incrementally |
|
170 | else: # append incrementally | |
167 | with open(self.path, 'ab') as f: |
|
171 | with open(self.path, b'ab') as f: | |
168 | for i in pycompat.xrange( |
|
172 | for i in pycompat.xrange( | |
169 | self._lastmaxrev + 1, len(self._rev2hsh) |
|
173 | self._lastmaxrev + 1, len(self._rev2hsh) | |
170 | ): |
|
174 | ): | |
@@ -179,7 +183,7 b' class revmap(object):' | |||||
179 | # which is faster than both LOAD_CONST and LOAD_GLOBAL. |
|
183 | # which is faster than both LOAD_CONST and LOAD_GLOBAL. | |
180 | flaglen = 1 |
|
184 | flaglen = 1 | |
181 | hshlen = _hshlen |
|
185 | hshlen = _hshlen | |
182 | with open(self.path, 'rb') as f: |
|
186 | with open(self.path, b'rb') as f: | |
183 | if f.read(len(self.HEADER)) != self.HEADER: |
|
187 | if f.read(len(self.HEADER)) != self.HEADER: | |
184 | raise error.CorruptedFileError() |
|
188 | raise error.CorruptedFileError() | |
185 | self.clear(flush=False) |
|
189 | self.clear(flush=False) | |
@@ -205,23 +209,23 b' class revmap(object):' | |||||
205 | """append a revision data to file""" |
|
209 | """append a revision data to file""" | |
206 | flag = self._rev2flag[rev] |
|
210 | flag = self._rev2flag[rev] | |
207 | hsh = self._rev2hsh[rev] |
|
211 | hsh = self._rev2hsh[rev] | |
208 | f.write(struct.pack('B', flag)) |
|
212 | f.write(struct.pack(b'B', flag)) | |
209 | if flag & renameflag: |
|
213 | if flag & renameflag: | |
210 | path = self.rev2path(rev) |
|
214 | path = self.rev2path(rev) | |
211 | if path is None: |
|
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 | f.write(path + b'\0') |
|
217 | f.write(path + b'\0') | |
214 | f.write(hsh) |
|
218 | f.write(hsh) | |
215 |
|
219 | |||
216 | @staticmethod |
|
220 | @staticmethod | |
217 | def _readcstr(f): |
|
221 | def _readcstr(f): | |
218 | """read a C-language-like '\0'-terminated string""" |
|
222 | """read a C-language-like '\0'-terminated string""" | |
219 | buf = '' |
|
223 | buf = b'' | |
220 | while True: |
|
224 | while True: | |
221 | ch = f.read(1) |
|
225 | ch = f.read(1) | |
222 | if not ch: # unexpected eof |
|
226 | if not ch: # unexpected eof | |
223 | raise error.CorruptedFileError() |
|
227 | raise error.CorruptedFileError() | |
224 | if ch == '\0': |
|
228 | if ch == b'\0': | |
225 | break |
|
229 | break | |
226 | buf += ch |
|
230 | buf += ch | |
227 | return buf |
|
231 | return buf | |
@@ -249,7 +253,7 b' def getlastnode(path):' | |||||
249 | """ |
|
253 | """ | |
250 | hsh = None |
|
254 | hsh = None | |
251 | try: |
|
255 | try: | |
252 | with open(path, 'rb') as f: |
|
256 | with open(path, b'rb') as f: | |
253 | f.seek(-_hshlen, io.SEEK_END) |
|
257 | f.seek(-_hshlen, io.SEEK_END) | |
254 | if f.tell() > len(revmap.HEADER): |
|
258 | if f.tell() > len(revmap.HEADER): | |
255 | hsh = f.read(_hshlen) |
|
259 | hsh = f.read(_hshlen) |
@@ -64,7 +64,7 b' def _convertoutputs(repo, annotated, con' | |||||
64 |
|
64 | |||
65 | def _getmaster(fctx): |
|
65 | def _getmaster(fctx): | |
66 | """(fctx) -> str""" |
|
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 | def _doannotate(fctx, follow=True, diffopts=None): |
|
70 | def _doannotate(fctx, follow=True, diffopts=None): | |
@@ -83,7 +83,7 b' def _doannotate(fctx, follow=True, diffo' | |||||
83 | except Exception: |
|
83 | except Exception: | |
84 | ac.rebuild() # try rebuild once |
|
84 | ac.rebuild() # try rebuild once | |
85 | fctx._repo.ui.debug( |
|
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 | try: |
|
88 | try: | |
89 | annotated, contents = ac.annotate( |
|
89 | annotated, contents = ac.annotate( | |
@@ -98,7 +98,7 b' def _doannotate(fctx, follow=True, diffo' | |||||
98 |
|
98 | |||
99 | def _hgwebannotate(orig, fctx, ui): |
|
99 | def _hgwebannotate(orig, fctx, ui): | |
100 | diffopts = patch.difffeatureopts( |
|
100 | diffopts = patch.difffeatureopts( | |
101 | ui, untrusted=True, section='annotate', whitespace=True |
|
101 | ui, untrusted=True, section=b'annotate', whitespace=True | |
102 | ) |
|
102 | ) | |
103 | return _doannotate(fctx, diffopts=diffopts) |
|
103 | return _doannotate(fctx, diffopts=diffopts) | |
104 |
|
104 | |||
@@ -115,7 +115,7 b' def _fctxannotate(' | |||||
115 | return _doannotate(self, follow, diffopts) |
|
115 | return _doannotate(self, follow, diffopts) | |
116 | except Exception as ex: |
|
116 | except Exception as ex: | |
117 | self._repo.ui.debug( |
|
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 | return orig(self, follow=follow, skiprevs=skiprevs, diffopts=diffopts) |
|
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 | def replacehgwebannotate(): |
|
132 | def replacehgwebannotate(): | |
133 | extensions.wrapfunction(hgweb.webutil, 'annotate', _hgwebannotate) |
|
133 | extensions.wrapfunction(hgweb.webutil, b'annotate', _hgwebannotate) | |
134 |
|
134 | |||
135 |
|
135 | |||
136 | def replacefctxannotate(): |
|
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 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
30 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
31 | # be specifying the version(s) of Mercurial they are tested with, or |
|
31 | # be specifying the version(s) of Mercurial they are tested with, or | |
32 | # leave the attribute unspecified. |
|
32 | # leave the attribute unspecified. | |
33 | testedwith = 'ships-with-hg-core' |
|
33 | testedwith = b'ships-with-hg-core' | |
34 |
|
34 | |||
35 |
|
35 | |||
36 | @command( |
|
36 | @command( | |
37 | 'fetch', |
|
37 | b'fetch', | |
38 | [ |
|
38 | [ | |
39 | ( |
|
39 | ( | |
40 | 'r', |
|
40 | b'r', | |
41 | 'rev', |
|
41 | b'rev', | |
42 | [], |
|
42 | [], | |
43 | _('a specific revision you would like to pull'), |
|
43 | _(b'a specific revision you would like to pull'), | |
44 | _('REV'), |
|
44 | _(b'REV'), | |
45 | ), |
|
45 | ), | |
46 | ('', 'edit', None, _('invoke editor on commit messages')), |
|
46 | (b'', b'edit', None, _(b'invoke editor on commit messages')), | |
47 | ('', 'force-editor', None, _('edit commit message (DEPRECATED)')), |
|
47 | (b'', b'force-editor', None, _(b'edit commit message (DEPRECATED)')), | |
48 | ('', 'switch-parent', None, _('switch parents when merging')), |
|
48 | (b'', b'switch-parent', None, _(b'switch parents when merging')), | |
49 | ] |
|
49 | ] | |
50 | + cmdutil.commitopts |
|
50 | + cmdutil.commitopts | |
51 | + cmdutil.commitopts2 |
|
51 | + cmdutil.commitopts2 | |
52 | + cmdutil.remoteopts, |
|
52 | + cmdutil.remoteopts, | |
53 | _('hg fetch [SOURCE]'), |
|
53 | _(b'hg fetch [SOURCE]'), | |
54 | helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT, |
|
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 | '''pull changes from a remote repository, merge new changes if needed. |
|
57 | '''pull changes from a remote repository, merge new changes if needed. | |
58 |
|
58 | |||
59 | This finds all changes from the repository at the specified path |
|
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 | opts = pycompat.byteskwargs(opts) |
|
76 | opts = pycompat.byteskwargs(opts) | |
77 | date = opts.get('date') |
|
77 | date = opts.get(b'date') | |
78 | if date: |
|
78 | if date: | |
79 | opts['date'] = dateutil.parsedate(date) |
|
79 | opts[b'date'] = dateutil.parsedate(date) | |
80 |
|
80 | |||
81 | parent = repo.dirstate.p1() |
|
81 | parent = repo.dirstate.p1() | |
82 | branch = repo.dirstate.branch() |
|
82 | branch = repo.dirstate.branch() | |
@@ -86,8 +86,8 b" def fetch(ui, repo, source='default', **" | |||||
86 | branchnode = None |
|
86 | branchnode = None | |
87 | if parent != branchnode: |
|
87 | if parent != branchnode: | |
88 | raise error.Abort( |
|
88 | raise error.Abort( | |
89 | _('working directory not at branch tip'), |
|
89 | _(b'working directory not at branch tip'), | |
90 | hint=_("use 'hg update' to check out branch tip"), |
|
90 | hint=_(b"use 'hg update' to check out branch tip"), | |
91 | ) |
|
91 | ) | |
92 |
|
92 | |||
93 | wlock = lock = None |
|
93 | wlock = lock = None | |
@@ -102,23 +102,23 b" def fetch(ui, repo, source='default', **" | |||||
102 | if len(bheads) > 1: |
|
102 | if len(bheads) > 1: | |
103 | raise error.Abort( |
|
103 | raise error.Abort( | |
104 | _( |
|
104 | _( | |
105 | 'multiple heads in this branch ' |
|
105 | b'multiple heads in this branch ' | |
106 | '(use "hg heads ." and "hg merge" to merge)' |
|
106 | b'(use "hg heads ." and "hg merge" to merge)' | |
107 | ) |
|
107 | ) | |
108 | ) |
|
108 | ) | |
109 |
|
109 | |||
110 | other = hg.peer(repo, opts, ui.expandpath(source)) |
|
110 | other = hg.peer(repo, opts, ui.expandpath(source)) | |
111 | ui.status( |
|
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 | revs = None |
|
114 | revs = None | |
115 | if opts['rev']: |
|
115 | if opts[b'rev']: | |
116 | try: |
|
116 | try: | |
117 | revs = [other.lookup(rev) for rev in opts['rev']] |
|
117 | revs = [other.lookup(rev) for rev in opts[b'rev']] | |
118 | except error.CapabilityError: |
|
118 | except error.CapabilityError: | |
119 | err = _( |
|
119 | err = _( | |
120 | "other repository doesn't support revision lookup, " |
|
120 | b"other repository doesn't support revision lookup, " | |
121 | "so a rev cannot be specified." |
|
121 | b"so a rev cannot be specified." | |
122 | ) |
|
122 | ) | |
123 | raise error.Abort(err) |
|
123 | raise error.Abort(err) | |
124 |
|
124 | |||
@@ -146,8 +146,8 b" def fetch(ui, repo, source='default', **" | |||||
146 | if len(newheads) > 1: |
|
146 | if len(newheads) > 1: | |
147 | ui.status( |
|
147 | ui.status( | |
148 | _( |
|
148 | _( | |
149 | 'not merging with %d other new branch heads ' |
|
149 | b'not merging with %d other new branch heads ' | |
150 | '(use "hg heads ." and "hg merge" to merge them)\n' |
|
150 | b'(use "hg heads ." and "hg merge" to merge them)\n' | |
151 | ) |
|
151 | ) | |
152 | % (len(newheads) - 1) |
|
152 | % (len(newheads) - 1) | |
153 | ) |
|
153 | ) | |
@@ -162,17 +162,17 b" def fetch(ui, repo, source='default', **" | |||||
162 | # By default, we consider the repository we're pulling |
|
162 | # By default, we consider the repository we're pulling | |
163 | # *from* as authoritative, so we merge our changes into |
|
163 | # *from* as authoritative, so we merge our changes into | |
164 | # theirs. |
|
164 | # theirs. | |
165 | if opts['switch_parent']: |
|
165 | if opts[b'switch_parent']: | |
166 | firstparent, secondparent = newparent, newheads[0] |
|
166 | firstparent, secondparent = newparent, newheads[0] | |
167 | else: |
|
167 | else: | |
168 | firstparent, secondparent = newheads[0], newparent |
|
168 | firstparent, secondparent = newheads[0], newparent | |
169 | ui.status( |
|
169 | ui.status( | |
170 | _('updating to %d:%s\n') |
|
170 | _(b'updating to %d:%s\n') | |
171 | % (repo.changelog.rev(firstparent), short(firstparent)) |
|
171 | % (repo.changelog.rev(firstparent), short(firstparent)) | |
172 | ) |
|
172 | ) | |
173 | hg.clean(repo, firstparent) |
|
173 | hg.clean(repo, firstparent) | |
174 | ui.status( |
|
174 | ui.status( | |
175 | _('merging with %d:%s\n') |
|
175 | _(b'merging with %d:%s\n') | |
176 | % (repo.changelog.rev(secondparent), short(secondparent)) |
|
176 | % (repo.changelog.rev(secondparent), short(secondparent)) | |
177 | ) |
|
177 | ) | |
178 | err = hg.merge(repo, secondparent, remind=False) |
|
178 | err = hg.merge(repo, secondparent, remind=False) | |
@@ -180,13 +180,15 b" def fetch(ui, repo, source='default', **" | |||||
180 | if not err: |
|
180 | if not err: | |
181 | # we don't translate commit messages |
|
181 | # we don't translate commit messages | |
182 | message = cmdutil.logmessage(ui, opts) or ( |
|
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') |
|
185 | editopt = opts.get(b'edit') or opts.get(b'force_editor') | |
186 | editor = cmdutil.getcommiteditor(edit=editopt, editform='fetch') |
|
186 | editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch') | |
187 | n = repo.commit(message, opts['user'], opts['date'], editor=editor) |
|
187 | n = repo.commit( | |
|
188 | message, opts[b'user'], opts[b'date'], editor=editor | |||
|
189 | ) | |||
188 | ui.status( |
|
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 | % (repo.changelog.rev(n), short(n)) |
|
192 | % (repo.changelog.rev(n), short(n)) | |
191 | ) |
|
193 | ) | |
192 |
|
194 |
@@ -157,7 +157,7 b' from mercurial import (' | |||||
157 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
157 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
158 | # be specifying the version(s) of Mercurial they are tested with, or |
|
158 | # be specifying the version(s) of Mercurial they are tested with, or | |
159 | # leave the attribute unspecified. |
|
159 | # leave the attribute unspecified. | |
160 | testedwith = 'ships-with-hg-core' |
|
160 | testedwith = b'ships-with-hg-core' | |
161 |
|
161 | |||
162 | cmdtable = {} |
|
162 | cmdtable = {} | |
163 | command = registrar.command(cmdtable) |
|
163 | command = registrar.command(cmdtable) | |
@@ -167,61 +167,61 b' configitem = registrar.configitem(config' | |||||
167 |
|
167 | |||
168 | # Register the suboptions allowed for each configured fixer, and default values. |
|
168 | # Register the suboptions allowed for each configured fixer, and default values. | |
169 | FIXER_ATTRS = { |
|
169 | FIXER_ATTRS = { | |
170 | 'command': None, |
|
170 | b'command': None, | |
171 | 'linerange': None, |
|
171 | b'linerange': None, | |
172 | 'pattern': None, |
|
172 | b'pattern': None, | |
173 | 'priority': 0, |
|
173 | b'priority': 0, | |
174 | 'metadata': 'false', |
|
174 | b'metadata': b'false', | |
175 | 'skipclean': 'true', |
|
175 | b'skipclean': b'true', | |
176 | 'enabled': 'true', |
|
176 | b'enabled': b'true', | |
177 | } |
|
177 | } | |
178 |
|
178 | |||
179 | for key, default in FIXER_ATTRS.items(): |
|
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 | # A good default size allows most source code files to be fixed, but avoids |
|
182 | # A good default size allows most source code files to be fixed, but avoids | |
183 | # letting fixer tools choke on huge inputs, which could be surprising to the |
|
183 | # letting fixer tools choke on huge inputs, which could be surprising to the | |
184 | # user. |
|
184 | # user. | |
185 | configitem('fix', 'maxfilesize', default='2MB') |
|
185 | configitem(b'fix', b'maxfilesize', default=b'2MB') | |
186 |
|
186 | |||
187 | # Allow fix commands to exit non-zero if an executed fixer tool exits non-zero. |
|
187 | # Allow fix commands to exit non-zero if an executed fixer tool exits non-zero. | |
188 | # This helps users do shell scripts that stop when a fixer tool signals a |
|
188 | # This helps users do shell scripts that stop when a fixer tool signals a | |
189 | # problem. |
|
189 | # problem. | |
190 | configitem('fix', 'failure', default='continue') |
|
190 | configitem(b'fix', b'failure', default=b'continue') | |
191 |
|
191 | |||
192 |
|
192 | |||
193 | def checktoolfailureaction(ui, message, hint=None): |
|
193 | def checktoolfailureaction(ui, message, hint=None): | |
194 | """Abort with 'message' if fix.failure=abort""" |
|
194 | """Abort with 'message' if fix.failure=abort""" | |
195 | action = ui.config('fix', 'failure') |
|
195 | action = ui.config(b'fix', b'failure') | |
196 | if action not in ('continue', 'abort'): |
|
196 | if action not in (b'continue', b'abort'): | |
197 | raise error.Abort( |
|
197 | raise error.Abort( | |
198 | _('unknown fix.failure action: %s') % (action,), |
|
198 | _(b'unknown fix.failure action: %s') % (action,), | |
199 | hint=_('use "continue" or "abort"'), |
|
199 | hint=_(b'use "continue" or "abort"'), | |
200 | ) |
|
200 | ) | |
201 | if action == 'abort': |
|
201 | if action == b'abort': | |
202 | raise error.Abort(message, hint=hint) |
|
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 | baseopt = ( |
|
206 | baseopt = ( | |
207 | '', |
|
207 | b'', | |
208 | 'base', |
|
208 | b'base', | |
209 | [], |
|
209 | [], | |
210 | _( |
|
210 | _( | |
211 | 'revisions to diff against (overrides automatic ' |
|
211 | b'revisions to diff against (overrides automatic ' | |
212 | 'selection, and applies to every revision being ' |
|
212 | b'selection, and applies to every revision being ' | |
213 | 'fixed)' |
|
213 | b'fixed)' | |
214 | ), |
|
214 | ), | |
215 | _('REV'), |
|
215 | _(b'REV'), | |
216 | ) |
|
216 | ) | |
217 | revopt = ('r', 'rev', [], _('revisions to fix'), _('REV')) |
|
217 | revopt = (b'r', b'rev', [], _(b'revisions to fix'), _(b'REV')) | |
218 | wdiropt = ('w', 'working-dir', False, _('fix the working directory')) |
|
218 | wdiropt = (b'w', b'working-dir', False, _(b'fix the working directory')) | |
219 | wholeopt = ('', 'whole', False, _('always fix every line of a file')) |
|
219 | wholeopt = (b'', b'whole', False, _(b'always fix every line of a file')) | |
220 | usage = _('[OPTION]... [FILE]...') |
|
220 | usage = _(b'[OPTION]... [FILE]...') | |
221 |
|
221 | |||
222 |
|
222 | |||
223 | @command( |
|
223 | @command( | |
224 | 'fix', |
|
224 | b'fix', | |
225 | [allopt, baseopt, revopt, wdiropt, wholeopt], |
|
225 | [allopt, baseopt, revopt, wdiropt, wholeopt], | |
226 | usage, |
|
226 | usage, | |
227 | helpcategory=command.CATEGORY_FILE_CONTENTS, |
|
227 | helpcategory=command.CATEGORY_FILE_CONTENTS, | |
@@ -250,12 +250,12 b' def fix(ui, repo, *pats, **opts):' | |||||
250 | override this default behavior, though it is not usually desirable to do so. |
|
250 | override this default behavior, though it is not usually desirable to do so. | |
251 | """ |
|
251 | """ | |
252 | opts = pycompat.byteskwargs(opts) |
|
252 | opts = pycompat.byteskwargs(opts) | |
253 | if opts['all']: |
|
253 | if opts[b'all']: | |
254 | if opts['rev']: |
|
254 | if opts[b'rev']: | |
255 | raise error.Abort(_('cannot specify both "--rev" and "--all"')) |
|
255 | raise error.Abort(_(b'cannot specify both "--rev" and "--all"')) | |
256 | opts['rev'] = ['not public() and not obsolete()'] |
|
256 | opts[b'rev'] = [b'not public() and not obsolete()'] | |
257 | opts['working_dir'] = True |
|
257 | opts[b'working_dir'] = True | |
258 | with repo.wlock(), repo.lock(), repo.transaction('fix'): |
|
258 | with repo.wlock(), repo.lock(), repo.transaction(b'fix'): | |
259 | revstofix = getrevstofix(ui, repo, opts) |
|
259 | revstofix = getrevstofix(ui, repo, opts) | |
260 | basectxs = getbasectxs(repo, opts, revstofix) |
|
260 | basectxs = getbasectxs(repo, opts, revstofix) | |
261 | workqueue, numitems = getworkqueue( |
|
261 | workqueue, numitems = getworkqueue( | |
@@ -297,7 +297,7 b' def fix(ui, repo, *pats, **opts):' | |||||
297 | wdirwritten = False |
|
297 | wdirwritten = False | |
298 | commitorder = sorted(revstofix, reverse=True) |
|
298 | commitorder = sorted(revstofix, reverse=True) | |
299 | with ui.makeprogress( |
|
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 | ) as progress: |
|
301 | ) as progress: | |
302 | for rev, path, filerevmetadata, newdata in results: |
|
302 | for rev, path, filerevmetadata, newdata in results: | |
303 | progress.increment(item=path) |
|
303 | progress.increment(item=path) | |
@@ -306,12 +306,12 b' def fix(ui, repo, *pats, **opts):' | |||||
306 | if newdata is not None: |
|
306 | if newdata is not None: | |
307 | filedata[rev][path] = newdata |
|
307 | filedata[rev][path] = newdata | |
308 | hookargs = { |
|
308 | hookargs = { | |
309 | 'rev': rev, |
|
309 | b'rev': rev, | |
310 | 'path': path, |
|
310 | b'path': path, | |
311 | 'metadata': filerevmetadata, |
|
311 | b'metadata': filerevmetadata, | |
312 | } |
|
312 | } | |
313 | repo.hook( |
|
313 | repo.hook( | |
314 | 'postfixfile', |
|
314 | b'postfixfile', | |
315 | throw=False, |
|
315 | throw=False, | |
316 | **pycompat.strkwargs(hookargs) |
|
316 | **pycompat.strkwargs(hookargs) | |
317 | ) |
|
317 | ) | |
@@ -332,11 +332,11 b' def fix(ui, repo, *pats, **opts):' | |||||
332 |
|
332 | |||
333 | cleanup(repo, replacements, wdirwritten) |
|
333 | cleanup(repo, replacements, wdirwritten) | |
334 | hookargs = { |
|
334 | hookargs = { | |
335 | 'replacements': replacements, |
|
335 | b'replacements': replacements, | |
336 | 'wdirwritten': wdirwritten, |
|
336 | b'wdirwritten': wdirwritten, | |
337 | 'metadata': aggregatemetadata, |
|
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 | def cleanup(repo, replacements, wdirwritten): |
|
342 | def cleanup(repo, replacements, wdirwritten): | |
@@ -353,7 +353,7 b' def cleanup(repo, replacements, wdirwrit' | |||||
353 | effects of the command, though we choose not to output anything here. |
|
353 | effects of the command, though we choose not to output anything here. | |
354 | """ |
|
354 | """ | |
355 | replacements = {prec: [succ] for prec, succ in replacements.iteritems()} |
|
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 | def getworkqueue(ui, repo, pats, opts, revstofix, basectxs): |
|
359 | def getworkqueue(ui, repo, pats, opts, revstofix, basectxs): | |
@@ -375,7 +375,7 b' def getworkqueue(ui, repo, pats, opts, r' | |||||
375 | """ |
|
375 | """ | |
376 | workqueue = [] |
|
376 | workqueue = [] | |
377 | numitems = collections.defaultdict(int) |
|
377 | numitems = collections.defaultdict(int) | |
378 | maxfilesize = ui.configbytes('fix', 'maxfilesize') |
|
378 | maxfilesize = ui.configbytes(b'fix', b'maxfilesize') | |
379 | for rev in sorted(revstofix): |
|
379 | for rev in sorted(revstofix): | |
380 | fixctx = repo[rev] |
|
380 | fixctx = repo[rev] | |
381 | match = scmutil.match(fixctx, pats, opts) |
|
381 | match = scmutil.match(fixctx, pats, opts) | |
@@ -387,7 +387,7 b' def getworkqueue(ui, repo, pats, opts, r' | |||||
387 | continue |
|
387 | continue | |
388 | if fctx.size() > maxfilesize: |
|
388 | if fctx.size() > maxfilesize: | |
389 | ui.warn( |
|
389 | ui.warn( | |
390 | _('ignoring file larger than %s: %s\n') |
|
390 | _(b'ignoring file larger than %s: %s\n') | |
391 | % (util.bytecount(maxfilesize), path) |
|
391 | % (util.bytecount(maxfilesize), path) | |
392 | ) |
|
392 | ) | |
393 | continue |
|
393 | continue | |
@@ -398,29 +398,29 b' def getworkqueue(ui, repo, pats, opts, r' | |||||
398 |
|
398 | |||
399 | def getrevstofix(ui, repo, opts): |
|
399 | def getrevstofix(ui, repo, opts): | |
400 | """Returns the set of revision numbers that should be fixed""" |
|
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 | for rev in revs: |
|
402 | for rev in revs: | |
403 | checkfixablectx(ui, repo, repo[rev]) |
|
403 | checkfixablectx(ui, repo, repo[rev]) | |
404 | if revs: |
|
404 | if revs: | |
405 | cmdutil.checkunfinished(repo) |
|
405 | cmdutil.checkunfinished(repo) | |
406 | checknodescendants(repo, revs) |
|
406 | checknodescendants(repo, revs) | |
407 | if opts.get('working_dir'): |
|
407 | if opts.get(b'working_dir'): | |
408 | revs.add(wdirrev) |
|
408 | revs.add(wdirrev) | |
409 | if list(merge.mergestate.read(repo).unresolved()): |
|
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 | if not revs: |
|
411 | if not revs: | |
412 | raise error.Abort( |
|
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 | return revs |
|
415 | return revs | |
416 |
|
416 | |||
417 |
|
417 | |||
418 | def checknodescendants(repo, revs): |
|
418 | def checknodescendants(repo, revs): | |
419 | if not obsolete.isenabled(repo, obsolete.allowunstableopt) and repo.revs( |
|
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 | raise error.Abort( |
|
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 | """Aborts if the revision shouldn't be replaced with a fixed one.""" |
|
428 | """Aborts if the revision shouldn't be replaced with a fixed one.""" | |
429 | if not ctx.mutable(): |
|
429 | if not ctx.mutable(): | |
430 | raise error.Abort( |
|
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 | if ctx.obsolete(): |
|
434 | if ctx.obsolete(): | |
434 | # It would be better to actually check if the revision has a successor. |
|
435 | # It would be better to actually check if the revision has a successor. | |
435 | allowdivergence = ui.configbool( |
|
436 | allowdivergence = ui.configbool( | |
436 | 'experimental', 'evolution.allowdivergence' |
|
437 | b'experimental', b'evolution.allowdivergence' | |
437 | ) |
|
438 | ) | |
438 | if not allowdivergence: |
|
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 | def pathstofix(ui, repo, pats, opts, match, basectxs, fixctx): |
|
445 | def pathstofix(ui, repo, pats, opts, match, basectxs, fixctx): | |
@@ -473,10 +476,10 b' def lineranges(opts, path, basectxs, fix' | |||||
473 | Another way to understand this is that we exclude line ranges that are |
|
476 | Another way to understand this is that we exclude line ranges that are | |
474 | common to the file in all base contexts. |
|
477 | common to the file in all base contexts. | |
475 | """ |
|
478 | """ | |
476 | if opts.get('whole'): |
|
479 | if opts.get(b'whole'): | |
477 | # Return a range containing all lines. Rely on the diff implementation's |
|
480 | # Return a range containing all lines. Rely on the diff implementation's | |
478 | # idea of how many lines are in the file, instead of reimplementing it. |
|
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 | rangeslist = [] |
|
484 | rangeslist = [] | |
482 | for basectx in basectxs: |
|
485 | for basectx in basectxs: | |
@@ -484,7 +487,7 b' def lineranges(opts, path, basectxs, fix' | |||||
484 | if basepath in basectx: |
|
487 | if basepath in basectx: | |
485 | content1 = basectx[basepath].data() |
|
488 | content1 = basectx[basepath].data() | |
486 | else: |
|
489 | else: | |
487 | content1 = '' |
|
490 | content1 = b'' | |
488 | rangeslist.extend(difflineranges(content1, content2)) |
|
491 | rangeslist.extend(difflineranges(content1, content2)) | |
489 | return unionranges(rangeslist) |
|
492 | return unionranges(rangeslist) | |
490 |
|
493 | |||
@@ -566,7 +569,7 b' def difflineranges(content1, content2):' | |||||
566 | ranges = [] |
|
569 | ranges = [] | |
567 | for lines, kind in mdiff.allblocks(content1, content2): |
|
570 | for lines, kind in mdiff.allblocks(content1, content2): | |
568 | firstline, lastline = lines[2:4] |
|
571 | firstline, lastline = lines[2:4] | |
569 | if kind == '!' and firstline != lastline: |
|
572 | if kind == b'!' and firstline != lastline: | |
570 | ranges.append((firstline + 1, lastline)) |
|
573 | ranges.append((firstline + 1, lastline)) | |
571 | return ranges |
|
574 | return ranges | |
572 |
|
575 | |||
@@ -581,8 +584,8 b' def getbasectxs(repo, opts, revstofix):' | |||||
581 | """ |
|
584 | """ | |
582 | # The --base flag overrides the usual logic, and we give every revision |
|
585 | # The --base flag overrides the usual logic, and we give every revision | |
583 | # exactly the set of baserevs that the user specified. |
|
586 | # exactly the set of baserevs that the user specified. | |
584 | if opts.get('base'): |
|
587 | if opts.get(b'base'): | |
585 | baserevs = set(scmutil.revrange(repo, opts.get('base'))) |
|
588 | baserevs = set(scmutil.revrange(repo, opts.get(b'base'))) | |
586 | if not baserevs: |
|
589 | if not baserevs: | |
587 | baserevs = {nullrev} |
|
590 | baserevs = {nullrev} | |
588 | basectxs = {repo[rev] for rev in baserevs} |
|
591 | basectxs = {repo[rev] for rev in baserevs} | |
@@ -621,7 +624,7 b' def fixfile(ui, repo, opts, fixers, fixc' | |||||
621 | command = fixer.command(ui, path, ranges) |
|
624 | command = fixer.command(ui, path, ranges) | |
622 | if command is None: |
|
625 | if command is None: | |
623 | continue |
|
626 | continue | |
624 | ui.debug('subprocess: %s\n' % (command,)) |
|
627 | ui.debug(b'subprocess: %s\n' % (command,)) | |
625 | proc = subprocess.Popen( |
|
628 | proc = subprocess.Popen( | |
626 | procutil.tonativestr(command), |
|
629 | procutil.tonativestr(command), | |
627 | shell=True, |
|
630 | shell=True, | |
@@ -636,11 +639,11 b' def fixfile(ui, repo, opts, fixers, fixc' | |||||
636 | newerdata = stdout |
|
639 | newerdata = stdout | |
637 | if fixer.shouldoutputmetadata(): |
|
640 | if fixer.shouldoutputmetadata(): | |
638 | try: |
|
641 | try: | |
639 | metadatajson, newerdata = stdout.split('\0', 1) |
|
642 | metadatajson, newerdata = stdout.split(b'\0', 1) | |
640 | metadata[fixername] = json.loads(metadatajson) |
|
643 | metadata[fixername] = json.loads(metadatajson) | |
641 | except ValueError: |
|
644 | except ValueError: | |
642 | ui.warn( |
|
645 | ui.warn( | |
643 | _('ignored invalid output from fixer tool: %s\n') |
|
646 | _(b'ignored invalid output from fixer tool: %s\n') | |
644 | % (fixername,) |
|
647 | % (fixername,) | |
645 | ) |
|
648 | ) | |
646 | continue |
|
649 | continue | |
@@ -650,14 +653,14 b' def fixfile(ui, repo, opts, fixers, fixc' | |||||
650 | newdata = newerdata |
|
653 | newdata = newerdata | |
651 | else: |
|
654 | else: | |
652 | if not stderr: |
|
655 | if not stderr: | |
653 | message = _('exited with status %d\n') % (proc.returncode,) |
|
656 | message = _(b'exited with status %d\n') % (proc.returncode,) | |
654 | showstderr(ui, fixctx.rev(), fixername, message) |
|
657 | showstderr(ui, fixctx.rev(), fixername, message) | |
655 | checktoolfailureaction( |
|
658 | checktoolfailureaction( | |
656 | ui, |
|
659 | ui, | |
657 | _('no fixes will be applied'), |
|
660 | _(b'no fixes will be applied'), | |
658 | hint=_( |
|
661 | hint=_( | |
659 | 'use --config fix.failure=continue to apply any ' |
|
662 | b'use --config fix.failure=continue to apply any ' | |
660 | 'successful fixes anyway' |
|
663 | b'successful fixes anyway' | |
661 | ), |
|
664 | ), | |
662 | ) |
|
665 | ) | |
663 | return metadata, newdata |
|
666 | return metadata, newdata | |
@@ -671,14 +674,14 b' def showstderr(ui, rev, fixername, stder' | |||||
671 | space and would tend to be included in the error message if they were |
|
674 | space and would tend to be included in the error message if they were | |
672 | relevant. |
|
675 | relevant. | |
673 | """ |
|
676 | """ | |
674 | for line in re.split('[\r\n]+', stderr): |
|
677 | for line in re.split(b'[\r\n]+', stderr): | |
675 | if line: |
|
678 | if line: | |
676 | ui.warn('[') |
|
679 | ui.warn(b'[') | |
677 | if rev is None: |
|
680 | if rev is None: | |
678 | ui.warn(_('wdir'), label='evolve.rev') |
|
681 | ui.warn(_(b'wdir'), label=b'evolve.rev') | |
679 | else: |
|
682 | else: | |
680 | ui.warn((str(rev)), label='evolve.rev') |
|
683 | ui.warn((str(rev)), label=b'evolve.rev') | |
681 | ui.warn('] %s: %s\n' % (fixername, line)) |
|
684 | ui.warn(b'] %s: %s\n' % (fixername, line)) | |
682 |
|
685 | |||
683 |
|
686 | |||
684 | def writeworkingdir(repo, ctx, filedata, replacements): |
|
687 | def writeworkingdir(repo, ctx, filedata, replacements): | |
@@ -694,7 +697,7 b' def writeworkingdir(repo, ctx, filedata,' | |||||
694 | for path, data in filedata.iteritems(): |
|
697 | for path, data in filedata.iteritems(): | |
695 | fctx = ctx[path] |
|
698 | fctx = ctx[path] | |
696 | fctx.write(data, fctx.flags()) |
|
699 | fctx.write(data, fctx.flags()) | |
697 | if repo.dirstate[path] == 'n': |
|
700 | if repo.dirstate[path] == b'n': | |
698 | repo.dirstate.normallookup(path) |
|
701 | repo.dirstate.normallookup(path) | |
699 |
|
702 | |||
700 | oldparentnodes = repo.dirstate.parents() |
|
703 | oldparentnodes = repo.dirstate.parents() | |
@@ -757,7 +760,7 b' def replacerev(ui, repo, ctx, filedata, ' | |||||
757 | ) |
|
760 | ) | |
758 |
|
761 | |||
759 | extra = ctx.extra().copy() |
|
762 | extra = ctx.extra().copy() | |
760 | extra['fix_source'] = ctx.hex() |
|
763 | extra[b'fix_source'] = ctx.hex() | |
761 |
|
764 | |||
762 | memctx = context.memctx( |
|
765 | memctx = context.memctx( | |
763 | repo, |
|
766 | repo, | |
@@ -774,7 +777,7 b' def replacerev(ui, repo, ctx, filedata, ' | |||||
774 | sucnode = memctx.commit() |
|
777 | sucnode = memctx.commit() | |
775 | prenode = ctx.node() |
|
778 | prenode = ctx.node() | |
776 | if prenode == sucnode: |
|
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 | else: |
|
781 | else: | |
779 | replacements[ctx.node()] = sucnode |
|
782 | replacements[ctx.node()] = sucnode | |
780 |
|
783 | |||
@@ -788,11 +791,11 b' def getfixers(ui):' | |||||
788 | fixers = {} |
|
791 | fixers = {} | |
789 | for name in fixernames(ui): |
|
792 | for name in fixernames(ui): | |
790 | fixers[name] = Fixer() |
|
793 | fixers[name] = Fixer() | |
791 | attrs = ui.configsuboptions('fix', name)[1] |
|
794 | attrs = ui.configsuboptions(b'fix', name)[1] | |
792 | for key, default in FIXER_ATTRS.items(): |
|
795 | for key, default in FIXER_ATTRS.items(): | |
793 | setattr( |
|
796 | setattr( | |
794 | fixers[name], |
|
797 | fixers[name], | |
795 | pycompat.sysstr('_' + key), |
|
798 | pycompat.sysstr(b'_' + key), | |
796 | attrs.get(key, default), |
|
799 | attrs.get(key, default), | |
797 | ) |
|
800 | ) | |
798 | fixers[name]._priority = int(fixers[name]._priority) |
|
801 | fixers[name]._priority = int(fixers[name]._priority) | |
@@ -805,11 +808,11 b' def getfixers(ui):' | |||||
805 | # default. |
|
808 | # default. | |
806 | if fixers[name]._pattern is None: |
|
809 | if fixers[name]._pattern is None: | |
807 | ui.warn( |
|
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 | del fixers[name] |
|
813 | del fixers[name] | |
811 | elif not fixers[name]._enabled: |
|
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 | del fixers[name] |
|
816 | del fixers[name] | |
814 | return collections.OrderedDict( |
|
817 | return collections.OrderedDict( | |
815 | sorted(fixers.items(), key=lambda item: item[1]._priority, reverse=True) |
|
818 | sorted(fixers.items(), key=lambda item: item[1]._priority, reverse=True) | |
@@ -819,9 +822,9 b' def getfixers(ui):' | |||||
819 | def fixernames(ui): |
|
822 | def fixernames(ui): | |
820 | """Returns the names of [fix] config options that have suboptions""" |
|
823 | """Returns the names of [fix] config options that have suboptions""" | |
821 | names = set() |
|
824 | names = set() | |
822 | for k, v in ui.configitems('fix'): |
|
825 | for k, v in ui.configitems(b'fix'): | |
823 | if ':' in k: |
|
826 | if b':' in k: | |
824 | names.add(k.split(':', 1)[0]) |
|
827 | names.add(k.split(b':', 1)[0]) | |
825 | return names |
|
828 | return names | |
826 |
|
829 | |||
827 |
|
830 | |||
@@ -849,7 +852,7 b' class Fixer(object):' | |||||
849 | expand( |
|
852 | expand( | |
850 | ui, |
|
853 | ui, | |
851 | self._command, |
|
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 | if self._linerange: |
|
858 | if self._linerange: | |
@@ -858,6 +861,8 b' class Fixer(object):' | |||||
858 | return None |
|
861 | return None | |
859 | for first, last in ranges: |
|
862 | for first, last in ranges: | |
860 | parts.append( |
|
863 | parts.append( | |
861 | expand(ui, self._linerange, {'first': first, 'last': last}) |
|
864 | expand( | |
|
865 | ui, self._linerange, {b'first': first, b'last': last} | |||
|
866 | ) | |||
862 | ) |
|
867 | ) | |
863 | return ' '.join(parts) |
|
868 | return b' '.join(parts) |
@@ -143,60 +143,60 b' from . import (' | |||||
143 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
|
143 | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | |
144 | # be specifying the version(s) of Mercurial they are tested with, or |
|
144 | # be specifying the version(s) of Mercurial they are tested with, or | |
145 | # leave the attribute unspecified. |
|
145 | # leave the attribute unspecified. | |
146 | testedwith = 'ships-with-hg-core' |
|
146 | testedwith = b'ships-with-hg-core' | |
147 |
|
147 | |||
148 | configtable = {} |
|
148 | configtable = {} | |
149 | configitem = registrar.configitem(configtable) |
|
149 | configitem = registrar.configitem(configtable) | |
150 |
|
150 | |||
151 | configitem( |
|
151 | configitem( | |
152 | 'fsmonitor', 'mode', default='on', |
|
152 | b'fsmonitor', b'mode', default=b'on', | |
153 | ) |
|
153 | ) | |
154 | configitem( |
|
154 | configitem( | |
155 | 'fsmonitor', 'walk_on_invalidate', default=False, |
|
155 | b'fsmonitor', b'walk_on_invalidate', default=False, | |
156 | ) |
|
156 | ) | |
157 | configitem( |
|
157 | configitem( | |
158 | 'fsmonitor', 'timeout', default='2', |
|
158 | b'fsmonitor', b'timeout', default=b'2', | |
159 | ) |
|
159 | ) | |
160 | configitem( |
|
160 | configitem( | |
161 | 'fsmonitor', 'blacklistusers', default=list, |
|
161 | b'fsmonitor', b'blacklistusers', default=list, | |
162 | ) |
|
162 | ) | |
163 | configitem( |
|
163 | configitem( | |
164 | 'fsmonitor', 'watchman_exe', default='watchman', |
|
164 | b'fsmonitor', b'watchman_exe', default=b'watchman', | |
165 | ) |
|
165 | ) | |
166 | configitem( |
|
166 | configitem( | |
167 | 'fsmonitor', 'verbose', default=True, experimental=True, |
|
167 | b'fsmonitor', b'verbose', default=True, experimental=True, | |
168 | ) |
|
168 | ) | |
169 | configitem( |
|
169 | configitem( | |
170 | 'experimental', 'fsmonitor.transaction_notify', default=False, |
|
170 | b'experimental', b'fsmonitor.transaction_notify', default=False, | |
171 | ) |
|
171 | ) | |
172 |
|
172 | |||
173 | # This extension is incompatible with the following blacklisted extensions |
|
173 | # This extension is incompatible with the following blacklisted extensions | |
174 | # and will disable itself when encountering one of these: |
|
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 | def debuginstall(ui, fm): |
|
178 | def debuginstall(ui, fm): | |
179 | fm.write( |
|
179 | fm.write( | |
180 | "fsmonitor-watchman", |
|
180 | b"fsmonitor-watchman", | |
181 | _("fsmonitor checking for watchman binary... (%s)\n"), |
|
181 | _(b"fsmonitor checking for watchman binary... (%s)\n"), | |
182 | ui.configpath("fsmonitor", "watchman_exe"), |
|
182 | ui.configpath(b"fsmonitor", b"watchman_exe"), | |
183 | ) |
|
183 | ) | |
184 | root = tempfile.mkdtemp() |
|
184 | root = tempfile.mkdtemp() | |
185 | c = watchmanclient.client(ui, root) |
|
185 | c = watchmanclient.client(ui, root) | |
186 | err = None |
|
186 | err = None | |
187 | try: |
|
187 | try: | |
188 | v = c.command("version") |
|
188 | v = c.command(b"version") | |
189 | fm.write( |
|
189 | fm.write( | |
190 | "fsmonitor-watchman-version", |
|
190 | b"fsmonitor-watchman-version", | |
191 | _(" watchman binary version %s\n"), |
|
191 | _(b" watchman binary version %s\n"), | |
192 | v["version"], |
|
192 | v[b"version"], | |
193 | ) |
|
193 | ) | |
194 | except watchmanclient.Unavailable as e: |
|
194 | except watchmanclient.Unavailable as e: | |
195 | err = str(e) |
|
195 | err = str(e) | |
196 | fm.condwrite( |
|
196 | fm.condwrite( | |
197 | err, |
|
197 | err, | |
198 | "fsmonitor-watchman-error", |
|
198 | b"fsmonitor-watchman-error", | |
199 | _(" watchman binary missing or broken: %s\n"), |
|
199 | _(b" watchman binary missing or broken: %s\n"), | |
200 | err, |
|
200 | err, | |
201 | ) |
|
201 | ) | |
202 | return 1 if err else 0 |
|
202 | return 1 if err else 0 | |
@@ -206,16 +206,16 b' def _handleunavailable(ui, state, ex):' | |||||
206 | """Exception handler for Watchman interaction exceptions""" |
|
206 | """Exception handler for Watchman interaction exceptions""" | |
207 | if isinstance(ex, watchmanclient.Unavailable): |
|
207 | if isinstance(ex, watchmanclient.Unavailable): | |
208 | # experimental config: fsmonitor.verbose |
|
208 | # experimental config: fsmonitor.verbose | |
209 | if ex.warn and ui.configbool('fsmonitor', 'verbose'): |
|
209 | if ex.warn and ui.configbool(b'fsmonitor', b'verbose'): | |
210 | if 'illegal_fstypes' not in str(ex): |
|
210 | if b'illegal_fstypes' not in str(ex): | |
211 | ui.warn(str(ex) + '\n') |
|
211 | ui.warn(str(ex) + b'\n') | |
212 | if ex.invalidate: |
|
212 | if ex.invalidate: | |
213 | state.invalidate() |
|
213 | state.invalidate() | |
214 | # experimental config: fsmonitor.verbose |
|
214 | # experimental config: fsmonitor.verbose | |
215 | if ui.configbool('fsmonitor', 'verbose'): |
|
215 | if ui.configbool(b'fsmonitor', b'verbose'): | |
216 | ui.log('fsmonitor', 'Watchman unavailable: %s\n', ex.msg) |
|
216 | ui.log(b'fsmonitor', b'Watchman unavailable: %s\n', ex.msg) | |
217 | else: |
|
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 | def _hashignore(ignore): |
|
221 | def _hashignore(ignore): | |
@@ -245,7 +245,7 b' def _watchmantofsencoding(path):' | |||||
245 | try: |
|
245 | try: | |
246 | decoded = path.decode(_watchmanencoding) |
|
246 | decoded = path.decode(_watchmanencoding) | |
247 | except UnicodeDecodeError as e: |
|
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 | try: |
|
250 | try: | |
251 | encoded = decoded.encode(_fsencoding, 'strict') |
|
251 | encoded = decoded.encode(_fsencoding, 'strict') | |
@@ -263,34 +263,34 b' def overridewalk(orig, self, match, subr' | |||||
263 | subset of files.''' |
|
263 | subset of files.''' | |
264 |
|
264 | |||
265 | def bail(reason): |
|
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 | return orig(match, subrepos, unknown, ignored, full=True) |
|
267 | return orig(match, subrepos, unknown, ignored, full=True) | |
268 |
|
268 | |||
269 | if full: |
|
269 | if full: | |
270 | return bail('full rewalk requested') |
|
270 | return bail(b'full rewalk requested') | |
271 | if ignored: |
|
271 | if ignored: | |
272 | return bail('listing ignored files') |
|
272 | return bail(b'listing ignored files') | |
273 | if not self._watchmanclient.available(): |
|
273 | if not self._watchmanclient.available(): | |
274 | return bail('client unavailable') |
|
274 | return bail(b'client unavailable') | |
275 | state = self._fsmonitorstate |
|
275 | state = self._fsmonitorstate | |
276 | clock, ignorehash, notefiles = state.get() |
|
276 | clock, ignorehash, notefiles = state.get() | |
277 | if not clock: |
|
277 | if not clock: | |
278 | if state.walk_on_invalidate: |
|
278 | if state.walk_on_invalidate: | |
279 | return bail('no clock') |
|
279 | return bail(b'no clock') | |
280 | # Initial NULL clock value, see |
|
280 | # Initial NULL clock value, see | |
281 | # https://facebook.github.io/watchman/docs/clockspec.html |
|
281 | # https://facebook.github.io/watchman/docs/clockspec.html | |
282 | clock = 'c:0:0' |
|
282 | clock = b'c:0:0' | |
283 | notefiles = [] |
|
283 | notefiles = [] | |
284 |
|
284 | |||
285 | ignore = self._ignore |
|
285 | ignore = self._ignore | |
286 | dirignore = self._dirignore |
|
286 | dirignore = self._dirignore | |
287 | if unknown: |
|
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 | # ignore list changed -- can't rely on Watchman state any more |
|
289 | # ignore list changed -- can't rely on Watchman state any more | |
290 | if state.walk_on_invalidate: |
|
290 | if state.walk_on_invalidate: | |
291 | return bail('ignore rules changed') |
|
291 | return bail(b'ignore rules changed') | |
292 | notefiles = [] |
|
292 | notefiles = [] | |
293 | clock = 'c:0:0' |
|
293 | clock = b'c:0:0' | |
294 | else: |
|
294 | else: | |
295 | # always ignore |
|
295 | # always ignore | |
296 | ignore = util.always |
|
296 | ignore = util.always | |
@@ -299,7 +299,7 b' def overridewalk(orig, self, match, subr' | |||||
299 | matchfn = match.matchfn |
|
299 | matchfn = match.matchfn | |
300 | matchalways = match.always() |
|
300 | matchalways = match.always() | |
301 | dmap = self._map |
|
301 | dmap = self._map | |
302 | if util.safehasattr(dmap, '_map'): |
|
302 | if util.safehasattr(dmap, b'_map'): | |
303 | # for better performance, directly access the inner dirstate map if the |
|
303 | # for better performance, directly access the inner dirstate map if the | |
304 | # standard dirstate implementation is in use. |
|
304 | # standard dirstate implementation is in use. | |
305 | dmap = dmap._map |
|
305 | dmap = dmap._map | |
@@ -339,7 +339,7 b' def overridewalk(orig, self, match, subr' | |||||
339 | if not work and (exact or skipstep3): |
|
339 | if not work and (exact or skipstep3): | |
340 | for s in subrepos: |
|
340 | for s in subrepos: | |
341 | del results[s] |
|
341 | del results[s] | |
342 | del results['.hg'] |
|
342 | del results[b'.hg'] | |
343 | return results |
|
343 | return results | |
344 |
|
344 | |||
345 | # step 2: query Watchman |
|
345 | # step 2: query Watchman | |
@@ -349,30 +349,34 b' def overridewalk(orig, self, match, subr' | |||||
349 | # overheads while transferring the data |
|
349 | # overheads while transferring the data | |
350 | self._watchmanclient.settimeout(state.timeout + 0.1) |
|
350 | self._watchmanclient.settimeout(state.timeout + 0.1) | |
351 | result = self._watchmanclient.command( |
|
351 | result = self._watchmanclient.command( | |
352 | 'query', |
|
352 | b'query', | |
353 | { |
|
353 | { | |
354 | 'fields': ['mode', 'mtime', 'size', 'exists', 'name'], |
|
354 | b'fields': [b'mode', b'mtime', b'size', b'exists', b'name'], | |
355 | 'since': clock, |
|
355 | b'since': clock, | |
356 | 'expression': [ |
|
356 | b'expression': [ | |
357 | 'not', |
|
357 | b'not', | |
358 | ['anyof', ['dirname', '.hg'], ['name', '.hg', 'wholename']], |
|
358 | [ | |
|
359 | b'anyof', | |||
|
360 | [b'dirname', b'.hg'], | |||
|
361 | [b'name', b'.hg', b'wholename'], | |||
|
362 | ], | |||
359 | ], |
|
363 | ], | |
360 | 'sync_timeout': int(state.timeout * 1000), |
|
364 | b'sync_timeout': int(state.timeout * 1000), | |
361 | 'empty_on_fresh_instance': state.walk_on_invalidate, |
|
365 | b'empty_on_fresh_instance': state.walk_on_invalidate, | |
362 | }, |
|
366 | }, | |
363 | ) |
|
367 | ) | |
364 | except Exception as ex: |
|
368 | except Exception as ex: | |
365 | _handleunavailable(self._ui, state, ex) |
|
369 | _handleunavailable(self._ui, state, ex) | |
366 | self._watchmanclient.clearconnection() |
|
370 | self._watchmanclient.clearconnection() | |
367 | return bail('exception during run') |
|
371 | return bail(b'exception during run') | |
368 | else: |
|
372 | else: | |
369 | # We need to propagate the last observed clock up so that we |
|
373 | # We need to propagate the last observed clock up so that we | |
370 | # can use it for our next query |
|
374 | # can use it for our next query | |
371 | state.setlastclock(result['clock']) |
|
375 | state.setlastclock(result[b'clock']) | |
372 | if result['is_fresh_instance']: |
|
376 | if result[b'is_fresh_instance']: | |
373 | if state.walk_on_invalidate: |
|
377 | if state.walk_on_invalidate: | |
374 | state.invalidate() |
|
378 | state.invalidate() | |
375 | return bail('fresh instance') |
|
379 | return bail(b'fresh instance') | |
376 | fresh_instance = True |
|
380 | fresh_instance = True | |
377 | # Ignore any prior noteable files from the state info |
|
381 | # Ignore any prior noteable files from the state info | |
378 | notefiles = [] |
|
382 | notefiles = [] | |
@@ -382,7 +386,7 b' def overridewalk(orig, self, match, subr' | |||||
382 | if normalize: |
|
386 | if normalize: | |
383 | foldmap = dict((normcase(k), k) for k in results) |
|
387 | foldmap = dict((normcase(k), k) for k in results) | |
384 |
|
388 | |||
385 | switch_slashes = pycompat.ossep == '\\' |
|
389 | switch_slashes = pycompat.ossep == b'\\' | |
386 | # The order of the results is, strictly speaking, undefined. |
|
390 | # The order of the results is, strictly speaking, undefined. | |
387 | # For case changes on a case insensitive filesystem we may receive |
|
391 | # For case changes on a case insensitive filesystem we may receive | |
388 | # two entries, one with exists=True and another with exists=False. |
|
392 | # two entries, one with exists=True and another with exists=False. | |
@@ -390,22 +394,22 b' def overridewalk(orig, self, match, subr' | |||||
390 | # as being happens-after the exists=False entries due to the way that |
|
394 | # as being happens-after the exists=False entries due to the way that | |
391 | # Watchman tracks files. We use this property to reconcile deletes |
|
395 | # Watchman tracks files. We use this property to reconcile deletes | |
392 | # for name case changes. |
|
396 | # for name case changes. | |
393 | for entry in result['files']: |
|
397 | for entry in result[b'files']: | |
394 | fname = entry['name'] |
|
398 | fname = entry[b'name'] | |
395 | if _fixencoding: |
|
399 | if _fixencoding: | |
396 | fname = _watchmantofsencoding(fname) |
|
400 | fname = _watchmantofsencoding(fname) | |
397 | if switch_slashes: |
|
401 | if switch_slashes: | |
398 | fname = fname.replace('\\', '/') |
|
402 | fname = fname.replace(b'\\', b'/') | |
399 | if normalize: |
|
403 | if normalize: | |
400 | normed = normcase(fname) |
|
404 | normed = normcase(fname) | |
401 | fname = normalize(fname, True, True) |
|
405 | fname = normalize(fname, True, True) | |
402 | foldmap[normed] = fname |
|
406 | foldmap[normed] = fname | |
403 | fmode = entry['mode'] |
|
407 | fmode = entry[b'mode'] | |
404 | fexists = entry['exists'] |
|
408 | fexists = entry[b'exists'] | |
405 | kind = getkind(fmode) |
|
409 | kind = getkind(fmode) | |
406 |
|
410 | |||
407 | if '/.hg/' in fname or fname.endswith('/.hg'): |
|
411 | if b'/.hg/' in fname or fname.endswith(b'/.hg'): | |
408 | return bail('nested-repo-detected') |
|
412 | return bail(b'nested-repo-detected') | |
409 |
|
413 | |||
410 | if not fexists: |
|
414 | if not fexists: | |
411 | # if marked as deleted and we don't already have a change |
|
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 | for s in subrepos: |
|
493 | for s in subrepos: | |
490 | del results[s] |
|
494 | del results[s] | |
491 | del results['.hg'] |
|
495 | del results[b'.hg'] | |
492 | return results |
|
496 | return results | |
493 |
|
497 | |||
494 |
|
498 | |||
495 | def overridestatus( |
|
499 | def overridestatus( | |
496 | orig, |
|
500 | orig, | |
497 | self, |
|
501 | self, | |
498 | node1='.', |
|
502 | node1=b'.', | |
499 | node2=None, |
|
503 | node2=None, | |
500 | match=None, |
|
504 | match=None, | |
501 | ignored=False, |
|
505 | ignored=False, | |
@@ -509,22 +513,22 b' def overridestatus(' | |||||
509 |
|
513 | |||
510 | def _cmpsets(l1, l2): |
|
514 | def _cmpsets(l1, l2): | |
511 | try: |
|
515 | try: | |
512 | if 'FSMONITOR_LOG_FILE' in encoding.environ: |
|
516 | if b'FSMONITOR_LOG_FILE' in encoding.environ: | |
513 | fn = encoding.environ['FSMONITOR_LOG_FILE'] |
|
517 | fn = encoding.environ[b'FSMONITOR_LOG_FILE'] | |
514 | f = open(fn, 'wb') |
|
518 | f = open(fn, b'wb') | |
515 | else: |
|
519 | else: | |
516 | fn = 'fsmonitorfail.log' |
|
520 | fn = b'fsmonitorfail.log' | |
517 | f = self.vfs.open(fn, 'wb') |
|
521 | f = self.vfs.open(fn, b'wb') | |
518 | except (IOError, OSError): |
|
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 | return |
|
524 | return | |
521 |
|
525 | |||
522 | try: |
|
526 | try: | |
523 | for i, (s1, s2) in enumerate(zip(l1, l2)): |
|
527 | for i, (s1, s2) in enumerate(zip(l1, l2)): | |
524 | if set(s1) != set(s2): |
|
528 | if set(s1) != set(s2): | |
525 | f.write('sets at position %d are unequal\n' % i) |
|
529 | f.write(b'sets at position %d are unequal\n' % i) | |
526 | f.write('watchman returned: %s\n' % s1) |
|
530 | f.write(b'watchman returned: %s\n' % s1) | |
527 | f.write('stat returned: %s\n' % s2) |
|
531 | f.write(b'stat returned: %s\n' % s2) | |
528 | finally: |
|
532 | finally: | |
529 | f.close() |
|
533 | f.close() | |
530 |
|
534 | |||
@@ -538,7 +542,7 b' def overridestatus(' | |||||
538 | ctx2 = self[node2] |
|
542 | ctx2 = self[node2] | |
539 |
|
543 | |||
540 | working = ctx2.rev() is None |
|
544 | working = ctx2.rev() is None | |
541 | parentworking = working and ctx1 == self['.'] |
|
545 | parentworking = working and ctx1 == self[b'.'] | |
542 | match = match or matchmod.always() |
|
546 | match = match or matchmod.always() | |
543 |
|
547 | |||
544 | # Maybe we can use this opportunity to update Watchman's state. |
|
548 | # Maybe we can use this opportunity to update Watchman's state. | |
@@ -552,7 +556,7 b' def overridestatus(' | |||||
552 | parentworking |
|
556 | parentworking | |
553 | and match.always() |
|
557 | and match.always() | |
554 | and not isinstance(ctx2, (context.workingcommitctx, context.memctx)) |
|
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 | try: |
|
562 | try: | |
@@ -607,7 +611,7 b' def overridestatus(' | |||||
607 |
|
611 | |||
608 | # don't do paranoid checks if we're not going to query Watchman anyway |
|
612 | # don't do paranoid checks if we're not going to query Watchman anyway | |
609 | full = listclean or match.traversedir is not None |
|
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 | # run status again and fall back to the old walk this time |
|
615 | # run status again and fall back to the old walk this time | |
612 | self.dirstate._fsmonitordisable = True |
|
616 | self.dirstate._fsmonitordisable = True | |
613 |
|
617 | |||
@@ -615,7 +619,7 b' def overridestatus(' | |||||
615 | quiet = self.ui.quiet |
|
619 | quiet = self.ui.quiet | |
616 | self.ui.quiet = True |
|
620 | self.ui.quiet = True | |
617 | fout, ferr = self.ui.fout, self.ui.ferr |
|
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 | try: |
|
624 | try: | |
621 | rv2 = orig( |
|
625 | rv2 = orig( | |
@@ -692,20 +696,20 b' def makedirstate(repo, dirstate):' | |||||
692 | def wrapdirstate(orig, self): |
|
696 | def wrapdirstate(orig, self): | |
693 | ds = orig(self) |
|
697 | ds = orig(self) | |
694 | # only override the dirstate when Watchman is available for the repo |
|
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 | makedirstate(self, ds) |
|
700 | makedirstate(self, ds) | |
697 | return ds |
|
701 | return ds | |
698 |
|
702 | |||
699 |
|
703 | |||
700 | def extsetup(ui): |
|
704 | def extsetup(ui): | |
701 | extensions.wrapfilecache( |
|
705 | extensions.wrapfilecache( | |
702 | localrepo.localrepository, 'dirstate', wrapdirstate |
|
706 | localrepo.localrepository, b'dirstate', wrapdirstate | |
703 | ) |
|
707 | ) | |
704 | if pycompat.isdarwin: |
|
708 | if pycompat.isdarwin: | |
705 | # An assist for avoiding the dangling-symlink fsevents bug |
|
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 | def wrapsymlink(orig, source, link_name): |
|
715 | def wrapsymlink(orig, source, link_name): | |
@@ -756,14 +760,14 b' class state_update(object):' | |||||
756 | # merge.update is going to take the wlock almost immediately. We are |
|
760 | # merge.update is going to take the wlock almost immediately. We are | |
757 | # effectively extending the lock around several short sanity checks. |
|
761 | # effectively extending the lock around several short sanity checks. | |
758 | if self.oldnode is None: |
|
762 | if self.oldnode is None: | |
759 | self.oldnode = self.repo['.'].node() |
|
763 | self.oldnode = self.repo[b'.'].node() | |
760 |
|
764 | |||
761 | if self.repo.currentwlock() is None: |
|
765 | if self.repo.currentwlock() is None: | |
762 | if util.safehasattr(self.repo, 'wlocknostateupdate'): |
|
766 | if util.safehasattr(self.repo, b'wlocknostateupdate'): | |
763 | self._lock = self.repo.wlocknostateupdate() |
|
767 | self._lock = self.repo.wlocknostateupdate() | |
764 | else: |
|
768 | else: | |
765 | self._lock = self.repo.wlock() |
|
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 | return self |
|
771 | return self | |
768 |
|
772 | |||
769 | def __exit__(self, type_, value, tb): |
|
773 | def __exit__(self, type_, value, tb): | |
@@ -773,36 +777,36 b' class state_update(object):' | |||||
773 | def exit(self, abort=False): |
|
777 | def exit(self, abort=False): | |
774 | try: |
|
778 | try: | |
775 | if self.need_leave: |
|
779 | if self.need_leave: | |
776 | status = 'failed' if abort else 'ok' |
|
780 | status = b'failed' if abort else b'ok' | |
777 | if self.newnode is None: |
|
781 | if self.newnode is None: | |
778 | self.newnode = self.repo['.'].node() |
|
782 | self.newnode = self.repo[b'.'].node() | |
779 | if self.distance is None: |
|
783 | if self.distance is None: | |
780 | self.distance = calcdistance( |
|
784 | self.distance = calcdistance( | |
781 | self.repo, self.oldnode, self.newnode |
|
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 | finally: |
|
788 | finally: | |
785 | self.need_leave = False |
|
789 | self.need_leave = False | |
786 | if self._lock: |
|
790 | if self._lock: | |
787 | self._lock.release() |
|
791 | self._lock.release() | |
788 |
|
792 | |||
789 | def _state(self, cmd, commithash, status='ok'): |
|
793 | def _state(self, cmd, commithash, status=b'ok'): | |
790 | if not util.safehasattr(self.repo, '_watchmanclient'): |
|
794 | if not util.safehasattr(self.repo, b'_watchmanclient'): | |
791 | return False |
|
795 | return False | |
792 | try: |
|
796 | try: | |
793 | self.repo._watchmanclient.command( |
|
797 | self.repo._watchmanclient.command( | |
794 | cmd, |
|
798 | cmd, | |
795 | { |
|
799 | { | |
796 | 'name': self.name, |
|
800 | b'name': self.name, | |
797 | 'metadata': { |
|
801 | b'metadata': { | |
798 | # the target revision |
|
802 | # the target revision | |
799 | 'rev': commithash, |
|
803 | b'rev': commithash, | |
800 | # approximate number of commits between current and target |
|
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 | # success/failure (only really meaningful for state-leave) |
|
806 | # success/failure (only really meaningful for state-leave) | |
803 | 'status': status, |
|
807 | b'status': status, | |
804 | # whether the working copy parent is changing |
|
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 | except Exception as e: |
|
814 | except Exception as e: | |
811 | # Swallow any errors; fire and forget |
|
815 | # Swallow any errors; fire and forget | |
812 | self.repo.ui.log( |
|
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 | return False |
|
819 | return False | |
816 |
|
820 | |||
@@ -844,7 +848,7 b' def wrapupdate(' | |||||
844 |
|
848 | |||
845 | distance = 0 |
|
849 | distance = 0 | |
846 | partial = True |
|
850 | partial = True | |
847 | oldnode = repo['.'].node() |
|
851 | oldnode = repo[b'.'].node() | |
848 | newnode = repo[node].node() |
|
852 | newnode = repo[node].node() | |
849 | if matcher is None or matcher.always(): |
|
853 | if matcher is None or matcher.always(): | |
850 | partial = False |
|
854 | partial = False | |
@@ -852,7 +856,7 b' def wrapupdate(' | |||||
852 |
|
856 | |||
853 | with state_update( |
|
857 | with state_update( | |
854 | repo, |
|
858 | repo, | |
855 | name="hg.update", |
|
859 | name=b"hg.update", | |
856 | oldnode=oldnode, |
|
860 | oldnode=oldnode, | |
857 | newnode=newnode, |
|
861 | newnode=newnode, | |
858 | distance=distance, |
|
862 | distance=distance, | |
@@ -873,8 +877,8 b' def wrapupdate(' | |||||
873 |
|
877 | |||
874 | def repo_has_depth_one_nested_repo(repo): |
|
878 | def repo_has_depth_one_nested_repo(repo): | |
875 | for f in repo.wvfs.listdir(): |
|
879 | for f in repo.wvfs.listdir(): | |
876 | if os.path.isdir(os.path.join(repo.root, f, '.hg')): |
|
880 | if os.path.isdir(os.path.join(repo.root, f, b'.hg')): | |
877 | msg = 'fsmonitor: sub-repository %r detected, fsmonitor disabled\n' |
|
881 | msg = b'fsmonitor: sub-repository %r detected, fsmonitor disabled\n' | |
878 | repo.ui.debug(msg % f) |
|
882 | repo.ui.debug(msg % f) | |
879 | return True |
|
883 | return True | |
880 | return False |
|
884 | return False | |
@@ -887,8 +891,8 b' def reposetup(ui, repo):' | |||||
887 | if ext in exts: |
|
891 | if ext in exts: | |
888 | ui.warn( |
|
892 | ui.warn( | |
889 | _( |
|
893 | _( | |
890 | 'The fsmonitor extension is incompatible with the %s ' |
|
894 | b'The fsmonitor extension is incompatible with the %s ' | |
891 | 'extension and has been disabled.\n' |
|
895 | b'extension and has been disabled.\n' | |
892 | ) |
|
896 | ) | |
893 | % ext |
|
897 | % ext | |
894 | ) |
|
898 | ) | |
@@ -899,14 +903,14 b' def reposetup(ui, repo):' | |||||
899 | # |
|
903 | # | |
900 | # if repo[None].substate can cause a dirstate parse, which is too |
|
904 | # if repo[None].substate can cause a dirstate parse, which is too | |
901 | # slow. Instead, look for a file called hgsubstate, |
|
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 | return |
|
907 | return | |
904 |
|
908 | |||
905 | if repo_has_depth_one_nested_repo(repo): |
|
909 | if repo_has_depth_one_nested_repo(repo): | |
906 | return |
|
910 | return | |
907 |
|
911 | |||
908 | fsmonitorstate = state.state(repo) |
|
912 | fsmonitorstate = state.state(repo) | |
909 | if fsmonitorstate.mode == 'off': |
|
913 | if fsmonitorstate.mode == b'off': | |
910 | return |
|
914 | return | |
911 |
|
915 | |||
912 | try: |
|
916 | try: | |
@@ -918,7 +922,7 b' def reposetup(ui, repo):' | |||||
918 | repo._fsmonitorstate = fsmonitorstate |
|
922 | repo._fsmonitorstate = fsmonitorstate | |
919 | repo._watchmanclient = client |
|
923 | repo._watchmanclient = client | |
920 |
|
924 | |||
921 | dirstate, cached = localrepo.isfilecached(repo, 'dirstate') |
|
925 | dirstate, cached = localrepo.isfilecached(repo, b'dirstate') | |
922 | if cached: |
|
926 | if cached: | |
923 | # at this point since fsmonitorstate wasn't present, |
|
927 | # at this point since fsmonitorstate wasn't present, | |
924 | # repo.dirstate is not a fsmonitordirstate |
|
928 | # repo.dirstate is not a fsmonitordirstate | |
@@ -935,7 +939,7 b' def reposetup(ui, repo):' | |||||
935 | def wlock(self, *args, **kwargs): |
|
939 | def wlock(self, *args, **kwargs): | |
936 | l = super(fsmonitorrepo, self).wlock(*args, **kwargs) |
|
940 | l = super(fsmonitorrepo, self).wlock(*args, **kwargs) | |
937 | if not ui.configbool( |
|
941 | if not ui.configbool( | |
938 | "experimental", "fsmonitor.transaction_notify" |
|
942 | b"experimental", b"fsmonitor.transaction_notify" | |
939 | ): |
|
943 | ): | |
940 | return l |
|
944 | return l | |
941 | if l.held != 1: |
|
945 | if l.held != 1: | |
@@ -951,12 +955,14 b' def reposetup(ui, repo):' | |||||
951 |
|
955 | |||
952 | try: |
|
956 | try: | |
953 | l.stateupdate = None |
|
957 | l.stateupdate = None | |
954 | l.stateupdate = state_update(self, name="hg.transaction") |
|
958 | l.stateupdate = state_update(self, name=b"hg.transaction") | |
955 | l.stateupdate.enter() |
|
959 | l.stateupdate.enter() | |
956 | l.releasefn = staterelease |
|
960 | l.releasefn = staterelease | |
957 | except Exception as e: |
|
961 | except Exception as e: | |
958 | # Swallow any errors; fire and forget |
|
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 | return l |
|
966 | return l | |
961 |
|
967 | |||
962 | repo.__class__ = fsmonitorrepo |
|
968 | repo.__class__ = fsmonitorrepo |
@@ -19,7 +19,7 b' from mercurial import (' | |||||
19 | ) |
|
19 | ) | |
20 |
|
20 | |||
21 | _version = 4 |
|
21 | _version = 4 | |
22 | _versionformat = ">I" |
|
22 | _versionformat = b">I" | |
23 |
|
23 | |||
24 |
|
24 | |||
25 | class state(object): |
|
25 | class state(object): | |
@@ -30,15 +30,15 b' class state(object):' | |||||
30 | self._lastclock = None |
|
30 | self._lastclock = None | |
31 | self._identity = util.filestat(None) |
|
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 | self.walk_on_invalidate = self._ui.configbool( |
|
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 | def get(self): |
|
39 | def get(self): | |
40 | try: |
|
40 | try: | |
41 | file = self._vfs('fsmonitor.state', 'rb') |
|
41 | file = self._vfs(b'fsmonitor.state', b'rb') | |
42 | except IOError as inst: |
|
42 | except IOError as inst: | |
43 | self._identity = util.filestat(None) |
|
43 | self._identity = util.filestat(None) | |
44 | if inst.errno != errno.ENOENT: |
|
44 | if inst.errno != errno.ENOENT: | |
@@ -50,9 +50,9 b' class state(object):' | |||||
50 | versionbytes = file.read(4) |
|
50 | versionbytes = file.read(4) | |
51 | if len(versionbytes) < 4: |
|
51 | if len(versionbytes) < 4: | |
52 | self._ui.log( |
|
52 | self._ui.log( | |
53 | 'fsmonitor', |
|
53 | b'fsmonitor', | |
54 | 'fsmonitor: state file only has %d bytes, ' |
|
54 | b'fsmonitor: state file only has %d bytes, ' | |
55 | 'nuking state\n' % len(versionbytes), |
|
55 | b'nuking state\n' % len(versionbytes), | |
56 | ) |
|
56 | ) | |
57 | self.invalidate() |
|
57 | self.invalidate() | |
58 | return None, None, None |
|
58 | return None, None, None | |
@@ -61,21 +61,21 b' class state(object):' | |||||
61 | if diskversion != _version: |
|
61 | if diskversion != _version: | |
62 | # different version, nuke state and start over |
|
62 | # different version, nuke state and start over | |
63 | self._ui.log( |
|
63 | self._ui.log( | |
64 | 'fsmonitor', |
|
64 | b'fsmonitor', | |
65 | 'fsmonitor: version switch from %d to ' |
|
65 | b'fsmonitor: version switch from %d to ' | |
66 | '%d, nuking state\n' % (diskversion, _version), |
|
66 | b'%d, nuking state\n' % (diskversion, _version), | |
67 | ) |
|
67 | ) | |
68 | self.invalidate() |
|
68 | self.invalidate() | |
69 | return None, None, None |
|
69 | return None, None, None | |
70 |
|
70 | |||
71 | state = file.read().split('\0') |
|
71 | state = file.read().split(b'\0') | |
72 | # state = hostname\0clock\0ignorehash\0 + list of files, each |
|
72 | # state = hostname\0clock\0ignorehash\0 + list of files, each | |
73 | # followed by a \0 |
|
73 | # followed by a \0 | |
74 | if len(state) < 3: |
|
74 | if len(state) < 3: | |
75 | self._ui.log( |
|
75 | self._ui.log( | |
76 | 'fsmonitor', |
|
76 | b'fsmonitor', | |
77 | 'fsmonitor: state file truncated (expected ' |
|
77 | b'fsmonitor: state file truncated (expected ' | |
78 | '3 chunks, found %d), nuking state\n', |
|
78 | b'3 chunks, found %d), nuking state\n', | |
79 | len(state), |
|
79 | len(state), | |
80 | ) |
|
80 | ) | |
81 | self.invalidate() |
|
81 | self.invalidate() | |
@@ -85,9 +85,9 b' class state(object):' | |||||
85 | if diskhostname != hostname: |
|
85 | if diskhostname != hostname: | |
86 | # file got moved to a different host |
|
86 | # file got moved to a different host | |
87 | self._ui.log( |
|
87 | self._ui.log( | |
88 | 'fsmonitor', |
|
88 | b'fsmonitor', | |
89 | 'fsmonitor: stored hostname "%s" ' |
|
89 | b'fsmonitor: stored hostname "%s" ' | |
90 | 'different from current "%s", nuking state\n' |
|
90 | b'different from current "%s", nuking state\n' | |
91 | % (diskhostname, hostname), |
|
91 | % (diskhostname, hostname), | |
92 | ) |
|
92 | ) | |
93 | self.invalidate() |
|
93 | self.invalidate() | |
@@ -110,31 +110,33 b' class state(object):' | |||||
110 |
|
110 | |||
111 | # Read the identity from the file on disk rather than from the open file |
|
111 | # Read the identity from the file on disk rather than from the open file | |
112 | # pointer below, because the latter is actually a brand new file. |
|
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 | if identity != self._identity: |
|
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 | return |
|
118 | return | |
117 |
|
119 | |||
118 | try: |
|
120 | try: | |
119 | file = self._vfs( |
|
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 | except (IOError, OSError): |
|
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 | return |
|
126 | return | |
125 |
|
127 | |||
126 | with file: |
|
128 | with file: | |
127 | file.write(struct.pack(_versionformat, _version)) |
|
129 | file.write(struct.pack(_versionformat, _version)) | |
128 | file.write(socket.gethostname() + '\0') |
|
130 | file.write(socket.gethostname() + b'\0') | |
129 | file.write(clock + '\0') |
|
131 | file.write(clock + b'\0') | |
130 | file.write(ignorehash + '\0') |
|
132 | file.write(ignorehash + b'\0') | |
131 | if notefiles: |
|
133 | if notefiles: | |
132 | file.write('\0'.join(notefiles)) |
|
134 | file.write(b'\0'.join(notefiles)) | |
133 | file.write('\0') |
|
135 | file.write(b'\0') | |
134 |
|
136 | |||
135 | def invalidate(self): |
|
137 | def invalidate(self): | |
136 | try: |
|
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 | except OSError as inst: |
|
140 | except OSError as inst: | |
139 | if inst.errno != errno.ENOENT: |
|
141 | if inst.errno != errno.ENOENT: | |
140 | raise |
|
142 | raise |
@@ -18,15 +18,15 b' class Unavailable(Exception):' | |||||
18 | def __init__(self, msg, warn=True, invalidate=False): |
|
18 | def __init__(self, msg, warn=True, invalidate=False): | |
19 | self.msg = msg |
|
19 | self.msg = msg | |
20 | self.warn = warn |
|
20 | self.warn = warn | |
21 | if self.msg == 'timed out waiting for response': |
|
21 | if self.msg == b'timed out waiting for response': | |
22 | self.warn = False |
|
22 | self.warn = False | |
23 | self.invalidate = invalidate |
|
23 | self.invalidate = invalidate | |
24 |
|
24 | |||
25 | def __str__(self): |
|
25 | def __str__(self): | |
26 | if self.warn: |
|
26 | if self.warn: | |
27 | return 'warning: Watchman unavailable: %s' % self.msg |
|
27 | return b'warning: Watchman unavailable: %s' % self.msg | |
28 | else: |
|
28 | else: | |
29 | return 'Watchman unavailable: %s' % self.msg |
|
29 | return b'Watchman unavailable: %s' % self.msg | |
30 |
|
30 | |||
31 |
|
31 | |||
32 | class WatchmanNoRoot(Unavailable): |
|
32 | class WatchmanNoRoot(Unavailable): | |
@@ -39,10 +39,10 b' class client(object):' | |||||
39 | def __init__(self, ui, root, timeout=1.0): |
|
39 | def __init__(self, ui, root, timeout=1.0): | |
40 | err = None |
|
40 | err = None | |
41 | if not self._user: |
|
41 | if not self._user: | |
42 | err = "couldn't get user" |
|
42 | err = b"couldn't get user" | |
43 | warn = True |
|
43 | warn = True | |
44 | if self._user in ui.configlist('fsmonitor', 'blacklistusers'): |
|
44 | if self._user in ui.configlist(b'fsmonitor', b'blacklistusers'): | |
45 | err = 'user %s in blacklist' % self._user |
|
45 | err = b'user %s in blacklist' % self._user | |
46 | warn = False |
|
46 | warn = False | |
47 |
|
47 | |||
48 | if err: |
|
48 | if err: | |
@@ -60,10 +60,10 b' class client(object):' | |||||
60 | self._watchmanclient.setTimeout(timeout) |
|
60 | self._watchmanclient.setTimeout(timeout) | |
61 |
|
61 | |||
62 | def getcurrentclock(self): |
|
62 | def getcurrentclock(self): | |
63 | result = self.command('clock') |
|
63 | result = self.command(b'clock') | |
64 | if not util.safehasattr(result, 'clock'): |
|
64 | if not util.safehasattr(result, b'clock'): | |
65 | raise Unavailable( |
|
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 | return result.clock |
|
68 | return result.clock | |
69 |
|
69 | |||
@@ -86,7 +86,9 b' class client(object):' | |||||
86 | try: |
|
86 | try: | |
87 | if self._watchmanclient is None: |
|
87 | if self._watchmanclient is None: | |
88 | self._firsttime = False |
|
88 | self._firsttime = False | |
89 |
watchman_exe = self._ui.configpath( |
|
89 | watchman_exe = self._ui.configpath( | |
|
90 | b'fsmonitor', b'watchman_exe' | |||
|
91 | ) | |||
90 | self._watchmanclient = pywatchman.client( |
|
92 | self._watchmanclient = pywatchman.client( | |
91 | timeout=self._timeout, |
|
93 | timeout=self._timeout, | |
92 | useImmutableBser=True, |
|
94 | useImmutableBser=True, | |
@@ -94,7 +96,7 b' class client(object):' | |||||
94 | ) |
|
96 | ) | |
95 | return self._watchmanclient.query(*watchmanargs) |
|
97 | return self._watchmanclient.query(*watchmanargs) | |
96 | except pywatchman.CommandError as ex: |
|
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 | raise WatchmanNoRoot(self._root, ex.msg) |
|
100 | raise WatchmanNoRoot(self._root, ex.msg) | |
99 | raise Unavailable(ex.msg) |
|
101 | raise Unavailable(ex.msg) | |
100 | except pywatchman.WatchmanError as ex: |
|
102 | except pywatchman.WatchmanError as ex: | |
@@ -107,7 +109,7 b' class client(object):' | |||||
107 | except WatchmanNoRoot: |
|
109 | except WatchmanNoRoot: | |
108 | # this 'watch' command can also raise a WatchmanNoRoot if |
|
110 | # this 'watch' command can also raise a WatchmanNoRoot if | |
109 | # watchman refuses to accept this root |
|
111 | # watchman refuses to accept this root | |
110 | self._command('watch') |
|
112 | self._command(b'watch') | |
111 | return self._command(*args) |
|
113 | return self._command(*args) | |
112 | except Unavailable: |
|
114 | except Unavailable: | |
113 | # this is in an outer scope to catch Unavailable form any of the |
|
115 | # this is in an outer scope to catch Unavailable form any of the |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file | ||
The requested commit or file is too big and content was truncated. Show full diff |
1 | NO CONTENT: modified file |
|
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