##// END OF EJS Templates
Expand import * to allow Pyflakes to find problems
Expand import * to allow Pyflakes to find problems

File last commit:

r6211:f89fd07f default
r6211:f89fd07f default
Show More
keyword.py
556 lines | 20.9 KiB | text/x-python | PythonLexer
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 # keyword.py - $Keyword$ expansion for Mercurial
#
Christian Ebert
keyword: fix some doc strings; update copyright
r5831 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
#
# $Id$
#
# Keyword expansion hack against the grain of a DSCM
#
# 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.
#
# For in-depth discussion refer to
# <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>.
#
# Keyword expansion is based on Mercurial's changeset template mappings.
#
# Binary files are not touched.
#
# Setup in hgrc:
#
# [extensions]
# # enable extension
# hgext.keyword =
#
# Files to act upon/ignore are specified in the [keyword] section.
# Customized keyword template mappings in the [keywordmaps] section.
#
# Run "hg help keyword" and "hg kwdemo" to get info on configuration.
'''keyword expansion in local repositories
This extension expands RCS/CVS-like or self-customized $Keywords$
in tracked text files selected by your configuration.
Keywords are only expanded in local repositories and not stored in
the change history. The mechanism can be regarded as a convenience
for the current user or for archive distribution.
Configuration is done in the [keyword] and [keywordmaps] sections
of hgrc files.
Example:
[keyword]
# expand keywords in every python file except those matching "x*"
**.py =
x* = ignore
Note: the more specific you are in your filename patterns
the less you lose speed in huge repos.
For [keywordmaps] template mapping and expansion demonstration and
control run "hg kwdemo".
An additional date template filter {date|utcdate} is provided.
The default template mappings (view with "hg kwdemo -d") can be replaced
with customized keywords and templates.
Again, run "hg kwdemo" to control the results of your config changes.
Before changing/disabling active keywords, run "hg kwshrink" to avoid
the risk of inadvertedly storing expanded keywords in the change history.
To force expansion after enabling it, or a configuration change, run
"hg kwexpand".
Christian Ebert
keyword: support mq; handle (q)record more gracefully...
r5884 Also, when committing with the record extension or using mq's qrecord, be aware
that keywords cannot be updated. Again, run "hg kwexpand" on the files in
question to update keyword expansions after all changes have been checked in.
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 Expansions spanning more than one line and incremental expansions,
like CVS' $Log$, are not supported. A keyword template map
"Log = {desc}" expands to the first line of the changeset description.
'''
Matt Mackall
templates: move filters to their own module...
r5976 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog
from mercurial import patch, localrepo, templater, templatefilters, util
Christian Ebert
keyword: no expansion in web diffs...
r6072 from mercurial.hgweb import webcommands
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from mercurial.node import nullid, hex
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 from mercurial.i18n import _
Christian Ebert
keyword: avoid os import by using util.splitpath
r6069 import re, shutil, tempfile, time
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
commands.optionalrepo += ' kwdemo'
Christian Ebert
keyword: nokwcommands, restricted string variables at top level...
r6024 # hg commands that do not act on keywords
Alexis S. L. Carvalho
keyword: remove "identify" and "remove" from nokwcommands...
r6157 nokwcommands = ('add addremove bundle copy export grep incoming init'
' log outgoing push rename rollback tip'
Christian Ebert
keyword: add glog to nokwcommands
r6082 ' convert email glog')
Christian Ebert
keyword: nokwcommands, restricted string variables at top level...
r6024
Christian Ebert
keyword: detect restricted commands thru variable
r5961 # hg commands that trigger expansion only when writing to working dir,
# not when reading filelog, and unexpand when reading from working dir
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 restricted = 'record qfold qimport qnew qpush qrefresh qrecord'
Christian Ebert
keyword: detect restricted commands thru variable
r5961
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 def utcdate(date):
'''Returns hgdate in cvs-like UTC format.'''
return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
Christian Ebert
keyword: support mq; handle (q)record more gracefully...
r5884
Christian Ebert
keyword: make main class and hg command accessible...
r6115 # make keyword tools accessible
kwtools = {'templater': None, 'hgcmd': None}
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052 # store originals of monkeypatches
_patchfile_init = patch.patchfile.__init__
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 _patch_diff = patch.diff
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052 _dispatch_parse = dispatch._parse
def _kwpatchfile_init(self, ui, fname, missing=False):
'''Monkeypatch/wrap patch.patchfile.__init__ to avoid
rejects or conflicts due to expanded keywords in working dir.'''
_patchfile_init(self, ui, fname, missing=missing)
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 # shrink keywords read from working dir
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwt = kwtools['templater']
self.lines = kwt.shrinklines(self.fname, self.lines)
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
fp=None, changes=None, opts=None):
Christian Ebert
keyword: make main class and hg command accessible...
r6115 '''Monkeypatch patch.diff to avoid expansion except when
comparing against working dir.'''
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 if node2 is not None:
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwtools['templater'].matcher = util.never
Christian Ebert
keyword: do not inspect node1 for diff if node2 is given
r6117 elif node1 is not None and node1 != repo.changectx().node():
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwtools['templater'].restrict = True
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 _patch_diff(repo, node1=node1, node2=node2, files=files, match=match,
fp=fp, changes=changes, opts=opts)
Christian Ebert
keyword: enable all monkey patches using _kwtemplater at reposetup...
r6081 def _kwweb_changeset(web, req, tmpl):
'''Wraps webcommands.changeset turning off keyword expansion.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwtools['templater'].matcher = util.never
Christian Ebert
keyword: enable all monkey patches using _kwtemplater at reposetup...
r6081 return web.changeset(tmpl, web.changectx(req))
def _kwweb_filediff(web, req, tmpl):
'''Wraps webcommands.filediff turning off keyword expansion.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwtools['templater'].matcher = util.never
Christian Ebert
keyword: enable all monkey patches using _kwtemplater at reposetup...
r6081 return web.filediff(tmpl, web.filectx(req))
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052 def _kwdispatch_parse(ui, args):
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 '''Monkeypatch dispatch._parse to obtain running hg command.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args)
kwtools['hgcmd'] = cmd
return cmd, func, args, options, cmdoptions
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052
Christian Ebert
keyword: enable all monkey patches using _kwtemplater at reposetup...
r6081 # dispatch._parse is run before reposetup, so wrap it here
Christian Ebert
keyword: monkeypatch dispatch._parse to avoid redundant run...
r6052 dispatch._parse = _kwdispatch_parse
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
class kwtemplater(object):
'''
Sets up keyword templates, corresponding keyword regex, and
provides keyword substitution functions.
'''
templates = {
'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}',
}
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def __init__(self, ui, repo, inc, exc):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 self.ui = ui
self.repo = repo
self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
Christian Ebert
keyword: make main class and hg command accessible...
r6115 self.restrict = kwtools['hgcmd'] in restricted.split()
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
kwmaps = self.ui.configitems('keywordmaps')
if kwmaps: # override default templates
kwmaps = [(k, templater.parsestring(v, quoted=False))
for (k, v) in kwmaps]
self.templates = dict(kwmaps)
escaped = map(re.escape, self.templates.keys())
kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
self.re_kw = re.compile(kwpat)
Matt Mackall
templates: move filters to their own module...
r5976 templatefilters.filters['utcdate'] = utcdate
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
False, '', False)
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def getnode(self, path, fnode):
'''Derives changenode from file path and filenode.'''
# used by kwfilelog.read and kwexpand
c = context.filectx(self.repo, path, fileid=fnode)
return c.node()
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def substitute(self, data, path, node, subfunc):
'''Replaces keywords in data with expanded template.'''
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 def kwsub(mobj):
kw = mobj.group(1)
self.ct.use_template(self.templates[kw])
self.ui.pushbuffer()
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 self.ct.show(changenode=node, root=self.repo.root, file=path)
Christian Ebert
keyword: split line continuation in 2 steps (style)
r6023 ekw = templatefilters.firstline(self.ui.popbuffer())
return '$%s: %s $' % (kw, ekw)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 return subfunc(kwsub, data)
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def expand(self, path, node, data):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 '''Returns data with keywords expanded.'''
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 if not self.restrict and self.matcher(path) and not util.binary(data):
changenode = self.getnode(path, node)
return self.substitute(data, path, changenode, self.re_kw.sub)
return data
def iskwfile(self, path, islink):
'''Returns true if path matches [keyword] pattern
and is not a symbolic link.
Caveat: localrepository._link fails on Windows.'''
return self.matcher(path) and not islink(path)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def overwrite(self, node=None, expand=True, files=None):
'''Overwrites selected files expanding/shrinking keywords.'''
ctx = self.repo.changectx(node)
mf = ctx.manifest()
if node is not None: # commit
files = [f for f in ctx.files() if f in mf]
notify = self.ui.debug
else: # kwexpand/kwshrink
notify = self.ui.note
candidates = [f for f in files if self.iskwfile(f, mf.linkf)]
if candidates:
self.restrict = True # do not expand when reading
candidates.sort()
action = expand and 'expanding' or 'shrinking'
for f in candidates:
fp = self.repo.file(f)
data = fp.read(mf[f])
if util.binary(data):
continue
if expand:
changenode = node or self.getnode(f, mf[f])
data, found = self.substitute(data, f, changenode,
self.re_kw.subn)
else:
found = self.re_kw.search(data)
if found:
notify(_('overwriting %s %s keywords\n') % (f, action))
self.repo.wwrite(f, data, mf.flags(f))
self.repo.dirstate.normal(f)
self.restrict = False
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def shrinktext(self, text):
'''Unconditionally removes all keyword substitutions from text.'''
return self.re_kw.sub(r'$\1$', text)
def shrink(self, fname, text):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 '''Returns text with all keyword substitutions removed.'''
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 if self.matcher(fname) and not util.binary(text):
return self.shrinktext(text)
return text
def shrinklines(self, fname, lines):
'''Returns lines with keyword substitutions removed.'''
if self.matcher(fname):
text = ''.join(lines)
if not util.binary(text):
return self.shrinktext(text).splitlines(True)
return lines
def wread(self, fname, data):
'''If in restricted mode returns data read from wdir with
keyword substitutions removed.'''
return self.restrict and self.shrink(fname, data) or data
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
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)
Christian Ebert
keyword: make main class and hg command accessible...
r6115 self.kwt = kwtools['templater']
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 self.path = path
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
def read(self, node):
'''Expands keywords when reading filelog.'''
data = super(kwfilelog, self).read(node)
Christian Ebert
keyword: make main class and hg command accessible...
r6115 return self.kwt.expand(self.path, node, data)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
def add(self, text, meta, tr, link, p1=None, p2=None):
'''Removes keyword substitutions when adding to filelog.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 text = self.kwt.shrink(self.path, text)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
def cmp(self, node, text):
'''Removes keyword substitutions for comparison.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 text = self.kwt.shrink(self.path, text)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 if self.renamed(node):
t2 = super(kwfilelog, self).read(node)
return t2 != text
return revlog.revlog.cmp(self, node, text)
Christian Ebert
keyword: make main class and hg command accessible...
r6115 def _status(ui, repo, kwt, *pats, **opts):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 '''Bails out if [keyword] configuration is not active.
Returns status of working directory.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 if kwt:
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 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 _kwfwrite(ui, repo, expand, *pats, **opts):
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 '''Selects files and passes them to kwtemplater.overwrite.'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwt = kwtools['templater']
status = _status(ui, repo, kwt, *pats, **opts)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 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'))
wlock = lock = None
try:
wlock = repo.wlock()
lock = repo.lock()
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwt.overwrite(expand=expand, files=clean)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 finally:
del wlock, lock
def demo(ui, repo, *args, **opts):
'''print [keywordmaps] configuration and an expansion example
Show current, custom, or default keyword template maps
and their expansion.
Extend current configuration by specifying maps as arguments
and optionally by reading from an additional hgrc file.
Override current keyword template maps with "default" option.
'''
def demostatus(stat):
ui.status(_('\n\t%s\n') % stat)
def demoitems(section, items):
ui.write('[%s]\n' % section)
for k, v in items:
ui.write('%s = %s\n' % (k, v))
msg = 'hg keyword config and expansion example'
kwstatus = 'current'
fn = 'demo.txt'
branchname = 'demobranch'
tmpdir = tempfile.mkdtemp('', 'kwdemo.')
ui.note(_('creating temporary repo at %s\n') % tmpdir)
repo = localrepo.localrepository(ui, path=tmpdir, create=True)
ui.setconfig('keyword', fn, '')
if args or opts.get('rcfile'):
kwstatus = 'custom'
if opts.get('rcfile'):
ui.readconfig(opts.get('rcfile'))
if opts.get('default'):
kwstatus = 'default'
kwmaps = kwtemplater.templates
if ui.configitems('keywordmaps'):
# override maps from optional rcfile
Christian Ebert
keyword: improve use of dicts...
r5946 for k, v in kwmaps.iteritems():
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 ui.setconfig('keywordmaps', k, v)
elif args:
# simulate hgrc parsing
rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
fp = repo.opener('hgrc', 'w')
fp.writelines(rcmaps)
fp.close()
ui.readconfig(repo.join('hgrc'))
if not opts.get('default'):
kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
reposetup(ui, repo)
for k, v in ui.configitems('extensions'):
if k.endswith('keyword'):
extension = '%s = %s' % (k, v)
break
demostatus('config using %s keyword template maps' % kwstatus)
ui.write('[extensions]\n%s\n' % extension)
demoitems('keyword', ui.configitems('keyword'))
Christian Ebert
keyword: improve use of dicts...
r5946 demoitems('keywordmaps', kwmaps.iteritems())
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
repo.wopener(fn, 'w').write(keywords)
repo.add([fn])
path = repo.wjoin(fn)
ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
ui.note(keywords)
ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
# silence branch command if not verbose
quiet = ui.quiet
Christian Ebert
keyword: clean up quiet setting in kwdemo and adding of untracked kwfiles
r5825 ui.quiet = not ui.verbose
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 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)
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)
def expand(ui, repo, *pats, **opts):
'''expand keywords in working directory
Run after (re)enabling keyword expansion.
kwexpand refuses to run if given files contain local changes.
'''
# 3rd argument sets expansion to True
_kwfwrite(ui, repo, True, *pats, **opts)
def files(ui, repo, *pats, **opts):
'''print files currently configured for keyword expansion
Crosscheck which files in working directory are potential targets for
keyword expansion.
That is, files matched by [keyword] config patterns but not symlinks.
'''
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwt = kwtools['templater']
status = _status(ui, repo, kwt, *pats, **opts)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 modified, added, removed, deleted, unknown, ignored, clean = status
Christian Ebert
keyword: clean up quiet setting in kwdemo and adding of untracked kwfiles
r5825 files = modified + added + clean
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 if opts.get('untracked'):
Christian Ebert
keyword: clean up quiet setting in kwdemo and adding of untracked kwfiles
r5825 files += unknown
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 files.sort()
Patrick Mezard
keyword: fix symlink detection under Windows
r6060 wctx = repo.workingctx()
islink = lambda p: 'l' in wctx.fileflags(p)
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwfiles = [f for f in files if kwt.iskwfile(f, islink)]
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 cwd = pats and repo.getcwd() or ''
kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
if opts.get('all') or opts.get('ignore'):
kwfstats += (('I', [f for f in files if f not in kwfiles]),)
for char, filenames in kwfstats:
format = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
for f in filenames:
ui.write(format % repo.pathto(f, cwd))
def shrink(ui, repo, *pats, **opts):
'''revert expanded keywords in working directory
Run before changing/disabling active keywords
or if you experience problems with "hg import" or "hg merge".
kwshrink refuses to run if given files contain local changes.
'''
# 3rd argument sets expansion to False
_kwfwrite(ui, repo, False, *pats, **opts)
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.'''
Christian Ebert
keyword: safeguards against erroneous behaviour or aborts...
r6051 try:
Christian Ebert
keyword: do not inspect node1 for diff if node2 is given
r6117 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
Christian Ebert
keyword: avoid os import by using util.splitpath
r6069 or '.hg' in util.splitpath(repo.root)
Christian Ebert
keyword: safeguards against erroneous behaviour or aborts...
r6051 or repo._url.startswith('bundle:')):
return
except AttributeError:
pass
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
Christian Ebert
keyword: safeguards against erroneous behaviour or aborts...
r6051 inc, exc = [], ['.hg*']
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 for pat, opt in ui.configitems('keyword'):
if opt != 'ignore':
inc.append(pat)
else:
exc.append(pat)
if not inc:
return
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
class kwrepo(repo.__class__):
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 def file(self, f):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 if f[0] == '/':
f = f[1:]
Christian Ebert
keyword: move expand/shrink decisions into kwtemplater...
r6114 return kwfilelog(self.sopener, f)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
Christian Ebert
keyword: support mq; handle (q)record more gracefully...
r5884 def wread(self, filename):
data = super(kwrepo, self).wread(filename)
Christian Ebert
keyword: make main class and hg command accessible...
r6115 return kwt.wread(filename, data)
Christian Ebert
keyword: support mq; handle (q)record more gracefully...
r5884
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 def commit(self, files=None, text='', user=None, date=None,
match=util.always, force=False, force_editor=False,
Christian Ebert
keyword: add empty_ok argument to kwrepo.commit
r6022 p1=None, p2=None, extra={}, empty_ok=False):
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 wlock = lock = None
_p1 = _p2 = None
try:
wlock = self.wlock()
lock = self.lock()
# store and postpone commit hooks
Christian Ebert
keyword: improve use of dicts...
r5946 commithooks = {}
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 for name, cmd in ui.configitems('hooks'):
if name.split('.', 1)[0] == 'commit':
Christian Ebert
keyword: improve use of dicts...
r5946 commithooks[name] = cmd
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 ui.setconfig('hooks', name, None)
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 = super(kwrepo,
self).commit(files=files, text=text, user=user,
date=date, match=match, force=force,
force_editor=force_editor,
Christian Ebert
keyword: add empty_ok argument to kwrepo.commit
r6022 p1=p1, p2=p2, extra=extra,
empty_ok=empty_ok)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
# restore commit hooks
Christian Ebert
keyword: improve use of dicts...
r5946 for name, cmd in commithooks.iteritems():
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 ui.setconfig('hooks', name, cmd)
if node is not None:
Christian Ebert
keyword: make main class and hg command accessible...
r6115 kwt.overwrite(node=node)
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815 repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
return node
finally:
del wlock, lock
repo.__class__ = kwrepo
patch.patchfile.__init__ = _kwpatchfile_init
Christian Ebert
keyword: monkeypatch patch.diff for non-interactive diffs...
r6092 patch.diff = _kw_diff
Christian Ebert
keyword: enable all monkey patches using _kwtemplater at reposetup...
r6081 webcommands.changeset = webcommands.rev = _kwweb_changeset
webcommands.filediff = webcommands.diff = _kwweb_filediff
Christian Ebert
Add extension for filewise RCS-keyword expansion in working dir...
r5815
cmdtable = {
'kwdemo':
(demo,
[('d', 'default', None, _('show default keyword template maps')),
('f', 'rcfile', [], _('read maps from rcfile'))],
_('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
'kwexpand': (expand, commands.walkopts,
_('hg kwexpand [OPTION]... [FILE]...')),
'kwfiles':
(files,
[('a', 'all', None, _('show keyword status flags of all files')),
('i', 'ignore', None, _('show files excluded from expansion')),
('u', 'untracked', None, _('additionally show untracked files')),
] + commands.walkopts,
_('hg kwfiles [OPTION]... [FILE]...')),
'kwshrink': (shrink, commands.walkopts,
_('hg kwshrink [OPTION]... [FILE]...')),
}