Rev 2481: Get merge_nested finally working: change nested tree iterators to take file_ids, and ensure the right branch is connected to in the merge logic. May not be suitable for shared repositories yet. in http://bazaar.launchpad.net/~bzr/bzr/dirstate

Robert Collins robertc at robertcollins.net
Tue Mar 6 12:29:49 GMT 2007


At http://bazaar.launchpad.net/~bzr/bzr/dirstate

------------------------------------------------------------
revno: 2481
revision-id: robertc at robertcollins.net-20070306122818-xk0lc3l01ecl6vbc
parent: mbp at sourcefrog.net-20070306121306-n387xz1h5aguv1he
committer: Robert Collins <robertc at robertcollins.net>
branch nick: dirstate.dogfood
timestamp: Tue 2007-03-06 23:28:18 +1100
message:
  Get merge_nested finally working: change nested tree iterators to take file_ids, and ensure the right branch is connected to in the merge logic. May not be suitable for shared repositories yet.
modified:
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
  bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
  bzrlib/merge.py                merge.py-20050513021216-953b65a438527106
  bzrlib/revisiontree.py         revisiontree.py-20060724012533-bg8xyryhxd0o0i0h-1
  bzrlib/tests/tree_implementations/test_tree.py test_tree.py-20061215160206-usu7lwcj8aq2n3br-1
  bzrlib/tests/workingtree_implementations/test_commit.py test_commit.py-20060421013633-1610ec2331c8190f
  bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2007-03-05 04:55:34 +0000
+++ b/bzrlib/branch.py	2007-03-06 12:28:18 +0000
@@ -687,12 +687,16 @@
             # branch tip correctly, and seed it with history.
             checkout_branch.pull(self, stop_revision=revision_id)
         tree = checkout.create_workingtree(revision_id)
-        for path, entry in tree.iter_reference_entries():
-            path = tree.id2path(entry.file_id)
-            reference_parent = self.reference_parent(entry.file_id, path)
-            reference_parent.create_checkout(tree.abspath(path),
-                                             entry.reference_revision,
-                                             lightweight)
+        basis_tree = tree.basis_tree()
+        basis_tree.lock_read()
+        try:
+            for path, file_id in basis_tree.iter_references():
+                reference_parent = self.reference_parent(file_id, path)
+                reference_parent.create_checkout(tree.abspath(path),
+                    basis_tree.get_reference_revision(file_id, path),
+                    lightweight)
+        finally:
+            basis_tree.unlock()
         return tree
 
     def reference_parent(self, file_id, path):

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2007-03-06 07:24:20 +0000
+++ b/bzrlib/bzrdir.py	2007-03-06 12:28:18 +0000
@@ -768,19 +768,28 @@
             wt = None
         if recurse == 'down':
             if wt is not None:
-                entries = wt.iter_reference_entries()
+                basis = wt.basis_tree()
+                basis.lock_read()
+                subtrees = basis.iter_references()
                 recurse_branch = wt.branch
             elif source_branch is not None:
-                entries = source_branch.basis_tree().iter_reference_entries()
+                basis = source_branch.basis_tree()
+                basis.lock_read()
+                subtrees = basis.iter_references()
                 recurse_branch = source_branch
             else:
-                entries = []
-            for path, entry in entries:
-                target = urlutils.join(url, urlutils.escape(path))
-                sublocation = source_branch.reference_parent(entry.file_id,
-                                                             path)
-                sublocation.bzrdir.sprout(target, entry.reference_revision,
-                    force_new_repo=force_new_repo, recurse=recurse)
+                subtrees = []
+                basis = None
+            try:
+                for path, file_id in subtrees:
+                    target = urlutils.join(url, urlutils.escape(path))
+                    sublocation = source_branch.reference_parent(file_id, path)
+                    sublocation.bzrdir.sprout(target,
+                        basis.get_reference_revision(file_id, path),
+                        force_new_repo=force_new_repo, recurse=recurse)
+            finally:
+                if basis is not None:
+                    basis.unlock()
         return result
 
 

=== modified file 'bzrlib/inventory.py'
--- a/bzrlib/inventory.py	2007-03-06 10:51:27 +0000
+++ b/bzrlib/inventory.py	2007-03-06 12:28:18 +0000
@@ -843,7 +843,8 @@
     def _read_tree_state(self, path, work_tree):
         """Populate fields in the inventory entry from the given tree.
         """
-        self.reference_revision = work_tree.get_reference_revision(self, path)
+        self.reference_revision = work_tree.get_reference_revision(
+            self.file_id, path)
 
     def _forget_tree_state(self):
         self.reference_revision = None 

=== modified file 'bzrlib/merge.py'
--- a/bzrlib/merge.py	2007-03-01 10:14:03 +0000
+++ b/bzrlib/merge.py	2007-03-06 12:28:18 +0000
@@ -298,6 +298,23 @@
             merge = self.merge_type(pb=self._pb,
                                     change_reporter=self.change_reporter,
                                     **kwargs)
+            if self.recurse == 'down':
+                for path, file_id in self.this_tree.iter_references():
+                    sub_tree = self.this_tree.get_nested_tree(file_id, path)
+                    other_revision = self.other_tree.get_reference_revision(
+                        file_id, path)
+                    if  other_revision == sub_tree.last_revision():
+                        continue
+                    sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
+                    sub_merge.merge_type = self.merge_type
+                    relpath = self.this_tree.relpath(path)
+                    other_branch = self.other_branch.reference_parent(file_id, relpath)
+                    sub_merge.set_other_revision(other_revision, other_branch)
+                    base_revision = self.base_tree.get_reference_revision(file_id)
+                    sub_merge.base_tree = \
+                        sub_tree.branch.repository.revision_tree(base_revision)
+                    sub_merge.do_merge()
+
         finally:
             if self.other_tree is not None:
                 self.other_tree.unlock()
@@ -310,26 +327,6 @@
         else:
             note("%d conflicts encountered." % len(merge.cooked_conflicts))
 
-        if self.recurse == 'down':
-            for path, entry in self.this_tree.iter_reference_entries():
-                sub_tree = self.this_tree.get_nested_tree(entry, path)
-                other_entry = self.other_tree.inventory[entry.file_id]
-                other_revision = self.other_tree.get_reference_revision(
-                    other_entry, path)
-                if  other_revision == sub_tree.last_revision():
-                    continue
-                sub_merge = Merger(sub_tree.branch, this_tree=sub_tree)
-                sub_merge.merge_type = self.merge_type
-                other_branch = self.other_branch.reference_parent(
-                    entry.file_id, path)
-                sub_merge.set_other_revision(other_revision, other_branch)
-                base_entry = self.base_tree.inventory[entry.file_id]
-                base_revision = \
-                    self.base_tree.get_reference_revision(base_entry)
-                sub_merge.base_tree = \
-                    sub_tree.branch.repository.revision_tree(base_revision)
-                sub_merge.do_merge()
-
         return len(merge.cooked_conflicts)
 
     def regen_inventory(self, new_entries):

=== modified file 'bzrlib/revisiontree.py'
--- a/bzrlib/revisiontree.py	2007-03-01 07:56:56 +0000
+++ b/bzrlib/revisiontree.py	2007-03-06 12:28:18 +0000
@@ -128,8 +128,8 @@
         ie = self._inventory[file_id]
         return ie.symlink_target;
 
-    def get_reference_revision(self, entry, path=None):
-        return entry.reference_revision
+    def get_reference_revision(self, file_id, path=None):
+        return self.inventory[file_id].reference_revision
 
     def get_root_id(self):
         if self.inventory.root:

=== modified file 'bzrlib/tests/tree_implementations/test_tree.py'
--- a/bzrlib/tests/tree_implementations/test_tree.py	2007-03-05 04:15:38 +0000
+++ b/bzrlib/tests/tree_implementations/test_tree.py	2007-03-06 12:28:18 +0000
@@ -58,23 +58,16 @@
 
     def test_get_reference_revision(self):
         tree = self.create_nested()
-        tree.lock_read()
-        try:
-            entry = tree.inventory['sub-root']
-        finally:
-            tree.unlock()
         path = tree.id2path('sub-root')
-        self.assertEqual('sub-1', tree.get_reference_revision(entry, path))
+        self.assertEqual('sub-1', tree.get_reference_revision('sub-root', path))
 
-    def test_iter_reference_entries(self):
+    def test_iter_references(self):
         tree = self.create_nested()
         tree.lock_read()
-        try:
-            entry = tree.inventory['sub-root']
-        finally:
-            tree.unlock()
-        self.assertEqual([entry], [e for p, e in
-                                   tree.iter_reference_entries()])
+        self.addCleanup(tree.unlock)
+        entry = tree.inventory['sub-root']
+        self.assertEqual([(tree.abspath('subtree'), 'sub-root')],
+            list(tree.iter_references()))
 
     def test_get_root_id(self):
         # trees should return some kind of root id; it can be none

=== modified file 'bzrlib/tests/workingtree_implementations/test_commit.py'
--- a/bzrlib/tests/workingtree_implementations/test_commit.py	2007-03-06 10:51:27 +0000
+++ b/bzrlib/tests/workingtree_implementations/test_commit.py	2007-03-06 12:28:18 +0000
@@ -234,8 +234,7 @@
         sub_basis.lock_read()
         self.addCleanup(sub_basis.unlock)
         self.assertEqual(subsubtree.last_revision(),
-            sub_basis.get_reference_revision(
-                sub_basis.inventory[sub_basis.path2id('subtree')]))
+            sub_basis.get_reference_revision(basis.path2id('subtree')))
         # the intermediate tree has changed, so should have had a commit
         # take place.
         self.assertNotEqual(None, subtree.last_revision())
@@ -245,8 +244,7 @@
         basis.lock_read()
         self.addCleanup(basis.unlock)
         self.assertEqual(subtree.last_revision(),
-            basis.get_reference_revision(
-                basis.inventory[basis.path2id('subtree')]))
+            basis.get_reference_revision(basis.path2id('subtree')))
         # the outer tree must have have changed too.
         self.assertNotEqual(None, rev_id)
         
@@ -278,8 +276,7 @@
         basis.lock_read()
         self.addCleanup(basis.unlock)
         self.assertEqual(subtree.last_revision(),
-            basis.get_reference_revision(
-                basis.inventory[basis.path2id('subtree')]))
+            basis.get_reference_revision(basis.path2id('subtree')))
         self.assertNotEqual(rev_id, rev_id2)
 
 

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2007-03-05 04:15:38 +0000
+++ b/bzrlib/tree.py	2007-03-06 12:28:18 +0000
@@ -177,16 +177,16 @@
         return self.inventory.iter_entries_by_dir(
             specific_file_ids=specific_file_ids)
 
-    def iter_reference_entries(self):
+    def iter_references(self):
         for path, entry in self.iter_entries_by_dir():
             if entry.kind == 'tree-reference':
-                yield path, entry
+                yield path, entry.file_id
 
     def kind(self, file_id):
         raise NotImplementedError("Tree subclass %s must implement kind"
             % self.__class__.__name__)
 
-    def get_reference_revision(self, entry, path=None):
+    def get_reference_revision(self, file_id, path=None):
         raise NotImplementedError("Tree subclass %s must implement "
                                   "get_reference_revision"
             % self.__class__.__name__)
@@ -705,8 +705,8 @@
                     self.target.get_symlink_target(file_id)):
                     changed_content = True
                 elif from_kind == 'tree-reference':
-                    if (self.source.get_reference_revision(from_entry, from_path)
-                        != self.target.get_reference_revision(to_entry, to_path)):
+                    if (self.source.get_reference_revision(file_id, from_path)
+                        != self.target.get_reference_revision(file_id, to_path)):
                         changed_content = True 
             parent = (from_parent, to_entry.parent_id)
             name = (from_name, to_entry.name)

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-03-06 10:29:01 +0000
+++ b/bzrlib/workingtree_4.py	2007-03-06 12:28:18 +0000
@@ -418,13 +418,14 @@
         """
         return self.current_dirstate().get_parent_ids()
 
-    def get_reference_revision(self, entry, path=None):
+    def get_reference_revision(self, file_id, path=None):
         # referenced tree's revision is whatever's currently there
-        return self.get_nested_tree(entry, path).last_revision()
+        return self.get_nested_tree(file_id, path).last_revision()
 
-    def get_nested_tree(self, entry, path=None):
+    def get_nested_tree(self, file_id, path=None):
         if path is None:
-            path = self.id2path(entry.file_id)
+            path = self.id2path(file_id)
+        # else: check file_id is at path?
         return WorkingTree.open(self.abspath(path))
 
     @needs_read_lock
@@ -468,6 +469,18 @@
                 result.append(key[2])
         return iter(result)
 
+    def iter_references(self):
+        for key, tree_details in self.current_dirstate()._iter_entries():
+            if tree_details[0][0] in ('a', 'r'): # absent, relocated
+                # not relevant to the working tree
+                continue
+            if not key[1]:
+                # the root is not a reference.
+                continue
+            path = pathjoin(self.basedir, key[0].decode('utf8'), key[1].decode('utf8'))
+            if self._kind(path) == 'tree-reference':
+                yield path, key[2]
+
     @needs_read_lock
     def kind(self, file_id):
         """Return the kind of a file.
@@ -478,6 +491,9 @@
         relpath = self.id2path(file_id)
         assert relpath != None, \
             "path for id {%s} is None!" % file_id
+        return self._kind(relpath)
+
+    def _kind(self, relpath):
         abspath = self.abspath(relpath)
         kind = file_kind(abspath)
         if kind == 'directory' and self._directory_is_tree_reference(relpath):
@@ -1403,8 +1419,8 @@
     def get_file_text(self, file_id):
         return ''.join(self.get_file_lines(file_id))
 
-    def get_reference_revision(self, entry, path=None):
-        return entry.reference_revision
+    def get_reference_revision(self, file_id, path=None):
+        return self.inventory[file_id].reference_revision
 
     def get_symlink_target(self, file_id):
         entry = self._get_entry(file_id=file_id)



More information about the bazaar-commits mailing list