Mercurial > hg
comparison hgext/keyword.py @ 33071:279c072a5c49
keyword: wrap functions only once at loading keyword extension
Before this patch, some functions are wrapped in reposetup(), but this
causes redundant nested wrapping, if two ore more repositories enable
keyword extension (e.g. hgweb serves multiple repositories).
Now, there is no need to define these wrapper functions in
reposetup(), because previous patches made them not directly refer to
kwtemplater instanciated in reposetup().
This patch factors these wrapper functions out from reposetup(), and
uses them to wrap functions only at once at loading keyword extension.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Mon, 26 Jun 2017 03:47:11 +0900 |
parents | 735218be6122 |
children | a39dce4a76b8 |
comparison
equal
deleted
inserted
replaced
33070:735218be6122 | 33071:279c072a5c49 |
---|---|
575 kwshrink refuses to run if given files contain local changes. | 575 kwshrink refuses to run if given files contain local changes. |
576 ''' | 576 ''' |
577 # 3rd argument sets expansion to False | 577 # 3rd argument sets expansion to False |
578 _kwfwrite(ui, repo, False, *pats, **opts) | 578 _kwfwrite(ui, repo, False, *pats, **opts) |
579 | 579 |
580 # monkeypatches | |
581 | |
582 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None): | |
583 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid | |
584 rejects or conflicts due to expanded keywords in working dir.''' | |
585 orig(self, ui, gp, backend, store, eolmode) | |
586 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None) | |
587 if kwt: | |
588 # shrink keywords read from working dir | |
589 self.lines = kwt.shrinklines(self.fname, self.lines) | |
590 | |
591 def kwdiff(orig, repo, *args, **kwargs): | |
592 '''Monkeypatch patch.diff to avoid expansion.''' | |
593 kwt = getattr(repo, '_keywordkwt', None) | |
594 if kwt: | |
595 restrict = kwt.restrict | |
596 kwt.restrict = True | |
597 try: | |
598 for chunk in orig(repo, *args, **kwargs): | |
599 yield chunk | |
600 finally: | |
601 if kwt: | |
602 kwt.restrict = restrict | |
603 | |
604 def kwweb_skip(orig, web, req, tmpl): | |
605 '''Wraps webcommands.x turning off keyword expansion.''' | |
606 kwt = getattr(web.repo, '_keywordkwt', None) | |
607 if kwt: | |
608 origmatch = kwt.match | |
609 kwt.match = util.never | |
610 try: | |
611 for chunk in orig(web, req, tmpl): | |
612 yield chunk | |
613 finally: | |
614 if kwt: | |
615 kwt.match = origmatch | |
616 | |
617 def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts): | |
618 '''Wraps cmdutil.amend expanding keywords after amend.''' | |
619 kwt = getattr(repo, '_keywordkwt', None) | |
620 if kwt is None: | |
621 return orig(ui, repo, commitfunc, old, extra, pats, opts) | |
622 with repo.wlock(): | |
623 kwt.postcommit = True | |
624 newid = orig(ui, repo, commitfunc, old, extra, pats, opts) | |
625 if newid != old.node(): | |
626 ctx = repo[newid] | |
627 kwt.restrict = True | |
628 kwt.overwrite(ctx, ctx.files(), False, True) | |
629 kwt.restrict = False | |
630 return newid | |
631 | |
632 def kw_copy(orig, ui, repo, pats, opts, rename=False): | |
633 '''Wraps cmdutil.copy so that copy/rename destinations do not | |
634 contain expanded keywords. | |
635 Note that the source of a regular file destination may also be a | |
636 symlink: | |
637 hg cp sym x -> x is symlink | |
638 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords) | |
639 For the latter we have to follow the symlink to find out whether its | |
640 target is configured for expansion and we therefore must unexpand the | |
641 keywords in the destination.''' | |
642 kwt = getattr(repo, '_keywordkwt', None) | |
643 if kwt is None: | |
644 return orig(ui, repo, pats, opts, rename) | |
645 with repo.wlock(): | |
646 orig(ui, repo, pats, opts, rename) | |
647 if opts.get('dry_run'): | |
648 return | |
649 wctx = repo[None] | |
650 cwd = repo.getcwd() | |
651 | |
652 def haskwsource(dest): | |
653 '''Returns true if dest is a regular file and configured for | |
654 expansion or a symlink which points to a file configured for | |
655 expansion. ''' | |
656 source = repo.dirstate.copied(dest) | |
657 if 'l' in wctx.flags(source): | |
658 source = pathutil.canonpath(repo.root, cwd, | |
659 os.path.realpath(source)) | |
660 return kwt.match(source) | |
661 | |
662 candidates = [f for f in repo.dirstate.copies() if | |
663 'l' not in wctx.flags(f) and haskwsource(f)] | |
664 kwt.overwrite(wctx, candidates, False, False) | |
665 | |
666 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts): | |
667 '''Wraps record.dorecord expanding keywords after recording.''' | |
668 kwt = getattr(repo, '_keywordkwt', None) | |
669 if kwt is None: | |
670 return orig(ui, repo, commitfunc, *pats, **opts) | |
671 with repo.wlock(): | |
672 # record returns 0 even when nothing has changed | |
673 # therefore compare nodes before and after | |
674 kwt.postcommit = True | |
675 ctx = repo['.'] | |
676 wstatus = ctx.status() | |
677 ret = orig(ui, repo, commitfunc, *pats, **opts) | |
678 recctx = repo['.'] | |
679 if ctx != recctx: | |
680 modified, added = _preselect(wstatus, recctx.files()) | |
681 kwt.restrict = False | |
682 kwt.overwrite(recctx, modified, False, True) | |
683 kwt.overwrite(recctx, added, False, True, True) | |
684 kwt.restrict = True | |
685 return ret | |
686 | |
687 def kwfilectx_cmp(orig, self, fctx): | |
688 if fctx._customcmp: | |
689 return fctx.cmp(self) | |
690 kwt = getattr(self._repo, '_keywordkwt', None) | |
691 if kwt is None: | |
692 return orig(self, fctx) | |
693 # keyword affects data size, comparing wdir and filelog size does | |
694 # not make sense | |
695 if (fctx._filenode is None and | |
696 (self._repo._encodefilterpats or | |
697 kwt.match(fctx.path()) and 'l' not in fctx.flags() or | |
698 self.size() - 4 == fctx.size()) or | |
699 self.size() == fctx.size()): | |
700 return self._filelog.cmp(self._filenode, fctx.data()) | |
701 return True | |
580 | 702 |
581 def uisetup(ui): | 703 def uisetup(ui): |
582 ''' Monkeypatches dispatch._parse to retrieve user command.''' | 704 ''' Monkeypatches dispatch._parse to retrieve user command. |
705 Overrides file method to return kwfilelog instead of filelog | |
706 if file matches user configuration. | |
707 Wraps commit to overwrite configured files with updated | |
708 keyword substitutions. | |
709 Monkeypatches patch and webcommands.''' | |
583 | 710 |
584 def kwdispatch_parse(orig, ui, args): | 711 def kwdispatch_parse(orig, ui, args): |
585 '''Monkeypatch dispatch._parse to obtain running hg command.''' | 712 '''Monkeypatch dispatch._parse to obtain running hg command.''' |
586 cmd, func, args, options, cmdoptions = orig(ui, args) | 713 cmd, func, args, options, cmdoptions = orig(ui, args) |
587 kwtools['hgcmd'] = cmd | 714 kwtools['hgcmd'] = cmd |
588 return cmd, func, args, options, cmdoptions | 715 return cmd, func, args, options, cmdoptions |
589 | 716 |
590 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse) | 717 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse) |
591 | 718 |
719 extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp) | |
720 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init) | |
721 extensions.wrapfunction(patch, 'diff', kwdiff) | |
722 extensions.wrapfunction(cmdutil, 'amend', kw_amend) | |
723 extensions.wrapfunction(cmdutil, 'copy', kw_copy) | |
724 extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord) | |
725 for c in nokwwebcommands.split(): | |
726 extensions.wrapfunction(webcommands, c, kwweb_skip) | |
727 | |
592 def reposetup(ui, repo): | 728 def reposetup(ui, repo): |
593 '''Sets up repo as kwrepo for keyword substitution. | 729 '''Sets up repo as kwrepo for keyword substitution.''' |
594 Overrides file method to return kwfilelog instead of filelog | |
595 if file matches user configuration. | |
596 Wraps commit to overwrite configured files with updated | |
597 keyword substitutions. | |
598 Monkeypatches patch and webcommands.''' | |
599 | 730 |
600 try: | 731 try: |
601 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() | 732 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() |
602 or '.hg' in util.splitpath(repo.root) | 733 or '.hg' in util.splitpath(repo.root) |
603 or repo._url.startswith('bundle:')): | 734 or repo._url.startswith('bundle:')): |
663 finally: | 794 finally: |
664 kwt.restrict = origrestrict | 795 kwt.restrict = origrestrict |
665 | 796 |
666 repo.__class__ = kwrepo | 797 repo.__class__ = kwrepo |
667 repo._keywordkwt = kwt | 798 repo._keywordkwt = kwt |
668 | |
669 # monkeypatches | |
670 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None): | |
671 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid | |
672 rejects or conflicts due to expanded keywords in working dir.''' | |
673 orig(self, ui, gp, backend, store, eolmode) | |
674 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None) | |
675 if kwt: | |
676 # shrink keywords read from working dir | |
677 self.lines = kwt.shrinklines(self.fname, self.lines) | |
678 | |
679 def kwdiff(orig, repo, *args, **kwargs): | |
680 '''Monkeypatch patch.diff to avoid expansion.''' | |
681 kwt = getattr(repo, '_keywordkwt', None) | |
682 if kwt: | |
683 restrict = kwt.restrict | |
684 kwt.restrict = True | |
685 try: | |
686 for chunk in orig(repo, *args, **kwargs): | |
687 yield chunk | |
688 finally: | |
689 if kwt: | |
690 kwt.restrict = restrict | |
691 | |
692 def kwweb_skip(orig, web, req, tmpl): | |
693 '''Wraps webcommands.x turning off keyword expansion.''' | |
694 kwt = getattr(web.repo, '_keywordkwt', None) | |
695 if kwt: | |
696 origmatch = kwt.match | |
697 kwt.match = util.never | |
698 try: | |
699 for chunk in orig(web, req, tmpl): | |
700 yield chunk | |
701 finally: | |
702 if kwt: | |
703 kwt.match = origmatch | |
704 | |
705 def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts): | |
706 '''Wraps cmdutil.amend expanding keywords after amend.''' | |
707 kwt = getattr(repo, '_keywordkwt', None) | |
708 if kwt is None: | |
709 return orig(ui, repo, commitfunc, old, extra, pats, opts) | |
710 with repo.wlock(): | |
711 kwt.postcommit = True | |
712 newid = orig(ui, repo, commitfunc, old, extra, pats, opts) | |
713 if newid != old.node(): | |
714 ctx = repo[newid] | |
715 kwt.restrict = True | |
716 kwt.overwrite(ctx, ctx.files(), False, True) | |
717 kwt.restrict = False | |
718 return newid | |
719 | |
720 def kw_copy(orig, ui, repo, pats, opts, rename=False): | |
721 '''Wraps cmdutil.copy so that copy/rename destinations do not | |
722 contain expanded keywords. | |
723 Note that the source of a regular file destination may also be a | |
724 symlink: | |
725 hg cp sym x -> x is symlink | |
726 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords) | |
727 For the latter we have to follow the symlink to find out whether its | |
728 target is configured for expansion and we therefore must unexpand the | |
729 keywords in the destination.''' | |
730 kwt = getattr(repo, '_keywordkwt', None) | |
731 if kwt is None: | |
732 return orig(ui, repo, pats, opts, rename) | |
733 with repo.wlock(): | |
734 orig(ui, repo, pats, opts, rename) | |
735 if opts.get('dry_run'): | |
736 return | |
737 wctx = repo[None] | |
738 cwd = repo.getcwd() | |
739 | |
740 def haskwsource(dest): | |
741 '''Returns true if dest is a regular file and configured for | |
742 expansion or a symlink which points to a file configured for | |
743 expansion. ''' | |
744 source = repo.dirstate.copied(dest) | |
745 if 'l' in wctx.flags(source): | |
746 source = pathutil.canonpath(repo.root, cwd, | |
747 os.path.realpath(source)) | |
748 return kwt.match(source) | |
749 | |
750 candidates = [f for f in repo.dirstate.copies() if | |
751 'l' not in wctx.flags(f) and haskwsource(f)] | |
752 kwt.overwrite(wctx, candidates, False, False) | |
753 | |
754 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts): | |
755 '''Wraps record.dorecord expanding keywords after recording.''' | |
756 kwt = getattr(repo, '_keywordkwt', None) | |
757 if kwt is None: | |
758 return orig(ui, repo, commitfunc, *pats, **opts) | |
759 with repo.wlock(): | |
760 # record returns 0 even when nothing has changed | |
761 # therefore compare nodes before and after | |
762 kwt.postcommit = True | |
763 ctx = repo['.'] | |
764 wstatus = ctx.status() | |
765 ret = orig(ui, repo, commitfunc, *pats, **opts) | |
766 recctx = repo['.'] | |
767 if ctx != recctx: | |
768 modified, added = _preselect(wstatus, recctx.files()) | |
769 kwt.restrict = False | |
770 kwt.overwrite(recctx, modified, False, True) | |
771 kwt.overwrite(recctx, added, False, True, True) | |
772 kwt.restrict = True | |
773 return ret | |
774 | |
775 def kwfilectx_cmp(orig, self, fctx): | |
776 if fctx._customcmp: | |
777 return fctx.cmp(self) | |
778 kwt = getattr(self._repo, '_keywordkwt', None) | |
779 if kwt is None: | |
780 return orig(self, fctx) | |
781 # keyword affects data size, comparing wdir and filelog size does | |
782 # not make sense | |
783 if (fctx._filenode is None and | |
784 (self._repo._encodefilterpats or | |
785 kwt.match(fctx.path()) and 'l' not in fctx.flags() or | |
786 self.size() - 4 == fctx.size()) or | |
787 self.size() == fctx.size()): | |
788 return self._filelog.cmp(self._filenode, fctx.data()) | |
789 return True | |
790 | |
791 extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp) | |
792 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init) | |
793 extensions.wrapfunction(patch, 'diff', kwdiff) | |
794 extensions.wrapfunction(cmdutil, 'amend', kw_amend) | |
795 extensions.wrapfunction(cmdutil, 'copy', kw_copy) | |
796 extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord) | |
797 for c in nokwwebcommands.split(): | |
798 extensions.wrapfunction(webcommands, c, kwweb_skip) |