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