[PATCH 3 of 6 STABLE V2] dirstate: add 'rdirs()' to examine 'directory pattern' matching correctly

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Thu Mar 22 10:06:33 CDT 2012


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1332428327 -32400
# Branch stable
# Node ID 200e12e1d1f146e52bf01aed854562df30089c45
# Parent  d09da50da3b2a89eb2addc4deaea23b8b1683076
dirstate: add 'rdirs()' to examine 'directory pattern' matching correctly

when files are marked as 'removed' in working context:

    - entry in 'dirstate' is dropped, and
    - if there is no other files in target directory:
      - entry in 'dirstate._dirs' is dropped, and
      - directory itself is removed from filesystem

so, 'f in dirstate.dirs()' can't examine whether specified pattern is
related to removed largefiles or not correctly, if it is 'directory
pattern'.

this patch adds 'dirstate.rdirs()' (removed-dirs) to know what
directories are related to removed files.

'dirstate.rdirs()' is not for serious purpose, but for checking of
directory matching to removed files, so it is updated only in
'_droppath()'.

in almost all cases, 'dirstate.rdirs()' is probably invoked after
examination with 'dirstate.dirs()', so 'dirstate._rdirs' property is
built in 'dirstate._dirs()' to prevent manifest from being scanned twice.

diff -r d09da50da3b2 -r 200e12e1d1f1 mercurial/dirstate.py
--- a/mercurial/dirstate.py	Thu Mar 22 23:58:47 2012 +0900
+++ b/mercurial/dirstate.py	Thu Mar 22 23:58:47 2012 +0900
@@ -46,6 +46,15 @@
             return
         del dirs[base]
 
+def _addrdirs(dirs, path):
+    pos = path.rfind('/')
+    while pos != -1:
+        path = path[:pos]
+        if path in dirs:
+            break # dirs already contains this and above
+        dirs.add(path)
+        pos = path.rfind('/')
+
 class dirstate(object):
 
     def __init__(self, opener, ui, root, validate):
@@ -113,9 +122,13 @@
     @propertycache
     def _dirs(self):
         dirs = {}
+        rdirs = set()
         for f, s in self._map.iteritems():
             if s[0] != 'r':
                 _incdirs(dirs, f)
+            else:
+                _addrdirs(rdirs, f)
+        self._rdirs = rdirs
         return dirs
 
     def dirs(self):
@@ -261,8 +274,9 @@
             self._pl = p
 
     def invalidate(self):
-        for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
-                "_ignore"):
+        for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl",
+                  "_dirs", "_rdirs",
+                  "_ignore"):
             if a in self.__dict__:
                 delattr(self, a)
         self._lastnormaltime = 0
@@ -285,8 +299,10 @@
         return self._copymap
 
     def _droppath(self, f):
-        if self[f] not in "?r" and "_dirs" in self.__dict__:
-            _decdirs(self._dirs, f)
+        if self[f] not in "?r":
+            if "_dirs" in self.__dict__:
+                _decdirs(self._dirs, f)
+                _addrdirs(self._rdirs, f)
 
     def _addpath(self, f, check=False):
         oldstate = self[f]
@@ -425,8 +441,9 @@
 
     def clear(self):
         self._map = {}
-        if "_dirs" in self.__dict__:
-            delattr(self, "_dirs")
+        for a in ("_dirs", "_rdirs"):
+            if a in self.__dict__:
+                delattr(self, a)
         self._copymap = {}
         self._pl = [nullid, nullid]
         self._lastnormaltime = 0
@@ -742,3 +759,14 @@
 
         return (lookup, modified, added, removed, deleted, unknown, ignored,
                 clean)
+
+    @propertycache
+    def _rdirs(self):
+        '''not for strict purpose, but for checking of directory
+        matching to removed files'''
+
+        self._dirs
+        return self._rdirs
+
+    def rdirs(self):
+        return self._rdirs


More information about the Mercurial-devel mailing list