--- a/hgkw/keyword.py Sat Jan 13 13:27:13 2007 +0100
+++ b/hgkw/keyword.py Sun Jan 14 12:56:52 2007 +0100
@@ -11,38 +11,55 @@
files (like LaTeX packages), that are mostly addressed to an audience
not running a version control system.
-Supported $keywords$ and their $keyword: substition $ are:
+You can either use the default cvs-like keywords or provide your
+own in hgrc.
+
+Default $keywords$ and their $keyword: substition $ are:
Revision: changeset id
- Author: short username
+ Author: username
Date: %Y/%m/%d %H:%M:%S [UTC]
RCSFile: basename,v
Source: /path/to/basename,v
- Id: basename,v csetid %Y/%m/%d %H:%M:%S shortname
- Header: /path/to/basename,v csetid %Y/%m/%d %H:%M:%S shortname
+ Id: basename,v csetid %Y/%m/%d %H:%M:%S username
+ Header: /path/to/basename,v csetid %Y/%m/%d %H:%M:%S username
Simple setup in hgrc:
# enable extension
- hgext.keyword =
- # or, if script not in hgext folder:
- # hgext.keyword = /full/path/to/script
+ hgext.keyword = /full/path/to/script
+ # or, if script in hgext folder:
+ # hgext.keyword =
# filename patterns for expansion are configured in this section
[keyword]
**.py = expand
...
+ # in case you prefer you own keyword maps over the cvs-like defaults:
+ [keywordmaps]
+ hgdate = {date|rfc822date}
+ lastlog = {desc}
+ checked in by = {author}
+ ...
'''
-from mercurial import context, util
+from mercurial import cmdutil, templater, util
import os.path, re, sys, time
-re_kw = re.compile(
- r'\$(Id|Header|Author|Date|Revision|RCSFile|Source)[^$]*?\$')
+deftemplates = {
+ 'Revision': '{node|short}',
+ 'Author': '{author|user}',
+ 'Date': '{date|utcdate}',
+ 'RCSFile': '{file|basename},v',
+ 'Source': '{root}/{file},v',
+ 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
+ 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
+ }
-def kwexpand(mobj, kwfctx):
- '''Called by kwfilelog.read and pretxnkw.
- Expands keywords according to file context.'''
- return '$%s: %s $' % (mobj.group(1), kwfctx.expand(mobj.group(1)))
+def utcdate(date):
+ '''Returns hgdate in cvs-like UTC format.'''
+ return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
+
+templater.common_filters['utcdate'] = utcdate
def kwfmatches(ui, repo, files):
'''Selects candidates for keyword substitution
@@ -60,41 +77,38 @@
break
return candidates
-def utcdate(date):
- '''Returns hgdate in cvs-like UTC format.'''
- return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
-
-class kwfilectx(context.filectx):
+class kwtemplater(object):
'''
- Provides keyword expansion functions based on file context.
+ Sets up keyword templates, corresponding keyword regex, and
+ provides keyword expansion function.
'''
- def __init__(self, repo, path, changeid=None, fileid=None, filelog=None):
- context.filectx.__init__(self, repo, path, changeid, fileid, filelog)
- def Revision(self):
- return str(self.changectx())
- def Author(self):
- return util.shortuser(self.user())
- def Date(self):
- return utcdate(self.date())
- def RCSFile(self):
- return os.path.basename(self._path)+',v'
- def Source(self):
- return self._repo.wjoin(self._path)+',v'
- def Header(self):
- return ' '.join(
- [self.Source(), self.Revision(), self.Date(), self.Author()])
- def Id(self):
- return ' '.join(
- [self.RCSFile(), self.Revision(), self.Date(), self.Author()])
- def expand(self, kw):
- '''Called from kwexpand, evaluates keyword.'''
- return eval('self.%s()' % kw)
+ def __init__(self, ui, repo, node=None):
+ self.ui = ui
+ self.repo = repo
+ self.node = node
+ templates = {}
+ for k, v in self.ui.configitems('keywordmaps'):
+ templates[k] = v
+ self.templates = templates or deftemplates
+ self.re_kw = re.compile(r'\$(%s)[^$]*?\$' %
+ '|'.join(re.escape(k) for k in self.templates.keys()))
+ self.t = cmdutil.changeset_templater(self.ui, self.repo,
+ False, '', False)
+
+ def expand(self, mobj, path):
+ kw = mobj.group(1)
+ template = templater.parsestring(self.templates[kw], quoted=False)
+ self.t.use_template(template)
+ self.ui.pushbuffer()
+ self.t.show(changenode=self.node,
+ changes=self.repo.changelog.read(self.node),
+ root=self.repo.root, file=path)
+ return '$%s: %s $' % (kw, self.ui.popbuffer())
def reposetup(ui, repo):
- from mercurial import filelog, revlog
-
+ from mercurial import context, filelog, revlog
if not repo.local():
return
@@ -114,6 +128,7 @@
super(kwfilelog, self).__init__(opener, path, defversion)
self._repo = repo
self._path = path
+ self.kwt = kwtemplater(ui, self._repo)
def iskwcandidate(self, data):
'''Decides whether to act on keywords.'''
@@ -124,22 +139,24 @@
'''Substitutes keywords when reading filelog.'''
data = super(kwfilelog, self).read(node)
if self.iskwcandidate(data):
- kwfctx = kwfilectx(self._repo, self._path,
- fileid=node, filelog=self)
- return re_kw.sub(lambda m: kwexpand(m, kwfctx), data)
+ c = context.filectx(self._repo, self._path,
+ fileid=node, filelog=self)
+ self.kwt.node = c.node()
+ return self.kwt.re_kw.sub(lambda m:
+ self.kwt.expand(m, self._path), 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 = re_kw.sub(r'$\1$', text)
+ text = self.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 = re_kw.sub(r'$\1$', text)
+ text = self.kwt.re_kw.sub(r'$\1$', text)
return super(kwfilelog, self).cmp(node, text)
filelog.filelog = kwfilelog
@@ -167,7 +184,7 @@
# above line for backwards compatibility; can be changed to
# from mercurial.i18n import _
# some day
- from mercurial import cmdutil, commands
+ from mercurial import commands
if hooktype != 'pretxncommit':
return True
@@ -178,12 +195,15 @@
files, match, anypats = cmdutil.matchpats(repo, sysargs, cmdopts)
modified, added = repo.status(files=files, match=match)[:2]
+ candidates = kwfmatches(ui, repo, modified+added)
+ if not candidates:
+ return False
- for f in kwfmatches(ui, repo, modified+added):
+ kwt = kwtemplater(ui, repo, node=repo.changelog.tip())
+ for f in candidates:
data = repo.wfile(f).read()
if not util.binary(data):
- kwfctx = kwfilectx(repo, f, changeid=args['node'])
- data, kwct = re_kw.subn(lambda m: kwexpand(m, kwfctx), data)
+ data, kwct = kwt.re_kw.subn(lambda m: kwt.expand(m, f), data)
if kwct:
ui.debug(_('overwriting %s expanding keywords\n' % f))
repo.wfile(f, 'w').write(data)