diff --git a/mercurial/manifest.py b/mercurial/manifest.py --- a/mercurial/manifest.py +++ b/mercurial/manifest.py @@ -1155,6 +1155,22 @@ class treemanifest(object): subp1, subp2 = subp2, subp1 writesubtree(subm, subp1, subp2) + def walksubtrees(self, matcher=None): + """Returns an iterator of the subtrees of this manifest, including this + manifest itself. + + If `matcher` is provided, it only returns subtrees that match. + """ + if matcher and not matcher.visitdir(self._dir[:-1] or '.'): + return + if not matcher or matcher(self._dir[:-1]): + yield self + + self._load() + for d, subm in self._dirs.iteritems(): + for subtree in subm.walksubtrees(matcher=matcher): + yield subtree + class manifestrevlog(revlog.revlog): '''A revlog that stores manifest texts. This is responsible for caching the full-text manifest contents. diff --git a/tests/test-manifest.py b/tests/test-manifest.py --- a/tests/test-manifest.py +++ b/tests/test-manifest.py @@ -467,5 +467,21 @@ class testtreemanifest(unittest.TestCase def parsemanifest(self, text): return manifestmod.treemanifest('', text) + def testWalkSubtrees(self): + m = self.parsemanifest(A_DEEPER_MANIFEST) + + dirs = [s._dir for s in m.walksubtrees()] + self.assertEqual( + sorted(['', 'a/', 'a/c/', 'a/d/', 'a/b/', 'a/b/c/', 'a/b/d/']), + sorted(dirs) + ) + + match = matchmod.match('/', '', ['path:a/b/']) + dirs = [s._dir for s in m.walksubtrees(matcher=match)] + self.assertEqual( + sorted(['a/b/', 'a/b/c/', 'a/b/d/']), + sorted(dirs) + ) + if __name__ == '__main__': silenttestrunner.main(__name__)