Move all that can be done only once per repo into reposetup kwmap-templates
authorChristian Ebert <blacktrash@gmx.net>
Thu, 18 Jan 2007 01:50:18 +0100
branchkwmap-templates
changeset 110 b0b85b383f36
parent 109 b2cc6a8d4a18
child 111 94315baadcaf
Move all that can be done only once per repo into reposetup Actually kwrepo is not set up if there aren't any files configured for keyword substitution. Stuff that now is done at reposetup and not at every filelog init or hook: 1) filename matching function 2) compilation of keyword regex 3) templates and changeset templater kwtemplater as an appended class should prevent namespace conflicts.
hgkw/keyword.py
--- a/hgkw/keyword.py	Thu Jan 18 00:06:11 2007 +0100
+++ b/hgkw/keyword.py	Thu Jan 18 01:50:18 2007 +0100
@@ -57,7 +57,8 @@
 # above line for backwards compatibility; can be changed to
 #   from mercurial.i18n import _
 # some day
-from mercurial import cmdutil, templater, util
+from mercurial import context, filelog, revlog
+from mercurial import commands, cmdutil, templater, util
 from mercurial.node import *
 import os.path, re, sys, time
 
@@ -75,22 +76,22 @@
     '''Returns hgdate in cvs-like UTC format.'''
     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
 
-def kwfmatches(ui, repo, files):
-    '''Selects candidates for keyword substitution
-    configured in keyword section in hgrc.'''
+def getkwconfig(ui, repo):
     inc = [pat for pat, opt in ui.configitems('keyword') if opt != 'ignore']
     if not inc:
-        ui.warn(_('keyword: no filename globs for expansion\n'))
-        return []
+        ui.warn(_('keyword: no filename globs for substitution\n'))
+        return None, None
     exc = [pat for pat, opt in ui.configitems('keyword') if opt == 'ignore']
-    kwfmatcher = util.matcher(repo.root, inc=inc, exc=['.hg*']+exc)[1]
-    return [f for f in files if kwfmatcher(f)]
+    return inc, exc
 
 
 class kwtemplater(object):
     '''
     Sets up keyword templates, corresponding keyword regex, and
     provides keyword expansion function.
+
+    If a repo is configured for keyword substitution, this class
+    will be set as an (appendix) attribute to the repo.
     '''
     def __init__(self, ui, repo):
         self.ui = ui
@@ -100,7 +101,6 @@
                 '|'.join(re.escape(k) for k in self.templates.keys()))
         templater.common_filters['utcdate'] = utcdate
         self.t = cmdutil.changeset_templater(ui, repo, False, '', False)
-            
 
     def expand(self, mobj, path, node):
         '''Expands keyword with corresponding template.'''
@@ -109,16 +109,20 @@
         self.t.use_template(template)
         self.ui.pushbuffer()
         self.t.show(changenode=node, root=self.repo.root, file=path)
-        expansion = templater.firstline(self.ui.popbuffer())
-        return '$%s: %s $' % (kw, expansion)
+        kwsub = templater.firstline(self.ui.popbuffer())
+        return '$%s: %s $' % (kw, kwsub)
 
 
 def reposetup(ui, repo):
     '''Sets up repo, and filelog especially, as kwrepo and kwfilelog
     for keyword substitution.  This is done for local repos only.'''
+    if not repo.local():
+        return
 
-    from mercurial import context, filelog, revlog
-    if not repo.local():
+    inc, exc = getkwconfig(ui, repo)
+    if not inc:
+        # no files configured for keyword substitution:
+        # no need to burden repo with extra ballast
         return
 
     class kwrepo(repo.__class__):
@@ -137,15 +141,15 @@
             super(kwfilelog, self).__init__(opener, path, defversion)
             self._repo = repo
             self._path = path
-            # only init kwtemplater if needed
-            if not isinstance(repo, int) and kwfmatches(ui, repo, [path]):
-                self.kwt = kwtemplater(ui, repo)
+            # check at init if file configured for keyword substition
+            if not isinstance(repo, int) and repo.kwfmatcher(path):
+                self.kwsub = True
             else:
-                self.kwt = None
+                self.kwsub = False
 
         def iskwcandidate(self, data):
             '''Decides whether to act on keywords.'''
-            return self.kwt is not None and not util.binary(data)
+            return self.kwsub and not util.binary(data)
 
         def read(self, node):
             '''Substitutes keywords when reading filelog.'''
@@ -153,25 +157,32 @@
             if self.iskwcandidate(data):
                 c = context.filectx(self._repo, self._path,
                                     fileid=node, filelog=self)
-                return self.kwt.re_kw.sub(lambda m:
-                        self.kwt.expand(m, self._path, c.node()), data)
+                return self._repo.kwt.re_kw.sub(lambda m:
+                        self._repo.kwt.expand(m, self._path, c.node()), data)
             return data
 
         def add(self, text, meta, tr, link, p1=None, p2=None):
             '''Removes keyword substitutions when adding to filelog.'''
             if self.iskwcandidate(text):
-                text = self.kwt.re_kw.sub(r'$\1$', text)
+                text = self._repo.kwt.re_kw.sub(r'$\1$', text)
             return super(kwfilelog, self).add(text,
                             meta, tr, link, p1=p1, p2=p2)
 
         def cmp(self, node, text):
             '''Removes keyword substitutions for comparison.'''
             if self.iskwcandidate(text):
-                text = self.kwt.re_kw.sub(r'$\1$', text)
+                text = self._repo.kwt.re_kw.sub(r'$\1$', text)
             return super(kwfilelog, self).cmp(node, text)
 
     filelog.filelog = kwfilelog
     repo.__class__ = kwrepo
+
+    # create filematching function once for repo
+    setattr(repo, 'kwfmatcher',
+            util.matcher(repo.root, inc=inc, exc=['.hg*']+exc)[1])
+    # initialize kwtemplater once for repo
+    setattr(repo, 'kwt', kwtemplater(ui, repo))
+
     # make pretxncommit hook import kwmodule regardless of where it's located
     for k, v in sys.modules.iteritems():
         if v is None:
@@ -185,13 +196,13 @@
         sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
         mod = os.path.splitext(os.path.basename(__file__))[0]
     ui.setconfig('hooks', 'pretxncommit.keyword', 'python:%s.pretxnkw' % mod)
-    del mod
+
+    del inc, exc, mod
 
 
 def pretxnkw(ui, repo, hooktype, **args):
     '''pretxncommit hook that collects candidates for keyword expansion
     on commit and expands keywords in working dir.'''
-    from mercurial import commands
 
     cmd, sysargs, globalopts, cmdopts = commands.parse(ui, sys.argv[1:])[1:]
     if repr(cmd).split()[1] in ('tag', 'import_'):
@@ -199,16 +210,16 @@
 
     files, match, anypats = cmdutil.matchpats(repo, sysargs, cmdopts)
     modified, added = repo.status(files=files, match=match)[:2]
-    candidates = kwfmatches(ui, repo, modified+added)
+    candidates = [f for f in modified+added if repo.kwfmatcher(f)]
     if not candidates:
         return
 
-    kwt = kwtemplater(ui, repo)
     node = bin(args['node'])
     for f in candidates:
         data = repo.wfile(f).read()
         if not util.binary(data):
-            data, kwct = kwt.re_kw.subn(lambda m: kwt.expand(m, f, node), data)
+            data, kwct = repo.kwt.re_kw.subn(lambda m:
+                    repo.kwt.expand(m, f, node), data)
             if kwct:
                 ui.debug(_('overwriting %s expanding keywords\n' % f))
                 repo.wfile(f, 'w').write(data)