hgext/keyword.py
changeset 33071 279c072a5c49
parent 33070 735218be6122
child 34086 a39dce4a76b8
--- a/hgext/keyword.py	Mon Jun 26 03:46:17 2017 +0900
+++ b/hgext/keyword.py	Mon Jun 26 03:47:11 2017 +0900
@@ -577,9 +577,136 @@
     # 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 @@
 
     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 @@
 
     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)