##// END OF EJS Templates
arbitraryfilecontext: skip the cmp fast path if any side is a symlink...
Phil Cohen -
r34836:14c87708 default
parent child Browse files
Show More
@@ -0,0 +1,57 b''
1 Setup:
2 $ cat > eval.py <<EOF
3 > from __future__ import absolute_import
4 > import filecmp
5 > from mercurial import commands, context, registrar
6 > cmdtable = {}
7 > command = registrar.command(cmdtable)
8 > @command(b'eval', [], 'hg eval CMD')
9 > def eval_(ui, repo, *cmds, **opts):
10 > cmd = " ".join(cmds)
11 > res = str(eval(cmd, globals(), locals()))
12 > ui.warn("%s" % res)
13 > EOF
14
15 $ echo "[extensions]" >> $HGRCPATH
16 $ echo "eval=`pwd`/eval.py" >> $HGRCPATH
17
18 Arbitraryfilectx.cmp does not follow symlinks:
19 $ mkdir case1
20 $ cd case1
21 $ hg init
22 $ printf "A" > real_A
23 $ printf "foo" > A
24 $ printf "foo" > B
25 $ ln -s A sym_A
26 $ hg add .
27 adding A
28 adding B
29 adding real_A
30 adding sym_A
31 $ hg commit -m "base"
32
33 These files are different and should return True (different):
34 (Note that filecmp.cmp's return semantics are inverted from ours, so we invert
35 for simplicity):
36 $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['real_A'])"
37 True (no-eol)
38 $ hg eval "not filecmp.cmp('A', 'real_A')"
39 True (no-eol)
40
41 These files are identical and should return False (same):
42 $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['A'])"
43 False (no-eol)
44 $ hg eval "context.arbitraryfilectx('A', repo).cmp(repo[None]['B'])"
45 False (no-eol)
46 $ hg eval "not filecmp.cmp('A', 'B')"
47 False (no-eol)
48
49 This comparison should also return False, since A and sym_A are substantially
50 the same in the eyes of ``filectx.cmp``, which looks at data only.
51 $ hg eval "context.arbitraryfilectx('real_A', repo).cmp(repo[None]['sym_A'])"
52 False (no-eol)
53
54 A naive use of filecmp on those two would wrongly return True, since it follows
55 the symlink to "A", which has different contents.
56 $ hg eval "not filecmp.cmp('real_A', 'sym_A')"
57 True (no-eol)
@@ -2570,9 +2570,13 b' class arbitraryfilectx(object):'
2570 2570 self._path = path
2571 2571
2572 2572 def cmp(self, fctx):
2573 if isinstance(fctx, workingfilectx) and self._repo:
2573 # filecmp follows symlinks whereas `cmp` should not, so skip the fast
2574 # path if either side is a symlink.
2575 symlinks = ('l' in self.flags() or 'l' in fctx.flags())
2576 if not symlinks and isinstance(fctx, workingfilectx) and self._repo:
2574 2577 # Add a fast-path for merge if both sides are disk-backed.
2575 # Note that filecmp uses the opposite return values as cmp.
2578 # Note that filecmp uses the opposite return values (True if same)
2579 # from our cmp functions (True if different).
2576 2580 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path()))
2577 2581 return self.data() != fctx.data()
2578 2582
General Comments 0
You need to be logged in to leave comments. Login now