Rev 2355: Create a paths2ids api to replace find_ids_across_trees, with tests. in sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/
Robert Collins
robertc at robertcollins.net
Thu Feb 22 01:18:35 GMT 2007
At sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/
------------------------------------------------------------
revno: 2355
revision-id: robertc at robertcollins.net-20070222011730-zff5fh9qvxrcqa56
parent: robertc at robertcollins.net-20070222011415-dtqnanb4cxdl4zus
committer: Robert Collins <robertc at robertcollins.net>
branch nick: dirstate
timestamp: Thu 2007-02-22 12:17:30 +1100
message:
Create a paths2ids api to replace find_ids_across_trees, with tests.
added:
bzrlib/tests/workingtree_implementations/test_paths2ids.py test_paths2ids.py-20070222011621-kesvovdwm69nndtx-1
modified:
bzrlib/tests/workingtree_implementations/__init__.py __init__.py-20060203003124-b2aa5aca21a8bfad
bzrlib/tree.py tree.py-20050309040759-9d5f2496be663e77
=== added file 'bzrlib/tests/workingtree_implementations/test_paths2ids.py'
--- a/bzrlib/tests/workingtree_implementations/test_paths2ids.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_paths2ids.py 2007-02-22 01:17:30 +0000
@@ -0,0 +1,132 @@
+# Copyright (C) 2007 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
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""Tests for WorkingTree.paths2ids.
+
+This API probably needs to be exposed as a tree implementation test, but these
+initial tests are for the specific cases being refactored from
+find_ids_across_trees.
+"""
+
+from operator import attrgetter
+
+from bzrlib import errors, inventory
+from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
+
+
+class TestPaths2Ids(TestCaseWithWorkingTree):
+
+ def assertExpectedIds(self, ids, tree, paths, trees=None):
+ """Run paths2ids for tree, and check the result."""
+ tree.lock_read()
+ if trees:
+ map(apply, map(attrgetter('lock_read'), trees))
+ result = tree.paths2ids(paths, trees)
+ map(apply, map(attrgetter('unlock'), trees))
+ else:
+ result = tree.paths2ids(paths)
+ self.assertEqual(set(ids), result)
+ tree.unlock()
+
+ def test_find_single_root(self):
+ tree = self.make_branch_and_tree('tree')
+ self.assertExpectedIds([tree.path2id('')], tree, [''])
+
+ def test_find_tree_and_clone_roots(self):
+ tree = self.make_branch_and_tree('tree')
+ clone = tree.bzrdir.clone('clone').open_workingtree()
+ clone.lock_tree_write()
+ clone_root_id = 'new-id'
+ clone.set_root_id(clone_root_id)
+ tree_root_id = tree.path2id('')
+ clone.unlock()
+ self.assertExpectedIds([tree_root_id, clone_root_id], tree, [''], [clone])
+
+ def test_find_tree_basis_roots(self):
+ tree = self.make_branch_and_tree('tree')
+ tree.commit('basis')
+ basis = tree.basis_tree()
+ basis_root_id = basis.path2id('')
+ tree.lock_tree_write()
+ tree_root_id = 'new-id'
+ tree.set_root_id(tree_root_id)
+ tree.unlock()
+ self.assertExpectedIds([tree_root_id, basis_root_id], tree, [''], [basis])
+
+ def test_find_children_of_moved_directories(self):
+ """Check the basic nasty corner case that path2ids should handle.
+
+ This is the following situation:
+ basis:
+ / ROOT
+ /dir dir
+ /dir/child-moves child-moves
+ /dir/child-stays child-stays
+ /dir/child-goes child-goes
+
+ current tree:
+ / ROOT
+ /child-moves child-moves
+ /newdir newdir
+ /newdir/dir dir
+ /newdir/dir/child-stays child-stays
+ /newdir/dir/new-child new-child
+
+ In english: we move a directory under a directory that was a sibling,
+ and at the same time remove, or move out of the directory, some of its
+ children, and give it a new child previous absent or a sibling.
+
+ current_tree.path2ids(['newdir'], [basis]) is meant to handle this
+ correctly: that is it should return the ids:
+ newdir because it was provided
+ dir, because its under newdir in current
+ child-moves because its under dir in old
+ child-stays either because its under newdir/dir in current, or under dir in old
+ child-goes because its under dir in old.
+ new-child because its under dir in new
+
+ Symmetrically, current_tree.path2ids(['dir'], [basis]) is meant to show
+ new-child, even though its not under the path 'dir' in current, because
+ its under a path selected by 'dir' in basis:
+ dir because its selected in basis.
+ child-moves because its under dir in old
+ child-stays either because its under newdir/dir in current, or under dir in old
+ child-goes because its under dir in old.
+ new-child because its under dir in new.
+ """
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree(
+ ['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays',
+ 'tree/dir/child-goes'])
+ tree.add(['dir', 'dir/child-moves', 'dir/child-stays', 'dir/child-goes'],
+ ['dir', 'child-moves', 'child-stays', 'child-goes'])
+ tree.commit('create basis')
+ basis = tree.basis_tree()
+ tree.unversion(['child-goes'])
+ tree.rename_one('dir/child-moves', 'child-moves')
+ self.build_tree(['tree/newdir/'])
+ tree.add(['newdir'], ['newdir'])
+ tree.rename_one('dir/child-stays', 'child-stays')
+ tree.rename_one('dir', 'newdir/dir')
+ tree.rename_one('child-stays', 'newdir/dir/child-stays')
+ self.build_tree(['tree/newdir/dir/new-child'])
+ tree.add(['newdir/dir/new-child'], ['new-child'])
+ self.assertExpectedIds(
+ ['newdir', 'dir', 'child-moves', 'child-stays', 'child-goes',
+ 'new-child'], tree, ['newdir'], [basis])
+ self.assertExpectedIds(
+ ['dir', 'child-moves', 'child-stays', 'child-goes', 'new-child'],
+ tree, ['dir'], [basis])
=== modified file 'bzrlib/tests/workingtree_implementations/__init__.py'
--- a/bzrlib/tests/workingtree_implementations/__init__.py 2007-02-16 01:07:12 +0000
+++ b/bzrlib/tests/workingtree_implementations/__init__.py 2007-02-22 01:17:30 +0000
@@ -65,6 +65,7 @@
'bzrlib.tests.workingtree_implementations.test_merge_from_branch',
'bzrlib.tests.workingtree_implementations.test_mkdir',
'bzrlib.tests.workingtree_implementations.test_parents',
+ 'bzrlib.tests.workingtree_implementations.test_paths2ids',
'bzrlib.tests.workingtree_implementations.test_pull',
'bzrlib.tests.workingtree_implementations.test_put_file',
'bzrlib.tests.workingtree_implementations.test_readonly',
=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py 2007-02-17 03:34:50 +0000
+++ b/bzrlib/tree.py 2007-02-22 01:17:30 +0000
@@ -216,6 +216,17 @@
"""Return the id for path in this tree."""
return self._inventory.path2id(path)
+ def paths2ids(self, paths, trees=[]):
+ """Return all the ids that can be reached by walking from paths.
+
+ Each path is looked up in each this tree and any extras provided in
+ trees, and this is repeated recursively: the children in an extra tree
+ of a directory that has been renamed under a provided path in this tree
+ are all returned, even if none exist until a provided path in this
+ tree, and vice versa.
+ """
+ return find_ids_across_trees(paths, [self] + trees)
+
def print_file(self, file_id):
"""Print file with id `file_id` to stdout."""
import sys
More information about the bazaar-commits
mailing list