Rev 3226: Create basic stackable branch facility. in http://people.ubuntu.com/~robertc/baz2.0/shallow-branch
Robert Collins
robertc at robertcollins.net
Thu Feb 14 00:40:37 GMT 2008
At http://people.ubuntu.com/~robertc/baz2.0/shallow-branch
------------------------------------------------------------
revno: 3226
revision-id:robertc at robertcollins.net-20080214004032-9vms1rfzv6tabsih
parent: robertc at robertcollins.net-20080213224222-mu1sxr294xoutwdt
committer: Robert Collins <robertc at robertcollins.net>
branch nick: StackableBranch
timestamp: Thu 2008-02-14 11:40:32 +1100
message:
Create basic stackable branch facility.
modified:
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/bzrdir.py bzrdir.py-20060131065624-156dfea39c4387cb
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
bzrlib/tests/test_branch.py test_branch.py-20060116013032-97819aa07b8ab3b5
bzrlib/tests/test_errors.py test_errors.py-20060210110251-41aba2deddf936a8
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py 2008-02-06 04:06:42 +0000
+++ b/bzrlib/branch.py 2008-02-14 00:40:32 +0000
@@ -350,6 +350,15 @@
"""
raise NotImplementedError(self.get_root_id)
+ def get_stacked_on(self):
+ """Get the URL this branch is stacked against.
+
+ :raises NotStacked: If the branch is not stacked.
+ :raises UnstackableBranchFormat: If the branch does not support
+ stacking.
+ """
+ raise NotImplementedError(self.get_stacked_on)
+
def print_file(self, file, revision_id):
"""Print `file` to stdout."""
raise NotImplementedError(self.print_file)
@@ -357,6 +366,16 @@
def set_revision_history(self, rev_history):
raise NotImplementedError(self.set_revision_history)
+ def set_stacked_on(self, url):
+ """set the URL this branch is stacked against.
+
+ :raises UnstackableBranchFormat: If the branch does not support
+ stacking.
+ :raises UnstackableRepositoryFormat: If the repository does not support
+ stacking.
+ """
+ raise NotImplementedError(self.set_stacked_on)
+
def _cache_revision_history(self, rev_history):
"""Set the cached revision history to rev_history.
@@ -1087,7 +1106,42 @@
return "Bazaar-NG branch format 4"
-class BzrBranchFormat5(BranchFormat):
+class BranchFormatMetadir(BranchFormat):
+ """Common logic for meta-dir based branch formats."""
+
+ def _branch_class(self):
+ """What class to instantiate on open calls."""
+ raise NotImplementedError(self._branch_class)
+
+ def open(self, a_bzrdir, _found=False):
+ """Return the branch object for a_bzrdir
+
+ _found is a private parameter, do not use it. It is used to indicate
+ if format probing has already be done.
+ """
+ if not _found:
+ format = BranchFormat.find_format(a_bzrdir)
+ assert format.__class__ == self.__class__
+ try:
+ transport = a_bzrdir.get_branch_transport(None)
+ control_files = lockable_files.LockableFiles(transport, 'lock',
+ lockdir.LockDir)
+ return self._branch_class()(_format=self,
+ _control_files=control_files,
+ a_bzrdir=a_bzrdir,
+ _repository=a_bzrdir.find_repository())
+ except NoSuchFile:
+ raise NotBranchError(path=transport.base)
+
+ def __init__(self):
+ super(BranchFormatMetadir, self).__init__()
+ self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
+
+ def supports_tags(self):
+ return True
+
+
+class BzrBranchFormat5(BranchFormatMetadir):
"""Bzr branch format 5.
This format has:
@@ -1100,6 +1154,9 @@
This format is new in bzr 0.8.
"""
+ def _branch_class(self):
+ return BzrBranch5
+
def get_format_string(self):
"""See BranchFormat.get_format_string()."""
return "Bazaar-NG branch format 5\n"
@@ -1115,32 +1172,11 @@
]
return self._initialize_helper(a_bzrdir, utf8_files)
- def __init__(self):
- super(BzrBranchFormat5, self).__init__()
- self._matchingbzrdir = bzrdir.BzrDirMetaFormat1()
-
- def open(self, a_bzrdir, _found=False):
- """Return the branch object for a_bzrdir
-
- _found is a private parameter, do not use it. It is used to indicate
- if format probing has already be done.
- """
- if not _found:
- format = BranchFormat.find_format(a_bzrdir)
- assert format.__class__ == self.__class__
- try:
- transport = a_bzrdir.get_branch_transport(None)
- control_files = lockable_files.LockableFiles(transport, 'lock',
- lockdir.LockDir)
- return BzrBranch5(_format=self,
- _control_files=control_files,
- a_bzrdir=a_bzrdir,
- _repository=a_bzrdir.find_repository())
- except NoSuchFile:
- raise NotBranchError(path=transport.base)
-
-
-class BzrBranchFormat6(BzrBranchFormat5):
+ def supports_tags(self):
+ return False
+
+
+class BzrBranchFormat6(BranchFormatMetadir):
"""Branch format with last-revision and tags.
Unlike previous formats, this has no explicit revision history. Instead,
@@ -1151,6 +1187,9 @@
and became the default in 0.91.
"""
+ def _branch_class(self):
+ return BzrBranch6
+
def get_format_string(self):
"""See BranchFormat.get_format_string()."""
return "Bazaar Branch Format 6 (bzr 0.15)\n"
@@ -1167,25 +1206,35 @@
]
return self._initialize_helper(a_bzrdir, utf8_files)
- def open(self, a_bzrdir, _found=False):
- """Return the branch object for a_bzrdir
-
- _found is a private parameter, do not use it. It is used to indicate
- if format probing has already be done.
- """
- if not _found:
- format = BranchFormat.find_format(a_bzrdir)
- assert format.__class__ == self.__class__
- transport = a_bzrdir.get_branch_transport(None)
- control_files = lockable_files.LockableFiles(transport, 'lock',
- lockdir.LockDir)
- return BzrBranch6(_format=self,
- _control_files=control_files,
- a_bzrdir=a_bzrdir,
- _repository=a_bzrdir.find_repository())
-
- def supports_tags(self):
- return True
+
+class BzrBranchFormat7(BranchFormatMetadir):
+ """Branch format with last-revision, tags, and a stacked location pointer.
+
+ The stacked location pointer is passed down to the repository and requires
+ a repository format with supports_external_lookups = True.
+
+ This format was introduced in bzr 1.3.
+ """
+
+ def _branch_class(self):
+ return BzrBranch7
+
+ def get_format_string(self):
+ """See BranchFormat.get_format_string()."""
+ return "Bazaar Branch Format 7 (needs bzr 1.3)\n"
+
+ def get_format_description(self):
+ """See BranchFormat.get_format_description()."""
+ return "Branch format 7"
+
+ def initialize(self, a_bzrdir):
+ """Create a branch of this format in a_bzrdir."""
+ utf8_files = [('last-revision', '0 null:\n'),
+ ('branch.conf', ''),
+ ('tags', ''),
+ ('stacked-on', '\n'),
+ ]
+ return self._initialize_helper(a_bzrdir, utf8_files)
class BranchReferenceFormat(BranchFormat):
@@ -1277,9 +1326,11 @@
# and not independently creatable, so are not registered.
__format5 = BzrBranchFormat5()
__format6 = BzrBranchFormat6()
+__format7 = BzrBranchFormat7()
BranchFormat.register_format(__format5)
BranchFormat.register_format(BranchReferenceFormat())
BranchFormat.register_format(__format6)
+BranchFormat.register_format(__format7)
BranchFormat.set_default_format(__format6)
_legacy_formats = [BzrBranchFormat4(),
]
@@ -1653,6 +1704,9 @@
except errors.InvalidURLJoin, e:
raise errors.InaccessibleParent(parent, self.base)
+ def get_stacked_on(self):
+ raise errors.UnstackableBranchFormat(self._format, self.base)
+
def set_push_location(self, location):
"""See Branch.set_push_location."""
self.get_config().set_user_option(
@@ -1685,6 +1739,9 @@
assert isinstance(url, str)
self.control_files.put_bytes('parent', url + '\n')
+ def set_stacked_on(self, url):
+ raise errors.UnstackableBranchFormat(self._format, self.base)
+
class BzrBranch5(BzrBranch):
"""A format 5 branch. This supports new features over plain branches.
@@ -1820,7 +1877,12 @@
return None
-class BzrBranch6(BzrBranch5):
+class BzrBranch7(BzrBranch5):
+
+ def _check_stackable_repo(self):
+ if not self.repository._format.supports_external_lookups:
+ raise errors.UnstackableRepositoryFormat(self.repository._format,
+ self.repository.base)
@needs_read_lock
def last_revision_info(self):
@@ -1930,6 +1992,9 @@
"""See Branch.get_old_bound_location"""
return self._get_bound_location(False)
+ def get_stacked_on(self):
+ self._check_stackable_repo()
+
def set_append_revisions_only(self, enabled):
if enabled:
value = 'True'
@@ -1938,6 +2003,9 @@
self.get_config().set_user_option('append_revisions_only', value,
warn_masked=True)
+ def set_stacked_on(self, url):
+ self._check_stackable_repo()
+
def _get_append_revisions_only(self):
value = self.get_config().get_user_option('append_revisions_only')
return value == 'True'
@@ -1975,6 +2043,19 @@
return BasicTags(self)
+class BzrBranch6(BzrBranch7):
+ """See BzrBranchFormat6 for the capabilities of this branch.
+
+ This subclass of BzrBranch7 disables the new features BzrBranch7 added.
+ """
+
+ def get_stacked_on(self):
+ raise errors.UnstackableBranchFormat(self._format, self.base)
+
+ def set_stacked_on(self, url):
+ raise errors.UnstackableBranchFormat(self._format, self.base)
+
+
######################################################################
# results of operations
=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py 2008-02-13 22:11:40 +0000
+++ b/bzrlib/bzrdir.py 2008-02-14 00:40:32 +0000
@@ -2686,27 +2686,27 @@
)
# The following two formats should always just be aliases.
format_registry.register_metadir('development',
- 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0',
+ 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
help='Current development format. Can convert data to and from pack-0.92 '
'(and anything compatible with pack-0.92) format repositories. '
- 'Repositories in this format can only be read by bzr.dev. '
+ 'Repositories and branches in this format can only be read by bzr.dev. '
'Please read '
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
'before use.',
- branch_format='bzrlib.branch.BzrBranchFormat6',
+ branch_format='bzrlib.branch.BzrBranchFormat7',
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
experimental=True,
alias=True,
)
format_registry.register_metadir('development-subtree',
- 'bzrlib.repofmt.pack_repo.RepositoryFormatPackDevelopment0Subtree',
+ 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
help='Current development format, subtree variant. Can convert data to and '
'from pack-0.92 (and anything compatible with pack-0.92) format '
- 'repositories. Repositories in this format can only be read by '
- 'bzr.dev. Please read '
+ 'repositories. Repositories and branches in this format can only be '
+ 'read by bzr.dev. Please read '
'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
'before use.',
- branch_format='bzrlib.branch.BzrBranchFormat6',
+ branch_format='bzrlib.branch.BzrBranchFormat7',
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
experimental=True,
alias=True,
@@ -2734,4 +2734,27 @@
hidden=True,
experimental=True,
)
+format_registry.register_metadir('development1',
+ 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack1',
+ help='pack-0.92 with a branch that supports stacking. '
+ 'Please read '
+ 'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
+ 'before use.',
+ branch_format='bzrlib.branch.BzrBranchFormat7',
+ tree_format='bzrlib.workingtree.WorkingTreeFormat4',
+ hidden=True,
+ experimental=True,
+ )
+format_registry.register_metadir('development1-subtree',
+ 'bzrlib.repofmt.pack_repo.RepositoryFormatKnitPack3',
+ help='pack-0.92-subtree with a branch that supports stacking. '
+ 'Please read '
+ 'http://doc.bazaar-vcs.org/latest/developers/development-repo.html '
+ 'before use.',
+ branch_format='bzrlib.branch.BzrBranchFormat7',
+ tree_format='bzrlib.workingtree.WorkingTreeFormat4',
+ hidden=True,
+ experimental=True,
+ )
+# The current format that is made on 'bzr init'.
format_registry.set_default('pack-0.92')
=== modified file 'bzrlib/errors.py'
--- a/bzrlib/errors.py 2008-02-12 02:13:43 +0000
+++ b/bzrlib/errors.py 2008-02-14 00:40:32 +0000
@@ -185,6 +185,13 @@
_fmt = "The tree builder is already building a tree."
+class BranchError(BzrError):
+ """Base class for concrete 'errors about a branch'."""
+
+ def __init__(self, branch):
+ BzrError.__init__(self, branch=branch)
+
+
class BzrCheckError(InternalBzrError):
_fmt = "Internal check failed: %(message)s"
@@ -305,6 +312,11 @@
BzrError.__init__(self, repository=repository, file_id=file_id)
+class NotStacked(BranchError):
+
+ _fmt = "The branch '%(branch)s' is not stacked."
+
+
class InventoryModified(InternalBzrError):
_fmt = ("The current inventory for the tree %(tree)r has been modified,"
@@ -561,6 +573,28 @@
PathError.__init__(self, url, extra=extra)
+class UnstackableBranchFormat(BzrError):
+
+ _fmt = ("The branch '%(url)s'(%(format)s) is not a stackable format. "
+ "You will need to upgrade the branch to permit branch stacking.")
+
+ def __init__(self, format, url):
+ BzrError.__init__(self)
+ self.format = format
+ self.url = url
+
+
+class UnstackableRepositoryFormat(BzrError):
+
+ _fmt = ("The repository '%(url)s'(%(format)s) is not a stackable format. "
+ "You will need to upgrade the repository to permit branch stacking.")
+
+ def __init__(self, format, url):
+ BzrError.__init__(self)
+ self.format = format
+ self.url = url
+
+
class ReadError(PathError):
_fmt = """Error reading from %(path)r."""
@@ -1164,13 +1198,10 @@
self.bases = bases
-class NoCommits(BzrError):
+class NoCommits(BranchError):
_fmt = "Branch %(branch)s has no commits."
- def __init__(self, branch):
- BzrError.__init__(self, branch=branch)
-
class UnlistableStore(BzrError):
=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py 2008-02-12 05:17:25 +0000
+++ b/bzrlib/remote.py 2008-02-14 00:40:32 +0000
@@ -1289,6 +1289,18 @@
self._ensure_real()
return self._real_branch.get_physical_lock_status()
+ def get_stacked_on(self):
+ """Get the URL this branch is stacked against.
+
+ :raises NotStacked: If the branch is not stacked.
+ :raises UnstackableBranchFormat: If the branch does not support
+ stacking.
+ :raises UnstackableRepositoryFormat: If the repository does not support
+ stacking.
+ """
+ self._ensure_real()
+ return self._real_branch.get_stacked_on()
+
def lock_read(self):
if not self._lock_mode:
self._lock_mode = 'r'
@@ -1464,6 +1476,17 @@
self._ensure_real()
return self._real_branch.set_parent(url)
+ def set_stacked_on(self, stacked_location):
+ """set the URL this branch is stacked against.
+
+ :raises UnstackableBranchFormat: If the branch does not support
+ stacking.
+ :raises UnstackableRepositoryFormat: If the repository does not support
+ stacking.
+ """
+ self._ensure_real()
+ return self._real_branch.set_stacked_on(stacked_location)
+
def get_config(self):
return RemoteBranchConfig(self)
=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py 2007-06-28 05:19:04 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py 2008-02-14 00:40:32 +0000
@@ -155,6 +155,7 @@
'bzrlib.tests.branch_implementations.test_revision_history',
'bzrlib.tests.branch_implementations.test_revision_id_to_revno',
'bzrlib.tests.branch_implementations.test_sprout',
+ 'bzrlib.tests.branch_implementations.test_stacking',
'bzrlib.tests.branch_implementations.test_tags',
'bzrlib.tests.branch_implementations.test_uncommit',
'bzrlib.tests.branch_implementations.test_update',
=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py 2007-10-04 05:50:44 +0000
+++ b/bzrlib/tests/test_branch.py 2008-02-14 00:40:32 +0000
@@ -200,26 +200,36 @@
self.make_branch_and_tree('bar')
-class TestBranch6(TestCaseWithTransport):
+class TestBranch67(object):
+ """Common tests for both branch 6 and 7 which are mostly the same."""
+
+ def get_format_name(self):
+ raise NotImplementedError(self.get_format_name)
+
+ def get_format_name_subtree(self):
+ raise NotImplementedError(self.get_format_name)
+
+ def get_class(self):
+ raise NotImplementedError(self.get_class)
def test_creation(self):
format = BzrDirMetaFormat1()
format.set_branch_format(_mod_branch.BzrBranchFormat6())
branch = self.make_branch('a', format=format)
- self.assertIsInstance(branch, _mod_branch.BzrBranch6)
- branch = self.make_branch('b', format='dirstate-tags')
- self.assertIsInstance(branch, _mod_branch.BzrBranch6)
+ self.assertIsInstance(branch, self.get_class())
+ branch = self.make_branch('b', format=self.get_format_name())
+ self.assertIsInstance(branch, self.get_class())
branch = _mod_branch.Branch.open('a')
- self.assertIsInstance(branch, _mod_branch.BzrBranch6)
+ self.assertIsInstance(branch, self.get_class())
def test_layout(self):
- branch = self.make_branch('a', format='dirstate-tags')
+ branch = self.make_branch('a', format=self.get_format_name())
self.failUnlessExists('a/.bzr/branch/last-revision')
self.failIfExists('a/.bzr/branch/revision-history')
def test_config(self):
"""Ensure that all configuration data is stored in the branch"""
- branch = self.make_branch('a', format='dirstate-tags')
+ branch = self.make_branch('a', format=self.get_format_name())
branch.set_parent('http://bazaar-vcs.org')
self.failIfExists('a/.bzr/branch/parent')
self.assertEqual('http://bazaar-vcs.org', branch.get_parent())
@@ -233,7 +243,7 @@
def test_set_revision_history(self):
tree = self.make_branch_and_memory_tree('.',
- format='dirstate-tags')
+ format=self.get_format_name())
tree.lock_write()
try:
tree.add('.')
@@ -247,11 +257,12 @@
tree.unlock()
def do_checkout_test(self, lightweight=False):
- tree = self.make_branch_and_tree('source', format='dirstate-with-subtree')
+ tree = self.make_branch_and_tree('source',
+ format=self.get_format_name_subtree())
subtree = self.make_branch_and_tree('source/subtree',
- format='dirstate-with-subtree')
+ format=self.get_format_name_subtree())
subsubtree = self.make_branch_and_tree('source/subtree/subsubtree',
- format='dirstate-with-subtree')
+ format=self.get_format_name_subtree())
self.build_tree(['source/subtree/file',
'source/subtree/subsubtree/file'])
subsubtree.add('file')
@@ -279,7 +290,7 @@
self.do_checkout_test(lightweight=True)
def test_set_push(self):
- branch = self.make_branch('source', format='dirstate-tags')
+ branch = self.make_branch('source', format=self.get_format_name())
branch.get_config().set_user_option('push_location', 'old',
store=config.STORE_LOCATION)
warnings = []
@@ -294,6 +305,54 @@
self.assertEqual(warnings[0], 'Value "new" is masked by "old" from '
'locations.conf')
+
+class TestBranch6(TestBranch67, TestCaseWithTransport):
+
+ def get_class(self):
+ return _mod_branch.BzrBranch6
+
+ def get_format_name(self):
+ return "dirstate-tags"
+
+ def get_format_name_subtree(self):
+ return "dirstate-with-subtree"
+
+ def test_set_stacked_on_errors(self):
+ branch = self.make_branch('a', format=self.get_format_name())
+ self.assertRaises(errors.UnstackableBranchFormat,
+ branch.set_stacked_on, None)
+
+ def test_default_stacked_location(self):
+ branch = self.make_branch('a', format=self.get_format_name())
+ self.assertRaises(errors.UnstackableBranchFormat, branch.get_stacked_on)
+
+
+class TestBranch7(TestBranch67, TestCaseWithTransport):
+
+ def get_class(self):
+ return _mod_branch.BzrBranch7
+
+ def get_format_name(self):
+ return "development"
+
+ def get_format_name_subtree(self):
+ return "development-subtree"
+
+ def test_set_stacked_on_unstackable_repo(self):
+ branch = self.make_branch('a', format=self.get_format_name())
+ target = self.make_branch('b')
+ self.assertRaises(errors.UnstackableRepositoryFormat,
+ branch.set_stacked_on, target.base)
+
+ def _test_default_stacked_location(self):
+ branch = self.make_branch('a', format=self.get_format_name())
+ self.assertRaises(errors.NotStacked, branch.get_stacked_on)
+
+ def test_stacked_location_file(self):
+ branch = self.make_branch('a', format=self.get_format_name())
+ self.assertFileEqual('\n', 'a/.bzr/branch/stacked-on')
+
+
class TestBranchReference(TestCaseWithTransport):
"""Tests for the branch reference facility."""
=== modified file 'bzrlib/tests/test_errors.py'
--- a/bzrlib/tests/test_errors.py 2008-02-13 01:42:47 +0000
+++ b/bzrlib/tests/test_errors.py 2008-02-14 00:40:32 +0000
@@ -174,6 +174,11 @@
" tree atree.", str(error))
self.assertIsInstance(error, errors.NoSuchRevision)
+ def test_not_stacked(self):
+ error = errors.NotStacked('a branch')
+ self.assertEqualDiff("The branch 'a branch' is not stacked.",
+ str(error))
+
def test_not_write_locked(self):
error = errors.NotWriteLocked('a thing to repr')
self.assertEqualDiff("'a thing to repr' is not write locked but needs "
@@ -209,6 +214,24 @@
" of bzrlib.",
str(error))
+ def test_unstackable_branch_format(self):
+ format = u'foo'
+ url = "/foo"
+ error = errors.UnstackableBranchFormat(format, url)
+ self.assertEqualDiff(
+ "The branch '/foo'(foo) is not a stackable format. "
+ "You will need to upgrade the branch to permit branch stacking.",
+ str(error))
+
+ def test_unstackable_repository_format(self):
+ format = u'foo'
+ url = "/foo"
+ error = errors.UnstackableRepositoryFormat(format, url)
+ self.assertEqualDiff(
+ "The repository '/foo'(foo) is not a stackable format. "
+ "You will need to upgrade the repository to permit branch stacking.",
+ str(error))
+
def test_up_to_date(self):
error = errors.UpToDateFormat(bzrdir.BzrDirFormat4())
self.assertEqualDiff("The branch format Bazaar-NG branch, "
More information about the bazaar-commits
mailing list