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 | self._path = path |
|
2570 | self._path = path | |
2571 |
|
2571 | |||
2572 | def cmp(self, fctx): |
|
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 | # Add a fast-path for merge if both sides are disk-backed. |
|
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 | return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path())) |
|
2580 | return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path())) | |
2577 | return self.data() != fctx.data() |
|
2581 | return self.data() != fctx.data() | |
2578 |
|
2582 |
General Comments 0
You need to be logged in to leave comments.
Login now