Implement self initializing pretxncommit hook
This is more expensive than overriding commit(), but
a) uses more "official" interface
b) less code
c) easier to maintain
Get all changes up to cee5fef33cf8 in here as well.
# keyword.py - keyword expansion for mercurial
'''keyword expansion hack against the grain of a DSCM
This extension lets you expand RCS/CVS-like keywords in a Mercurial
repository.
There are many good reasons why this is not needed in a distributed
SCM, still it may be useful in very small projects based on single
files (like LaTeX packages), that are mostly addressed to an audience
not running a version control system.
Supported $keywords$ and their $keyword: substition $ are:
Revision: changeset id
Author: full username
Date: %a %b %d %H:%M:%S %Y %z $
RCSFile: basename,v
Source: /path/to/basename,v
Id: basename,v csetid %Y-%m-%d %H:%M:%S %z shortname
Header: /path/to/basename,v csetid %Y-%m-%d %H:%M:%S %z shortname
Install:
Copy keyword.py in hgext folder.
Simple setup in hgrc:
# enable extension
hgext.keyword =
# filename patterns for expansion are configured in this section
[keyword]
**.py = expand
...
'''
from mercurial import context, util
import os.path, re
re_kw = re.compile(
r'\$(Id|Header|Author|Date|Revision|RCSFile|Source)[^$]*?\$')
def kwexpand(matchobj, repo, path, changeid=None, fileid=None, filelog=None):
'''Called by kwfilelog.read and pretxnkw.
Sets supported keywords as local variables and evaluates them to
their expansion if matchobj is equal to string representation.'''
c = context.filectx(repo, path,
changeid=changeid, fileid=fileid, filelog=filelog)
date = c.date()
Revision = c.changectx()
Author = c.user()
RCSFile = os.path.basename(path)+',v'
Source = repo.wjoin(path)+',v'
Date = util.datestr(date=date)
revdateauth = '%s %s %s' % (Revision,
util.datestr(date=date, format=util.defaultdateformats[0]),
util.shortuser(Author))
Header = '%s %s' % (Source, revdateauth)
Id = '%s %s' % (RCSFile, revdateauth)
return '$%s: %s $' % (matchobj.group(1), eval(matchobj.group(1)))
def kwfmatches(ui, repo, files):
'''Selects candidates for keyword substitution
configured in keyword section in hgrc.'''
files = [f for f in files if not f.startswith('.hg')]
if not files:
return []
candidates = []
fmatchers = [util.matcher(repo.root, '', [pat], [], [])[1]
for pat, opt in ui.configitems('keyword')
if opt == 'expand']
for f in files:
for mf in fmatchers:
if mf(f):
candidates.append(f)
break
return candidates
def reposetup(ui, repo):
from mercurial import filelog, revlog
if not repo.local():
return
class kwrepo(repo.__class__):
def file(self, f):
if f[0] == '/':
f = f[1:]
return filelog.filelog(self.sopener, f, self, self.revlogversion)
class kwfilelog(filelog.filelog):
'''
Superclass over filelog to customize it's read, add, cmp methods.
Keywords are "stored" unexpanded, and expanded on reading.
'''
def __init__(self, opener, path, repo,
defversion=revlog.REVLOG_DEFAULT_VERSION):
super(kwfilelog, self).__init__(opener, path, defversion)
self._repo = repo
self._path = path
def iskwcandidate(self, data):
'''Decides whether to act on keywords.'''
return (kwfmatches(ui, self._repo, [self._path])
and not util.binary(data))
def read(self, node):
'''Substitutes keywords when reading filelog.'''
data = super(kwfilelog, self).read(node)
if self.iskwcandidate(data):
return re_kw.sub(lambda m:
kwexpand(m, self._repo, self._path,
fileid=node, filelog=self), 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)
return super(kwfilelog, self).add(text,
meta, tr, link, p1=None, p2=None)
def cmp(self, node, text):
'''Removes keyword substitutions for comparison.'''
if self.iskwcandidate(text):
text = re_kw.sub(r'$\1$', text)
return super(kwfilelog, self).cmp(node, text)
filelog.filelog = kwfilelog
repo.__class__ = kwrepo
ui.setconfig('hooks',
'pretxncommit.keyword', 'python:hgext.keyword.pretxnkw')
def pretxnkw(ui, repo, hooktype, **args):
'''pretxncommit hook that collects candidates for keyword expansion
on commit and expands keywords in working dir.'''
from mercurial.i18n import gettext as _
from mercurial import cmdutil, commands
import sys
if hooktype != 'pretxncommit':
return True
cmd, sysargs, globalopts, cmdopts = commands.parse(ui, sys.argv[1:])[1:]
if repr(cmd).split()[1] in ('tag', 'import_'):
return False
files, match, anypats = cmdutil.matchpats(repo, sysargs, cmdopts)
modified, added = repo.status(files=files, match=match)[:2]
for f in kwfmatches(ui, repo, modified+added):
data = repo.wfile(f).read()
if not util.binary(data):
data, kwct = re_kw.subn(lambda m:
kwexpand(m, repo, f, changeid=args['node']),
data)
if kwct:
ui.debug(_('overwriting %s expanding keywords\n' % f))
repo.wfile(f, 'w').write(data)