--- a/hgkw/keyword.py Fri Jan 25 17:31:55 2008 +0000
+++ b/hgkw/keyword.py Tue Jan 29 17:32:10 2008 +0100
@@ -80,40 +80,18 @@
"Log = {desc}" expands to the first line of the changeset description.
'''
-from mercurial import commands, cmdutil, context, dispatch, filelog
-from mercurial import patch, localrepo, revlog, templater, util
+from mercurial import commands, cmdutil, context, localrepo
+from mercurial import patch, revlog, templater, util
from mercurial.node import *
from mercurial.i18n import _
-import re, shutil, sys, tempfile, time
+import re, shutil, tempfile, time
commands.optionalrepo += ' kwdemo'
-# handle for external callers
-externalcall = None, None, {}
-
-def externalcmdhook(hgcmd, *args, **opts):
- '''Hook for external callers to pass hg commands to keyword.
-
- Caveat: hgcmd, args, opts are not checked for validity.
- This is the responsibility of the caller.
-
- hgmcd can be either the hg function object, eg diff or patch,
- or its string represenation, eg 'diff' or 'patch'.'''
- global externalcall
- if not isinstance(hgcmd, str):
- hgcmd = hgcmd.__name__.split('.')[-1]
- externalcall = hgcmd, args, opts
-
-# hg commands that trigger expansion only when writing to working dir,
-# not when reading filelog, and unexpand when reading from working dir
-restricted = ('diff1', 'record',
- 'qfold', 'qimport', 'qnew', 'qpush', 'qrefresh', 'qrecord')
-
def utcdate(date):
'''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):
@@ -131,13 +109,11 @@
'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
}
- def __init__(self, ui, repo, inc, exc, hgcmd):
+ def __init__(self, ui, repo, inc, exc):
self.ui = ui
self.repo = repo
self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
- self.hgcmd = hgcmd
- self.commitnode = None
- self.path = ''
+ self.ctx = None
kwmaps = self.ui.configitems('keywordmaps')
if kwmaps: # override default templates
@@ -152,78 +128,50 @@
self.ct = cmdutil.changeset_templater(self.ui, self.repo,
False, '', False)
- def substitute(self, node, data, subfunc):
- '''Obtains file's changenode if commit node not given,
+ def substitute(self, path, data, node, subfunc):
+ '''Obtains file's changenode if node not given,
and calls given substitution function.'''
- if self.commitnode:
- fnode = self.commitnode
- else:
- c = context.filectx(self.repo, self.path, fileid=node)
- fnode = c.node()
+ if node is None:
+ # kwrepo.wwrite except when overwriting on commit
+ if self.ctx is None:
+ self.ctx = self.repo.changectx()
+ fnode = self.ctx.filenode(path)
+ fl = self.repo.file(path)
+ c = context.filectx(self.repo, path, fileid=fnode, filelog=fl)
+ node = c.node()
def kwsub(mobj):
'''Substitutes keyword using corresponding template.'''
kw = mobj.group(1)
self.ct.use_template(self.templates[kw])
self.ui.pushbuffer()
- self.ct.show(changenode=fnode, root=self.repo.root, file=self.path)
+ self.ct.show(changenode=node, root=self.repo.root, file=path)
return '$%s: %s $' % (kw, templater.firstline(self.ui.popbuffer()))
return subfunc(kwsub, data)
- def expand(self, node, data):
+ def expand(self, path, data):
'''Returns data with keywords expanded.'''
- if util.binary(data) or self.hgcmd in restricted:
+ if util.binary(data):
return data
- return self.substitute(node, data, self.re_kw.sub)
+ return self.substitute(path, data, None, self.re_kw.sub)
- def process(self, node, data, expand):
+ def process(self, path, data, expand, ctx, node):
'''Returns a tuple: data, count.
Count is number of keywords/keyword substitutions,
telling caller whether to act on file containing data.'''
if util.binary(data):
return data, None
if expand:
- return self.substitute(node, data, self.re_kw.subn)
- return data, self.re_kw.search(data)
-
- def shrink(self, text):
- '''Returns text with all keyword substitutions removed.'''
- if util.binary(text):
- return text
- return self.re_kw.sub(r'$\1$', text)
-
-class kwfilelog(filelog.filelog):
- '''
- Subclass of filelog to hook into its read, add, cmp methods.
- Keywords are "stored" unexpanded, and processed on reading.
- '''
- def __init__(self, opener, path):
- super(kwfilelog, self).__init__(opener, path)
- _kwtemplater.path = path
+ self.ctx = ctx
+ return self.substitute(path, data, node, self.re_kw.subn)
+ return self.re_kw.subn(r'$\1$', data)
- def kwctread(self, node, expand):
- '''Reads expanding and counting keywords, called from _overwrite.'''
- data = super(kwfilelog, self).read(node)
- return _kwtemplater.process(node, data, expand)
-
- def read(self, node):
- '''Expands keywords when reading filelog.'''
- data = super(kwfilelog, self).read(node)
- return _kwtemplater.expand(node, data)
-
- def add(self, text, meta, tr, link, p1=None, p2=None):
- '''Removes keyword substitutions when adding to filelog.'''
- text = _kwtemplater.shrink(text)
- return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
-
- def cmp(self, node, text):
- '''Removes keyword substitutions for comparison.'''
- text = _kwtemplater.shrink(text)
- if self.renamed(node):
- t2 = super(kwfilelog, self).read(node)
- return t2 != text
- return revlog.revlog.cmp(self, node, text)
+ def shrink(self, data):
+ '''Returns text with all keyword substitutions removed.'''
+ if util.binary(data):
+ return data
+ return self.re_kw.sub(r'$\1$', data)
# store original patch.patchfile.__init__
@@ -257,22 +205,22 @@
'''Overwrites selected files expanding/shrinking keywords.'''
ctx = repo.changectx(node)
mf = ctx.manifest()
- if node is not None: # commit
- _kwtemplater.commitnode = node
+ if node is not None:
+ # commit
files = [f for f in ctx.files() if f in mf]
notify = ui.debug
- else: # kwexpand/kwshrink
+ else:
+ # kwexpand/kwshrink
notify = ui.note
candidates = [f for f in files if _iskwfile(f, mf.linkf)]
if candidates:
candidates.sort()
action = expand and 'expanding' or 'shrinking'
for f in candidates:
- fp = repo.file(f, kwmatch=True)
- data, kwfound = fp.kwctread(mf[f], expand)
+ data, kwfound = repo._wreadkwct(f, expand, ctx, node)
if kwfound:
notify(_('overwriting %s %s keywords\n') % (f, action))
- repo.wwrite(f, data, mf.flags(f))
+ repo.wwrite(f, data, mf.flags(f), overwrite=True)
repo.dirstate.normal(f)
def _kwfwrite(ui, repo, expand, *pats, **opts):
@@ -366,7 +314,7 @@
repo.commit(text=msg)
format = ui.verbose and ' in %s' % path or ''
demostatus('%s keywords expanded%s' % (kwstatus, format))
- ui.write(repo.wread(fn))
+ ui.write(repo.wopener(fn).read())
ui.debug(_('\nremoving temporary repo %s\n') % tmpdir)
shutil.rmtree(tmpdir, ignore_errors=True)
@@ -416,44 +364,10 @@
def reposetup(ui, repo):
- '''Sets up repo as kwrepo for keyword substitution.
- Overrides file method to return kwfilelog instead of filelog
- if file matches user configuration.
- Wraps commit to overwrite configured files with updated
- keyword substitutions.
- This is done for local repos only, and only if there are
- files configured at all for keyword substitution.'''
-
if not repo.local():
return
- nokwcommands = ('add', 'addremove', 'bundle', 'clone', 'copy',
- 'export', 'grep', 'identify', 'incoming', 'init',
- 'log', 'outgoing', 'push', 'remove', 'rename',
- 'rollback', 'tip',
- 'convert')
- try:
- hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:])
- except (cmdutil.UnknownCommand, dispatch.ParseError):
- # must be an external caller, otherwise Exception would have been
- # raised at core command line parsing
- hgcmd, args, cmdopts = externalcall
- if hgcmd is None:
- # not an "official" hg command as from command line
- return
- if hgcmd in nokwcommands:
- return
-
- if hgcmd == 'diff':
- # only expand if comparing against working dir
- node1, node2 = cmdutil.revpair(repo, cmdopts.get('rev'))
- if node2 is not None:
- return
- # shrink if rev is not current node
- if node1 is not None and node1 != repo.changectx().node():
- hgcmd = 'diff1'
-
- inc, exc = [], ['.hgtags']
+ inc, exc = [], ['.hgtags', '.hg_archival.txt']
for pat, opt in ui.configitems('keyword'):
if opt != 'ignore':
inc.append(pat)
@@ -463,22 +377,31 @@
return
global _kwtemplater
- _kwtemplater = kwtemplater(ui, repo, inc, exc, hgcmd)
+ _kwtemplater = kwtemplater(ui, repo, inc, exc)
class kwrepo(repo.__class__):
- def file(self, f, kwmatch=False):
- if f[0] == '/':
- f = f[1:]
- if kwmatch or _kwtemplater.matcher(f):
- return kwfilelog(self.sopener, f)
- return filelog.filelog(self.sopener, f)
+ def _wreadkwct(self, filename, expand, ctx, node):
+ '''Reads filename and returns tuple of data with keywords
+ expanded/shrunk and count of keywords (for _overwrite).'''
+ data = super(kwrepo, self).wread(filename)
+ return _kwtemplater.process(filename, data, expand, ctx, node)
def wread(self, filename):
data = super(kwrepo, self).wread(filename)
- if hgcmd in restricted and _kwtemplater.matcher(filename):
+ if _kwtemplater.matcher(filename):
return _kwtemplater.shrink(data)
return data
+ def wwrite(self, filename, data, flags, overwrite=False):
+ if not overwrite and _kwtemplater.matcher(filename):
+ data = _kwtemplater.expand(filename, data)
+ super(kwrepo, self).wwrite(filename, data, flags)
+
+ def wwritedata(self, filename, data):
+ if _kwtemplater.matcher(filename):
+ data = _kwtemplater.expand(filename, data)
+ return super(kwrepo, self).wwritedata(filename, data)
+
def commit(self, files=None, text='', user=None, date=None,
match=util.always, force=False, force_editor=False,
p1=None, p2=None, extra={}):