Rev 2250: (robertc) Split branch pushing out of branch pulling. in http://people.ubuntu.com/~robertc/baz2.0/integration

Robert Collins robertc at robertcollins.net
Thu Feb 1 17:18:46 GMT 2007


------------------------------------------------------------
revno: 2250
revision-id: robertc at robertcollins.net-20070201171842-aw4059y8znmigwgn
parent: pqm at pqm.ubuntu.com-20070131184047-424584b0fabcee96
parent: robertc at robertcollins.net-20070130211105-u8p44qh31vsn4xh3
committer: Robert Collins <robertc at robertcollins.net>
branch nick: integration
timestamp: Fri 2007-02-02 04:18:42 +1100
message:
  (robertc) Split branch pushing out of branch pulling.
added:
  bzrlib/tests/branch_implementations/test_push.py test_push.py-20070130153159-fhfap8uoifevg30j-1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
  bzrlib/tests/branch_implementations/test_bound_sftp.py test_bound_sftp.py-20051231055311-2f96048c4f0940ef
  bzrlib/tests/branch_implementations/test_pull.py test_pull.py-20060410103942-83c35b26657414fc
    ------------------------------------------------------------
    revno: 2245.2.3
    merged: robertc at robertcollins.net-20070130211105-u8p44qh31vsn4xh3
    parent: robertc at robertcollins.net-20070130210611-6ogb9vztebubsqyx
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: split-branch-pull
    timestamp: Wed 2007-01-31 08:11:05 +1100
    message:
      Add a NEWS entry.
    ------------------------------------------------------------
    revno: 2245.2.2
    merged: robertc at robertcollins.net-20070130210611-6ogb9vztebubsqyx
    parent: robertc at robertcollins.net-20070130205825-cagx4gvf17ioe2i5
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: split-branch-pull
    timestamp: Wed 2007-01-31 08:06:11 +1100
    message:
      Update cmd_push to invoke the correct 'push' method on branch, rather than pull. This does not alter tests because the behaviour for push and pull is still symmetrical.
    ------------------------------------------------------------
    revno: 2245.2.1
    merged: robertc at robertcollins.net-20070130205825-cagx4gvf17ioe2i5
    parent: pqm at pqm.ubuntu.com-20070125194626-4ded330415b7276d
    committer: Robert Collins <robertc at robertcollins.net>
    branch nick: split-branch-pull
    timestamp: Wed 2007-01-31 07:58:25 +1100
    message:
      Split branch pushing out of branch pulling.
=== added file 'bzrlib/tests/branch_implementations/test_push.py'
--- a/bzrlib/tests/branch_implementations/test_push.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_push.py	2007-01-30 20:58:25 +0000
@@ -0,0 +1,79 @@
+# Copyright (C) 2004, 2005, 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 branch.push behaviour."""
+
+import os
+
+from bzrlib.branch import Branch
+from bzrlib import errors
+from bzrlib.tests import TestCaseWithTransport
+
+
+class TestPush(TestCaseWithTransport):
+
+    def test_push_convergence_simple(self):
+        # when revisions are pushed, the left-most accessible parents must 
+        # become the revision-history.
+        mine = self.make_branch_and_tree('mine')
+        mine.commit('1st post', rev_id='P1', allow_pointless=True)
+        other = mine.bzrdir.sprout('other').open_workingtree()
+        other.commit('my change', rev_id='M1', allow_pointless=True)
+        mine.merge_from_branch(other.branch)
+        mine.commit('merge my change', rev_id='P2')
+        mine.branch.push(other.branch)
+        self.assertEqual(['P1', 'P2'], other.branch.revision_history())
+
+    def test_push_merged_indirect(self):
+        # it should be possible to do a push from one branch into another
+        # when the tip of the target was merged into the source branch
+        # via a third branch - so its buried in the ancestry and is not
+        # directly accessible.
+        mine = self.make_branch_and_tree('mine')
+        mine.commit('1st post', rev_id='P1', allow_pointless=True)
+        target = mine.bzrdir.sprout('target').open_workingtree()
+        target.commit('my change', rev_id='M1', allow_pointless=True)
+        other = mine.bzrdir.sprout('other').open_workingtree()
+        other.merge_from_branch(target.branch)
+        other.commit('merge my change', rev_id='O2')
+        mine.merge_from_branch(other.branch)
+        mine.commit('merge other', rev_id='P2')
+        mine.branch.push(target.branch)
+        self.assertEqual(['P1', 'P2'], target.branch.revision_history())
+
+    def test_push_to_checkout_updates_master(self):
+        """Pushing into a checkout updates the checkout and the master branch"""
+        master_tree = self.make_branch_and_tree('master')
+        rev1 = master_tree.commit('master')
+        checkout = master_tree.branch.create_checkout('checkout')
+
+        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+        rev2 = other.commit('other commit')
+        # now push, which should update both checkout and master.
+        other.branch.push(checkout.branch)
+        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
+        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
+
+    def test_push_raises_specific_error_on_master_connection_error(self):
+        master_tree = self.make_branch_and_tree('master')
+        checkout = master_tree.branch.create_checkout('checkout')
+        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+        # move the branch out of the way on disk to cause a connection
+        # error.
+        os.rename('master', 'master_gone')
+        # try to push, which should raise a BoundBranchConnectionFailure.
+        self.assertRaises(errors.BoundBranchConnectionFailure,
+                other.branch.push, checkout.branch)

=== modified file 'NEWS'
--- a/NEWS	2007-01-30 11:52:30 +0000
+++ b/NEWS	2007-02-01 17:18:42 +0000
@@ -30,6 +30,10 @@
       push, pull, commit, and so on. Developed for use with the branchrss
       plugin. See bzrlib.branch.BranchHooks for more details. (Robert Collins)
 
+    * New method ``Branch.push()`` which should be used when pushing from a
+      branch as it makes performance and policy decisions to match the UI
+      level command ``push``. (Robert Collins).
+
   BUGFIXES:
 
   TESTING:

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2007-01-30 11:52:30 +0000
+++ b/bzrlib/branch.py	2007-02-01 17:18:42 +0000
@@ -377,8 +377,19 @@
         return history[revno - 1]
 
     def pull(self, source, overwrite=False, stop_revision=None):
+        """Mirror source into this branch.
+
+        This branch is considered to be 'local', having low latency.
+        """
         raise NotImplementedError(self.pull)
 
+    def push(self, target, overwrite=False, stop_revision=None):
+        """Mirror this branch into target.
+
+        This branch is considered to be 'local', having low latency.
+        """
+        raise NotImplementedError(self.push)
+
     def basis_tree(self):
         """Return `Tree` object for last revision."""
         return self.repository.revision_tree(self.last_revision())
@@ -601,7 +612,7 @@
             format = self.repository.bzrdir.cloning_metadir()
         return format
 
-    def create_checkout(self, to_location, revision_id=None, 
+    def create_checkout(self, to_location, revision_id=None,
                         lightweight=False):
         """Create a checkout of a branch.
         
@@ -1248,6 +1259,24 @@
         finally:
             source.unlock()
 
+    @needs_read_lock
+    def push(self, target, overwrite=False, stop_revision=None):
+        """See Branch.push."""
+        target.lock_write()
+        try:
+            old_count = len(target.revision_history())
+            try:
+                target.update_revisions(self, stop_revision)
+            except DivergedBranches:
+                if not overwrite:
+                    raise
+            if overwrite:
+                target.set_revision_history(self.revision_history())
+            new_count = len(target.revision_history())
+            return new_count - old_count
+        finally:
+            target.unlock()
+
     def get_parent(self):
         """See Branch.get_parent."""
 
@@ -1326,7 +1355,7 @@
         
     @needs_write_lock
     def pull(self, source, overwrite=False, stop_revision=None):
-        """Updates branch.pull to be bound branch aware."""
+        """Extends branch.pull to be bound branch aware."""
         bound_location = self.get_bound_location()
         if source.base != bound_location:
             # not pulling from master, so we need to update master.
@@ -1336,6 +1365,22 @@
                 source = master_branch
         return super(BzrBranch5, self).pull(source, overwrite, stop_revision)
 
+    @needs_write_lock
+    def push(self, target, overwrite=False, stop_revision=None):
+        """Updates branch.push to be bound branch aware."""
+        bound_location = target.get_bound_location()
+        if target.base != bound_location:
+            # not pushing to master, so we need to update master.
+            master_branch = target.get_master_branch()
+            if master_branch:
+                # push into the master from this branch.
+                super(BzrBranch5, self).push(master_branch, overwrite,
+                    stop_revision)
+        # and push into the target branch from this. Note that we push from
+        # this branch again, because its considered the highest bandwidth
+        # repository.
+        return super(BzrBranch5, self).push(target, overwrite, stop_revision)
+
     def get_bound_location(self):
         try:
             return self.control_files.get_utf8('bound').read()[:-1]

=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2007-01-24 17:06:02 +0000
+++ b/bzrlib/builtins.py	2007-01-30 21:06:11 +0000
@@ -676,11 +676,16 @@
                 except errors.NotLocalUrl:
                     warning('This transport does not update the working '
                             'tree of: %s' % (br_to.base,))
-                    count = br_to.pull(br_from, overwrite)
+                    count = br_from.push(br_to, overwrite)
                 except errors.NoWorkingTree:
-                    count = br_to.pull(br_from, overwrite)
+                    count = br_from.push(br_to, overwrite)
                 else:
-                    count = tree_to.pull(br_from, overwrite)
+                    tree_to.lock_write()
+                    try:
+                        count = br_from.push(tree_to.branch, overwrite)
+                        tree_to.update()
+                    finally:
+                        tree_to.unlock()
             except errors.DivergedBranches:
                 raise errors.BzrCommandError('These branches have diverged.'
                                         '  Try using "merge" and then "push".')

=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py	2007-01-29 16:58:49 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py	2007-02-01 17:18:42 +0000
@@ -48,6 +48,7 @@
         'bzrlib.tests.branch_implementations.test_parent',
         'bzrlib.tests.branch_implementations.test_permissions',
         'bzrlib.tests.branch_implementations.test_pull',
+        'bzrlib.tests.branch_implementations.test_push',
         'bzrlib.tests.branch_implementations.test_update',
         ]
     adapter = BranchTestProviderAdapter(

=== modified file 'bzrlib/tests/branch_implementations/test_bound_sftp.py'
--- a/bzrlib/tests/branch_implementations/test_bound_sftp.py	2007-01-05 17:12:03 +0000
+++ b/bzrlib/tests/branch_implementations/test_bound_sftp.py	2007-01-30 20:58:25 +0000
@@ -184,18 +184,6 @@
         self.assertEqual(['r at b-1'], wt_child.branch.revision_history())
         self.assertEqual(['r at b-1'], sftp_b_newbase.revision_history())
 
-    def test_pull_updates_both(self):
-        b_base, wt_child = self.create_branches()
-
-        wt_newchild = b_base.bzrdir.sprout('newchild').open_workingtree()
-        open('newchild/b', 'wb').write('newchild b contents\n')
-        wt_newchild.commit('newchild', rev_id='r at d-2')
-        self.assertEqual(['r at b-1', 'r at d-2'], wt_newchild.branch.revision_history())
-
-        wt_child.pull(wt_newchild.branch)
-        self.assertEqual(['r at b-1', 'r at d-2'], wt_child.branch.revision_history())
-        self.assertEqual(['r at b-1', 'r at d-2'], b_base.revision_history())
-
     def test_bind_diverged(self):
         from bzrlib.builtins import merge
 
@@ -333,25 +321,6 @@
         self.assertRaises(errors.BoundBranchConnectionFailure,
                 wt_child.commit, 'added text', rev_id='r at c-2')
 
-    def test_pull_fails(self):
-        b_base, wt_child = self.create_branches()
-
-        wt_other = wt_child.bzrdir.sprout('other').open_workingtree()
-        open('other/a', 'wb').write('new contents\n')
-        wt_other.commit('changed a', rev_id='r at d-2')
-
-        self.assertEqual(['r at b-1'], b_base.revision_history())
-        self.assertEqual(['r at b-1'], wt_child.branch.revision_history())
-        self.assertEqual(['r at b-1', 'r at d-2'], wt_other.branch.revision_history())
-
-        # this deletes the branch from memory
-        del b_base
-        # and this moves it out of the way on disk
-        os.rename('base', 'hidden_base')
-
-        self.assertRaises(errors.BoundBranchConnectionFailure,
-                wt_child.pull, wt_other.branch)
-
     # TODO: jam 20051231 We need invasive failure tests, so that we can show
     #       performance even when something fails.
 

=== modified file 'bzrlib/tests/branch_implementations/test_pull.py'
--- a/bzrlib/tests/branch_implementations/test_pull.py	2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/branch_implementations/test_pull.py	2007-01-30 20:58:25 +0000
@@ -19,7 +19,7 @@
 import os
 
 from bzrlib.branch import Branch
-from bzrlib.osutils import abspath, realpath
+from bzrlib import errors
 from bzrlib.tests import TestCaseWithTransport
 
 
@@ -53,3 +53,27 @@
         parent.commit('merge other', rev_id='P2')
         mine.pull(parent.branch)
         self.assertEqual(['P1', 'P2'], mine.branch.revision_history())
+
+    def test_pull_updates_checkout_and_master(self):
+        """Pulling into a checkout updates the checkout and the master branch"""
+        master_tree = self.make_branch_and_tree('master')
+        rev1 = master_tree.commit('master')
+        checkout = master_tree.branch.create_checkout('checkout')
+
+        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+        rev2 = other.commit('other commit')
+        # now pull, which should update both checkout and master.
+        checkout.branch.pull(other.branch)
+        self.assertEqual([rev1, rev2], checkout.branch.revision_history())
+        self.assertEqual([rev1, rev2], master_tree.branch.revision_history())
+
+    def test_pull_raises_specific_error_on_master_connection_error(self):
+        master_tree = self.make_branch_and_tree('master')
+        checkout = master_tree.branch.create_checkout('checkout')
+        other = master_tree.branch.bzrdir.sprout('other').open_workingtree()
+        # move the branch out of the way on disk to cause a connection
+        # error.
+        os.rename('master', 'master_gone')
+        # try to pull, which should raise a BoundBranchConnectionFailure.
+        self.assertRaises(errors.BoundBranchConnectionFailure,
+                checkout.branch.pull, other.branch)



More information about the bazaar-commits mailing list