Discard wread/wwrite approach, merge with stable
authorChristian Ebert <blacktrash@gmx.net>
Wed, 06 Feb 2008 17:25:37 +0100
changeset 378 0683aaf458d8
parent 377 ce5eb725d0c6 (current diff)
parent 375 ed160b097bad (diff)
child 381 17e94f77de6a
Discard wread/wwrite approach, merge with stable A basic "hg update" did not give correct results.
hgkw/keyword.py
tests/test-keyword
tests/test-keyword.out
--- a/hgkw/keyword.py	Wed Feb 06 11:32:34 2008 +0100
+++ b/hgkw/keyword.py	Wed Feb 06 17:25:37 2008 +0100
@@ -80,19 +80,29 @@
 "Log = {desc}" expands to the first line of the changeset description.
 '''
 
-from mercurial import commands, cmdutil, context, localrepo
-from mercurial import patch, revlog, templater, templatefilters, util
+from mercurial import commands, cmdutil, context, dispatch, filelog, revlog
+from mercurial import patch, localrepo, templater, templatefilters, util
 from mercurial.node import *
-from mercurial.hgweb import webcommands
 from mercurial.i18n import _
-import mimetypes, re, shutil, tempfile, time
+import re, shutil, sys, tempfile, time
 
 commands.optionalrepo += ' kwdemo'
 
+# hg commands that do not act on keywords
+nokwcommands = ('add addremove bundle copy export grep identify incoming init'
+                ' log outgoing push remove rename rollback tip convert')
+
+# 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):
     '''
     Sets up keyword templates, corresponding keyword regex, and
@@ -108,11 +118,13 @@
         'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
     }
 
-    def __init__(self, ui, repo, inc, exc):
+    def __init__(self, ui, repo, inc, exc, restricted):
         self.ui = ui
         self.repo = repo
         self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
-        self.ctx = None
+        self.restricted = restricted
+        self.commitnode = None
+        self.path = ''
 
         kwmaps = self.ui.configitems('keywordmaps')
         if kwmaps: # override default templates
@@ -127,67 +139,102 @@
         self.ct = cmdutil.changeset_templater(self.ui, self.repo,
                                               False, '', False)
 
-    def substitute(self, path, data, node, subfunc):
-        '''Obtains file's changenode if node not given,
+    def substitute(self, node, data, subfunc):
+        '''Obtains file's changenode if commit node not given,
         and calls given substitution function.'''
-        if node is None:
-            # kwrepo.wwrite except when overwriting on commit
-            try:
-                fnode = self.ctx.filenode(path)
-                fl = self.repo.file(path)
-                c = context.filectx(self.repo, path, fileid=fnode, filelog=fl)
-                node = c.node()
-            except revlog.LookupError:
-                # eg: convert
-                return subfunc == self.re_kw.sub and data or (data, None)
+        if self.commitnode:
+            fnode = self.commitnode
+        else:
+            c = context.filectx(self.repo, self.path, fileid=node)
+            fnode = 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=node, root=self.repo.root, file=path)
+            self.ct.show(changenode=fnode, root=self.repo.root, file=self.path)
             ekw = templatefilters.firstline(self.ui.popbuffer())
             return '$%s: %s $' % (kw, ekw)
 
         return subfunc(kwsub, data)
 
-    def expand(self, path, data, ctx):
+    def expand(self, node, data):
         '''Returns data with keywords expanded.'''
-        if util.binary(data):
+        if self.restricted or util.binary(data):
             return data
-        if self.ctx is None:
-            self.ctx = ctx or self.repo.changectx()
-        return self.substitute(path, data, None, self.re_kw.sub)
+        return self.substitute(node, data, self.re_kw.sub)
 
-    def process(self, path, data, expand, ctx, node):
+    def process(self, node, data, expand):
         '''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:
-            self.ctx = ctx
-            return self.substitute(path, data, node, self.re_kw.subn)
-        return self.re_kw.subn(r'$\1$', data)
+            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
 
-    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)
+    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)
+
 
 # store original patch.patchfile.__init__
 _patchfile_init = patch.patchfile.__init__
 
+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)
 
-def _iskwfile(f, link, kwt):
-    return not link(f) and kwt.matcher(f)
+    if _kwtemplater.matcher(self.fname):
+        # shrink keywords read from working dir
+        kwshrunk = _kwtemplater.shrink(''.join(self.lines))
+        self.lines = kwshrunk.splitlines(True)
+
+
+def _iskwfile(f, link):
+    return not link(f) and _kwtemplater.matcher(f)
 
 def _status(ui, repo, *pats, **opts):
     '''Bails out if [keyword] configuration is not active.
     Returns status of working directory.'''
-    if hasattr(repo, '_kwt'):
+    if _kwtemplater:
         files, match, anypats = cmdutil.matchpats(repo, pats, opts)
         return repo.status(files=files, match=match, list_clean=True)
     if ui.configitems('keyword'):
@@ -198,22 +245,22 @@
     '''Overwrites selected files expanding/shrinking keywords.'''
     ctx = repo.changectx(node)
     mf = ctx.manifest()
-    if node is not None:
-        # commit
+    if node is not None:   # commit
+        _kwtemplater.commitnode = node
         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, repo._kwt)]
+    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:
-            data, kwfound = repo._wreadkwct(f, expand, ctx, node)
+            fp = repo.file(f, kwmatch=True)
+            data, kwfound = fp.kwctread(mf[f], expand)
             if kwfound:
                 notify(_('overwriting %s %s keywords\n') % (f, action))
-                repo.wwrite(f, data, mf.flags(f), overwrite=True)
+                repo.wwrite(f, data, mf.flags(f))
                 repo.dirstate.normal(f)
 
 def _kwfwrite(ui, repo, expand, *pats, **opts):
@@ -230,35 +277,6 @@
     finally:
         del wlock, lock
 
-def cat(ui, repo, file1, *pats, **opts):
-    '''output the current or given revision of files expanding keywords
-
-    Print the specified files as they were at the given revision.
-    If no revision is given, the parent of the working directory is used,
-    or tip if no revision is checked out.
-
-    Output may be to a file, in which case the name of the file is
-    given using a format string.  The formatting rules are the same as
-    for the export command, with the following additions:
-
-    %s   basename of file being printed
-    %d   dirname of file being printed, or '.' if in repo root
-    %p   root-relative path name of file being printed
-    '''
-    ctx = repo.changectx(opts['rev'])
-    err = 1
-    for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts,
-                                             ctx.node()):
-        fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
-        data = ctx.filectx(abs).data()
-        try:
-            if repo._kwt.matcher(abs):
-                data = repo._kwt.expand(abs, data, ctx)
-        except AttributeError:
-            pass
-        fp.write(data)
-        err = 0
-    return err
 
 def demo(ui, repo, *args, **opts):
     '''print [keywordmaps] configuration and an expansion example
@@ -336,7 +354,7 @@
     repo.commit(text=msg)
     format = ui.verbose and ' in %s' % path or ''
     demostatus('%s keywords expanded%s' % (kwstatus, format))
-    ui.write(repo.wopener(fn).read())
+    ui.write(repo.wread(fn))
     ui.debug(_('\nremoving temporary repo %s\n') % tmpdir)
     shutil.rmtree(tmpdir, ignore_errors=True)
 
@@ -363,7 +381,7 @@
     if opts.get('untracked'):
         files += unknown
     files.sort()
-    kwfiles = [f for f in files if _iskwfile(f, repo._link, repo._kwt)]
+    kwfiles = [f for f in files if _iskwfile(f, repo._link)]
     cwd = pats and repo.getcwd() or ''
     kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
     if opts.get('all') or opts.get('ignore'):
@@ -386,10 +404,31 @@
 
 
 def reposetup(ui, repo):
-    if not repo.local() or repo.root.endswith('/.hg/patches'):
+    '''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
 
-    inc, exc = [], ['.hgtags', '.hg_archival.txt']
+    hgcmd, func, args, opts, cmdopts = dispatch._parse(ui, sys.argv[1:])
+    if hgcmd in nokwcommands.split():
+        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']
     for pat, opt in ui.configitems('keyword'):
         if opt != 'ignore':
             inc.append(pat)
@@ -398,29 +437,24 @@
     if not inc:
         return
 
+    global _kwtemplater
+    _restricted = hgcmd in restricted.split()
+    _kwtemplater = kwtemplater(ui, repo, inc, exc, _restricted)
+
     class kwrepo(repo.__class__):
-        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 self._kwt.process(filename, data, expand, ctx, node)
+        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 wread(self, filename):
             data = super(kwrepo, self).wread(filename)
-            if self._kwt.matcher(filename):
-                return self._kwt.shrink(data)
+            if _restricted and _kwtemplater.matcher(filename):
+                return _kwtemplater.shrink(data)
             return data
 
-        def wwrite(self, filename, data, flags, overwrite=False):
-            if not overwrite and self._kwt.matcher(filename):
-                data = self._kwt.expand(filename, data, None)
-            super(kwrepo, self).wwrite(filename, data, flags)
-
-        def wwritedata(self, filename, data):
-            if self._kwt.matcher(filename):
-                data = self._kwt.expand(filename, data, None)
-            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={}, empty_ok=False):
@@ -464,50 +498,11 @@
             finally:
                 del wlock, lock
 
-    kwt = kwrepo._kwt = kwtemplater(ui, repo, inc, exc)
-
-    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)
-
-        if kwt.matcher(self.fname):
-            # shrink keywords read from working dir
-            kwshrunk = kwt.shrink(''.join(self.lines))
-            self.lines = kwshrunk.splitlines(True)
-
-    def kwweb_rawfile(web, req, tmpl):
-        '''Monkeypatch webcommands.rawfile so it expands keywords.'''
-        path = web.cleanpath(req.form.get('file', [''])[0])
-        if not path:
-            content = web.manifest(tmpl, web.changectx(req), path)
-            req.respond(webcommands.HTTP_OK, web.ctype)
-            return content
-        try:
-            fctx = web.filectx(req)
-        except revlog.LookupError:
-            content = web.manifest(tmpl, web.changectx(req), path)
-            req.respond(webcommands.HTTP_OK, web.ctype)
-            return content
-        path = fctx.path()
-        text = fctx.data()
-        if kwt.matcher(path):
-            text = kwt.expand(path, text, web.changectx(req))
-        mt = mimetypes.guess_type(path)[0]
-        if mt is None or util.binary(text):
-            mt = mt or 'application/octet-stream'
-        req.respond(webcommands.HTTP_OK, mt, path, len(text))
-        return [text]
-
     repo.__class__ = kwrepo
-    patch.patchfile.__init__ = kwpatchfile_init
-    webcommands.rawfile = kwweb_rawfile
+    patch.patchfile.__init__ = _kwpatchfile_init
 
 
 cmdtable = {
-    'kwcat':
-        (cat, commands.table['cat'][1],
-         _('hg kwcat [OPTION]... FILE...')),
     'kwdemo':
         (demo,
          [('d', 'default', None, _('show default keyword template maps')),
--- a/tests/test-keyword	Wed Feb 06 11:32:34 2008 +0100
+++ b/tests/test-keyword	Wed Feb 06 17:25:37 2008 +0100
@@ -24,29 +24,17 @@
 
 hg --quiet kwdemo "Branch = {branches}"
 
-hg init t
-cd t
-echo % kwshrink should exit silently in empty/invalid repo
-hg kwshrink
-
-echo % symlink nonexisting file
-ln -s a sym
-echo % commit hook must fail with missing file
-hg --debug commit -A -msym -d '0 0' -u 'User Name <user@example.com>'
-echo % bundle null revision containing empty symlink
-hg bundle --base null ../test-keyword.hg
-cd ..
-
 hg init Test
 cd Test
 
-echo % pull from bundle
-hg pull --traceback -u ../test-keyword.hg
+echo % kwshrink should exit silently in empty/invalid repo
+hg kwshrink
 
 echo 'expand $Id$' > a
 echo 'do not process $Id:' >> a
 echo 'xxx $' >> a
 echo 'ignore $Id$' > b
+ln -s a sym
 echo % cat
 cat sym a b
 
@@ -62,15 +50,15 @@
 hg status
 
 echo % commit
-hg --debug commit -mabsym -d '1 0' -u 'User Name <user@example.com>'
+hg --debug commit -mabsym -d '0 0' -u 'User Name <user@example.com>'
 echo % status
 hg status
 echo % identify
 hg --quiet identify
 echo % cat
 cat sym a b
-echo % hg kwcat
-hg kwcat sym a b
+echo % hg cat
+hg cat sym a b
 
 echo
 echo % diff a hooktest
@@ -96,18 +84,14 @@
 echo '$Id$' > c
 echo 'tests for different changenodes' >> c
 echo % commit c
-hg commit -A -mcndiff -d '2 0' -u 'User Name <user@example.com>'
+hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
 echo % force expansion
 hg -v kwexpand
 echo % compare changenodes in a c
 cat a c
 
-echo % qinit -c
-hg qinit -c
 echo % qimport
 hg qimport -r tip -n mqtest.diff
-echo % qcommit
-hg qcommit -mqtest
 echo % keywords should not be expanded in patch
 cat .hg/patches/mqtest.diff
 echo % qpop
@@ -126,7 +110,7 @@
 hg kwfiles
 
 echo % commit
-hg --debug commit -ma2c -d '2 0' -u 'User Name <user@example.com>'
+hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
 echo % cat a c
 cat a c
 echo % touch copied c after 1 second
@@ -139,7 +123,7 @@
 hg kwfiles
 
 echo % diff --rev
-hg diff --rev 1 | grep -v 'b/c'
+hg diff --rev 0 | grep -v 'b/c'
 
 echo % rollback
 hg rollback
@@ -160,8 +144,8 @@
 
 echo % cat
 cat sym a b
-echo % hg kwcat
-hg kwcat sym a b
+echo % hg cat
+hg cat sym a b
 
 echo
 echo '$Xinfo$' >> a
@@ -176,15 +160,15 @@
 hg status
 
 echo % commit
-hg --debug commit -l log -d '3 0' -u 'User Name <user@example.com>'
+hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
 rm log
 echo % status
 hg status
 
 echo % cat
 cat sym a b
-echo % hg kwcat
-hg kwcat sym a b
+echo % hg cat
+hg cat sym a b
 echo
 
 echo % remove
@@ -203,7 +187,7 @@
 
 echo % clone to test incoming
 cd ..
-hg clone -r1 Test Test-a
+hg clone -r0 Test Test-a
 cd Test-a
 cat <<EOF >> .hg/hgrc
 [paths]
@@ -216,7 +200,7 @@
 sed -e 's/Id.*/& rejecttest/' a > a.new
 mv a.new a
 echo % commit rejecttest
-hg --debug commit -m'rejects?' -d '4 0' -u 'User Name <user@example.com>'
+hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
 echo % export
 hg export -o ../rejecttest.diff tip
 
@@ -240,7 +224,7 @@
 echo % kwexpand x/a should abort
 hg --verbose kwexpand x/a
 cd x
-hg --debug commit -m xa -d '4 0' -u 'User Name <user@example.com>'
+hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
 echo % cat a
 cat a
 echo % kwshrink a inside directory x
@@ -252,11 +236,18 @@
 echo % kwexpand nonexistent
 hg kwexpand nonexistent
 
+echo % switch off expansion
 echo % kwshrink with unknown file u
 cp a u
 hg --verbose kwshrink
 echo % cat
 cat sym a b
-echo % hg kwcat
-hg kwcat sym a b
+echo % hg cat
+hg cat sym a b
 echo
+rm $HGRCPATH
+echo % cat
+cat sym a b
+echo % hg cat
+hg cat sym a b
+echo
--- a/tests/test-keyword.out	Wed Feb 06 11:32:34 2008 +0100
+++ b/tests/test-keyword.out	Wed Feb 06 17:25:37 2008 +0100
@@ -46,7 +46,6 @@
 
 list of commands:
 
- kwcat      output the current or given revision of files expanding keywords
  kwdemo     print [keywordmaps] configuration and an expansion example
  kwexpand   expand keywords in working directory
  kwfiles    print files currently configured for keyword expansion
@@ -85,23 +84,6 @@
 Branch = {branches}
 $Branch: demobranch $
 % kwshrink should exit silently in empty/invalid repo
-% symlink nonexisting file
-% commit hook must fail with missing file
-cp: a: No such file or directory
-adding sym
-sym
-running hook commit.test: cp a hooktest
-warning: commit.test hook exited with status 1
-% bundle null revision containing empty symlink
-1 changesets found
-% pull from bundle
-pulling from ../test-keyword.hg
-requesting all changes
-adding changesets
-adding manifests
-adding file changes
-added 1 changesets with 1 changes to 1 files
-1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % cat
 expand $Id$
 do not process $Id:
@@ -113,38 +95,43 @@
 % addremove
 adding a
 adding b
+adding sym
 % status
 A a
 A b
+A sym
 % default keyword expansion including commit hook
 % interrupted commit should not change state or run commit hook
 a
 b
+sym
 transaction abort!
 rollback completed
 abort: empty commit message
 % status
 A a
 A b
+A sym
 % commit
 a
 b
+sym
 overwriting a expanding keywords
 running hook commit.test: cp a hooktest
 % status
 ? hooktest
 % identify
-cecf1e2cc3d3
+f782df5f9602
 % cat
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
 ignore $Id$
-% hg kwcat
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+% hg cat
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
 ignore $Id$
@@ -156,10 +143,10 @@
 % update
 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % cat
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
 ignore $Id$
@@ -170,25 +157,23 @@
 overwriting a expanding keywords
 overwriting c expanding keywords
 % compare changenodes in a c
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
-$Id: c,v c033759cd8fd 1970/01/01 00:00:02 user $
+$Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $
 tests for different changenodes
-% qinit -c
 % qimport
-% qcommit
 % keywords should not be expanded in patch
 # HG changeset patch
 # User User Name <user@example.com>
-# Date 2 0
-# Node ID c033759cd8fd162b7863dc4e5d1eea433603880f
-# Parent  cecf1e2cc3d3447fcc20dd4eac5c4faa8a615df3
+# Date 1 0
+# Node ID ba4426d1938ec9673e03ab274d88c44e24618f7f
+# Parent  f782df5f9602483b4e51c31a12315f353bba380c
 cndiff
 
-diff -r cecf1e2cc3d3 -r c033759cd8fd c
+diff -r f782df5f9602 -r ba4426d1938e c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
-+++ b/c	Thu Jan 01 00:00:02 1970 +0000
++++ b/c	Thu Jan 01 00:00:01 1970 +0000
 @@ -0,0 +1,2 @@
 +$Id$
 +tests for different changenodes
@@ -198,7 +183,7 @@
 applying mqtest.diff
 Now at: mqtest.diff
 % cat
-$Id: c,v c033759cd8fd 1970/01/01 00:00:02 user $
+$Id: c,v ba4426d1938e 1970/01/01 00:00:01 user $
 tests for different changenodes
 % qpop and move on
 Patch queue now empty
@@ -211,10 +196,10 @@
  c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
 overwriting c expanding keywords
 % cat a c
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
-expand $Id: c,v 1fed52d26fd0 1970/01/01 00:00:02 user $
+expand $Id: c,v 0ba462c0f077 1970/01/01 00:00:01 user $
 do not process $Id:
 xxx $
 % touch copied c after 1 second
@@ -223,7 +208,7 @@
 a
 c
 % diff --rev
-diff -r cecf1e2cc3d3 c
+diff -r f782df5f9602 c
 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
 @@ -0,0 +1,3 @@
 +expand $Id$
@@ -247,15 +232,15 @@
 Xinfo = {author}: {desc}
 $Xinfo: test: hg keyword config and expansion example $
 % cat
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
-expand $Id: a,v cecf1e2cc3d3 1970/01/01 00:00:01 user $
+expand $Id: a,v f782df5f9602 1970/01/01 00:00:00 user $
 do not process $Id:
 xxx $
 ignore $Id$
-% hg kwcat
-expand $Id: a cecf1e2cc3d3 Thu, 01 Jan 1970 00:00:01 +0000 user $
+% hg cat
+expand $Id: a f782df5f9602 Thu, 01 Jan 1970 00:00:00 +0000 user $
 do not process $Id:
 xxx $
 ignore $Id$
@@ -272,17 +257,17 @@
 overwriting a expanding keywords
 % status
 % cat
-expand $Id: a a576e5647736 Thu, 01 Jan 1970 00:00:03 +0000 user $
+expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: firstline $
-expand $Id: a a576e5647736 Thu, 01 Jan 1970 00:00:03 +0000 user $
+expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: firstline $
 ignore $Id$
-% hg kwcat
-expand $Id: a a576e5647736 Thu, 01 Jan 1970 00:00:03 +0000 user $
+% hg cat
+expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: firstline $
@@ -296,7 +281,7 @@
 R a
 % revert a
 % cat a
-expand $Id: a a576e5647736 Thu, 01 Jan 1970 00:00:03 +0000 user $
+expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: firstline $
@@ -305,15 +290,15 @@
 adding changesets
 adding manifests
 adding file changes
-added 2 changesets with 3 changes to 3 files
+added 1 changesets with 3 changes to 3 files
 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
 % incoming
 comparing with test-keyword/Test
 searching for changes
-changeset:   2:a576e5647736
+changeset:   1:0729690beff6
 tag:         tip
 user:        User Name <user@example.com>
-date:        Thu Jan 01 00:00:03 1970 +0000
+date:        Thu Jan 01 00:00:02 1970 +0000
 summary:     firstline
 
 % commit rejecttest
@@ -323,11 +308,11 @@
 % import
 applying ../rejecttest.diff
 % cat
-expand $Id: a 97b8d4afd122 Thu, 01 Jan 1970 00:00:04 +0000 user $ rejecttest
+expand $Id: a 82983f13f138 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
 do not process $Id: rejecttest
 xxx $
 $Xinfo: User Name <user@example.com>: rejects? $
-expand $Id: a 97b8d4afd122 Thu, 01 Jan 1970 00:00:04 +0000 user $ rejecttest
+expand $Id: a 82983f13f138 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
 do not process $Id: rejecttest
 xxx $
 $Xinfo: User Name <user@example.com>: rejects? $
@@ -347,7 +332,7 @@
  x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
 overwriting x/a expanding keywords
 % cat a
-expand $Id: x/a 6ae8e7fbf16c Thu, 01 Jan 1970 00:00:04 +0000 user $
+expand $Id: x/a f27c134d2d9b Thu, 01 Jan 1970 00:00:03 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: xa $
@@ -360,6 +345,7 @@
 $Xinfo$
 % kwexpand nonexistent
 nonexistent: No such file or directory
+% switch off expansion
 % kwshrink with unknown file u
 overwriting a shrinking keywords
 overwriting x/a shrinking keywords
@@ -373,10 +359,27 @@
 xxx $
 $Xinfo$
 ignore $Id$
-% hg kwcat
-expand $Id: a a576e5647736 Thu, 01 Jan 1970 00:00:03 +0000 user $
+% hg cat
+expand $Id: a 0729690beff6 Thu, 01 Jan 1970 00:00:02 +0000 user $
 do not process $Id:
 xxx $
 $Xinfo: User Name <user@example.com>: firstline $
 ignore $Id$
 a
+% cat
+expand $Id$
+do not process $Id:
+xxx $
+$Xinfo$
+expand $Id$
+do not process $Id:
+xxx $
+$Xinfo$
+ignore $Id$
+% hg cat
+expand $Id$
+do not process $Id:
+xxx $
+$Xinfo$
+ignore $Id$
+a