--- a/hgkw/keyword.py Mon Nov 26 12:52:54 2007 +0100
+++ b/hgkw/keyword.py Tue Dec 04 09:56:12 2007 +0100
@@ -82,11 +82,30 @@
from mercurial import commands, cmdutil, context
from mercurial import filelog, localrepo, revlog, templater, util
+from mercurial.node import *
from mercurial.i18n import gettext as _
import getopt, os.path, re, shutil, sys, tempfile, time
# backwards compatibility hacks
+def _wwrite(repo, f, data, mf):
+ '''Makes repo.wwrite backwards compatible.'''
+ # 656e06eebda7 removed file descriptor argument
+ # 67982d3ee76c added flags argument
+ try:
+ repo.wwrite(f, data, mf.flags(f))
+ except (AttributeError, TypeError):
+ repo.wwrite(f, data)
+
+def _normal(repo, files):
+ '''Backwards compatible repo.dirstate.normal/update.'''
+ # 6fd953d5faea introduced dirstate.normal()
+ try:
+ for f in files:
+ repo.dirstate.normal(f)
+ except AttributeError:
+ repo.dirstate.update(files, 'n')
+
def _pathto(repo, f, cwd=None):
'''kwfiles behaves similar to status, using pathto since 78b6add1f966.'''
try:
@@ -147,6 +166,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
@@ -162,12 +183,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.t = expand or None
- self.path = path
- self.node = node
+ self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
+ self.node = None
+ self.path = ''
kwmaps = self.ui.configitems('keywordmaps')
if kwmaps: # override default templates
@@ -177,9 +198,9 @@
escaped = map(re.escape, self.templates.keys())
kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
self.re_kw = re.compile(kwpat)
- if self.t:
- templater.common_filters['utcdate'] = utcdate
- self.t = self._changeset_templater()
+
+ templater.common_filters['utcdate'] = utcdate
+ self.ct = self._changeset_templater()
def _changeset_templater(self):
'''Backwards compatible cmdutil.changeset_templater.'''
@@ -191,24 +212,6 @@
return cmdutil.changeset_templater(self.ui, self.repo,
False, None, '', False)
- def _wwrite(self, f, data, man):
- '''Makes repo.wwrite backwards compatible.'''
- # 656e06eebda7 removed file descriptor argument
- # 67982d3ee76c added flags argument
- try:
- self.repo.wwrite(f, data, man.flags(f))
- except (AttributeError, TypeError):
- self.repo.wwrite(f, data)
-
- def _normal(self, files):
- '''Backwards compatible repo.dirstate.normal/update.'''
- # 6fd953d5faea introduced dirstate.normal()
- try:
- for f in files:
- self.repo.dirstate.normal(f)
- except AttributeError:
- self.repo.dirstate.update(files, 'n')
-
def substitute(self, node, data, subfunc):
'''Obtains node if missing, and calls given substitution function.'''
if not self.node:
@@ -218,10 +221,10 @@
def kwsub(mobj):
'''Substitutes keyword using corresponding template.'''
kw = mobj.group(1)
- self.t.use_template(self.templates[kw])
+ self.ct.use_template(self.templates[kw])
self.ui.pushbuffer()
- self.t.show(changenode=self.node,
- root=self.repo.root, file=self.path)
+ self.ct.show(changenode=self.node,
+ root=self.repo.root, file=self.path)
return '$%s: %s $' % (kw, templater.firstline(self.ui.popbuffer()))
return subfunc(kwsub, data)
@@ -232,14 +235,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.t:
+ if expand:
return self.substitute(node, data, self.re_kw.subn)
return data, self.re_kw.search(data)
@@ -249,23 +252,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.t is not None
- action = ('shrinking', 'expanding')[expand]
- notify = (self.ui.note, self.ui.debug)[commit]
- overwritten = []
- 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._wwrite(f, data, man)
- overwritten.append(f)
- self._normal(overwritten)
-
class kwfilelog(filelog.filelog):
'''
Subclass of filelog to hook into its read, add, cmp methods.
@@ -274,12 +260,13 @@
def __init__(self, opener, path, kwtemplater):
super(kwfilelog, self).__init__(opener, path)
self.kwtemplater = kwtemplater
+ self.kwtemplater.path = path
- 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.'''
@@ -299,28 +286,47 @@
return t2 != text
return revlog.revlog.cmp(self, node, text)
-def _status(ui, repo, *pats, **opts):
+def _iskwfile(f, kwtemplater, link):
+ return not link(f) and kwtemplater.matcher(f)
+
+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 _iskwfile(f, kwtemplater, mf.linkf)]
+ if candidates:
+ overwritten = []
+ 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))
+ _wwrite(repo, f, data, mf)
+ overwritten.append(f)
+ _normal(repo, overwritten)
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'))
@@ -328,12 +334,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
@@ -407,10 +408,14 @@
ui.quiet = not verbose
commands.branch(ui, repo, branchname)
ui.quiet = quiet
+ for name, cmd in ui.configitems('hooks'):
+ if name.split('.', 1)[0].find('commit') > -1:
+ repo.ui.setconfig('hooks', name, '')
+ ui.note(_('unhooked all commit hooks\n'))
ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
repo.commit(text=msg)
- pathinfo = ('', ' in %s' % path)[ui.verbose]
- demostatus('%s keywords expanded%s' % (kwstatus, pathinfo))
+ format = ui.verbose and ' in %s' % path or ''
+ demostatus('%s keywords expanded%s' % (kwstatus, format))
ui.write(repo.wread(fn))
ui.debug(_('\nremoving temporary repo %s\n') % tmpdir)
shutil.rmtree(tmpdir, ignore_errors=True)
@@ -432,7 +437,8 @@
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
@@ -440,7 +446,7 @@
files = modified + added + clean
files.sort()
# use the full definition of repo._link for backwards compatibility
- kwfiles = [f for f in files if ui.kwfmatcher(f)
+ kwfiles = [f for f in files if _kwtemplater.matcher(f)
and not os.path.islink(repo.wjoin(f))]
cwd = pats and repo.getcwd() or ''
allf = opts['all']
@@ -452,12 +458,9 @@
if allf or ignore:
kwfstats += (('I', [f for f in files if f not in kwfiles]),)
for char, filenames in kwfstats:
- if allf or ui.verbose:
- format = '%s %%s\n' % char
- else:
- format = '%s\n'
+ format = (allf or ui.verbose) and '%s %%s\n' % char or '%s\n'
for f in filenames:
- ui.write(format % repo.pathto(f, cwd))
+ ui.write(format % _pathto(repo, f, cwd))
def shrink(ui, repo, *pats, **opts):
'''revert expanded keywords in working directory
@@ -503,15 +506,15 @@
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.matcher(f):
+ return kwfilelog(self.sopener, f, _kwtemplater)
return filelog.filelog(self.sopener, f)
def _commit(self, files, text, user, date, match, force, lock, wlock,
@@ -540,21 +543,39 @@
_lock = lock
_wlock = wlock
del wlock, lock
+ _p1 = _p2 = None
try:
if not _wlock:
_wlock = self.wlock()
if not _lock:
_lock = self.lock()
+ # store and postpone commit hooks
+ commithooks = []
+ for name, cmd in ui.configitems('hooks'):
+ if name.split('.', 1)[0] == 'commit':
+ commithooks.append((name, cmd))
+ ui.setconfig('hooks', name, '')
+ if commithooks:
+ # store parents for commit hook environment
+ if p1 is None:
+ _p1, _p2 = repo.dirstate.parents()
+ else:
+ _p1, _p2 = p1, p2 or nullid
+ _p1 = hex(_p1)
+ if _p2 == nullid:
+ _p2 = ''
+ else:
+ _p2 = hex(_p2)
+
node = self._commit(files, text, user, date, match, force,
_lock, _wlock, force_editor, p1, p2, extra)
+
+ # restore commit hooks
+ 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:
del _wlock, _lock