Rev 3516: Handle the case when a record is missing in base in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/multi_walker
John Arbash Meinel
john at arbash-meinel.com
Mon Jun 30 20:48:31 BST 2008
At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/multi_walker
------------------------------------------------------------
revno: 3516
revision-id: john at arbash-meinel.com-20080630194801-gdodhpossmf1n85a
parent: john at arbash-meinel.com-20080630192436-hv4ppxq7dpp38mii
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: multi_walker
timestamp: Mon 2008-06-30 14:48:01 -0500
message:
Handle the case when a record is missing in base
-------------- next part --------------
=== modified file 'bzrlib/tests/test_tree.py'
--- a/bzrlib/tests/test_tree.py 2008-06-30 19:24:36 +0000
+++ b/bzrlib/tests/test_tree.py 2008-06-30 19:48:01 +0000
@@ -180,6 +180,32 @@
self.assertStepOne(False, None, None, iterator)
self.assertStepOne(False, None, None, iterator)
+ def assertWalkerNext(self, exp_path, exp_file_id, master_is_None,
+ exp_other_paths, iterator):
+ """Check what happens when we step the iterator.
+
+ :param path: The path for this entry
+ :param file_id: The file_id for this entry
+ :param master_is_None: Is this node None for the master tree?
+ :param exp_other_paths: A list of other_path values.
+ :param iterator: The iterator to step
+ """
+ path, file_id, master_ie, other_values = iterator.next()
+ self.assertEqual(exp_path, path)
+ self.assertEqual(exp_file_id, file_id)
+ if master_is_None:
+ self.assertIs(None, master_ie)
+ else:
+ self.assertIsNot(None, master_ie)
+ self.assertEqual(len(exp_other_paths), len(other_values))
+ for exp_other_path, (other_path, other_ie) in \
+ zip(exp_other_paths, other_values):
+ self.assertEqual(exp_other_path, other_path)
+ if exp_other_path is None:
+ self.assertIs(None, other_ie)
+ else:
+ self.assertEqual(file_id, other_ie.file_id)
+
def test_simple_stepping(self):
tree = self.make_branch_and_tree('tree')
self.build_tree(['tree/a', 'tree/b/', 'tree/b/c'])
@@ -192,39 +218,36 @@
basis_tree.lock_read()
self.addCleanup(basis_tree.unlock)
- walker = _mod_tree.MultiWalker(tree, [basis_tree])
- iterator = walker.iter_all()
- master_path, file_id, master_ie, other_values = iterator.next()
- root_id = tree.path2id('')
- self.assertEqual('', master_path)
- self.assertEqual(root_id, file_id)
- self.assertEqual(1, len(other_values))
- other_path, other_ie = other_values[0]
- self.assertEqual('', other_path)
- self.assertEqual(root_id, other_ie.file_id)
-
- master_path, file_id, master_ie, other_values = iterator.next()
- self.assertEqual(u'a', master_path)
- self.assertEqual('a-id', file_id)
- self.assertEqual(1, len(other_values))
- other_path, other_ie = other_values[0]
- self.assertEqual(u'a', other_path)
- self.assertEqual('a-id', other_ie.file_id)
-
- master_path, file_id, master_ie, other_values = iterator.next()
- self.assertEqual(u'b', master_path)
- self.assertEqual('b-id', file_id)
- self.assertEqual(1, len(other_values))
- other_path, other_ie = other_values[0]
- self.assertEqual(u'b', other_path)
- self.assertEqual('b-id', other_ie.file_id)
-
- master_path, file_id, master_ie, other_values = iterator.next()
- self.assertEqual(u'b/c', master_path)
- self.assertEqual('c-id', file_id)
- self.assertEqual(1, len(other_values))
- other_path, other_ie = other_values[0]
- self.assertEqual(u'b/c', other_path)
- self.assertEqual('c-id', other_ie.file_id)
-
+ root_id = tree.path2id('')
+
+ walker = _mod_tree.MultiWalker(tree, [basis_tree])
+ iterator = walker.iter_all()
+ self.assertWalkerNext(u'', root_id, False, [u''], iterator)
+ self.assertWalkerNext(u'a', 'a-id', False, [u'a'], iterator)
+ self.assertWalkerNext(u'b', 'b-id', False, [u'b'], iterator)
+ self.assertWalkerNext(u'b/c', 'c-id', False, [u'b/c'], iterator)
+ self.assertRaises(StopIteration, iterator.next)
+
+ def test_master_has_extra(self):
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree(['tree/a', 'tree/b/', 'tree/c', 'tree/d'])
+ tree.add(['a', 'b', 'd'], ['a-id', 'b-id', 'd-id'])
+
+ tree.commit('first', rev_id='first-rev-id')
+ basis_tree = tree.basis_tree()
+
+ tree.add(['c'], ['c-id'])
+ tree.lock_read()
+ self.addCleanup(tree.unlock)
+ basis_tree.lock_read()
+ self.addCleanup(basis_tree.unlock)
+
+ root_id = tree.path2id('')
+ walker = _mod_tree.MultiWalker(tree, [basis_tree])
+ iterator = walker.iter_all()
+ self.assertWalkerNext(u'', root_id, False, [u''], iterator)
+ self.assertWalkerNext(u'a', 'a-id', False, [u'a'], iterator)
+ self.assertWalkerNext(u'b', 'b-id', False, [u'b'], iterator)
+ self.assertWalkerNext(u'c', 'c-id', False, [None], iterator)
+ self.assertWalkerNext(u'd', 'd-id', False, [u'd'], iterator)
self.assertRaises(StopIteration, iterator.next)
=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py 2008-06-30 19:24:36 +0000
+++ b/bzrlib/tree.py 2008-06-30 19:48:01 +0000
@@ -940,15 +940,44 @@
else:
return True, path, ie
+ @staticmethod
+ def _cmp_path_by_dirblock(path1, path2):
+ """Compare two paths based on what directory they are in.
+
+ This generates a sort order, such that all children of a directory are
+ sorted together, and grandchildren are in the same order as the
+ children appear. But all grandchildren come after all children.
+
+ :param path1: first path
+ :param path2: the second path
+ :return: negative number if ``path1`` comes first,
+ 0 if paths are equal
+ and a positive number if ``path2`` sorts first
+ """
+ # This is stolen from _dirstate_helpers_py.py, only switching it to
+ # Unicode objects. Consider using encode_utf8() and then using the
+ # optimized versions, or maybe writing optimized unicode versions.
+ if not isinstance(path1, unicode):
+ raise TypeError("'path1' must be a unicode string, not %s: %r"
+ % (type(path1), path1))
+ if not isinstance(path2, unicode):
+ raise TypeError("'path2' must be a unicode string, not %s: %r"
+ % (type(path2), path2))
+ dirname1, basename1 = os.path.split(path1)
+ key1 = (dirname1.split('/'), basename1)
+ dirname2, basename2 = os.path.split(path2)
+ key2 = (dirname2.split('/'), basename2)
+ return cmp(key1, key2)
+
def iter_all(self):
"""Match up the values in the different trees."""
- import pdb; pdb.set_trace()
master_iterator = self._master_tree.iter_entries_by_dir()
other_walkers = [other.iter_entries_by_dir()
for other in self._other_trees]
other_entries = [self._step_one(walker) for walker in other_walkers]
+
master_has_more = True
while master_has_more:
(master_has_more, master_path,
@@ -956,7 +985,7 @@
if not master_has_more:
break
- master_file_id = master_ie.file_id
+ file_id = master_ie.file_id
other_values = []
next_other_entries = []
for other_walker, (other_has_more, other_path, other_ie) in \
@@ -964,7 +993,7 @@
if not other_has_more:
other_values.append((None, None))
next_other_entries.append(False, None, None)
- elif master_file_id == other_ie.file_id:
+ elif file_id == other_ie.file_id:
# This walker matched, so consume this path, and go on to
# the next
other_values.append((other_path, other_ie))
@@ -972,8 +1001,20 @@
else:
# This walker did not match, step it until it either
# matches, or we know we are past the current walker.
- raise NotImplementedError
+ while (other_has_more and
+ self._cmp_path_by_dirblock(other_path, master_path) < 0):
+ other_has_more, other_path, other_ie = \
+ self._step_one(other_walker)
+ if other_has_more and other_ie.file_id == file_id:
+ # We ended up walking to this point, match and continue
+ other_values.append((other_path, other_ie))
+ other_has_more, other_path, other_ie = \
+ self._step_one(other_walker)
+ else:
+ other_values.append((None, None))
+ next_other_entries.append((other_has_more, other_path,
+ other_ie))
other_entries = next_other_entries
# We've matched all the walkers, yield this datapoint
- yield master_path, master_file_id, master_ie, other_values
+ yield master_path, file_id, master_ie, other_values
More information about the bazaar-commits
mailing list