Rev 4262: (robertc) Add InterCHKRevisionTree. (Vincent Ladeuil) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Apr 7 09:11:22 BST 2009


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

------------------------------------------------------------
revno: 4262
revision-id: pqm at pqm.ubuntu.com-20090407081119-1sok81r9ekyriw0y
parent: pqm at pqm.ubuntu.com-20090407063231-wwssbcpv1p0p31jk
parent: robertc at robertcollins.net-20090407072017-rxvtpahno3yfb52e
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2009-04-07 09:11:19 +0100
message:
  (robertc) Add InterCHKRevisionTree. (Vincent Ladeuil)
modified:
  bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
  bzrlib/tests/intertree_implementations/__init__.py __init__.py-20060724101752-09ysswo1a92uqyoz-3
  bzrlib/tests/intertree_implementations/test_compare.py test_compare.py-20060724101752-09ysswo1a92uqyoz-2
    ------------------------------------------------------------
    revno: 4241.6.7
    revision-id: robertc at robertcollins.net-20090407072017-rxvtpahno3yfb52e
    parent: robertc at robertcollins.net-20090407054228-zslrfatxy9nw231i
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: integration
    timestamp: Tue 2009-04-07 17:20:17 +1000
    message:
      Add InterCHKRevisionTree
    modified:
      bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
      bzrlib/tests/intertree_implementations/__init__.py __init__.py-20060724101752-09ysswo1a92uqyoz-3
      bzrlib/tests/intertree_implementations/test_compare.py test_compare.py-20060724101752-09ysswo1a92uqyoz-2
=== modified file 'bzrlib/revisiontree.py'
--- a/bzrlib/revisiontree.py	2009-03-25 16:27:34 +0000
+++ b/bzrlib/revisiontree.py	2009-04-07 07:20:17 +0000
@@ -23,11 +23,11 @@
     osutils,
     revision,
     symbol_versioning,
+    tree,
     )
-from bzrlib.tree import Tree
-
-
-class RevisionTree(Tree):
+
+
+class RevisionTree(tree.Tree):
     """Tree viewing a previous revision.
 
     File text can be retrieved from the text store.
@@ -208,3 +208,71 @@
             self._rules_searcher = super(RevisionTree,
                 self)._get_rules_searcher(default_searcher)
         return self._rules_searcher
+
+
+class InterCHKRevisionTree(tree.InterTree):
+    """Fast path optimiser for RevisionTrees with CHK inventories."""
+
+    @staticmethod
+    def is_compatible(source, target):
+        if (isinstance(source, RevisionTree)
+            and isinstance(target, RevisionTree)):
+            try:
+                # Only CHK inventories have id_to_entry attribute
+                source.inventory.id_to_entry
+                target.inventory.id_to_entry
+                return True
+            except AttributeError:
+                pass
+        return False
+
+    def iter_changes(self, include_unchanged=False,
+                     specific_files=None, pb=None, extra_trees=[],
+                     require_versioned=True, want_unversioned=False):
+        lookup_trees = [self.source]
+        if extra_trees:
+             lookup_trees.extend(extra_trees)
+        if specific_files == []:
+            specific_file_ids = []
+        else:
+            specific_file_ids = self.target.paths2ids(specific_files,
+                lookup_trees, require_versioned=require_versioned)
+
+        # FIXME: It should be possible to delegate include_unchanged handling
+        # to CHKInventory.iter_changes and do a better job there -- vila
+        # 20090304
+        if include_unchanged:
+            changed_file_ids = []
+        for result in self.target.inventory.iter_changes(self.source.inventory):
+            if (specific_file_ids is not None
+                and not result[0] in specific_file_ids):
+                # CHKMap.iter_changes is clean and fast. Better filter out
+                # the specific files *after* it did its job.
+                continue
+            yield result
+            if include_unchanged:
+                # Keep track of yielded results (cheaper than building the
+                # whole inventory).
+                changed_file_ids.append(result[0])
+        if include_unchanged:
+            # CHKMap avoid being O(tree), so we go to O(tree) only if
+            # required to.
+            # Now walk the whole inventory, excluding the already yielded
+            # file ids
+            changed_file_ids = set(changed_file_ids)
+            for relpath, entry in self.target.inventory.iter_entries():
+                if (specific_file_ids is not None
+                    and not entry.file_id in specific_file_ids):
+                    continue
+                if not entry.file_id in changed_file_ids:
+                    yield (entry.file_id,
+                           (relpath, relpath), # Not renamed
+                           False, # Not modified
+                           (True, True), # Still  versioned
+                           (entry.parent_id, entry.parent_id),
+                           (entry.name, entry.name),
+                           (entry.kind, entry.kind),
+                           (entry.executable, entry.executable))
+
+
+tree.InterTree.register_optimiser(InterCHKRevisionTree)

=== modified file 'bzrlib/tests/intertree_implementations/__init__.py'
--- a/bzrlib/tests/intertree_implementations/__init__.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/intertree_implementations/__init__.py	2009-04-07 07:20:17 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2006 Canonical Ltd
+# Copyright (C) 2006, 2009 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,11 @@
 """
 
 import bzrlib
-import bzrlib.errors as errors
+from bzrlib import (
+    errors,
+    revisiontree,
+    tests,
+    )
 from bzrlib.transport import get_transport
 from bzrlib.transform import TransformPreview
 from bzrlib.tests import (
@@ -39,6 +43,7 @@
 from bzrlib.workingtree import (
     WorkingTreeFormat3,
     )
+from bzrlib.workingtree_4 import WorkingTreeFormat4
 
 
 def return_provided_trees(test_case, source, target):
@@ -48,6 +53,23 @@
 
 class TestCaseWithTwoTrees(TestCaseWithTree):
 
+    def not_applicable_if_cannot_represent_unversioned(self, tree):
+        if isinstance(tree, revisiontree.RevisionTree):
+            # The locked test trees conversion could not preserve the
+            # unversioned file status. This is normal (e.g. InterDirstateTree
+            # falls back to InterTree if the basis is not a
+            # DirstateRevisionTree, and revision trees cannot have unversioned
+            # files.
+            raise tests.TestNotApplicable('cannot represent unversioned files')
+
+    def not_applicable_if_missing_in(self, relpath, tree):
+        if not tree.path2id(relpath):
+            # The locked test trees conversion could not preserve the missing
+            # file status. This is normal (e.g. InterDirstateTree falls back
+            # to InterTree if the basis is not a DirstateRevisionTree, and
+            # revision trees cannot have missing files.
+            raise tests.TestNotApplicable('cannot represent missing files')
+
     def make_to_branch_and_tree(self, relpath):
         """Make a to_workingtree_format branch and tree."""
         made_control = self.make_bzrdir(relpath,
@@ -94,6 +116,11 @@
     test_case.addCleanup(preview.finalize)
     return source, preview.get_preview_tree()
 
+def mutable_trees_to_revision_trees(test_case, source, target):
+    """Convert both trees to repository based revision trees."""
+    return (revision_tree_from_workingtree(test_case, source),
+        revision_tree_from_workingtree(test_case, target))
+
 
 def load_tests(standard_tests, module, loader):
     default_tree_format = WorkingTreeFormat3()
@@ -102,10 +129,23 @@
         ])
     test_intertree_permutations = [
         # test InterTree with two default-format working trees.
-        (InterTree.__name__, InterTree, default_tree_format, default_tree_format,
+        (InterTree.__name__, InterTree,
+         default_tree_format, default_tree_format,
          return_provided_trees)]
     for optimiser in InterTree._optimisers:
-        if optimiser is bzrlib.workingtree_4.InterDirStateTree:
+        if optimiser is revisiontree.InterCHKRevisionTree:
+            # XXX: we shouldn't use an Intertree object to detect inventories
+            # -- vila 20090311
+            chk_tree_format = WorkingTreeFormat4()
+            chk_tree_format._get_matchingbzrdir = \
+                lambda:bzrlib.bzrdir.format_registry.make_bzrdir('development')
+            test_intertree_permutations.append(
+                (InterTree.__name__ + "(CHKInventory)",
+                 InterTree,
+                 chk_tree_format,
+                 chk_tree_format,
+                 mutable_trees_to_revision_trees))
+        elif optimiser is bzrlib.workingtree_4.InterDirStateTree:
             # Its a little ugly to be conditional here, but less so than having
             # the optimiser listed twice.
             # Add once, compiled version

=== modified file 'bzrlib/tests/intertree_implementations/test_compare.py'
--- a/bzrlib/tests/intertree_implementations/test_compare.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/intertree_implementations/test_compare.py	2009-04-07 07:20:17 +0000
@@ -19,7 +19,11 @@
 import os
 import shutil
 
-from bzrlib import errors, tests, workingtree_4
+from bzrlib import (
+    errors,
+    tests,
+    workingtree_4,
+    )
 from bzrlib.osutils import file_kind, has_symlinks
 from bzrlib.tests import TestNotApplicable
 from bzrlib.tests.intertree_implementations import TestCaseWithTwoTrees
@@ -328,6 +332,7 @@
         else:
             links_supported = False
         tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         d = self.intertree_class(tree1, tree2).compare(want_unversioned=True)
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -672,6 +677,8 @@
         shutil.rmtree('2/b')
         # TODO ? have a symlink here?
         tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
+        self.not_applicable_if_missing_in('a', tree2)
+        self.not_applicable_if_missing_in('b', tree2)
         root_id = tree1.path2id('')
         expected = sorted([
             self.missing('a-id', 'a', 'a', root_id, 'file'),
@@ -690,6 +697,7 @@
         tree2.add(['directory'], ['file-id'])
         os.rmdir('tree2/directory')
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_missing_in('directory', tree2)
 
         root_id = tree1.path2id('')
         expected = sorted([
@@ -705,13 +713,8 @@
         tree1.add(['file'], ['file-id'])
         os.unlink('tree1/file')
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_missing_in('file', tree1)
         root_id = tree1.path2id('')
-        if not tree1.path2id('file'):
-            # The locked test trees conversion could not preserve the missing
-            # file status. This is normal (e.g. InterDirstateTree falls back
-            # to InterTree if the basis is not a DirstateRevisionTree, and
-            # revision trees cannot have missing files.
-            raise TestNotApplicable()
         expected = [('file-id', ('file', None), False, (True, False),
             (root_id, None), ('file', None), (None, None), (False, None))]
         self.assertEqual(expected, self.do_iter_changes(tree1, tree2))
@@ -724,6 +727,7 @@
         tree2.add(['file'], ['file-id'])
         os.unlink('tree2/file')
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_missing_in('file', tree2)
         root_id = tree1.path2id('')
         expected = [('file-id', (None, 'file'), False, (False, True),
             (None, root_id), (None, 'file'), (None, None), (None, False))]
@@ -842,6 +846,7 @@
         else:
             links_supported = False
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         expected = [
             self.unversioned(tree2, 'file'),
             self.unversioned(tree2, 'dir'),
@@ -862,6 +867,7 @@
         else:
             links_supported = False
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         expected = [
             self.unversioned(tree2, 'file'),
             self.unversioned(tree2, 'dir'),
@@ -902,6 +908,7 @@
             tree1.add(['link'], ['link-id'])
             tree2.add(['movedlink'], ['link-id'])
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         root_id = tree1.path2id('')
         expected = [
             self.renamed(tree1, tree2, 'dir-id', False),
@@ -951,6 +958,7 @@
                   ['a-id', 'b-id', 'c-id', 'd-id', 'a-c-id', 'e-id'])
 
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
 
         self.assertEqual([], self.do_iter_changes(tree1, tree2,
                                                   want_unversioned=True))
@@ -975,6 +983,7 @@
         tree2.set_root_id(tree1.get_root_id())
         self.build_tree(['tree2/dir/', 'tree2/dir/file'])
         tree1, tree2 = self.mutable_trees_to_test_trees(self, tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         expected = [
             self.unversioned(tree2, 'dir'),
             ]
@@ -1024,6 +1033,7 @@
     def test_versioned_symlinks(self):
         self.requireFeature(tests.SymlinkFeature)
         tree1, tree2 = self.make_trees_with_symlinks()
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
         root_id = tree1.path2id('')
         expected = [
             self.unchanged(tree1, tree1.path2id('')),
@@ -1283,6 +1293,7 @@
         tree2.add([u'\u03b1'], [a_id])
 
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
 
         expected = sorted([
             self.unversioned(tree2, u'\u03b1/unknown_dir'),
@@ -1333,6 +1344,7 @@
         self.build_tree(['tree2/a/file', 'tree2/a/dir/', 'tree2/a/dir/subfile'])
 
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
 
         expected = sorted([
             self.unversioned(tree2, u'a/file'),
@@ -1400,6 +1412,7 @@
         tree2.add(['a', 'c'], ['a-id', 'c-id'])
 
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_cannot_represent_unversioned(tree2)
 
         expected = sorted([
             self.deleted(tree1, 'b-id'),
@@ -1473,6 +1486,7 @@
         os.rename('tree2/a', 'tree2/a2')
 
         tree1, tree2 = self.mutable_trees_to_locked_test_trees(tree1, tree2)
+        self.not_applicable_if_missing_in('a', tree2)
 
         expected = sorted([
             self.missing('a-id', 'a', 'a', tree2.get_root_id(), 'file'),




More information about the bazaar-commits mailing list