[PATCH 1 of 3] manifest: move changectx.walk() to manifests

Drew Gottlieb drgott at google.com
Tue Apr 7 22:56:10 UTC 2015


# HG changeset patch
# User Drew Gottlieb <drgott at google.com>
# Date 1428445132 25200
#      Tue Apr 07 15:18:52 2015 -0700
# Node ID 8d24c368a96deb93ceda8cd036234186907c4eda
# Parent  54e5c239c2d9ad87fc2080fd9be35765cf0ebc9f
manifest: move changectx.walk() to manifests

The logic of walking a manifest to yield files matching a match object is
currently being done by context, not the manifest itself. This moves the walk()
function to both manifestdict and treemanifest. This separate implementation
will also permit differing, optimized implementations for each manifest.

diff --git a/mercurial/context.py b/mercurial/context.py
--- a/mercurial/context.py
+++ b/mercurial/context.py
@@ -587,26 +587,15 @@
         return self._repo.changelog.descendant(self._rev, other._rev)
 
     def walk(self, match):
-        fset = set(match.files())
-        # avoid the entire walk if we're only looking for specific files
-        if fset and not match.anypats():
-            if util.all(fn in self for fn in fset):
-                for fn in sorted(fset):
-                    yield fn
-                raise StopIteration
+        '''Generates matching file names.'''
 
-        for fn in self:
-            if fn in fset:
-                # specified pattern is the exact name
-                fset.remove(fn)
-            if match(fn):
-                yield fn
-        # for dirstate.walk, files=['.'] means "walk the whole tree".
-        # follow that here, too
-        fset.discard('.')
-        for fn in sorted(fset):
-            if not self.hasdir(fn):
-                match.bad(fn, _('no such file in rev %s') % self)
+        # Override match.bad method to have message with nodeid
+        oldbad = match.bad
+        def bad(fn, msg):
+            oldbad(fn, _('no such file in rev %s') % self)
+        match.bad = bad
+
+        return self._manifest.walk(match)
 
     def matches(self, match):
         return self.walk(match)
@@ -1268,6 +1257,7 @@
         return self._parents[0].ancestor(c2) # punt on two parents for now
 
     def walk(self, match):
+        '''Generates matching file names.'''
         return sorted(self._repo.dirstate.walk(match, sorted(self.substate),
                                                True, False))
 
diff --git a/mercurial/manifest.py b/mercurial/manifest.py
--- a/mercurial/manifest.py
+++ b/mercurial/manifest.py
@@ -225,6 +225,38 @@
     def hasdir(self, dir):
         return dir in self._dirs
 
+    def walk(self, match):
+        '''Generates matching file names.
+
+        Equivalent to manifest.matches(match).iterkeys(), but without creating
+        an entirely new manifest.
+
+        It also reports nonexistent files by marking them bad with match.bad().
+        '''
+        fset = set(match.files())
+
+        # avoid the entire walk if we're only looking for specific files
+        if fset and not match.anypats():
+            if util.all(fn in self for fn in fset):
+                for fn in sorted(fset):
+                    yield fn
+                raise StopIteration
+
+        for fn in self:
+            if fn in fset:
+                # specified pattern is the exact name
+                fset.remove(fn)
+            if match(fn):
+                yield fn
+
+        # for dirstate.walk, files=['.'] means "walk the whole tree".
+        # follow that here, too
+        fset.discard('.')
+
+        for fn in sorted(fset):
+            if not self.hasdir(fn):
+                match.bad(fn, None)
+
     def matches(self, match):
         '''generate a new manifest filtered by the match argument'''
         if match.always():
@@ -574,6 +606,38 @@
             return False
         return (dir + '/') in self._dirs
 
+    def walk(self, match):
+        '''Generates matching file names.
+
+        Equivalent to manifest.matches(match).iterkeys(), but without creating
+        an entirely new manifest.
+
+        It also reports nonexistent files by marking them bad with match.bad().
+        '''
+        fset = set(match.files())
+
+        # avoid the entire walk if we're only looking for specific files
+        if fset and not match.anypats():
+            if util.all(fn in self for fn in fset):
+                for fn in sorted(fset):
+                    yield fn
+                raise StopIteration
+
+        for fn in self:
+            if fn in fset:
+                # specified pattern is the exact name
+                fset.remove(fn)
+            if match(fn):
+                yield fn
+
+        # for dirstate.walk, files=['.'] means "walk the whole tree".
+        # follow that here, too
+        fset.discard('.')
+
+        for fn in sorted(fset):
+            if not self.hasdir(fn):
+                match.bad(fn, None)
+
     def matches(self, match):
         '''generate a new manifest filtered by the match argument'''
         if match.always():


More information about the Mercurial-devel mailing list