Rev 3044: TreeTransform handles case-insensitive filesystems well in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Nov 28 23:08:47 GMT 2007


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 3044
revision-id:pqm at pqm.ubuntu.com-20071128230840-b2ra2nso0qtqxon6
parent: pqm at pqm.ubuntu.com-20071128171926-dafi3r2iq6e4vle1
parent: bialix at ukr.net-20071128210408-bfc2z901pk1e6fje
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2007-11-28 23:08:40 +0000
message:
  TreeTransform handles case-insensitive filesystems well
modified:
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
  bzrlib/tests/workingtree_implementations/test_workingtree.py test_workingtree.py-20060203003124-817757d3e31444fb
  bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
  bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3034.4.9
    revision-id:bialix at ukr.net-20071128210408-bfc2z901pk1e6fje
    parent: bialix at ukr.net-20071128205924-ozm9qxt0texyc4ln
    committer: Alexander Belchenko <bialix at ukr.net>
    branch nick: aaron
    timestamp: Wed 2007-11-28 23:04:08 +0200
    message:
      skip test_workingtree.TestWorkingTree.test_case_sensitive for WT2
    modified:
      bzrlib/tests/workingtree_implementations/test_workingtree.py test_workingtree.py-20060203003124-817757d3e31444fb
    ------------------------------------------------------------
    revno: 3034.4.8
    revision-id:bialix at ukr.net-20071128205924-ozm9qxt0texyc4ln
    parent: abentley at panoramicfeedback.com-20071128145615-6ckqqiymro15jbb1
    committer: Alexander Belchenko <bialix at ukr.net>
    branch nick: aaron
    timestamp: Wed 2007-11-28 22:59:24 +0200
    message:
      TestCaseInTempDir.build_tree now checks type of shape argument.
    modified:
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
    ------------------------------------------------------------
    revno: 3034.4.7
    revision-id:abentley at panoramicfeedback.com-20071128145615-6ckqqiymro15jbb1
    parent: abentley at panoramicfeedback.com-20071128142240-kkw4ft7p545p0a0k
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: transform-case
    timestamp: Wed 2007-11-28 09:56:15 -0500
    message:
      Add test for filename conflicts with existing files
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
    ------------------------------------------------------------
    revno: 3034.4.6
    revision-id:abentley at panoramicfeedback.com-20071128142240-kkw4ft7p545p0a0k
    parent: abentley at panoramicfeedback.com-20071128141636-bbm7lusqat2ek2ao
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: transform-case
    timestamp: Wed 2007-11-28 09:22:40 -0500
    message:
      Update apply_case_conflict tests
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
    ------------------------------------------------------------
    revno: 3034.4.5
    revision-id:abentley at panoramicfeedback.com-20071128141636-bbm7lusqat2ek2ao
    parent: aaron.bentley at utoronto.ca-20071128022527-juav8ud1712wphwz
    committer: Aaron Bentley <abentley at panoramicfeedback.com>
    branch nick: transform-case
    timestamp: Wed 2007-11-28 09:16:36 -0500
    message:
      Add workingtree test for case_insensitive var
    modified:
      bzrlib/tests/workingtree_implementations/test_workingtree.py test_workingtree.py-20060203003124-817757d3e31444fb
    ------------------------------------------------------------
    revno: 3034.4.4
    revision-id:aaron.bentley at utoronto.ca-20071128022527-juav8ud1712wphwz
    parent: aaron.bentley at utoronto.ca-20071128012128-gz9ep3oyvh1xt38n
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: transform-case
    timestamp: Tue 2007-11-27 21:25:27 -0500
    message:
      Fix case-sensitivity detection
    modified:
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
    ------------------------------------------------------------
    revno: 3034.4.3
    revision-id:aaron.bentley at utoronto.ca-20071128012128-gz9ep3oyvh1xt38n
    parent: aaron.bentley at utoronto.ca-20071128000531-mq2lgadv5c9471nf
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: transform-case
    timestamp: Tue 2007-11-27 20:21:28 -0500
    message:
      Add case-sensitivity handling to WorkingTree
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
    ------------------------------------------------------------
    revno: 3034.4.2
    revision-id:aaron.bentley at utoronto.ca-20071128000531-mq2lgadv5c9471nf
    parent: aaron.bentley at utoronto.ca-20071127132444-zq5nq2cs13ljnm6z
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: transform-case
    timestamp: Tue 2007-11-27 19:05:31 -0500
    message:
      Get conflict handling and case-insensitive tree creation under test
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
    ------------------------------------------------------------
    revno: 3034.4.1
    revision-id:aaron.bentley at utoronto.ca-20071127132444-zq5nq2cs13ljnm6z
    parent: pqm at pqm.ubuntu.com-20071127023739-a1ajr28wi7so2up6
    committer: Aaron Bentley <aaron.bentley at utoronto.ca>
    branch nick: transform-case
    timestamp: Tue 2007-11-27 08:24:44 -0500
    message:
      Start handling case-insensitivity
    modified:
      bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2007-11-23 00:19:02 +0000
+++ b/bzrlib/tests/__init__.py	2007-11-28 20:59:24 +0000
@@ -2046,6 +2046,7 @@
 
         This doesn't add anything to a branch.
 
+        :type shape:    list or tuple.
         :param line_endings: Either 'binary' or 'native'
             in binary mode, exact contents are written in native mode, the
             line endings match the default platform endings.
@@ -2053,6 +2054,8 @@
             If the transport is readonly or None, "." is opened automatically.
         :return: None
         """
+        assert type(shape) in (list, tuple), ("Parameter 'shape' should be "
+            "a list or a tuple. Got %s instead" % type(shape))
         # It's OK to just create them using forward slashes on windows.
         if transport is None or transport.is_readonly():
             transport = get_transport(".")

=== modified file 'bzrlib/tests/test_transform.py'
--- a/bzrlib/tests/test_transform.py	2007-11-28 02:06:15 +0000
+++ b/bzrlib/tests/test_transform.py	2007-11-28 23:08:40 +0000
@@ -44,7 +44,7 @@
 from bzrlib.transform import (TreeTransform, ROOT_PARENT, FinalPaths, 
                               resolve_conflicts, cook_conflicts, 
                               find_interesting, build_tree, get_backup_name,
-                              change_entry, _FileMover)
+                              change_entry, _FileMover, resolve_checkout)
 
 
 class TestTreeTransform(tests.TestCaseWithTransport):
@@ -237,6 +237,105 @@
         transform3.adjust_path('tip', root_id, tip_id)
         transform3.apply()
 
+    def test_conflict_on_case_insensitive(self):
+        tree = self.make_branch_and_tree('tree')
+        # Don't try this at home, kids!
+        # Force the tree to report that it is case sensitive, for conflict
+        # resolution tests
+        tree.case_sensitive = True
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        transform.new_file('file', transform.root, 'content')
+        transform.new_file('FiLe', transform.root, 'content')
+        result = transform.find_conflicts()
+        self.assertEqual([], result)
+        # Force the tree to report that it is case insensitive, for conflict
+        # generation tests
+        tree.case_sensitive = False
+        result = transform.find_conflicts()
+        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
+
+    def test_conflict_on_case_insensitive_existing(self):
+        tree = self.make_branch_and_tree('tree')
+        self.build_tree(['tree/FiLe'])
+        # Don't try this at home, kids!
+        # Force the tree to report that it is case sensitive, for conflict
+        # resolution tests
+        tree.case_sensitive = True
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        transform.new_file('file', transform.root, 'content')
+        result = transform.find_conflicts()
+        self.assertEqual([], result)
+        # Force the tree to report that it is case insensitive, for conflict
+        # generation tests
+        tree.case_sensitive = False
+        result = transform.find_conflicts()
+        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
+
+    def test_resolve_case_insensitive_conflict(self):
+        tree = self.make_branch_and_tree('tree')
+        # Don't try this at home, kids!
+        # Force the tree to report that it is case insensitive, for conflict
+        # resolution tests
+        tree.case_sensitive = False
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        transform.new_file('file', transform.root, 'content')
+        transform.new_file('FiLe', transform.root, 'content')
+        resolve_conflicts(transform)
+        transform.apply()
+        self.failUnlessExists('tree/file')
+        self.failUnlessExists('tree/FiLe.moved')
+
+    def test_resolve_checkout_case_conflict(self):
+        tree = self.make_branch_and_tree('tree')
+        # Don't try this at home, kids!
+        # Force the tree to report that it is case insensitive, for conflict
+        # resolution tests
+        tree.case_sensitive = False
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        transform.new_file('file', transform.root, 'content')
+        transform.new_file('FiLe', transform.root, 'content')
+        resolve_conflicts(transform,
+                          pass_func=lambda t, c: resolve_checkout(t, c, []))
+        transform.apply()
+        self.failUnlessExists('tree/file')
+        self.failUnlessExists('tree/FiLe.moved')
+
+    def test_apply_case_conflict(self):
+        """Ensure that a transform with case conflicts can always be applied"""
+        tree = self.make_branch_and_tree('tree')
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        transform.new_file('file', transform.root, 'content')
+        transform.new_file('FiLe', transform.root, 'content')
+        dir = transform.new_directory('dir', transform.root)
+        transform.new_file('dirfile', dir, 'content')
+        transform.new_file('dirFiLe', dir, 'content')
+        resolve_conflicts(transform)
+        transform.apply()
+        self.failUnlessExists('tree/file')
+        if not os.path.exists('tree/FiLe.moved'):
+            self.failUnlessExists('tree/FiLe')
+        self.failUnlessExists('tree/dir/dirfile')
+        if not os.path.exists('tree/dir/dirFiLe.moved'):
+            self.failUnlessExists('tree/dir/dirFiLe')
+
+    def test_case_insensitive_limbo(self):
+        tree = self.make_branch_and_tree('tree')
+        # Don't try this at home, kids!
+        # Force the tree to report that it is case insensitive
+        tree.case_sensitive = False
+        transform = TreeTransform(tree)
+        self.addCleanup(transform.finalize)
+        dir = transform.new_directory('dir', transform.root)
+        first = transform.new_file('file', dir, 'content')
+        second = transform.new_file('FiLe', dir, 'content')
+        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
+        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
+
     def test_add_del(self):
         start, root = self.get_transform()
         start.new_directory('a', root, 'a')

=== modified file 'bzrlib/tests/workingtree_implementations/test_workingtree.py'
--- a/bzrlib/tests/workingtree_implementations/test_workingtree.py	2007-11-13 17:48:49 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_workingtree.py	2007-11-28 21:04:08 +0000
@@ -30,11 +30,10 @@
 from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
 from bzrlib.trace import mutter
 from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
-                                WorkingTree)
+                                WorkingTree, WorkingTree2)
 from bzrlib.conflicts import ConflictList, TextConflict, ContentsConflict
 
 
-
 class TestWorkingTree(TestCaseWithWorkingTree):
 
     def test_list_files(self):
@@ -848,3 +847,19 @@
         tree.commit('foo')
         tree.remove('file')
         self.assertRaises(errors.NoSuchId, tree.get_file_sha1, 'file-id')
+
+    def test_case_sensitive(self):
+        """If filesystem is case-sensitive, tree should report this.
+
+        We check case-sensitivity by creating a file with a lowercase name,
+        then testing whether it exists with an uppercase name.
+        """
+        self.build_tree(['filename'])
+        if os.path.exists('FILENAME'):
+            case_sensitive = False
+        else:
+            case_sensitive = True
+        tree = self.make_branch_and_tree('test')
+        if tree.__class__ == WorkingTree2:
+            raise TestSkipped('WorkingTree2 is not supported')
+        self.assertEqual(case_sensitive, tree.case_sensitive)

=== modified file 'bzrlib/transform.py'
--- a/bzrlib/transform.py	2007-11-26 19:54:09 +0000
+++ b/bzrlib/transform.py	2007-11-27 13:24:44 +0000
@@ -798,6 +798,8 @@
             return conflicts
         for children in by_parent.itervalues():
             name_ids = [(self.final_name(t), t) for t in children]
+            if not self._tree.case_sensitive:
+                name_ids = [(n.lower(), t) for n, t in name_ids]
             name_ids.sort()
             last_name = None
             last_trans_id = None
@@ -924,9 +926,20 @@
                 # the direct path can only be used if no other file has
                 # already taken this pathname, i.e. if the name is unused, or
                 # if it is already associated with this trans_id.
-                elif (self._limbo_children_names[parent].get(filename)
-                      in (trans_id, None)):
-                    use_direct_path = True
+                elif self._tree.case_sensitive:
+                    if (self._limbo_children_names[parent].get(filename)
+                        in (trans_id, None)):
+                        use_direct_path = True
+                else:
+                    for l_filename, l_trans_id in\
+                        self._limbo_children_names[parent].iteritems():
+                        if l_trans_id == trans_id:
+                            continue
+                        if l_filename.lower() == filename.lower():
+                            break
+                    else:
+                        use_direct_path = True
+
         if use_direct_path:
             limbo_name = pathjoin(self._limbo_files[parent], filename)
             self._limbo_children[parent].add(trans_id)
@@ -1787,16 +1800,15 @@
                                conflict[1], conflict[2], ))
         elif c_type == 'duplicate':
             # files that were renamed take precedence
-            new_name = tt.final_name(conflict[1])+'.moved'
             final_parent = tt.final_parent(conflict[1])
             if tt.path_changed(conflict[1]):
-                tt.adjust_path(new_name, final_parent, conflict[2])
-                new_conflicts.add((c_type, 'Moved existing file to', 
-                                   conflict[2], conflict[1]))
+                existing_file, new_file = conflict[2], conflict[1]
             else:
-                tt.adjust_path(new_name, final_parent, conflict[1])
-                new_conflicts.add((c_type, 'Moved existing file to', 
-                                  conflict[1], conflict[2]))
+                existing_file, new_file = conflict[1], conflict[2]
+            new_name = tt.final_name(existing_file)+'.moved'
+            tt.adjust_path(new_name, final_parent, existing_file)
+            new_conflicts.add((c_type, 'Moved existing file to', 
+                               existing_file, new_file))
         elif c_type == 'parent loop':
             # break the loop by undoing one of the ops that caused the loop
             cur = conflict[1]

=== modified file 'bzrlib/workingtree.py'
--- a/bzrlib/workingtree.py	2007-11-23 20:19:57 +0000
+++ b/bzrlib/workingtree.py	2007-11-28 02:25:27 +0000
@@ -270,6 +270,16 @@
             # the Format factory and creation methods that are
             # permitted to do this.
             self._set_inventory(_inventory, dirty=False)
+        self._detect_case_handling()
+
+    def _detect_case_handling(self):
+        wt_trans = self.bzrdir.get_workingtree_transport(None)
+        try:
+            wt_trans.stat("FoRMaT")
+        except errors.NoSuchFile:
+            self.case_sensitive = True
+        else:
+            self.case_sensitive = False
 
     branch = property(
         fget=lambda self: self._branch,

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-11-27 20:35:02 +0000
+++ b/bzrlib/workingtree_4.py	2007-11-28 23:08:40 +0000
@@ -151,6 +151,7 @@
         self._dirstate = None
         self._inventory = None
         #-------------
+        self._detect_case_handling()
 
     @needs_tree_write_lock
     def _add(self, files, ids, kinds):




More information about the bazaar-commits mailing list