84
114
"""Return true if this bzrdir is one whose format we can convert from."""
117
def check_conversion_target(self, target_format):
118
target_repo_format = target_format.repository_format
119
source_repo_format = self._format.repository_format
120
source_repo_format.check_conversion_target(target_repo_format)
88
def _check_supported(format, allow_unsupported):
89
"""Check whether format is a supported format.
91
If allow_unsupported is True, this is a no-op.
123
def _check_supported(format, allow_unsupported,
124
recommend_upgrade=True,
126
"""Give an error or warning on old formats.
128
:param format: may be any kind of format - workingtree, branch,
131
:param allow_unsupported: If true, allow opening
132
formats that are strongly deprecated, and which may
133
have limited functionality.
135
:param recommend_upgrade: If true (default), warn
136
the user through the ui object that they may wish
137
to upgrade the object.
139
# TODO: perhaps move this into a base Format class; it's not BzrDir
140
# specific. mbp 20070323
93
141
if not allow_unsupported and not format.is_supported():
94
142
# see open_downlevel to open legacy branches.
95
raise errors.UnsupportedFormatError(
96
'sorry, format %s not supported' % format,
97
['use a different bzr version',
98
'or remove the .bzr directory'
99
' and "bzr init" again'])
143
raise errors.UnsupportedFormatError(format=format)
144
if recommend_upgrade \
145
and getattr(format, 'upgrade_recommended', False):
146
ui.ui_factory.recommend_upgrade(
147
format.get_format_description(),
101
def clone(self, url, revision_id=None, basis=None, force_new_repo=False):
150
def clone(self, url, revision_id=None, force_new_repo=False):
102
151
"""Clone this bzrdir and its contents to url verbatim.
104
153
If urls last component does not exist, it will be created.
147
204
except errors.NotBranchError:
150
self.open_workingtree().clone(result, basis=basis_tree)
207
self.open_workingtree().clone(result)
151
208
except (errors.NoWorkingTree, errors.NotLocalUrl):
155
def _get_basis_components(self, basis):
156
"""Retrieve the basis components that are available at basis."""
158
return None, None, None
160
basis_tree = basis.open_workingtree()
161
basis_branch = basis_tree.branch
162
basis_repo = basis_branch.repository
163
except (errors.NoWorkingTree, errors.NotLocalUrl):
166
basis_branch = basis.open_branch()
167
basis_repo = basis_branch.repository
168
except errors.NotBranchError:
171
basis_repo = basis.open_repository()
172
except errors.NoRepositoryPresent:
174
return basis_repo, basis_branch, basis_tree
212
# TODO: This should be given a Transport, and should chdir up; otherwise
213
# this will open a new connection.
176
214
def _make_tail(self, url):
177
segments = url.split('/')
178
if segments and segments[-1] not in ('', '.'):
179
parent = '/'.join(segments[:-1])
180
t = bzrlib.transport.get_transport(parent)
182
t.mkdir(segments[-1])
183
except errors.FileExists:
215
t = get_transport(url)
187
def create(cls, base):
219
def create(cls, base, format=None, possible_transports=None):
188
220
"""Create a new BzrDir at the url 'base'.
190
222
This will call the current default formats initialize with base
191
223
as the only parameter.
193
If you need a specific format, consider creating an instance
194
of that and calling initialize().
225
:param format: If supplied, the format of branch to create. If not
226
supplied, the default is used.
227
:param possible_transports: If supplied, a list of transports that
228
can be reused to share a remote connection.
196
230
if cls is not BzrDir:
197
raise AssertionError("BzrDir.create always creates the default format, "
198
"not one of %r" % cls)
199
segments = base.split('/')
200
if segments and segments[-1] not in ('', '.'):
201
parent = '/'.join(segments[:-1])
202
t = bzrlib.transport.get_transport(parent)
204
t.mkdir(segments[-1])
205
except errors.FileExists:
207
return BzrDirFormat.get_default_format().initialize(safe_unicode(base))
231
raise AssertionError("BzrDir.create always creates the default"
232
" format, not one of %r" % cls)
233
t = get_transport(base, possible_transports)
236
format = BzrDirFormat.get_default_format()
237
return format.initialize(base, possible_transports)
209
239
def create_branch(self):
210
240
"""Create a branch in this BzrDir.
265
300
:param force_new_repo: If True a new repository is always created.
266
301
:param force_new_tree: If True or False force creation of a tree or
267
302
prevent such creation respectively.
268
:param format: Override for the for the bzrdir format to create
303
:param format: Override for the for the bzrdir format to create.
304
:param possible_transports: An optional reusable transports list.
270
306
if force_new_tree:
271
307
# check for non local urls
272
t = get_transport(safe_unicode(base))
308
t = get_transport(base, possible_transports)
273
309
if not isinstance(t, LocalTransport):
274
310
raise errors.NotLocalUrl(base)
276
bzrdir = BzrDir.create(base)
278
bzrdir = format.initialize(base)
311
bzrdir = BzrDir.create(base, format, possible_transports)
279
312
repo = bzrdir._find_or_create_repository(force_new_repo)
280
313
result = bzrdir.create_branch()
281
if force_new_tree or (repo.make_working_trees() and
314
if force_new_tree or (repo.make_working_trees() and
282
315
force_new_tree is None):
284
317
bzrdir.create_workingtree()
285
318
except errors.NotLocalUrl:
290
def create_repository(base, shared=False):
323
@deprecated_function(zero_ninetyone)
324
def create_repository(base, shared=False, format=None):
291
325
"""Create a new BzrDir and Repository at the url 'base'.
293
This will use the current default BzrDirFormat, and use whatever
294
repository format that that uses for bzrdirformat.create_repository.
327
If no format is supplied, this will default to the current default
328
BzrDirFormat by default, and use whatever repository format that that
329
uses for bzrdirformat.create_repository.
296
;param shared: Create a shared repository rather than a standalone
331
:param shared: Create a shared repository rather than a standalone
298
333
The Repository object is returned.
300
335
This must be overridden as an instance method in child classes, where
301
336
it should take no parameters and construct whatever repository format
302
337
that child class desires.
339
This method is deprecated, please call create_repository on a bzrdir
304
bzrdir = BzrDir.create(base)
305
return bzrdir.create_repository()
342
bzrdir = BzrDir.create(base, format)
343
return bzrdir.create_repository(shared)
308
def create_standalone_workingtree(base):
346
def create_standalone_workingtree(base, format=None):
309
347
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
311
349
'base' must be a local path or a file:// url.
448
537
return BzrDir.open(base, _unsupported=True)
451
def open(base, _unsupported=False):
540
def open(base, _unsupported=False, possible_transports=None):
452
541
"""Open an existing bzrdir, rooted at 'base' (url)
454
543
_unsupported is a private parameter to the BzrDir class.
456
t = get_transport(base)
457
mutter("trying to open %r with transport %r", base, t)
458
format = BzrDirFormat.find_format(t)
545
t = get_transport(base, possible_transports=possible_transports)
546
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
549
def open_from_transport(transport, _unsupported=False,
550
_server_formats=True):
551
"""Open a bzrdir within a particular directory.
553
:param transport: Transport containing the bzrdir.
554
:param _unsupported: private.
556
base = transport.base
558
def find_format(transport):
559
return transport, BzrDirFormat.find_format(
560
transport, _server_formats=_server_formats)
562
def redirected(transport, e, redirection_notice):
563
qualified_source = e.get_source_url()
564
relpath = transport.relpath(qualified_source)
565
if not e.target.endswith(relpath):
566
# Not redirected to a branch-format, not a branch
567
raise errors.NotBranchError(path=e.target)
568
target = e.target[:-len(relpath)]
569
note('%s is%s redirected to %s',
570
transport.base, e.permanently, target)
571
# Let's try with a new transport
572
qualified_target = e.get_target_url()[:-len(relpath)]
573
# FIXME: If 'transport' has a qualifier, this should
574
# be applied again to the new transport *iff* the
575
# schemes used are the same. It's a bit tricky to
576
# verify, so I'll punt for now
578
return get_transport(target)
581
transport, format = do_catching_redirections(find_format,
584
except errors.TooManyRedirections:
585
raise errors.NotBranchError(base)
459
587
BzrDir._check_supported(format, _unsupported)
460
return format.open(t, _found=True)
588
return format.open(transport, _found=True)
462
590
def open_branch(self, unsupported=False):
463
591
"""Open the branch object at this BzrDir if one is present.
489
618
If there is one and it is either an unrecognised format or an unsupported
490
619
format, UnknownFormatError or UnsupportedFormatError are raised.
491
620
If there is one, it is returned, along with the unused portion of url.
622
:return: The BzrDir that contains the path, and a Unicode path
623
for the rest of the URL.
493
625
# this gets the normalised url back. I.e. '.' -> the full path.
494
626
url = a_transport.base
497
format = BzrDirFormat.find_format(a_transport)
498
BzrDir._check_supported(format, False)
499
return format.open(a_transport), a_transport.relpath(url)
629
result = BzrDir.open_from_transport(a_transport)
630
return result, urlutils.unescape(a_transport.relpath(url))
500
631
except errors.NotBranchError, e:
501
mutter('not a branch in: %r %s', a_transport.base, e)
502
new_t = a_transport.clone('..')
634
new_t = a_transport.clone('..')
635
except errors.InvalidURLJoin:
636
# reached the root, whatever that may be
637
raise errors.NotBranchError(path=url)
503
638
if new_t.base == a_transport.base:
504
639
# reached the root, whatever that may be
505
640
raise errors.NotBranchError(path=url)
506
641
a_transport = new_t
644
def open_containing_tree_or_branch(klass, location):
645
"""Return the branch and working tree contained by a location.
647
Returns (tree, branch, relpath).
648
If there is no tree at containing the location, tree will be None.
649
If there is no branch containing the location, an exception will be
651
relpath is the portion of the path that is contained by the branch.
653
bzrdir, relpath = klass.open_containing(location)
655
tree = bzrdir.open_workingtree()
656
except (errors.NoWorkingTree, errors.NotLocalUrl):
658
branch = bzrdir.open_branch()
661
return tree, branch, relpath
508
663
def open_repository(self, _unsupported=False):
509
664
"""Open the repository object at this BzrDir if one is present.
548
707
workingtree and discards it, and that's somewhat expensive.)
551
self.open_workingtree()
710
self.open_workingtree(recommend_upgrade=False)
553
712
except errors.NoWorkingTree:
556
def sprout(self, url, revision_id=None, basis=None, force_new_repo=False):
715
def _cloning_metadir(self):
716
"""Produce a metadir suitable for cloning with"""
717
result_format = self._format.__class__()
720
branch = self.open_branch()
721
source_repository = branch.repository
722
except errors.NotBranchError:
724
source_repository = self.open_repository()
725
except errors.NoRepositoryPresent:
726
source_repository = None
728
# XXX TODO: This isinstance is here because we have not implemented
729
# the fix recommended in bug # 103195 - to delegate this choice the
731
repo_format = source_repository._format
732
if not isinstance(repo_format, remote.RemoteRepositoryFormat):
733
result_format.repository_format = repo_format
735
# TODO: Couldn't we just probe for the format in these cases,
736
# rather than opening the whole tree? It would be a little
737
# faster. mbp 20070401
738
tree = self.open_workingtree(recommend_upgrade=False)
739
except (errors.NoWorkingTree, errors.NotLocalUrl):
740
result_format.workingtree_format = None
742
result_format.workingtree_format = tree._format.__class__()
743
return result_format, source_repository
745
def cloning_metadir(self):
746
"""Produce a metadir suitable for cloning or sprouting with.
748
These operations may produce workingtrees (yes, even though they're
749
"cloning" something that doesn't have a tree, so a viable workingtree
750
format must be selected.
752
format, repository = self._cloning_metadir()
753
if format._workingtree_format is None:
754
if repository is None:
756
tree_format = repository._format._matchingbzrdir.workingtree_format
757
format.workingtree_format = tree_format.__class__()
760
def checkout_metadir(self):
761
return self.cloning_metadir()
763
def sprout(self, url, revision_id=None, force_new_repo=False,
764
recurse='down', possible_transports=None):
557
765
"""Create a copy of this bzrdir prepared for use as a new line of
595
802
result.create_repository()
596
803
elif source_repository is not None and result_repo is None:
597
804
# have source, and want to make a new target repo
598
# we dont clone the repo because that preserves attributes
599
# like is_shared(), and we have not yet implemented a
600
# repository sprout().
601
result_repo = result.create_repository()
602
if result_repo is not None:
805
result_repo = source_repository.sprout(result,
806
revision_id=revision_id)
603
808
# fetch needed content into target.
605
# XXX FIXME RBC 20060214 need tests for this when the basis
607
result_repo.fetch(basis_repo, revision_id=revision_id)
608
result_repo.fetch(source_repository, revision_id=revision_id)
809
if source_repository is not None:
811
# source_repository.copy_content_into(result_repo,
812
# revision_id=revision_id)
813
# so we can override the copy method
814
result_repo.fetch(source_repository, revision_id=revision_id)
609
815
if source_branch is not None:
610
816
source_branch.sprout(result, revision_id=revision_id)
612
818
result.create_branch()
613
if result_repo is None or result_repo.make_working_trees():
614
result.create_workingtree()
819
if isinstance(target_transport, LocalTransport) and (
820
result_repo is None or result_repo.make_working_trees()):
821
wt = result.create_workingtree()
824
if wt.path2id('') is None:
826
wt.set_root_id(self.open_workingtree.get_root_id())
827
except errors.NoWorkingTree:
833
if recurse == 'down':
835
basis = wt.basis_tree()
837
subtrees = basis.iter_references()
838
recurse_branch = wt.branch
839
elif source_branch is not None:
840
basis = source_branch.basis_tree()
842
subtrees = basis.iter_references()
843
recurse_branch = source_branch
848
for path, file_id in subtrees:
849
target = urlutils.join(url, urlutils.escape(path))
850
sublocation = source_branch.reference_parent(file_id, path)
851
sublocation.bzrdir.sprout(target,
852
basis.get_reference_revision(file_id, path),
853
force_new_repo=force_new_repo, recurse=recurse)
855
if basis is not None:
1270
1701
repository_format = property(__return_repository_format, __set_repository_format)
1703
def __get_workingtree_format(self):
1704
if self._workingtree_format is None:
1705
from bzrlib.workingtree import WorkingTreeFormat
1706
self._workingtree_format = WorkingTreeFormat.get_default_format()
1707
return self._workingtree_format
1709
def __set_workingtree_format(self, wt_format):
1710
self._workingtree_format = wt_format
1712
workingtree_format = property(__get_workingtree_format,
1713
__set_workingtree_format)
1716
# Register bzr control format
1717
BzrDirFormat.register_control_format(BzrDirFormat)
1719
# Register bzr formats
1273
1720
BzrDirFormat.register_format(BzrDirFormat4())
1274
1721
BzrDirFormat.register_format(BzrDirFormat5())
1275
1722
BzrDirFormat.register_format(BzrDirFormat6())
1276
1723
__default_format = BzrDirMetaFormat1()
1277
1724
BzrDirFormat.register_format(__default_format)
1278
BzrDirFormat.set_default_format(__default_format)
1281
class BzrDirTestProviderAdapter(object):
1282
"""A tool to generate a suite testing multiple bzrdir formats at once.
1284
This is done by copying the test once for each transport and injecting
1285
the transport_server, transport_readonly_server, and bzrdir_format
1286
classes into each copy. Each copy is also given a new id() to make it
1290
def __init__(self, transport_server, transport_readonly_server, formats):
1291
self._transport_server = transport_server
1292
self._transport_readonly_server = transport_readonly_server
1293
self._formats = formats
1295
def adapt(self, test):
1296
result = TestSuite()
1297
for format in self._formats:
1298
new_test = deepcopy(test)
1299
new_test.transport_server = self._transport_server
1300
new_test.transport_readonly_server = self._transport_readonly_server
1301
new_test.bzrdir_format = format
1302
def make_new_test_id():
1303
new_id = "%s(%s)" % (new_test.id(), format.__class__.__name__)
1304
return lambda: new_id
1305
new_test.id = make_new_test_id()
1306
result.addTest(new_test)
1310
class ScratchDir(BzrDir6):
1311
"""Special test class: a bzrdir that cleans up itself..
1313
>>> d = ScratchDir()
1314
>>> base = d.transport.base
1317
>>> b.transport.__del__()
1322
def __init__(self, files=[], dirs=[], transport=None):
1323
"""Make a test branch.
1325
This creates a temporary directory and runs init-tree in it.
1327
If any files are listed, they are created in the working copy.
1329
if transport is None:
1330
transport = bzrlib.transport.local.ScratchTransport()
1331
# local import for scope restriction
1332
BzrDirFormat6().initialize(transport.base)
1333
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1334
self.create_repository()
1335
self.create_branch()
1336
self.create_workingtree()
1338
super(ScratchDir, self).__init__(transport, BzrDirFormat6())
1340
# BzrBranch creates a clone to .bzr and then forgets about the
1341
# original transport. A ScratchTransport() deletes itself and
1342
# everything underneath it when it goes away, so we need to
1343
# grab a local copy to prevent that from happening
1344
self._transport = transport
1347
self._transport.mkdir(d)
1350
self._transport.put(f, 'content of %s' % f)
1354
>>> orig = ScratchDir(files=["file1", "file2"])
1355
>>> os.listdir(orig.base)
1356
[u'.bzr', u'file1', u'file2']
1357
>>> clone = orig.clone()
1358
>>> if os.name != 'nt':
1359
... os.path.samefile(orig.base, clone.base)
1361
... orig.base == clone.base
1364
>>> os.listdir(clone.base)
1365
[u'.bzr', u'file1', u'file2']
1367
from shutil import copytree
1368
from bzrlib.osutils import mkdtemp
1371
copytree(self.base, base, symlinks=True)
1373
transport=bzrlib.transport.local.ScratchTransport(base))
1725
BzrDirFormat._default_format = __default_format
1376
1728
class Converter(object):
1728
2089
# we hard code the formats here because we are converting into
1729
2090
# the meta format. The meta format upgrader can take this to a
1730
2091
# future format within each component.
1731
self.put_format('repository', bzrlib.repository.RepositoryFormat7())
2092
self.put_format('repository', RepositoryFormat7())
1732
2093
for entry in repository_names:
1733
2094
self.move_entry('repository', entry)
1735
2096
self.step('Upgrading branch ')
1736
2097
self.bzrdir.transport.mkdir('branch', mode=self.dir_mode)
1737
2098
self.make_lock('branch')
1738
self.put_format('branch', bzrlib.branch.BzrBranchFormat5())
2099
self.put_format('branch', BzrBranchFormat5())
1739
2100
branch_files = [('revision-history', True),
1740
2101
('branch-name', True),
1741
2102
('parent', False)]
1742
2103
for entry in branch_files:
1743
2104
self.move_entry('branch', entry)
1745
self.step('Upgrading working tree')
1746
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
1747
self.make_lock('checkout')
1748
self.put_format('checkout', bzrlib.workingtree.WorkingTreeFormat3())
1749
self.bzrdir.transport.delete_multi(self.garbage_inventories, self.pb)
1750
2106
checkout_files = [('pending-merges', True),
1751
2107
('inventory', True),
1752
2108
('stat-cache', False)]
1753
for entry in checkout_files:
1754
self.move_entry('checkout', entry)
1755
if last_revision is not None:
1756
self.bzrdir._control_files.put_utf8('checkout/last-revision',
1758
self.bzrdir._control_files.put_utf8('branch-format', BzrDirMetaFormat1().get_format_string())
2109
# If a mandatory checkout file is not present, the branch does not have
2110
# a functional checkout. Do not create a checkout in the converted
2112
for name, mandatory in checkout_files:
2113
if mandatory and name not in bzrcontents:
2114
has_checkout = False
2118
if not has_checkout:
2119
self.pb.note('No working tree.')
2120
# If some checkout files are there, we may as well get rid of them.
2121
for name, mandatory in checkout_files:
2122
if name in bzrcontents:
2123
self.bzrdir.transport.delete(name)
2125
from bzrlib.workingtree import WorkingTreeFormat3
2126
self.step('Upgrading working tree')
2127
self.bzrdir.transport.mkdir('checkout', mode=self.dir_mode)
2128
self.make_lock('checkout')
2130
'checkout', WorkingTreeFormat3())
2131
self.bzrdir.transport.delete_multi(
2132
self.garbage_inventories, self.pb)
2133
for entry in checkout_files:
2134
self.move_entry('checkout', entry)
2135
if last_revision is not None:
2136
self.bzrdir._control_files.put_utf8(
2137
'checkout/last-revision', last_revision)
2138
self.bzrdir._control_files.put_utf8(
2139
'branch-format', BzrDirMetaFormat1().get_format_string())
1759
2140
return BzrDir.open(self.bzrdir.root_transport.base)
1761
2142
def make_lock(self, name):
1762
2143
"""Make a lock for the new control dir name."""
1763
2144
self.step('Make %s lock' % name)
1764
ld = LockDir(self.bzrdir.transport,
1766
file_modebits=self.file_mode,
1767
dir_modebits=self.dir_mode)
2145
ld = lockdir.LockDir(self.bzrdir.transport,
2147
file_modebits=self.file_mode,
2148
dir_modebits=self.dir_mode)
1770
2151
def move_entry(self, new_dir, entry):
1809
2190
self.pb.note('starting repository conversion')
1810
2191
converter = CopyConverter(self.target_format.repository_format)
1811
2192
converter.convert(repo, pb)
2194
branch = self.bzrdir.open_branch()
2195
except errors.NotBranchError:
2198
# TODO: conversions of Branch and Tree should be done by
2199
# InterXFormat lookups
2200
# Avoid circular imports
2201
from bzrlib import branch as _mod_branch
2202
if (branch._format.__class__ is _mod_branch.BzrBranchFormat5 and
2203
self.target_format.get_branch_format().__class__ is
2204
_mod_branch.BzrBranchFormat6):
2205
branch_converter = _mod_branch.Converter5to6()
2206
branch_converter.convert(branch)
2208
tree = self.bzrdir.open_workingtree(recommend_upgrade=False)
2209
except (errors.NoWorkingTree, errors.NotLocalUrl):
2212
# TODO: conversions of Branch and Tree should be done by
2213
# InterXFormat lookups
2214
if (isinstance(tree, workingtree.WorkingTree3) and
2215
not isinstance(tree, workingtree_4.WorkingTree4) and
2216
isinstance(self.target_format.workingtree_format,
2217
workingtree_4.WorkingTreeFormat4)):
2218
workingtree_4.Converter3to4().convert(tree)
1812
2219
return to_convert
2222
# This is not in remote.py because it's small, and needs to be registered.
2223
# Putting it in remote.py creates a circular import problem.
2224
# we can make it a lazy object if the control formats is turned into something
2226
class RemoteBzrDirFormat(BzrDirMetaFormat1):
2227
"""Format representing bzrdirs accessed via a smart server"""
2229
def get_format_description(self):
2230
return 'bzr remote bzrdir'
2233
def probe_transport(klass, transport):
2234
"""Return a RemoteBzrDirFormat object if it looks possible."""
2236
client = transport.get_smart_client()
2237
except (NotImplementedError, AttributeError,
2238
errors.TransportNotPossible):
2239
# no smart server, so not a branch for this format type.
2240
raise errors.NotBranchError(path=transport.base)
2242
# Send a 'hello' request in protocol version one, and decline to
2243
# open it if the server doesn't support our required version (2) so
2244
# that the VFS-based transport will do it.
2245
request = client.get_request()
2246
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
2247
server_version = smart_protocol.query_version()
2248
if server_version != 2:
2249
raise errors.NotBranchError(path=transport.base)
2252
def initialize_on_transport(self, transport):
2254
# hand off the request to the smart server
2255
shared_medium = transport.get_shared_medium()
2256
except errors.NoSmartMedium:
2257
# TODO: lookup the local format from a server hint.
2258
local_dir_format = BzrDirMetaFormat1()
2259
return local_dir_format.initialize_on_transport(transport)
2260
client = _SmartClient(shared_medium)
2261
path = client.remote_path_from_transport(transport)
2262
response = _SmartClient(shared_medium).call('BzrDirFormat.initialize',
2264
assert response[0] in ('ok', ), 'unexpected response code %s' % (response,)
2265
return remote.RemoteBzrDir(transport)
2267
def _open(self, transport):
2268
return remote.RemoteBzrDir(transport)
2270
def __eq__(self, other):
2271
if not isinstance(other, RemoteBzrDirFormat):
2273
return self.get_format_description() == other.get_format_description()
2276
BzrDirFormat.register_control_server_format(RemoteBzrDirFormat)
2279
class BzrDirFormatInfo(object):
2281
def __init__(self, native, deprecated, hidden):
2282
self.deprecated = deprecated
2283
self.native = native
2284
self.hidden = hidden
2287
class BzrDirFormatRegistry(registry.Registry):
2288
"""Registry of user-selectable BzrDir subformats.
2290
Differs from BzrDirFormat._control_formats in that it provides sub-formats,
2291
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
2294
def register_metadir(self, key,
2295
repository_format, help, native=True, deprecated=False,
2299
"""Register a metadir subformat.
2301
These all use a BzrDirMetaFormat1 bzrdir, but can be parameterized
2302
by the Repository format.
2304
:param repository_format: The fully-qualified repository format class
2306
:param branch_format: Fully-qualified branch format class name as
2308
:param tree_format: Fully-qualified tree format class name as
2311
# This should be expanded to support setting WorkingTree and Branch
2312
# formats, once BzrDirMetaFormat1 supports that.
2313
def _load(full_name):
2314
mod_name, factory_name = full_name.rsplit('.', 1)
2316
mod = __import__(mod_name, globals(), locals(),
2318
except ImportError, e:
2319
raise ImportError('failed to load %s: %s' % (full_name, e))
2321
factory = getattr(mod, factory_name)
2322
except AttributeError:
2323
raise AttributeError('no factory %s in module %r'
2328
bd = BzrDirMetaFormat1()
2329
if branch_format is not None:
2330
bd.set_branch_format(_load(branch_format))
2331
if tree_format is not None:
2332
bd.workingtree_format = _load(tree_format)
2333
if repository_format is not None:
2334
bd.repository_format = _load(repository_format)
2336
self.register(key, helper, help, native, deprecated, hidden)
2338
def register(self, key, factory, help, native=True, deprecated=False,
2340
"""Register a BzrDirFormat factory.
2342
The factory must be a callable that takes one parameter: the key.
2343
It must produce an instance of the BzrDirFormat when called.
2345
This function mainly exists to prevent the info object from being
2348
registry.Registry.register(self, key, factory, help,
2349
BzrDirFormatInfo(native, deprecated, hidden))
2351
def register_lazy(self, key, module_name, member_name, help, native=True,
2352
deprecated=False, hidden=False):
2353
registry.Registry.register_lazy(self, key, module_name, member_name,
2354
help, BzrDirFormatInfo(native, deprecated, hidden))
2356
def set_default(self, key):
2357
"""Set the 'default' key to be a clone of the supplied key.
2359
This method must be called once and only once.
2361
registry.Registry.register(self, 'default', self.get(key),
2362
self.get_help(key), info=self.get_info(key))
2364
def set_default_repository(self, key):
2365
"""Set the FormatRegistry default and Repository default.
2367
This is a transitional method while Repository.set_default_format
2370
if 'default' in self:
2371
self.remove('default')
2372
self.set_default(key)
2373
format = self.get('default')()
2374
assert isinstance(format, BzrDirMetaFormat1)
2376
def make_bzrdir(self, key):
2377
return self.get(key)()
2379
def help_topic(self, topic):
2380
output = textwrap.dedent("""\
2381
These formats can be used for creating branches, working trees, and
2385
default_realkey = None
2386
default_help = self.get_help('default')
2388
for key in self.keys():
2389
if key == 'default':
2391
help = self.get_help(key)
2392
if help == default_help:
2393
default_realkey = key
2395
help_pairs.append((key, help))
2397
def wrapped(key, help, info):
2399
help = '(native) ' + help
2400
return ':%s:\n%s\n\n' % (key,
2401
textwrap.fill(help, initial_indent=' ',
2402
subsequent_indent=' '))
2403
if default_realkey is not None:
2404
output += wrapped(default_realkey, '(default) %s' % default_help,
2405
self.get_info('default'))
2406
deprecated_pairs = []
2407
for key, help in help_pairs:
2408
info = self.get_info(key)
2411
elif info.deprecated:
2412
deprecated_pairs.append((key, help))
2414
output += wrapped(key, help, info)
2415
if len(deprecated_pairs) > 0:
2416
output += "Deprecated formats are shown below.\n\n"
2417
for key, help in deprecated_pairs:
2418
info = self.get_info(key)
2419
output += wrapped(key, help, info)
2424
format_registry = BzrDirFormatRegistry()
2425
format_registry.register('weave', BzrDirFormat6,
2426
'Pre-0.8 format. Slower than knit and does not'
2427
' support checkouts or shared repositories.',
2429
format_registry.register_metadir('knit',
2430
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2431
'Format using knits. Recommended for interoperation with bzr <= 0.14.',
2432
branch_format='bzrlib.branch.BzrBranchFormat5',
2433
tree_format='bzrlib.workingtree.WorkingTreeFormat3')
2434
format_registry.register_metadir('metaweave',
2435
'bzrlib.repofmt.weaverepo.RepositoryFormat7',
2436
'Transitional format in 0.8. Slower than knit.',
2437
branch_format='bzrlib.branch.BzrBranchFormat5',
2438
tree_format='bzrlib.workingtree.WorkingTreeFormat3',
2440
format_registry.register_metadir('dirstate',
2441
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2442
help='New in 0.15: Fast local operations. Compatible with bzr 0.8 and '
2443
'above when accessed over the network.',
2444
branch_format='bzrlib.branch.BzrBranchFormat5',
2445
# this uses bzrlib.workingtree.WorkingTreeFormat4 because importing
2446
# directly from workingtree_4 triggers a circular import.
2447
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2449
format_registry.register_metadir('dirstate-tags',
2450
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit1',
2451
help='New in 0.15: Fast local operations and improved scaling for '
2452
'network operations. Additionally adds support for tags.'
2453
' Incompatible with bzr < 0.15.',
2454
branch_format='bzrlib.branch.BzrBranchFormat6',
2455
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2457
format_registry.register_metadir('dirstate-with-subtree',
2458
'bzrlib.repofmt.knitrepo.RepositoryFormatKnit3',
2459
help='New in 0.15: Fast local operations and improved scaling for '
2460
'network operations. Additionally adds support for versioning nested '
2461
'bzr branches. Incompatible with bzr < 0.15.',
2462
branch_format='bzrlib.branch.BzrBranchFormat6',
2463
tree_format='bzrlib.workingtree.WorkingTreeFormat4',
2466
format_registry.set_default('dirstate-tags')