diff -r b285ab731fff -r fd5d3a974ea7 hgkw/keyword.py --- a/hgkw/keyword.py Fri Jan 05 14:51:58 2007 +0100 +++ b/hgkw/keyword.py Mon Jan 08 18:27:18 2007 +0100 @@ -10,22 +10,17 @@ files (like LaTeX packages), that are mostly addressed to an audience not running a version control system. -Supported keywords are (changeset 000000000000): - $Revision: 000000000000 $ - $Author: Your Name
$ - $Date: %a %b %d %H:%M:%S %Y %z $ - $RCSFile: basename,v $ - $Source: /path/to/basename,v $ - $Id: basename,v 000000000000 %Y-%m-%d %H:%M:%S %z shortname $ - $Header: /path/to/basename,v 000000000000 %Y-%m-%d %H:%M:%S %z shortname $ +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 -The extension, according to its hackish nature, is a hybrid and consists -actually in 2 parts: - - 1. pure extension code (reposetup) that is triggered on checkout and - logging of changes. - 2. a pretxncommit hook (hgrc (5)) that expands keywords immediately - at commit time in the working directory. +Install: + Copy keyword.py in hgext folder. Simple setup in hgrc: @@ -34,16 +29,10 @@ # filename patterns for expansion are configured in this section [keyword] - *.sty = expand + **.py = expand ... - - # set up pretxncommit hook - [hooks] - pretxncommit = - pretxncommit.keyword = python:hgext.keyword.pretxnkw ''' -from mercurial.i18n import _ from mercurial import context, util import os.path, re @@ -56,11 +45,9 @@ '''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' @@ -71,14 +58,24 @@ util.shortuser(Author)) Header = '%s %s' % (Source, revdateauth) Id = '%s %s' % (RCSFile, revdateauth) - return '$%s: %s $' % (matchobj.group(1), eval(matchobj.group(1))) -def kwfmatchers(ui, repo): - '''Returns filename matchers from ui keyword section.''' - return [util.matcher(repo.root, '', [pat], [], [])[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): @@ -94,44 +91,53 @@ 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 not self._path.startswith('.hg') and not util.binary(data): - for mf in kwfmatchers(ui, self._repo): - if mf(self._path): - ui.debug(_('expanding keywords in %s\n' % self._path)) - return re_kw.sub(lambda m: - kwexpand(m, self._repo, self._path, - fileid=node, filelog=self), - data) + if self.iskwcandidate(data): + return re_kw.sub(lambda m: + kwexpand(m, self._repo, self._path, + fileid=node, filelog=self), data) return data - def size(self, rev): - '''Overrides filelog's size() to use kwfilelog.read().''' - node = revlog.node(self, rev) - if super(kwfilelog, self).renamed(node): - return len(self.read(node)) - return revlog.size(self, rev) + 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): - '''Overrides filelog's cmp() to use kwfilelog.read().''' - if super(kwfilelog, self).renamed(node): - t2 = self.read(node) - return t2 != 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 @@ -144,20 +150,13 @@ files, match, anypats = cmdutil.matchpats(repo, sysargs, cmdopts) modified, added = repo.status(files=files, match=match)[:2] - candidates = [f for f in modified + added if not f.startswith('.hg')] - if not candidates: - return False - fmatchers = kwfmatchers(ui, repo) - for f in candidates: - for mf in fmatchers: - if mf(f): - 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) - break + 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)