Rev 4731: (mbp) fix renaming when entries differ only by case in file:///home/pqm/archives/thelove/bzr/2.0/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Feb 12 04:49:52 GMT 2010


At file:///home/pqm/archives/thelove/bzr/2.0/

------------------------------------------------------------
revno: 4731 [merge]
revision-id: pqm at pqm.ubuntu.com-20100212044951-a34u2j4bd0etf3hu
parent: pqm at pqm.ubuntu.com-20100205074746-v2eq314fui8vk5m1
parent: mbp at sourcefrog.net-20100212033433-zc6lpwxj7dv9c0s2
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: 2.0
timestamp: Fri 2010-02-12 04:49:51 +0000
message:
  (mbp) fix renaming when entries differ only by case
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/per_tree/test_inv.py test_inv.py-20070312023226-0cdvk5uwhutis9vg-1
  bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
=== modified file 'NEWS'
--- a/NEWS	2010-02-05 06:30:42 +0000
+++ b/NEWS	2010-02-11 08:47:14 +0000
@@ -14,6 +14,9 @@
 Bug Fixes
 *********
 
+* Handle renames correctly when there are files or directories that 
+  differ only in case.  (Chris Jones, Martin Pool, #368931)
+
 * If ``bzr push --create-prefix`` triggers an unexpected ``NoSuchFile``
   error, report that error rather than failing with an unhelpful
   ``UnboundLocalError``.

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-10-29 04:19:13 +0000
+++ b/bzrlib/tests/__init__.py	2010-02-12 03:34:33 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
+# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -4060,6 +4060,23 @@
 CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
 
+class _CaseSensitiveFilesystemFeature(Feature):
+
+    def _probe(self):
+        if CaseInsCasePresFilenameFeature.available():
+            return False
+        elif CaseInsensitiveFilesystemFeature.available():
+            return False
+        else:
+            return True
+
+    def feature_name(self):
+        return 'case-sensitive filesystem'
+
+# new coding style is for feature instances to be lowercase
+case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
+
+
 class _SubUnitFeature(Feature):
     """Check if subunit is available."""
 

=== modified file 'bzrlib/tests/per_tree/test_inv.py'
--- a/bzrlib/tests/per_tree/test_inv.py	2009-07-10 07:14:02 +0000
+++ b/bzrlib/tests/per_tree/test_inv.py	2010-02-12 03:33:36 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2007, 2008 Canonical Ltd
+# Copyright (C) 2007, 2008, 2010 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -23,7 +23,10 @@
 from bzrlib import (
     tests,
     )
-from bzrlib.tests import per_tree
+from bzrlib.tests import (
+    features,
+    per_tree,
+    )
 from bzrlib.mutabletree import MutableTree
 from bzrlib.tests import SymlinkFeature, TestSkipped
 from bzrlib.transform import _PreviewTree
@@ -131,6 +134,8 @@
         work_tree.add(['dir', 'dir/file'])
         if commit:
             work_tree.commit('commit 1')
+        # XXX: this isn't actually guaranteed to return the class we want to
+        # test -- mbp 2010-02-12
         return work_tree
 
     def test_canonical_path(self):
@@ -163,3 +168,21 @@
         work_tree = self._make_canonical_test_tree()
         self.assertEqual('dir/None',
                          work_tree.get_canonical_inventory_path('Dir/None'))
+
+    def test_canonical_tree_name_mismatch(self):
+        # see <https://bugs.edge.launchpad.net/bzr/+bug/368931>
+        # some of the trees we want to use can only exist on a disk, not in
+        # memory - therefore we can only test this if the filesystem is
+        # case-sensitive.
+        self.requireFeature(tests.case_sensitive_filesystem_feature)
+        work_tree = self.make_branch_and_tree('.')
+        self.build_tree(['test/', 'test/file', 'Test'])
+        work_tree.add(['test/', 'test/file', 'Test'])
+
+        test_tree = self._convert_tree(work_tree)
+        test_tree.lock_read()
+        self.addCleanup(test_tree.unlock)
+
+        self.assertEqual(['test', 'test/file', 'Test', 'test/foo', 'Test/foo'],
+            test_tree.get_canonical_inventory_paths(
+                ['test', 'test/file', 'Test', 'test/foo', 'Test/foo']))

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2009-08-26 05:38:16 +0000
+++ b/bzrlib/tree.py	2010-02-11 08:47:14 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2005, 2009 Canonical Ltd
+# Copyright (C) 2005, 2009, 2010 Canonical Ltd
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -404,16 +404,34 @@
             bit_iter = iter(path.split("/"))
             for elt in bit_iter:
                 lelt = elt.lower()
+                new_path = None
                 for child in self.iter_children(cur_id):
                     try:
+                        # XXX: it seem like if the child is known to be in the
+                        # tree, we shouldn't need to go from its id back to
+                        # its path -- mbp 2010-02-11
+                        #
+                        # XXX: it seems like we could be more efficient
+                        # by just directly looking up the original name and
+                        # only then searching all children; also by not
+                        # chopping paths so much. -- mbp 2010-02-11
                         child_base = os.path.basename(self.id2path(child))
-                        if child_base.lower() == lelt:
+                        if (child_base == elt):
+                            # if we found an exact match, we can stop now; if
+                            # we found an approximate match we need to keep
+                            # searching because there might be an exact match
+                            # later.  
                             cur_id = child
-                            cur_path = osutils.pathjoin(cur_path, child_base)
+                            new_path = osutils.pathjoin(cur_path, child_base)
                             break
+                        elif child_base.lower() == lelt:
+                            cur_id = child
+                            new_path = osutils.pathjoin(cur_path, child_base)
                     except NoSuchId:
                         # before a change is committed we can see this error...
                         continue
+                if new_path:
+                    cur_path = new_path
                 else:
                     # got to the end of this directory and no entries matched.
                     # Return what matched so far, plus the rest as specified.




More information about the bazaar-commits mailing list