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 |
|
|
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