hgkw/keyword.py
changeset 307 32061d23db14
parent 306 78b80b2511de
child 308 2a20fa267041
--- a/hgkw/keyword.py	Sat Dec 01 13:15:13 2007 +0100
+++ b/hgkw/keyword.py	Sat Dec 01 20:31:13 2007 +0100
@@ -92,6 +92,8 @@
     '''Returns hgdate in cvs-like UTC format.'''
     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
 
+_kwtemplater = None
+
 class kwtemplater(object):
     '''
     Sets up keyword templates, corresponding keyword regex, and
@@ -107,12 +109,12 @@
         'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
     }
 
-    def __init__(self, ui, repo, expand, path='', node=None):
+    def __init__(self, ui, repo, inc, exc):
         self.ui = ui
         self.repo = repo
-        self.ct = expand or None
-        self.path = path
-        self.node = node
+        self.match = util.matcher(repo.root, inc=inc, exc=exc)[1]
+        self.node = None
+        self.path = ''
 
         kwmaps = self.ui.configitems('keywordmaps')
         if kwmaps: # override default templates
@@ -122,10 +124,10 @@
         escaped = map(re.escape, self.templates.keys())
         kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
         self.re_kw = re.compile(kwpat)
-        if self.ct:
-            templater.common_filters['utcdate'] = utcdate
-            self.ct = cmdutil.changeset_templater(self.ui, self.repo,
-                                                  False, '', False)
+
+        templater.common_filters['utcdate'] = utcdate
+        self.ct = cmdutil.changeset_templater(self.ui, self.repo,
+                                              False, '', False)
 
     def substitute(self, node, data, subfunc):
         '''Obtains node if missing, and calls given substitution function.'''
@@ -150,14 +152,14 @@
             return data
         return self.substitute(node, data, self.re_kw.sub)
 
-    def process(self, node, data):
+    def process(self, node, data, expand):
         '''Returns a tuple: data, count.
         Count is number of keywords/keyword substitutions, indicates
         to caller whether to act on file containing data.
         Keywords in data are expanded, if templater was initialized.'''
         if util.binary(data):
             return data, None
-        if self.ct:
+        if expand:
             return self.substitute(node, data, self.re_kw.subn)
         return data, self.re_kw.search(data)
 
@@ -167,21 +169,6 @@
             return text
         return self.re_kw.sub(r'$\1$', text)
 
-    def overwrite(self, candidates, man, commit):
-        '''Overwrites files in working directory if keywords are detected.
-        Keywords are expanded if keyword templater is initialized,
-        otherwise their substitution is removed.'''
-        expand = self.ct is not None
-        action = ('shrinking', 'expanding')[expand]
-        notify = (self.ui.note, self.ui.debug)[commit]
-        for f in candidates:
-            fp = self.repo.file(f, kwexp=expand, kwmatch=True)
-            data, kwfound = fp.kwctread(man[f])
-            if kwfound:
-                notify(_('overwriting %s %s keywords\n') % (f, action))
-                self.repo.wwrite(f, data, man.flags(f))
-                self.repo.dirstate.normal(f)
-
 class kwfilelog(filelog.filelog):
     '''
     Subclass of filelog to hook into its read, add, cmp methods.
@@ -191,11 +178,11 @@
         super(kwfilelog, self).__init__(opener, path)
         self.kwtemplater = kwtemplater
 
-    def kwctread(self, node):
+    def kwctread(self, node, expand):
         '''Reads expanding and counting keywords
         (only called from kwtemplater.overwrite).'''
         data = super(kwfilelog, self).read(node)
-        return self.kwtemplater.process(node, data)
+        return self.kwtemplater.process(node, data, expand)
 
     def read(self, node):
         '''Expands keywords when reading filelog.'''
@@ -215,28 +202,42 @@
             return t2 != text
         return revlog.revlog.cmp(self, node, text)
 
-def _status(ui, repo, *pats, **opts):
+def _status(ui, repo, kwtemplater, *pats, **opts):
     '''Bails out if [keyword] configuration is not active.
     Returns status of working directory.'''
-    if hasattr(ui, 'kwfmatcher'):
+    if kwtemplater:
         files, match, anypats = cmdutil.matchpats(repo, pats, opts)
         return repo.status(files=files, match=match, list_clean=True)
     if ui.configitems('keyword'):
         raise util.Abort(_('[keyword] patterns cannot match'))
     raise util.Abort(_('no [keyword] patterns configured'))
 
-def _iskwfile(ui, man, f):
-    return not man.linkf(f) and ui.kwfmatcher(f)
-
-def _overwrite(ui, repo, files, node, man, expand, commit):
-    '''Passes given files to kwtemplater for overwriting.'''
-    files.sort()
-    kwt = kwtemplater(ui, repo, expand, node=node)
-    kwt.overwrite(files, man, commit)
+def _overwrite(ui, repo, kwtemplater, node=None, expand=True, files=None):
+    '''Overwrites selected files expanding/shrinking keywords.'''
+    ctx = repo.changectx(node)
+    mf = ctx.manifest()
+    if files is None:
+        notify = ui.debug # commit
+        files = [f for f in ctx.files() if mf.has_key(f)]
+    else:
+        notify = ui.note  # kwexpand/kwshrink
+    candidates = [f for f in files if not mf.linkf(f) and kwtemplater.match(f)]
+    if candidates:
+        candidates.sort()
+        action = expand and 'expanding' or 'shrinking'
+        kwtemplater.node = node or ctx.node()
+        for f in candidates:
+            fp = repo.file(f, kwmatch=True)
+            data, kwfound = fp.kwctread(mf[f], expand)
+            if kwfound:
+                notify(_('overwriting %s %s keywords\n') % (f, action))
+                repo.wwrite(f, data, mf.flags(f))
+                repo.dirstate.normal(f)
 
 def _kwfwrite(ui, repo, expand, *pats, **opts):
     '''Selects files and passes them to _overwrite.'''
-    status = _status(ui, repo, *pats, **opts)
+    global _kwtemplater
+    status = _status(ui, repo, _kwtemplater, *pats, **opts)
     modified, added, removed, deleted, unknown, ignored, clean = status
     if modified or added or removed or deleted:
         raise util.Abort(_('outstanding uncommitted changes in given files'))
@@ -244,12 +245,7 @@
     try:
         wlock = repo.wlock()
         lock = repo.lock()
-        ctx = repo.changectx()
-        man = ctx.manifest()
-        candidates = [f for f in clean if _iskwfile(ui, man, f)]
-        if candidates:
-            # 7th argument sets commit to False
-            _overwrite(ui, repo, candidates, ctx.node(), man, expand, False)
+        _overwrite(ui, repo, _kwtemplater, expand=expand, files=clean)
     finally:
         del wlock, lock
 
@@ -352,14 +348,15 @@
     keyword expansion.
     That is, files matched by [keyword] config patterns but not symlinks.
     '''
-    status = _status(ui, repo, *pats, **opts)
+    global _kwtemplater
+    status = _status(ui, repo, _kwtemplater, *pats, **opts)
     modified, added, removed, deleted, unknown, ignored, clean = status
     if opts['untracked']:
         files = modified + added + unknown + clean
     else:
         files = modified + added + clean
     files.sort()
-    kwfiles = [f for f in files if ui.kwfmatcher(f) and not repo._link(f)]
+    kwfiles = [f for f in files if _kwtemplater.match(f) and not repo._link(f)]
     cwd = pats and repo.getcwd() or ''
     allf = opts['all']
     ignore = opts['ignore']
@@ -421,15 +418,16 @@
     if not inc:
         return
 
-    ui.kwfmatcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
+    global _kwtemplater
+    _kwtemplater = kwtemplater(ui, repo, inc, exc)
 
     class kwrepo(repo.__class__):
-        def file(self, f, kwexp=True, kwmatch=False):
+        def file(self, f, kwmatch=False):
             if f[0] == '/':
                 f = f[1:]
-            if kwmatch or ui.kwfmatcher(f):
-                kwt = kwtemplater(ui, self, kwexp, path=f)
-                return kwfilelog(self.sopener, f, kwt)
+            if kwmatch or _kwtemplater.match(f):
+                _kwtemplater.path = f
+                return kwfilelog(self.sopener, f, _kwtemplater)
             return filelog.filelog(self.sopener, f)
 
         def commit(self, files=None, text='', user=None, date=None,
@@ -468,13 +466,7 @@
                 for name, cmd in commithooks:
                     ui.setconfig('hooks', name, cmd)
                 if node is not None:
-                    cl = self.changelog.read(node)
-                    mn = self.manifest.read(cl[0])
-                    candidates = [f for f in cl[3] if mn.has_key(f)
-                                  and _iskwfile(ui, mn, f)]
-                    if candidates:
-                        # 6th, 7th arguments set expansion, commit to True
-                        _overwrite(ui, self, candidates, node, mn, True, True)
+                    _overwrite(ui, self, _kwtemplater, node=node)
                     repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
                 return node
             finally: