changeset 7096:6dab29f6df37

dirstate._dirs: fix refcounting broken by 7dfac37cfabf reported by Patrick Waugh
author Benoit Boissinot <benoit.boissinot@ens-lyon.org>
date Wed, 15 Oct 2008 01:14:29 +0200
parents 0ed11838bd1a
children d4218edd55bd 8a5c88c7e97b
files mercurial/dirstate.py tests/test-dirstatedirs tests/test-dirstatedirs.out
diffstat 3 files changed, 34 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstate.py	Tue Oct 07 13:57:00 2008 +0200
+++ b/mercurial/dirstate.py	Wed Oct 15 01:14:29 2008 +0200
@@ -21,6 +21,20 @@
         yield path[:pos]
         pos = path.rfind('/', 0, pos)
 
+def _incdirs(dirs, path):
+    for base in _finddirs(path):
+        if base in dirs:
+            dirs[base] += 1
+            return
+        dirs[base] = 1
+
+def _decdirs(dirs, path):
+    for base in _finddirs(path):
+        if dirs[base] > 1:
+            dirs[base] -= 1
+            return
+        del dirs[base]
+
 class dirstate(object):
 
     def __init__(self, opener, ui, root):
@@ -65,14 +79,7 @@
             dirs = {}
             for f,s in self._map.iteritems():
                 if s[0] != 'r':
-                    pos = f.rfind('/')
-                    while pos != -1:
-                        f = f[:pos]
-                        if f in dirs:
-                            dirs[f] += 1
-                            break
-                        dirs[f] = 1
-                        pos = f.rfind('/')
+                    _incdirs(dirs, f)
             self._dirs = dirs
             return self._dirs
         elif name == '_ignore':
@@ -222,12 +229,7 @@
 
     def _droppath(self, f):
         if self[f] not in "?r" and "_dirs" in self.__dict__:
-            dirs = self._dirs
-            for base in _finddirs(f):
-                if dirs[base] == 1:
-                    del dirs[base]
-                    return
-                dirs[base] -= 1
+            _decdirs(self._dirs, f)
 
     def _addpath(self, f, check=False):
         oldstate = self[f]
@@ -245,9 +247,7 @@
                     raise util.Abort(
                         _('file %r in dirstate clashes with %r') % (d, f))
         if oldstate in "?r" and "_dirs" in self.__dict__:
-            dirs = self._dirs
-            for base in _finddirs(f):
-                dirs[base] = dirs.get(base, 0) + 1
+            _incdirs(self._dirs, f)
 
     def normal(self, f):
         'mark a file normal and clean'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-dirstatedirs	Wed Oct 15 01:14:29 2008 +0200
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# test dirstate._dirs refcounting
+hg init t
+cd t
+mkdir -p a/b/c/d
+touch a/b/c/d/x
+touch a/b/c/d/y
+touch a/b/c/d/z
+hg ci -Am m
+hg mv a z
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-dirstatedirs.out	Wed Oct 15 01:14:29 2008 +0200
@@ -0,0 +1,6 @@
+adding a/b/c/d/x
+adding a/b/c/d/y
+adding a/b/c/d/z
+moving a/b/c/d/x to z/b/c/d/x
+moving a/b/c/d/y to z/b/c/d/y
+moving a/b/c/d/z to z/b/c/d/z