Rev 111: * bzr-loom requires bzr 2.2.0 (or very recent 2.2b releases) due to an API in http://bazaar.launchpad.net/~bzr-loom-devs/bzr-loom/trunk/
Robert Collins
robertc at robertcollins.net
Mon Jun 14 07:59:27 BST 2010
At http://bazaar.launchpad.net/~bzr-loom-devs/bzr-loom/trunk/
------------------------------------------------------------
revno: 111
revision-id: robertc at robertcollins.net-20100614065918-pjvn2dtyu0i7dz0x
parent: robertc at robertcollins.net-20100420112812-yy07j2ogikz0s9np
committer: Robert Collins <robertc at robertcollins.net>
branch nick: trunk
timestamp: Mon 2010-06-14 18:59:18 +1200
message:
* bzr-loom requires bzr 2.2.0 (or very recent 2.2b releases) due to an API
change in bzr needed to fix branching and pulling of looms. On older versions
of bzr bzr-loom will still work for most operations but will fail when making
new branches as part of a push or branch operation. (Robert Collins, #201613)
=== modified file 'NEWS'
--- a/NEWS 2010-04-20 11:13:54 +0000
+++ b/NEWS 2010-06-14 06:59:18 +0000
@@ -10,6 +10,11 @@
NOTES WHEN UPGRADING
--------------------
+* bzr-loom requires bzr 2.2.0 (or very recent 2.2b releases) due to an API
+ change in bzr needed to fix branching and pulling of looms. On older versions
+ of bzr bzr-loom will still work for most operations but will fail when making
+ new branches as part of a push or branch operation. (Robert Collins, #201613)
+
CHANGES
-------
=== modified file 'branch.py'
--- a/branch.py 2010-04-20 11:13:54 +0000
+++ b/branch.py 2010-06-14 06:59:18 +0000
@@ -31,7 +31,7 @@
from bzrlib.decorators import needs_read_lock, needs_write_lock
import bzrlib.errors
import bzrlib.osutils
-from bzrlib import symbol_versioning
+from bzrlib import remote, symbol_versioning
import bzrlib.trace
import bzrlib.ui
from bzrlib.revision import is_null, NULL_REVISION
@@ -240,8 +240,10 @@
def clone(self, to_bzrdir, revision_id=None, repository_policy=None):
"""Clone the branch into to_bzrdir.
- This differs from the base clone by cloning the loom and
- setting the current nick to the top of the loom.
+ This differs from the base clone by cloning the loom, setting the
+ current nick to the top of the loom, not honouring any branch format
+ selection on the target bzrdir, and ensuring that the format of
+ the created branch is stacking compatible.
"""
# If the target is a stackable repository, force-upgrade the
# output loom format
@@ -253,79 +255,10 @@
result = format.initialize(to_bzrdir)
if repository_policy is not None:
repository_policy.configure_branch(result)
- self.copy_content_into(result, revision_id=revision_id)
+ bzrlib.branch.InterBranch.get(self, result).copy_content_into(
+ revision_id=revision_id)
return result
- @needs_read_lock
- def copy_content_into(self, destination, revision_id=None):
- # XXX: hint for bzrlib - break this into two routines, one for
- # copying the last-rev pointer, one for copying parent etc.
- destination.lock_write()
- try:
- source_nick = self.nick
- state = self.get_loom_state()
- parents = state.get_parents()
- if parents:
- loom_tip = parents[0]
- else:
- loom_tip = None
- threads = self.get_threads(state.get_basis_revision_id())
- if revision_id not in (None, NULL_REVISION):
- if threads:
- # revision_id should be in the loom, or its an error
- found_threads = [thread for thread, rev in threads
- if rev == revision_id]
- if not found_threads:
- # the thread we have been asked to set in the remote
- # side has not been recorded yet, so its data is not
- # present at this point.
- raise UnrecordedRevision(self, revision_id)
-
- # pull in the warp, which was skipped during the initial pull
- # because the front end does not know what to pull.
- # nb: this is mega huge hacky. THINK. RBC 2006062
- nested = bzrlib.ui.ui_factory.nested_progress_bar()
- try:
- if parents:
- destination.repository.fetch(self.repository,
- revision_id=parents[0])
- if threads:
- for thread, rev_id in reversed(threads):
- # fetch the loom content for this revision
- destination.repository.fetch(self.repository,
- revision_id=rev_id)
- finally:
- nested.finished()
- state = loom_state.LoomState()
- try:
- require_loom_branch(destination)
- if threads:
- last_rev = threads[-1][1]
- if last_rev == EMPTY_REVISION:
- last_rev = bzrlib.revision.NULL_REVISION
- destination.generate_revision_history(last_rev)
- state.set_parents([loom_tip])
- state.set_threads(
- (thread + ([thread[1]],) for thread in threads)
- )
- else:
- # no threads yet, be a normal branch.
- self._synchronize_history(destination, revision_id)
- destination._set_last_loom(state)
- except NotALoom:
- self._synchronize_history(destination, revision_id)
- try:
- parent = self.get_parent()
- except bzrlib.errors.InaccessibleParent, e:
- bzrlib.trace.mutter('parent was not accessible to copy: %s', e)
- else:
- if parent:
- destination.set_parent(parent)
- if threads:
- destination.nick = threads[-1][0]
- finally:
- destination.unlock()
-
def _get_checkout_format(self):
"""Checking out a Loom gets a regular branch for now.
@@ -453,24 +386,6 @@
result.append((name, rev_id))
return result
- @needs_write_lock
- def pull(self, source, overwrite=False, stop_revision=None,
- run_hooks=True, possible_transports=None, _override_hook_target=None,
- local=False):
- """Pull from a branch into this loom.
-
- If the remote branch is a non-loom branch, the pull is done against the
- current warp. If it is a loom branch, then the pull is done against the
- entire loom and the current thread set to the top thread.
- """
- if not isinstance(source, LoomSupport):
- return super(LoomSupport, self).pull(source,
- overwrite=overwrite, stop_revision=stop_revision,
- possible_transports=possible_transports,
- _override_hook_target=_override_hook_target, local=local)
- return _Puller(source, self).transfer(overwrite, stop_revision,
- run_hooks, possible_transports, _override_hook_target, local)
-
@needs_read_lock
def push(self, target, overwrite=False, stop_revision=None,
_override_hook_source_branch=None):
@@ -625,10 +540,20 @@
class _Puller(object):
+ # XXX: Move into InterLoomBranch.
def __init__(self, source, target):
self.target = target
self.source = source
+ # If _Puller has been created, we need real branch objects.
+ self.real_target = self.unwrap_branch(target)
+ self.real_source = self.unwrap_branch(source)
+
+ def unwrap_branch(self, branch):
+ if isinstance(branch, remote.RemoteBranch):
+ branch._ensure_real()
+ return branch._real_branch
+ return branch
def prepare_result(self, _override_hook_target):
result = self.make_result()
@@ -699,7 +624,7 @@
self.target.lock_write()
self.source.lock_read()
try:
- source_state = self.source.get_loom_state()
+ source_state = self.real_source.get_loom_state()
source_parents = source_state.get_parents()
if not source_parents:
return self.plain_transfer(result, run_hooks,
@@ -952,6 +877,128 @@
bzrlib.branch.BranchFormat.register_format(BzrBranchLoomFormat6())
bzrlib.branch.BranchFormat.register_format(BzrBranchLoomFormat7())
+# Handle the smart server:
+
+class InterLoomBranch(bzrlib.branch.GenericInterBranch):
+
+ def unwrap_branch(self, branch):
+ if isinstance(branch, remote.RemoteBranch):
+ branch._ensure_real()
+ return branch._real_branch
+ return branch
+
+ @classmethod
+ def unwrap_format(klass, format):
+ if isinstance(format, remote.RemoteBranchFormat):
+ format._ensure_real()
+ return format._custom_format
+ return format
+
+ @classmethod
+ def is_compatible(klass, source, target):
+ source_format = klass.unwrap_format(source._format)
+ target_format = klass.unwrap_format(target._format)
+ # 1st cut: special case and handle all *->Loom and Loom->*
+ return (isinstance(source_format, LoomFormatMixin) or
+ isinstance(target_format, LoomFormatMixin))
+
+ def get_loom_state(self, branch):
+ branch = self.unwrap_branch(branch)
+ return branch.get_loom_state()
+
+ def get_threads(self, branch, revision_id):
+ branch = self.unwrap_branch(branch)
+ return branch.get_threads(revision_id)
+
+ @needs_write_lock
+ def copy_content_into(self, revision_id=None):
+ # XXX: hint for bzrlib - break this into two routines, one for
+ # copying the last-rev pointer, one for copying parent etc.
+ source_nick = self.source.nick
+ state = self.get_loom_state(self.source)
+ parents = state.get_parents()
+ if parents:
+ loom_tip = parents[0]
+ else:
+ loom_tip = None
+ threads = self.get_threads(self.source, state.get_basis_revision_id())
+ if revision_id not in (None, NULL_REVISION):
+ if threads:
+ # revision_id should be in the loom, or its an error
+ found_threads = [thread for thread, rev in threads
+ if rev == revision_id]
+ if not found_threads:
+ # the thread we have been asked to set in the remote
+ # side has not been recorded yet, so its data is not
+ # present at this point.
+ raise UnrecordedRevision(self.source, revision_id)
+
+ # pull in the warp, which was skipped during the initial pull
+ # because the front end does not know what to pull.
+ # nb: this is mega huge hacky. THINK. RBC 2006062
+ nested = bzrlib.ui.ui_factory.nested_progress_bar()
+ try:
+ if parents:
+ self.target.repository.fetch(self.source.repository,
+ revision_id=parents[0])
+ if threads:
+ for thread, rev_id in reversed(threads):
+ # fetch the loom content for this revision
+ self.target.repository.fetch(self.source.repository,
+ revision_id=rev_id)
+ finally:
+ nested.finished()
+ state = loom_state.LoomState()
+ try:
+ require_loom_branch(self.target)
+ if threads:
+ last_rev = threads[-1][1]
+ if last_rev == EMPTY_REVISION:
+ last_rev = bzrlib.revision.NULL_REVISION
+ self.target.generate_revision_history(last_rev)
+ state.set_parents([loom_tip])
+ state.set_threads(
+ (thread + ([thread[1]],) for thread in threads)
+ )
+ else:
+ # no threads yet, be a normal branch.
+ self.source._synchronize_history(self.target, revision_id)
+ self.target._set_last_loom(state)
+ except NotALoom:
+ self.source._synchronize_history(self.target, revision_id)
+ try:
+ parent = self.source.get_parent()
+ except bzrlib.errors.InaccessibleParent, e:
+ bzrlib.trace.mutter('parent was not accessible to copy: %s', e)
+ else:
+ if parent:
+ self.target.set_parent(parent)
+ if threads:
+ self.target.nick = threads[-1][0]
+
+ @needs_write_lock
+ def pull(self, overwrite=False, stop_revision=None,
+ run_hooks=True, possible_transports=None, _override_hook_target=None,
+ local=False):
+ """Pull from a branch into this loom.
+
+ If the remote branch is a non-loom branch, the pull is done against the
+ current warp. If it is a loom branch, then the pull is done against the
+ entire loom and the current thread set to the top thread.
+ """
+ # Special code only needed when target is a loom
+ target_format = self.__class__.unwrap_format(self.target._format)
+ if not isinstance(target_format, LoomFormatMixin):
+ return super(InterLoomBranch, self).pull(
+ overwrite=overwrite, stop_revision=stop_revision,
+ possible_transports=possible_transports,
+ _override_hook_target=_override_hook_target, local=local)
+ return _Puller(self.source, self.target).transfer(overwrite, stop_revision,
+ run_hooks, possible_transports, _override_hook_target, local)
+
+
+bzrlib.branch.InterBranch.register_optimiser(InterLoomBranch)
+
LOOM_FORMATS = [
BzrBranchLoomFormat1,
=== modified file 'tests/__init__.py'
--- a/tests/__init__.py 2007-11-23 01:36:56 +0000
+++ b/tests/__init__.py 2010-06-14 06:59:18 +0000
@@ -22,6 +22,7 @@
import bzrlib.plugins.loom.branch
from bzrlib.tests import TestCaseWithTransport
from bzrlib.tests.TestUtil import TestLoader, TestSuite
+from bzrlib.workingtree import WorkingTree
def test_suite():
@@ -41,7 +42,9 @@
def get_tree_with_loom(self, path="."):
"""Get a tree with no commits in loom format."""
- tree = self.make_branch_and_tree(path)
+ # May open on Remote - we want the vfs backed version for loom tests.
+ self.make_branch_and_tree(path)
+ tree = WorkingTree.open(path)
bzrlib.plugins.loom.branch.loomify(tree.branch)
return tree.bzrdir.open_workingtree()
=== modified file 'tests/test_branch.py'
--- a/tests/test_branch.py 2009-09-22 03:40:53 +0000
+++ b/tests/test_branch.py 2010-06-14 06:59:18 +0000
@@ -33,7 +33,10 @@
from bzrlib.plugins.loom.tree import LoomTreeDecorator
import bzrlib.revision
from bzrlib.revision import NULL_REVISION
-from bzrlib.tests import TestCaseWithTransport
+from bzrlib.tests import (
+ TestCaseWithTransport,
+ test_server,
+ )
from bzrlib.transport import get_transport
from bzrlib.workingtree import WorkingTree
@@ -253,6 +256,9 @@
def test_clone_nonempty_loom_bottom(self):
"""Cloning loom should reset the current loom pointer."""
+ self.make_and_clone_simple_loom()
+
+ def make_and_clone_simple_loom(self):
source_tree = self.get_tree_with_one_commit('source')
source_tree.branch.new_thread('bottom')
source_tree.branch.new_thread('top')
@@ -260,10 +266,17 @@
source_tree.commit('phwoar', allow_pointless=True)
source_tree.branch.record_loom('commit to loom')
LoomTreeDecorator(source_tree).down_thread()
- # now clone
- target_tree = source_tree.bzrdir.clone('target').open_workingtree()
+ # now clone from the 'default url' - transport_server rather than
+ # vfs_server.
+ source_branch = Branch.open(self.get_url('source'))
+ target_tree = source_branch.bzrdir.sprout('target').open_workingtree()
self.assertLoomSproutedOk(source_tree, target_tree)
+ def test_sprout_remote_loom(self):
+ # RemoteBranch should permit sprouting properly.
+ self.transport_server = test_server.SmartTCPServer_for_testing
+ self.make_and_clone_simple_loom()
+
def test_sprout_nonempty_loom_bottom(self):
"""Sprouting always resets the loom to the top."""
source_tree = self.get_tree_with_one_commit('source')
@@ -356,6 +369,9 @@
def test_pull_into_empty_loom(self):
"""Doing a pull into a loom with no loom revisions works."""
+ self.pull_into_empty_loom()
+
+ def pull_into_empty_loom(self):
source = self.get_tree_with_loom('source')
target = source.bzrdir.sprout('target').open_branch()
source.branch.new_thread('a thread')
@@ -363,7 +379,10 @@
# put a commit in the thread for source.
bottom_rev1 = source.commit('commit a thread')
source.branch.record_loom('commit to loom')
- target.pull(source.branch)
+ # now pull from the 'default url' - transport_server rather than
+ # vfs_server - this may be a RemoteBranch.
+ source_branch = Branch.open(self.get_url('source'))
+ target.pull(source_branch)
# check loom threads
threads = target.get_loom_state().get_threads()
self.assertEqual(
@@ -375,6 +394,11 @@
self.assertTrue(target.repository.has_revision(rev_id))
self.assertEqual(source.branch.loom_parents(), target.loom_parents())
+ def test_pull_remote_loom(self):
+ # RemoteBranch should permit sprouting properly.
+ self.transport_server = test_server.SmartTCPServer_for_testing
+ self.pull_into_empty_loom()
+
def test_pull_thread_at_null(self):
"""Doing a pull when the source loom has a thread with no history."""
source = self.get_tree_with_loom('source')
More information about the bazaar-commits
mailing list