[PATCH STABLE] keyword: copy: when copied source is a symlink, follow it

Christian Ebert blacktrash at gmx.net
Wed Dec 1 03:53:33 CST 2010


# HG changeset patch
# User Christian Ebert <blacktrash at gmx.net>
# Date 1291197109 -3600
# Branch stable
# Node ID 83373cb7718c8915f40e4267ea580d29caf062d2
# Parent  2649be11ab0bf0523bf8169af07de442cfa3141f
keyword: copy: when copied source is a symlink, follow it

1) hg cp symlink copy -> copy is a symlink.
2) cp symlink copy; hg cp -A symlink copy -> copy is a regular file.

In the second case we have to follow the symlink to its target
to find out whether we have to unexpand keywords in the copy.

Add test covering the case where the copied link's target is ignored
by keyword but has content which would match the regex for expanded
keywords to check whether we indeed leave the destination alone.

diff --git a/hgext/keyword.py b/hgext/keyword.py
--- a/hgext/keyword.py
+++ b/hgext/keyword.py
@@ -86,7 +86,7 @@
 from mercurial import localrepo, match, patch, templatefilters, templater, util
 from mercurial.hgweb import webcommands
 from mercurial.i18n import _
-import re, shutil, tempfile
+import os, re, shutil, tempfile
 
 commands.optionalrepo += ' kwdemo'
 
@@ -555,17 +555,31 @@
     def kw_copy(orig, ui, repo, pats, opts, rename=False):
         '''Wraps cmdutil.copy so that copy/rename destinations do not
         contain expanded keywords.
-        Note that the source may also be a symlink as:
+        Note that the source of a regular file destination may also be a
+        symlink:
         hg cp sym x                -> x is symlink
         cp sym x; hg cp -A sym x   -> x is file (maybe expanded keywords)
-        '''
+        For the latter we have to follow the symlink to find out whether its
+        target is configured for expansion and we therefore must unexpand the
+        keywords in the destination.'''
         orig(ui, repo, pats, opts, rename)
         if opts.get('dry_run'):
             return
         wctx = repo[None]
+        cwd = repo.getcwd()
+
+        def haskwsource(dest):
+            '''Returns true if dest is a regular file and configured for
+            expansion or a symlink which points to a file configured for
+            expansion. '''
+            source = repo.dirstate.copied(dest)
+            if 'l' in wctx.flags(source):
+                source = util.canonpath(repo.root, cwd,
+                                        os.path.realpath(source))
+            return kwt.match(source)
+
         candidates = [f for f in repo.dirstate.copies() if
-                      kwt.match(repo.dirstate.copied(f)) and
-                      not 'l' in wctx.flags(f)]
+                      not 'l' in wctx.flags(f) and haskwsource(f)]
         kwt.overwrite(wctx, candidates, False, False)
 
     def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
diff --git a/tests/test-keyword.t b/tests/test-keyword.t
--- a/tests/test-keyword.t
+++ b/tests/test-keyword.t
@@ -553,7 +553,8 @@
   $ hg forget i
   $ rm i
 
-cp symlink (becomes regular file), and hg copy after
+cp symlink file; hg cp -A symlink file (part1)
+- copied symlink points to kwfile: overwrite
 
   $ cp sym i
   $ ls -l i
@@ -602,6 +603,26 @@
   $ hg update --clean
   0 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
+cp symlink file; hg cp -A symlink file (part2)
+- copied symlink points to kw ignored file: do not overwrite
+
+  $ cat a > i
+  $ ln -s i symignored
+  $ hg commit -Am 'fake expansion in ignored and symlink' i symignored
+  $ cp symignored x
+  $ hg copy --after --verbose symignored x
+  copying symignored to x
+  $ head -n 1 x
+  expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
+  $ hg forget x
+  $ rm x
+
+  $ hg rollback
+  rolling back to revision 1 (undo commit)
+  $ hg update --clean
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ rm i symignored
+
 Custom keywordmaps as argument to kwdemo
 
   $ hg --quiet kwdemo "Xinfo = {author}: {desc}"


More information about the Mercurial-devel mailing list