[PATCH 1 of 7] keyword: refactor kwtemplater.overwrite()

Christian Ebert blacktrash at gmx.net
Fri Oct 8 12:40:14 CDT 2010


# HG changeset patch
# User Christian Ebert <blacktrash at gmx.net>
# Date 1286559586 -3600
# Node ID 3a4b3955af3ee3a0084cad68dc4db66c444221e8
# Parent  64db820c66a29ee3b57e452d77be00ed5be675ef
keyword: refactor kwtemplater.overwrite()

Make kwexpand, kwshrink restricted commands - i.e. read from
filelog without expansion for substition in kwtemplater.overwrite,
and set/unset restricted mode for overwrite() in in kwcommitctx
and the dorecord wrapper.

Preselect candidates when working on changed files (rollback, record)
outside kwtemplater class, and remove 6th argument from overwrite().

Avoid duplicate substitution/search in overwrite():
Only go into restricted read mode when reading from filelog.
rollback and record read from the working directory, where
restricted mode would already shrink keywords before overwrite()
either expands or shrinks them again.

This ensures that the usual automatic operations on keywords
are turned off during overwrite() and only overwrite() itself
acts on them.

Reduce manifest calculation to the cases where it is needed.

Move helper function for expansion removal outside kwtemplater class.

diff --git a/hgext/keyword.py b/hgext/keyword.py
--- a/hgext/keyword.py
+++ b/hgext/keyword.py
@@ -96,7 +96,7 @@
 
 # hg commands that trigger expansion only when writing to working dir,
 # not when reading filelog, and unexpand when reading from working dir
-restricted = 'merge record qrecord resolve transplant'
+restricted = 'merge kwexpand kwshrink record qrecord resolve transplant'
 
 # commands using dorecord
 recordcommands = 'record qrecord'
@@ -138,6 +138,12 @@
     templates.update(kwsets[ui.configbool('keywordset', 'svn')])
     return templates
 
+def _shrinktext(text, subfunc):
+    '''Helper for keyword expansion removal in text.
+    Depending on subfunc also returns number of substitutions.'''
+    return subfunc(r'$\1$', text)
+
+
 class kwtemplater(object):
     '''
     Sets up keyword templates, corresponding keyword regex, and
@@ -191,49 +197,44 @@
         Caveat: localrepository._link fails on Windows.'''
         return self.match(path) and not 'l' in flagfunc(path)
 
-    def overwrite(self, ctx, candidates, iswctx, expand, changed):
+    def overwrite(self, ctx, candidates, lookup, expand):
         '''Overwrites selected files expanding/shrinking keywords.'''
-        if changed is not None:
-            candidates = [f for f in candidates if f in changed]
         candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
-        if candidates:
-            restrict = self.restrict
-            self.restrict = True        # do not expand when reading
-            rollback = kwtools['hgcmd'] == 'rollback'
+        if not candidates:
+            return
+        commit = self.restrict and not lookup
+        if self.restrict or expand and lookup:
             mf = ctx.manifest()
-            msg = (expand and _('overwriting %s expanding keywords\n')
-                   or _('overwriting %s shrinking keywords\n'))
-            for f in candidates:
-                if not self.record and not rollback:
-                    data = self.repo.file(f).read(mf[f])
-                else:
-                    data = self.repo.wread(f)
-                if util.binary(data):
-                    continue
-                if expand:
-                    if iswctx:
-                        ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
-                    data, found = self.substitute(data, f, ctx,
-                                                  self.re_kw.subn)
-                else:
-                    found = self.re_kw.search(data)
-                if found:
-                    self.ui.note(msg % f)
-                    self.repo.wwrite(f, data, mf.flags(f))
-                    if iswctx and not rollback:
-                        self.repo.dirstate.normal(f)
-                    elif self.record:
-                        self.repo.dirstate.normallookup(f)
-            self.restrict = restrict
-
-    def shrinktext(self, text):
-        '''Unconditionally removes all keyword substitutions from text.'''
-        return self.re_kw.sub(r'$\1$', text)
+        fctx = ctx
+        msg = (expand and _('overwriting %s expanding keywords\n')
+               or _('overwriting %s shrinking keywords\n'))
+        for f in candidates:
+            if self.restrict:
+                data = self.repo.file(f).read(mf[f])
+            else:
+                data = self.repo.wread(f)
+            if util.binary(data):
+                continue
+            if expand:
+                if lookup:
+                    fctx = self.repo.filectx(f, fileid=mf[f]).changectx()
+                data, found = self.substitute(data, f, fctx, self.re_kw.subn)
+            elif self.restrict:
+                found = self.re_kw.search(data)
+            else:
+                data, found = _shrinktext(data, self.re_kw.subn)
+            if found:
+                self.ui.note(msg % f)
+                self.repo.wwrite(f, data, ctx.flags(f))
+                if commit:
+                    self.repo.dirstate.normal(f)
+                elif self.record:
+                    self.repo.dirstate.normallookup(f)
 
     def shrink(self, fname, text):
         '''Returns text with all keyword substitutions removed.'''
         if self.match(fname) and not util.binary(text):
-            return self.shrinktext(text)
+            return _shrinktext(text, self.re_kw.sub)
         return text
 
     def shrinklines(self, fname, lines):
@@ -241,7 +242,7 @@
         if self.match(fname):
             text = ''.join(lines)
             if not util.binary(text):
-                return self.shrinktext(text).splitlines(True)
+                return _shrinktext(text, self.re_kw.sub).splitlines(True)
         return lines
 
     def wread(self, fname, data):
@@ -299,7 +300,7 @@
         modified, added, removed, deleted, unknown, ignored, clean = status
         if modified or added or removed or deleted:
             raise util.Abort(_('outstanding uncommitted changes'))
-        kwt.overwrite(wctx, clean, True, expand, None)
+        kwt.overwrite(wctx, clean, True, expand)
     finally:
         wlock.release()
 
@@ -502,8 +503,11 @@
             n = super(kwrepo, self).commitctx(ctx, error)
             # no lock needed, only called from repo.commit() which already locks
             if not kwt.record:
+                restrict = kwt.restrict
+                kwt.restrict = True
                 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
-                              False, True, None)
+                              False, True)
+                kwt.restrict = restrict
             return n
 
         def rollback(self, dryrun=False):
@@ -515,8 +519,10 @@
                 if not dryrun:
                     ctx = self['.']
                     modified, added = self[None].status()[:2]
-                    kwt.overwrite(ctx, added, True, False, changed)
-                    kwt.overwrite(ctx, modified, True, True, changed)
+                    modified = [f for f in modified if f in changed]
+                    added = [f for f in added if f in changed]
+                    kwt.overwrite(ctx, added, True, False)
+                    kwt.overwrite(ctx, modified, True, True)
                 return ret
             finally:
                 wlock.release()
@@ -551,8 +557,10 @@
             ret = orig(ui, repo, commitfunc, *pats, **opts)
             recordctx = repo['.']
             if ctx != recordctx:
-                kwt.overwrite(recordctx, recordctx.files(),
-                              False, True, recordctx)
+                candidates = [f for f in recordctx.files() if f in recordctx]
+                kwt.restrict = False
+                kwt.overwrite(recordctx, candidates, False, True)
+                kwt.restrict = True
             return ret
         finally:
             wlock.release()


More information about the Mercurial-devel mailing list