Rev 5286: * ``Branch.copy_content_into`` is now a convenience method dispatching to in http://bazaar.launchpad.net/~lifeless/bzr/loomsupport
Robert Collins
robertc at robertcollins.net
Mon Jun 14 07:57:30 BST 2010
At http://bazaar.launchpad.net/~lifeless/bzr/loomsupport
------------------------------------------------------------
revno: 5286
revision-id: robertc at robertcollins.net-20100614065725-up4020n2mlt8r4fr
parent: robertc at robertcollins.net-20100614063711-t97euf6219nh19vo
committer: Robert Collins <robertc at robertcollins.net>
branch nick: loomsupport
timestamp: Mon 2010-06-14 18:57:25 +1200
message:
* ``Branch.copy_content_into`` is now a convenience method dispatching to
a ``InterBranch`` multi-method. This permits ``bzr-loom`` and other
plugins to intercept this even when a ``RemoteBranch`` proxy is in use.
(Robert Collins, #201613)
=== modified file 'NEWS'
--- a/NEWS 2010-06-14 06:37:11 +0000
+++ b/NEWS 2010-06-14 06:57:25 +0000
@@ -46,6 +46,11 @@
Improvements
************
+* ``Branch.copy_content_into`` is now a convenience method dispatching to
+ a ``InterBranch`` multi-method. This permits ``bzr-loom`` and other
+ plugins to intercept this even when a ``RemoteBranch`` proxy is in use.
+ (Robert Collins, #201613)
+
* Use lazy imports in ``bzrlib/merge.py`` so that plugins like ``news_merge``
do not cause modules to be loaded unnecessarily just because the plugin
registers a merge hook. This improves ``bzr rocks`` time by about 25%
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2010-06-14 06:37:11 +0000
+++ b/bzrlib/branch.py 2010-06-14 06:57:25 +0000
@@ -962,7 +962,6 @@
raise errors.NoSuchRevision(self, stop_revision)
return other_history[self_len:stop_revision]
- @needs_write_lock
def update_revisions(self, other, stop_revision=None, overwrite=False,
graph=None):
"""Pull in new perfect-fit revisions.
@@ -1266,24 +1265,14 @@
revno = 1
destination.set_last_revision_info(revno, revision_id)
- @needs_read_lock
def copy_content_into(self, destination, revision_id=None):
"""Copy the content of self into destination.
revision_id: if not None, the revision history in the new branch will
be truncated to end with revision_id.
"""
- self.update_references(destination)
- self._synchronize_history(destination, revision_id)
- try:
- parent = self.get_parent()
- except errors.InaccessibleParent, e:
- mutter('parent was not accessible to copy: %s', e)
- else:
- if parent:
- destination.set_parent(parent)
- if self._push_should_merge_tags():
- self.tags.merge_to(destination.tags)
+ return InterBranch.get(self, destination).copy_content_into(
+ revision_id=revision_id)
def update_references(self, target):
if not getattr(self._format, 'supports_reference_locations', False):
@@ -3245,48 +3234,64 @@
return format._custom_format
return format
+ @needs_write_lock
+ def copy_content_into(self, revision_id=None):
+ """Copy the content of source into target
+
+ revision_id: if not None, the revision history in the new branch will
+ be truncated to end with revision_id.
+ """
+ self.source.update_references(self.target)
+ self.source._synchronize_history(self.target, revision_id)
+ try:
+ parent = self.source.get_parent()
+ except errors.InaccessibleParent, e:
+ mutter('parent was not accessible to copy: %s', e)
+ else:
+ if parent:
+ self.target.set_parent(parent)
+ if self.source._push_should_merge_tags():
+ self.tags.merge_to(self.target.tags)
+
+ @needs_write_lock
def update_revisions(self, stop_revision=None, overwrite=False,
graph=None):
"""See InterBranch.update_revisions()."""
- self.source.lock_read()
- try:
- other_revno, other_last_revision = self.source.last_revision_info()
- stop_revno = None # unknown
- if stop_revision is None:
- stop_revision = other_last_revision
- if _mod_revision.is_null(stop_revision):
- # if there are no commits, we're done.
- return
- stop_revno = other_revno
+ other_revno, other_last_revision = self.source.last_revision_info()
+ stop_revno = None # unknown
+ if stop_revision is None:
+ stop_revision = other_last_revision
+ if _mod_revision.is_null(stop_revision):
+ # if there are no commits, we're done.
+ return
+ stop_revno = other_revno
- # what's the current last revision, before we fetch [and change it
- # possibly]
- last_rev = _mod_revision.ensure_null(self.target.last_revision())
- # we fetch here so that we don't process data twice in the common
- # case of having something to pull, and so that the check for
- # already merged can operate on the just fetched graph, which will
- # be cached in memory.
- self.target.fetch(self.source, stop_revision)
- # Check to see if one is an ancestor of the other
- if not overwrite:
- if graph is None:
- graph = self.target.repository.get_graph()
- if self.target._check_if_descendant_or_diverged(
- stop_revision, last_rev, graph, self.source):
- # stop_revision is a descendant of last_rev, but we aren't
- # overwriting, so we're done.
- return
- if stop_revno is None:
- if graph is None:
- graph = self.target.repository.get_graph()
- this_revno, this_last_revision = \
- self.target.last_revision_info()
- stop_revno = graph.find_distance_to_null(stop_revision,
- [(other_last_revision, other_revno),
- (this_last_revision, this_revno)])
- self.target.set_last_revision_info(stop_revno, stop_revision)
- finally:
- self.source.unlock()
+ # what's the current last revision, before we fetch [and change it
+ # possibly]
+ last_rev = _mod_revision.ensure_null(self.target.last_revision())
+ # we fetch here so that we don't process data twice in the common
+ # case of having something to pull, and so that the check for
+ # already merged can operate on the just fetched graph, which will
+ # be cached in memory.
+ self.target.fetch(self.source, stop_revision)
+ # Check to see if one is an ancestor of the other
+ if not overwrite:
+ if graph is None:
+ graph = self.target.repository.get_graph()
+ if self.target._check_if_descendant_or_diverged(
+ stop_revision, last_rev, graph, self.source):
+ # stop_revision is a descendant of last_rev, but we aren't
+ # overwriting, so we're done.
+ return
+ if stop_revno is None:
+ if graph is None:
+ graph = self.target.repository.get_graph()
+ this_revno, this_last_revision = \
+ self.target.last_revision_info()
+ stop_revno = graph.find_distance_to_null(stop_revision,
+ [(other_last_revision, other_revno),
+ (this_last_revision, this_revno)])
+ self.target.set_last_revision_info(stop_revno, stop_revision)
def pull(self, overwrite=False, stop_revision=None,
possible_transports=None, run_hooks=True,
=== modified file 'bzrlib/tests/per_interbranch/__init__.py'
--- a/bzrlib/tests/per_interbranch/__init__.py 2010-06-14 06:37:11 +0000
+++ b/bzrlib/tests/per_interbranch/__init__.py 2010-06-14 06:57:25 +0000
@@ -144,9 +144,38 @@
return newbranch.bzrdir
+class StubWithFormat(object):
+ """A stub object used to check that convenience methods call Inter's."""
+
+ _format = object()
+
+
+class StubMatchingInter(object):
+ """An inter for tests.
+
+ This is not a subclass of InterBranch so that missing methods are caught
+ and added rather than actually trying to do something.
+ """
+
+ _uses = []
+
+ def __init__(self, source, target):
+ self.source = source
+ self.target = target
+
+ @classmethod
+ def is_compatible(klass, source, target):
+ return StubWithFormat._format in (source._format, target._format)
+
+ def copy_content_into(self, *args, **kwargs):
+ self.__class__._uses.append(
+ (self, 'copy_content_into', args, kwargs))
+
+
def load_tests(standard_tests, module, loader):
submod_tests = loader.loadTestsFromModuleNames([
'bzrlib.tests.per_interbranch.test_get',
+ 'bzrlib.tests.per_interbranch.test_copy_content_into',
'bzrlib.tests.per_interbranch.test_pull',
'bzrlib.tests.per_interbranch.test_push',
'bzrlib.tests.per_interbranch.test_update_revisions',
=== added file 'bzrlib/tests/per_interbranch/test_copy_content_into.py'
--- a/bzrlib/tests/per_interbranch/test_copy_content_into.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/per_interbranch/test_copy_content_into.py 2010-06-14 06:57:25 +0000
@@ -0,0 +1,47 @@
+# Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Tests for bzrlib.branch.InterBranch.copy_content_into."""
+
+from bzrlib import branch
+from bzrlib.tests.per_interbranch import (
+ StubMatchingInter,
+ StubWithFormat,
+ TestCaseWithInterBranch,
+ )
+
+
+class TestCopyContentInto(TestCaseWithInterBranch):
+
+ def test_contract_convenience_method(self):
+ self.tree1 = self.make_branch_and_tree('tree1')
+ rev1 = self.tree1.commit('one')
+ branch2 = self.make_to_branch('tree2')
+ branch2.repository.fetch(self.tree1.branch.repository)
+ self.tree1.branch.copy_content_into(branch2, revision_id=rev1)
+
+ def test_inter_is_used(self):
+ self.tree1 = self.make_branch_and_tree('tree1')
+ self.addCleanup(branch.InterBranch.unregister_optimiser,
+ StubMatchingInter)
+ branch.InterBranch.register_optimiser(StubMatchingInter)
+ del StubMatchingInter._uses[:]
+ self.tree1.branch.copy_content_into(StubWithFormat(), revision_id='54')
+ self.assertLength(1, StubMatchingInter._uses)
+ use = StubMatchingInter._uses[0]
+ self.assertEqual('copy_content_into', use[1])
+ self.assertEqual('54', use[3]['revision_id'])
+ del StubMatchingInter._uses[:]
More information about the bazaar-commits
mailing list