# HG changeset patch # User Arseniy Alekseyev # Date 1712932761 -3600 # Node ID b32c3146ec34ed2a7221026f15aaa465cb03f044 # Parent 2a89d2f6336f767c65a58a75cb152b819f763872 match: fix the "visitdir" method on "rootfilesin" matchers This fixes just the Python side, the fix for the rust side will follow shortly. diff -r 2a89d2f6336f -r b32c3146ec34 mercurial/match.py --- 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 diff -r 2a89d2f6336f -r b32c3146ec34 tests/test-match.py --- 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( diff -r 2a89d2f6336f -r b32c3146ec34 tests/test-status.t --- 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.