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