match: fix the "visitdir" method on "rootfilesin" matchers
This fixes just the Python side, the fix for the rust side will follow shortly.
--- a/mercurial/match.py Fri Apr 12 14:21:14 2024 +0100
+++ b/mercurial/match.py Fri Apr 12 15:39:21 2024 +0100
@@ -638,7 +638,10 @@
super(patternmatcher, self).__init__(badfn)
kindpats.sort()
+ roots, dirs, parents = _rootsdirsandparents(kindpats)
self._files = _explicitfiles(kindpats)
+ self._dirs_explicit = set(dirs)
+ self._dirs = parents
self._prefix = _prefix(kindpats)
self._pats, self._matchfn = _buildmatch(kindpats, b'$', root)
@@ -647,14 +650,14 @@
return True
return self._matchfn(fn)
- @propertycache
- def _dirs(self):
- return set(pathutil.dirs(self._fileset))
-
def visitdir(self, dir):
if self._prefix and dir in self._fileset:
return b'all'
- return dir in self._dirs or path_or_parents_in_set(dir, self._fileset)
+ return (
+ dir in self._dirs
+ or path_or_parents_in_set(dir, self._fileset)
+ or path_or_parents_in_set(dir, self._dirs_explicit)
+ )
def visitchildrenset(self, dir):
ret = self.visitdir(dir)
@@ -1461,7 +1464,7 @@
allgroups = []
regexps = []
exact = set()
- for (kind, pattern, _source) in kindpats:
+ for kind, pattern, _source in kindpats:
if kind == b'filepath':
exact.add(pattern)
continue
--- a/tests/test-match.py Fri Apr 12 14:21:14 2024 +0100
+++ b/tests/test-match.py Fri Apr 12 15:39:21 2024 +0100
@@ -94,12 +94,14 @@
patterns=[b'rootfilesin:dir/subdir'],
)
assert isinstance(m, matchmod.patternmatcher)
- self.assertFalse(m.visitdir(b'dir/subdir/x'))
+ # OPT: we shouldn't visit [x] as a directory,
+ # but we should still visit it as a file.
+ # Unfortunately, `visitdir` is used for both.
+ self.assertTrue(m.visitdir(b'dir/subdir/x'))
self.assertFalse(m.visitdir(b'folder'))
- # FIXME: These should probably be True.
- self.assertFalse(m.visitdir(b''))
- self.assertFalse(m.visitdir(b'dir'))
- self.assertFalse(m.visitdir(b'dir/subdir'))
+ self.assertTrue(m.visitdir(b''))
+ self.assertTrue(m.visitdir(b'dir'))
+ self.assertTrue(m.visitdir(b'dir/subdir'))
def testVisitchildrensetRootfilesin(self):
m = matchmod.match(
@@ -108,13 +110,13 @@
patterns=[b'rootfilesin:dir/subdir'],
)
assert isinstance(m, matchmod.patternmatcher)
- self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), set())
+ self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), b'this')
self.assertEqual(m.visitchildrenset(b'folder'), set())
- # FIXME: These should probably be {'dir'}, {'subdir'} and 'this',
- # respectively, or at least 'this' for all three.
- self.assertEqual(m.visitchildrenset(b''), set())
- self.assertEqual(m.visitchildrenset(b'dir'), set())
- self.assertEqual(m.visitchildrenset(b'dir/subdir'), set())
+ # OPT: These should probably be {'dir'}, {'subdir'} and 'this',
+ # respectively
+ self.assertEqual(m.visitchildrenset(b''), b'this')
+ self.assertEqual(m.visitchildrenset(b'dir'), b'this')
+ self.assertEqual(m.visitchildrenset(b'dir/subdir'), b'this')
def testVisitdirGlob(self):
m = matchmod.match(
--- a/tests/test-status.t Fri Apr 12 14:21:14 2024 +0100
+++ b/tests/test-status.t Fri Apr 12 15:39:21 2024 +0100
@@ -863,6 +863,7 @@
M subdir/modified (no-rhg !)
R subdir/removed (no-rhg !)
! subdir/deleted (no-rhg !)
+ ? subdir/unknown (no-rhg !)
Note: `hg status some-name` creates a patternmatcher which is not supported
yet by the Rust implementation of status, but includematcher is supported.