match: do not weirdly include explicit files excluded by -X option
Actually, this was the original behavior. Before
a83a7d27911e, "log" and
"files" showed nothing if "FILE -X FILE" was specified, whereas "debugwalk"
got confused by an explicit FILE pattern. Under the hood, "log" and "files"
use m() and ctx.matches(m) respectively, and "debugwalk" uses ctx.walk(m).
I suspect dirstate.walk() goes wrong in _walkexplicit(), which seems to
blindly trust m.files().
I reckon the original "log"/"files" behavior is correct, and drop the hack
from the differencematcher.
--- a/mercurial/match.py Sun Jan 14 15:56:22 2018 -0500
+++ b/mercurial/match.py Tue Jan 16 22:14:33 2018 +0900
@@ -457,17 +457,10 @@
class differencematcher(basematcher):
'''Composes two matchers by matching if the first matches and the second
- does not. Well, almost... If the user provides a pattern like "-X foo foo",
- Mercurial actually does match "foo" against that. That's because exact
- matches are treated specially. So, since this differencematcher is used for
- excludes, it needs to special-case exact matching.
+ does not.
The second matcher's non-matching-attributes (root, cwd, bad, explicitdir,
traversedir) are ignored.
-
- TODO: If we want to keep the behavior described above for exact matches, we
- should consider instead treating the above case something like this:
- union(exact(foo), difference(pattern(foo), include(foo)))
'''
def __init__(self, m1, m2):
super(differencematcher, self).__init__(m1._root, m1._cwd)
@@ -478,7 +471,7 @@
self.traversedir = m1.traversedir
def matchfn(self, f):
- return self._m1(f) and (not self._m2(f) or self._m1.exact(f))
+ return self._m1(f) and not self._m2(f)
@propertycache
def _files(self):
@@ -493,9 +486,6 @@
def visitdir(self, dir):
if self._m2.visitdir(dir) == 'all':
- # There's a bug here: If m1 matches file 'dir/file' and m2 excludes
- # 'dir' (recursively), we should still visit 'dir' due to the
- # exception we have for exact matches.
return False
return bool(self._m1.visitdir(dir))
--- a/tests/test-locate.t Sun Jan 14 15:56:22 2018 -0500
+++ b/tests/test-locate.t Tue Jan 16 22:14:33 2018 +0900
@@ -103,6 +103,11 @@
$ hg files b
b
+-X with explicit path:
+
+ $ hg files b -X b
+ [1]
+
$ mkdir otherdir
$ cd otherdir
--- a/tests/test-log.t Sun Jan 14 15:56:22 2018 -0500
+++ b/tests/test-log.t Tue Jan 16 22:14:33 2018 +0900
@@ -102,6 +102,10 @@
summary: c
+-X, with explicit path
+
+ $ hg log a -X a
+
-f, non-existent directory
$ hg log -f dir
--- a/tests/test-walk.t Sun Jan 14 15:56:22 2018 -0500
+++ b/tests/test-walk.t Tue Jan 16 22:14:33 2018 +0900
@@ -344,6 +344,21 @@
abort: path 'beans/.hg' is inside nested repo 'beans'
[255]
+Test explicit paths and excludes:
+(BROKEN: nothing should be included, but wctx.walk() does)
+
+ $ hg debugwalk fennel -X fennel
+ matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:fennel(?:/|$))'>>
+ f fennel fennel exact
+ $ hg debugwalk fennel -X 'f*'
+ matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:f[^/]*(?:/|$))'>>
+ f fennel fennel exact
+ $ hg debugwalk beans/black -X 'path:beans'
+ matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
+ f beans/black beans/black exact
+ $ hg debugwalk -I 'path:beans/black' -X 'path:beans'
+ matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
+
Test absolute paths:
$ hg debugwalk `pwd`/beans