Rev 4525: Quicker check for changes in mutable trees in http://bazaar.launchpad.net/~vila/bzr/integration

Vincent Ladeuil v.ladeuil+lp at free.fr
Fri Jul 10 09:33:24 BST 2009


At http://bazaar.launchpad.net/~vila/bzr/integration

------------------------------------------------------------
revno: 4525 [merge]
revision-id: v.ladeuil+lp at free.fr-20090710083311-ulnr2ic6lvevjr3a
parent: pqm at pqm.ubuntu.com-20090710063538-2hap9pxafqfe6r20
parent: v.ladeuil+lp at free.fr-20090708133629-hb2ipu8s13ek0bm7
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: integration
timestamp: Fri 2009-07-10 10:33:11 +0200
message:
  Quicker check for changes in mutable trees
modified:
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
  bzrlib/mutabletree.py          mutabletree.py-20060906023413-4wlkalbdpsxi2r4y-2
  bzrlib/reconfigure.py          reconfigure.py-20070908040425-6ykgo7escxhyrg9p-1
  bzrlib/send.py                 send.py-20090521192735-j7cdb33ykmtmzx4w-1
  bzrlib/tests/intertree_implementations/test_compare.py test_compare.py-20060724101752-09ysswo1a92uqyoz-2
-------------- next part --------------
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2009-07-02 21:17:35 +0000
+++ b/bzrlib/builtins.py	2009-07-10 08:33:11 +0000
@@ -449,18 +449,18 @@
         except errors.NoWorkingTree:
             raise errors.BzrCommandError("No working tree to remove")
         except errors.NotLocalUrl:
-            raise errors.BzrCommandError("You cannot remove the working tree of a "
-                                         "remote path")
+            raise errors.BzrCommandError("You cannot remove the working tree"
+                                         " of a remote path")
         if not force:
-            changes = working.changes_from(working.basis_tree())
-            if changes.has_changed():
+            # XXX: What about pending merges ? -- vila 20090629
+            if working.has_changes(working.basis_tree()):
                 raise errors.UncommittedChanges(working)
 
         working_path = working.bzrdir.root_transport.base
         branch_path = working.branch.bzrdir.root_transport.base
         if working_path != branch_path:
-            raise errors.BzrCommandError("You cannot remove the working tree from "
-                                         "a lightweight checkout")
+            raise errors.BzrCommandError("You cannot remove the working tree"
+                                         " from a lightweight checkout")
 
         d.destroy_workingtree()
 
@@ -1114,8 +1114,8 @@
             revision_id = None
         if (tree is not None and revision_id is None
             and (strict is None or strict)): # Default to True:
-            changes = tree.changes_from(tree.basis_tree())
-            if changes.has_changed() or len(tree.get_parent_ids()) > 1:
+            if (tree.has_changes(tree.basis_tree())
+                 or len(tree.get_parent_ids()) > 1):
                 raise errors.UncommittedChanges(
                     tree, more='Use --no-strict to force the push.')
             if tree.last_revision() != tree.branch.last_revision():
@@ -3641,8 +3641,7 @@
         except errors.NoSuchRevision:
             basis_tree = tree.basis_tree()
         if not force:
-            changes = tree.changes_from(basis_tree)
-            if changes.has_changed():
+            if tree.has_changes(basis_tree):
                 raise errors.UncommittedChanges(tree)
 
         view_info = _get_view_info_for_change_reporter(tree)

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2009-04-14 15:02:46 +0000
+++ b/bzrlib/merge.py	2009-07-02 13:07:14 +0000
@@ -243,8 +243,7 @@
 
         if self.other_rev_id is None:
             other_basis_tree = self.revision_tree(self.other_basis)
-            changes = other_basis_tree.changes_from(self.other_tree)
-            if changes.has_changed():
+            if other_basis_tree.has_changes(self.other_tree):
                 raise WorkingTreeNotRevision(self.this_tree)
             other_rev_id = self.other_basis
             self.other_tree = other_basis_tree
@@ -276,8 +275,7 @@
             basis_tree = self.revision_tree(self.this_tree.last_revision())
         except errors.NoSuchRevision:
             basis_tree = self.this_tree.basis_tree()
-        changes = self.this_tree.changes_from(basis_tree)
-        if not changes.has_changed():
+        if not self.this_tree.has_changes(basis_tree):
             self.this_rev_id = self.this_basis
 
     def set_interesting_files(self, file_list):

=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py	2009-07-02 07:22:27 +0000
+++ b/bzrlib/mutabletree.py	2009-07-10 08:33:11 +0000
@@ -233,6 +233,23 @@
         raise NotImplementedError(self._gather_kinds)
 
     @needs_read_lock
+    def has_changes(self, from_tree):
+        """Quickly check that the tree contains at least one change.
+
+        :return: True if a change is found. False otherwise
+        """
+        changes = self.iter_changes(from_tree)
+        try:
+            change = changes.next()
+            # Exclude root (talk about black magic... --vila 20090629)
+            if change[4] == (None, None):
+                change = changes.next()
+            return True
+        except StopIteration:
+            # No changes
+            return False
+
+    @needs_read_lock
     def last_revision(self):
         """Return the revision id of the last commit performed in this tree.
 

=== modified file 'bzrlib/reconfigure.py'
--- a/bzrlib/reconfigure.py	2009-07-06 06:46:30 +0000
+++ b/bzrlib/reconfigure.py	2009-07-10 08:33:11 +0000
@@ -218,8 +218,8 @@
     def _check(self):
         """Raise if reconfiguration would destroy local changes"""
         if self._destroy_tree:
-            changes = self.tree.changes_from(self.tree.basis_tree())
-            if changes.has_changed():
+            # XXX: What about pending merges ? -- vila 20090629
+            if self.tree.has_changes(self.tree.basis_tree()):
                 raise errors.UncommittedChanges(self.tree)
         if self._create_reference and self.local_branch is not None:
             reference_branch = branch.Branch.open(self._select_bind_location())

=== modified file 'bzrlib/send.py'
--- a/bzrlib/send.py	2009-07-01 15:17:33 +0000
+++ b/bzrlib/send.py	2009-07-02 13:07:14 +0000
@@ -119,8 +119,8 @@
                     except KeyError:
                         strict = None
             if tree is not None and (strict is None or strict):
-                changes = tree.changes_from(tree.basis_tree())
-                if changes.has_changed() or len(tree.get_parent_ids()) > 1:
+                if (tree.has_changes(tree.basis_tree())
+                    or len(tree.get_parent_ids()) > 1):
                     raise errors.UncommittedChanges(
                         tree, more='Use --no-strict to force the send.')
                 if tree.last_revision() != tree.branch.last_revision():

=== modified file 'bzrlib/tests/intertree_implementations/test_compare.py'
--- a/bzrlib/tests/intertree_implementations/test_compare.py	2009-04-09 20:23:07 +0000
+++ b/bzrlib/tests/intertree_implementations/test_compare.py	2009-07-08 13:36:29 +0000
@@ -21,6 +21,7 @@
 
 from bzrlib import (
     errors,
+    mutabletree,
     tests,
     workingtree_4,
     )
@@ -367,6 +368,25 @@
             tree1.unlock()
             tree2.unlock()
 
+    def check_has_changes(self, expected, tree1, tree2):
+        # has_changes is defined for mutable trees only
+        print '\nt1, t2: %r, %r' % (type(tree1), type(tree2))
+        if not isinstance(tree2, mutabletree.MutableTree):
+            if isinstance(tree1, mutabletree.MutableTree):
+                # Let's switch the trees since has_changes() is commutative
+                # (where we can apply it)
+                tree2, tree1 = tree1, tree2
+            else:
+                # Neither tree can be used
+                return
+        tree1.lock_read()
+        tree2.lock_read()
+        try:
+            return tree2.has_changes(tree1)
+        finally:
+            tree1.unlock()
+            tree2.unlock()
+
     def mutable_trees_to_locked_test_trees(self, tree1, tree2):
         """Convert the working trees into test trees.
 
@@ -436,6 +456,7 @@
         tree2 = self.get_tree_no_parents_no_content(tree2)
         tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
         self.assertEqual([], self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(False, tree1, tree2)
 
     def added(self, tree, file_id):
         path, entry = self.get_path_entry(tree, file_id)
@@ -519,6 +540,7 @@
             self.added(tree2, 'c-id'),
             self.deleted(tree1, 'empty-root-id')])
         self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_empty_specific_files(self):
         tree1 = self.make_branch_and_tree('1')
@@ -542,6 +564,7 @@
             self.added(tree2, 'c-id'),
             self.deleted(tree1, 'empty-root-id')])
         self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_empty_to_abc_content_a_only(self):
         tree1 = self.make_branch_and_tree('1')
@@ -593,6 +616,7 @@
         self.assertEqual(
             expected_results,
             self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_content_modification(self):
         tree1 = self.make_branch_and_tree('1')
@@ -605,6 +629,7 @@
                            (root_id, root_id), ('a', 'a'),
                            ('file', 'file'), (False, False))],
                          self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_meta_modification(self):
         tree1 = self.make_branch_and_tree('1')
@@ -834,6 +859,7 @@
             self.content_changed(tree2, 'c-id'),
             ])
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_unversioned_paths_in_tree(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1051,6 +1077,7 @@
         self.assertEqual(expected,
             self.do_iter_changes(tree1, tree2, include_unchanged=True,
                 want_unversioned=True))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_versioned_symlinks_specific_files(self):
         self.requireFeature(tests.SymlinkFeature)
@@ -1072,17 +1099,20 @@
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2,
             specific_files=['added', 'changed', 'fromdir', 'fromfile',
             'removed', 'unchanged', 'todir', 'tofile']))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_tree_with_special_names(self):
         tree1, tree2, paths, path_ids = self.make_tree_with_special_names()
         expected = sorted(self.added(tree2, f_id) for f_id in path_ids)
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_trees_with_special_names(self):
         tree1, tree2, paths, path_ids = self.make_trees_with_special_names()
         expected = sorted(self.content_changed(tree2, f_id) for f_id in path_ids
                           if f_id.endswith('_f-id'))
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_trees_with_deleted_dir(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1106,6 +1136,7 @@
             self.deleted(tree1, 'e-id'),
             ])
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_added_unicode(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1134,6 +1165,7 @@
         self.assertEqual([self.added(tree2, added_id)],
                          self.do_iter_changes(tree1, tree2,
                                               specific_files=[u'\u03b1']))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_deleted_unicode(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1162,6 +1194,7 @@
         self.assertEqual([self.deleted(tree1, deleted_id)],
                          self.do_iter_changes(tree1, tree2,
                                               specific_files=[u'\u03b1']))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_modified_unicode(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1191,6 +1224,7 @@
         self.assertEqual([self.content_changed(tree1, mod_id)],
                          self.do_iter_changes(tree1, tree2,
                                               specific_files=[u'\u03b1']))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_renamed_unicode(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1221,6 +1255,7 @@
         self.assertEqual([self.renamed(tree1, tree2, rename_id, False)],
                          self.do_iter_changes(tree1, tree2,
                                               specific_files=[u'\u03b1']))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_unchanged_unicode(self):
         tree1 = self.make_branch_and_tree('tree1')
@@ -1309,6 +1344,7 @@
                                               want_unversioned=True))
         self.assertEqual([], # Without want_unversioned we should get nothing
                          self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(False, tree1, tree2)
 
         # We should also be able to select just a subset
         expected = sorted([
@@ -1389,6 +1425,7 @@
             ])
         self.assertEqual(expected,
                          self.do_iter_changes(tree1, tree2))
+        self.check_has_changes(True, tree1, tree2)
 
     def test_deleted_and_unknown(self):
         """Test a file marked removed, but still present on disk."""



More information about the bazaar-commits mailing list