Patchwork [9,of,9] keyword: wrap functions only once at loading keyword extension

login
register
mail settings
Submitter Katsunori FUJIWARA
Date June 25, 2017, 7:09 p.m.
Message ID <36525ddf2b384ceb4e84.1498417782@speaknoevil>
Download mbox | patch
Permalink /patch/21710/
State Accepted
Headers show

Comments

Katsunori FUJIWARA - June 25, 2017, 7:09 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1498416431 -32400
#      Mon Jun 26 03:47:11 2017 +0900
# Node ID 36525ddf2b384ceb4e84607408b80d3d3065449f
# Parent  b534af046ded2dbbb6d537e12cff7c87f1159629
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.
Augie Fackler - June 26, 2017, 5:59 p.m.
On Mon, Jun 26, 2017 at 04:09:42AM +0900, FUJIWARA Katsunori wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> # Date 1498416431 -32400
> #      Mon Jun 26 03:47:11 2017 +0900
> # Node ID 36525ddf2b384ceb4e84607408b80d3d3065449f
> # Parent  b534af046ded2dbbb6d537e12cff7c87f1159629
> keyword: wrap functions only once at loading keyword extension

queued, thanks

Patch

diff --git a/hgext/keyword.py b/hgext/keyword.py
--- a/hgext/keyword.py
+++ b/hgext/keyword.py
@@ -577,9 +577,136 @@  def shrink(ui, repo, *pats, **opts):
     # 3rd argument sets expansion to False
     _kwfwrite(ui, repo, False, *pats, **opts)
 
+# monkeypatches
+
+def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
+    '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
+    rejects or conflicts due to expanded keywords in working dir.'''
+    orig(self, ui, gp, backend, store, eolmode)
+    kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None)
+    if kwt:
+        # shrink keywords read from working dir
+        self.lines = kwt.shrinklines(self.fname, self.lines)
+
+def kwdiff(orig, repo, *args, **kwargs):
+    '''Monkeypatch patch.diff to avoid expansion.'''
+    kwt = getattr(repo, '_keywordkwt', None)
+    if kwt:
+        restrict = kwt.restrict
+        kwt.restrict = True
+    try:
+        for chunk in orig(repo, *args, **kwargs):
+            yield chunk
+    finally:
+        if kwt:
+            kwt.restrict = restrict
+
+def kwweb_skip(orig, web, req, tmpl):
+    '''Wraps webcommands.x turning off keyword expansion.'''
+    kwt = getattr(web.repo, '_keywordkwt', None)
+    if kwt:
+        origmatch = kwt.match
+        kwt.match = util.never
+    try:
+        for chunk in orig(web, req, tmpl):
+            yield chunk
+    finally:
+        if kwt:
+            kwt.match = origmatch
+
+def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
+    '''Wraps cmdutil.amend expanding keywords after amend.'''
+    kwt = getattr(repo, '_keywordkwt', None)
+    if kwt is None:
+        return orig(ui, repo, commitfunc, old, extra, pats, opts)
+    with repo.wlock():
+        kwt.postcommit = True
+        newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
+        if newid != old.node():
+            ctx = repo[newid]
+            kwt.restrict = True
+            kwt.overwrite(ctx, ctx.files(), False, True)
+            kwt.restrict = False
+        return newid
+
+def kw_copy(orig, ui, repo, pats, opts, rename=False):
+    '''Wraps cmdutil.copy so that copy/rename destinations do not
+    contain expanded keywords.
+    Note that the source of a regular file destination may also be a
+    symlink:
+    hg cp sym x                -> x is symlink
+    cp sym x; hg cp -A sym x   -> x is file (maybe expanded keywords)
+    For the latter we have to follow the symlink to find out whether its
+    target is configured for expansion and we therefore must unexpand the
+    keywords in the destination.'''
+    kwt = getattr(repo, '_keywordkwt', None)
+    if kwt is None:
+        return orig(ui, repo, pats, opts, rename)
+    with repo.wlock():
+        orig(ui, repo, pats, opts, rename)
+        if opts.get('dry_run'):
+            return
+        wctx = repo[None]
+        cwd = repo.getcwd()
+
+        def haskwsource(dest):
+            '''Returns true if dest is a regular file and configured for
+            expansion or a symlink which points to a file configured for
+            expansion. '''
+            source = repo.dirstate.copied(dest)
+            if 'l' in wctx.flags(source):
+                source = pathutil.canonpath(repo.root, cwd,
+                                           os.path.realpath(source))
+            return kwt.match(source)
+
+        candidates = [f for f in repo.dirstate.copies() if
+                      'l' not in wctx.flags(f) and haskwsource(f)]
+        kwt.overwrite(wctx, candidates, False, False)
+
+def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
+    '''Wraps record.dorecord expanding keywords after recording.'''
+    kwt = getattr(repo, '_keywordkwt', None)
+    if kwt is None:
+        return orig(ui, repo, commitfunc, *pats, **opts)
+    with repo.wlock():
+        # record returns 0 even when nothing has changed
+        # therefore compare nodes before and after
+        kwt.postcommit = True
+        ctx = repo['.']
+        wstatus = ctx.status()
+        ret = orig(ui, repo, commitfunc, *pats, **opts)
+        recctx = repo['.']
+        if ctx != recctx:
+            modified, added = _preselect(wstatus, recctx.files())
+            kwt.restrict = False
+            kwt.overwrite(recctx, modified, False, True)
+            kwt.overwrite(recctx, added, False, True, True)
+            kwt.restrict = True
+        return ret
+
+def kwfilectx_cmp(orig, self, fctx):
+    if fctx._customcmp:
+        return fctx.cmp(self)
+    kwt = getattr(self._repo, '_keywordkwt', None)
+    if kwt is None:
+        return orig(self, fctx)
+    # keyword affects data size, comparing wdir and filelog size does
+    # not make sense
+    if (fctx._filenode is None and
+        (self._repo._encodefilterpats or
+         kwt.match(fctx.path()) and 'l' not in fctx.flags() or
+         self.size() - 4 == fctx.size()) or
+        self.size() == fctx.size()):
+        return self._filelog.cmp(self._filenode, fctx.data())
+    return True
 
 def uisetup(ui):
-    ''' Monkeypatches dispatch._parse to retrieve user command.'''
+    ''' Monkeypatches dispatch._parse to retrieve user command.
+    Overrides file method to return kwfilelog instead of filelog
+    if file matches user configuration.
+    Wraps commit to overwrite configured files with updated
+    keyword substitutions.
+    Monkeypatches patch and webcommands.'''
 
     def kwdispatch_parse(orig, ui, args):
         '''Monkeypatch dispatch._parse to obtain running hg command.'''
@@ -589,13 +716,17 @@  def uisetup(ui):
 
     extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
 
+    extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
+    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
+    extensions.wrapfunction(patch, 'diff', kwdiff)
+    extensions.wrapfunction(cmdutil, 'amend', kw_amend)
+    extensions.wrapfunction(cmdutil, 'copy', kw_copy)
+    extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord)
+    for c in nokwwebcommands.split():
+        extensions.wrapfunction(webcommands, c, kwweb_skip)
+
 def reposetup(ui, repo):
-    '''Sets up repo as kwrepo for keyword substitution.
-    Overrides file method to return kwfilelog instead of filelog
-    if file matches user configuration.
-    Wraps commit to overwrite configured files with updated
-    keyword substitutions.
-    Monkeypatches patch and webcommands.'''
+    '''Sets up repo as kwrepo for keyword substitution.'''
 
     try:
         if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
@@ -665,134 +796,3 @@  def reposetup(ui, repo):
 
     repo.__class__ = kwrepo
     repo._keywordkwt = kwt
-
-    # monkeypatches
-    def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
-        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
-        rejects or conflicts due to expanded keywords in working dir.'''
-        orig(self, ui, gp, backend, store, eolmode)
-        kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None)
-        if kwt:
-            # shrink keywords read from working dir
-            self.lines = kwt.shrinklines(self.fname, self.lines)
-
-    def kwdiff(orig, repo, *args, **kwargs):
-        '''Monkeypatch patch.diff to avoid expansion.'''
-        kwt = getattr(repo, '_keywordkwt', None)
-        if kwt:
-            restrict = kwt.restrict
-            kwt.restrict = True
-        try:
-            for chunk in orig(repo, *args, **kwargs):
-                yield chunk
-        finally:
-            if kwt:
-                kwt.restrict = restrict
-
-    def kwweb_skip(orig, web, req, tmpl):
-        '''Wraps webcommands.x turning off keyword expansion.'''
-        kwt = getattr(web.repo, '_keywordkwt', None)
-        if kwt:
-            origmatch = kwt.match
-            kwt.match = util.never
-        try:
-            for chunk in orig(web, req, tmpl):
-                yield chunk
-        finally:
-            if kwt:
-                kwt.match = origmatch
-
-    def kw_amend(orig, ui, repo, commitfunc, old, extra, pats, opts):
-        '''Wraps cmdutil.amend expanding keywords after amend.'''
-        kwt = getattr(repo, '_keywordkwt', None)
-        if kwt is None:
-            return orig(ui, repo, commitfunc, old, extra, pats, opts)
-        with repo.wlock():
-            kwt.postcommit = True
-            newid = orig(ui, repo, commitfunc, old, extra, pats, opts)
-            if newid != old.node():
-                ctx = repo[newid]
-                kwt.restrict = True
-                kwt.overwrite(ctx, ctx.files(), False, True)
-                kwt.restrict = False
-            return newid
-
-    def kw_copy(orig, ui, repo, pats, opts, rename=False):
-        '''Wraps cmdutil.copy so that copy/rename destinations do not
-        contain expanded keywords.
-        Note that the source of a regular file destination may also be a
-        symlink:
-        hg cp sym x                -> x is symlink
-        cp sym x; hg cp -A sym x   -> x is file (maybe expanded keywords)
-        For the latter we have to follow the symlink to find out whether its
-        target is configured for expansion and we therefore must unexpand the
-        keywords in the destination.'''
-        kwt = getattr(repo, '_keywordkwt', None)
-        if kwt is None:
-            return orig(ui, repo, pats, opts, rename)
-        with repo.wlock():
-            orig(ui, repo, pats, opts, rename)
-            if opts.get('dry_run'):
-                return
-            wctx = repo[None]
-            cwd = repo.getcwd()
-
-            def haskwsource(dest):
-                '''Returns true if dest is a regular file and configured for
-                expansion or a symlink which points to a file configured for
-                expansion. '''
-                source = repo.dirstate.copied(dest)
-                if 'l' in wctx.flags(source):
-                    source = pathutil.canonpath(repo.root, cwd,
-                                               os.path.realpath(source))
-                return kwt.match(source)
-
-            candidates = [f for f in repo.dirstate.copies() if
-                          'l' not in wctx.flags(f) and haskwsource(f)]
-            kwt.overwrite(wctx, candidates, False, False)
-
-    def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
-        '''Wraps record.dorecord expanding keywords after recording.'''
-        kwt = getattr(repo, '_keywordkwt', None)
-        if kwt is None:
-            return orig(ui, repo, commitfunc, *pats, **opts)
-        with repo.wlock():
-            # record returns 0 even when nothing has changed
-            # therefore compare nodes before and after
-            kwt.postcommit = True
-            ctx = repo['.']
-            wstatus = ctx.status()
-            ret = orig(ui, repo, commitfunc, *pats, **opts)
-            recctx = repo['.']
-            if ctx != recctx:
-                modified, added = _preselect(wstatus, recctx.files())
-                kwt.restrict = False
-                kwt.overwrite(recctx, modified, False, True)
-                kwt.overwrite(recctx, added, False, True, True)
-                kwt.restrict = True
-            return ret
-
-    def kwfilectx_cmp(orig, self, fctx):
-        if fctx._customcmp:
-            return fctx.cmp(self)
-        kwt = getattr(self._repo, '_keywordkwt', None)
-        if kwt is None:
-            return orig(self, fctx)
-        # keyword affects data size, comparing wdir and filelog size does
-        # not make sense
-        if (fctx._filenode is None and
-            (self._repo._encodefilterpats or
-             kwt.match(fctx.path()) and 'l' not in fctx.flags() or
-             self.size() - 4 == fctx.size()) or
-            self.size() == fctx.size()):
-            return self._filelog.cmp(self._filenode, fctx.data())
-        return True
-
-    extensions.wrapfunction(context.filectx, 'cmp', kwfilectx_cmp)
-    extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
-    extensions.wrapfunction(patch, 'diff', kwdiff)
-    extensions.wrapfunction(cmdutil, 'amend', kw_amend)
-    extensions.wrapfunction(cmdutil, 'copy', kw_copy)
-    extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord)
-    for c in nokwwebcommands.split():
-        extensions.wrapfunction(webcommands, c, kwweb_skip)