207
207
raise errors.NoColocatedBranchSupport(self)
210
def get_branch_transport(self, branch_format, name=None):
211
"""Get the transport for use by branch format in this ControlDir.
213
Note that bzr dirs that do not support format strings will raise
214
IncompatibleFormat if the branch format they are given has
215
a format string, and vice versa.
217
If branch_format is None, the transport is returned with no
218
checking. If it is not None, then the returned transport is
219
guaranteed to point to an existing directory ready for use.
221
raise NotImplementedError(self.get_branch_transport)
223
def get_repository_transport(self, repository_format):
224
"""Get the transport for use by repository format in this ControlDir.
226
Note that bzr dirs that do not support format strings will raise
227
IncompatibleFormat if the repository format they are given has
228
a format string, and vice versa.
230
If repository_format is None, the transport is returned with no
231
checking. If it is not None, then the returned transport is
232
guaranteed to point to an existing directory ready for use.
234
raise NotImplementedError(self.get_repository_transport)
236
def get_workingtree_transport(self, tree_format):
237
"""Get the transport for use by workingtree format in this ControlDir.
239
Note that bzr dirs that do not support format strings will raise
240
IncompatibleFormat if the workingtree format they are given has a
241
format string, and vice versa.
243
If workingtree_format is None, the transport is returned with no
244
checking. If it is not None, then the returned transport is
245
guaranteed to point to an existing directory ready for use.
247
raise NotImplementedError(self.get_workingtree_transport)
210
249
def open_branch(self, name=None, unsupported=False,
211
250
ignore_fallbacks=False):
212
251
"""Open the branch object at this ControlDir if one is present.
327
366
:param create_tree_if_local: If true, a working-tree will be created
328
367
when working locally.
330
raise NotImplementedError(self.sprout)
369
operation = cleanup.OperationWithCleanups(self._sprout)
370
return operation.run(url, revision_id=revision_id,
371
force_new_repo=force_new_repo, recurse=recurse,
372
possible_transports=possible_transports,
373
accelerator_tree=accelerator_tree, hardlink=hardlink,
374
stacked=stacked, source_branch=source_branch,
375
create_tree_if_local=create_tree_if_local)
377
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
378
recurse='down', possible_transports=None,
379
accelerator_tree=None, hardlink=False, stacked=False,
380
source_branch=None, create_tree_if_local=True):
381
add_cleanup = op.add_cleanup
382
fetch_spec_factory = fetch.FetchSpecFactory()
383
if revision_id is not None:
384
fetch_spec_factory.add_revision_ids([revision_id])
385
fetch_spec_factory.source_branch_stop_revision_id = revision_id
386
target_transport = _mod_transport.get_transport(url,
388
target_transport.ensure_base()
389
cloning_format = self.cloning_metadir(stacked)
390
# Create/update the result branch
391
result = cloning_format.initialize_on_transport(target_transport)
392
source_branch, source_repository = self._find_source_repo(
393
add_cleanup, source_branch)
394
fetch_spec_factory.source_branch = source_branch
395
# if a stacked branch wasn't requested, we don't create one
396
# even if the origin was stacked
397
if stacked and source_branch is not None:
398
stacked_branch_url = self.root_transport.base
400
stacked_branch_url = None
401
repository_policy = result.determine_repository_policy(
402
force_new_repo, stacked_branch_url, require_stacking=stacked)
403
result_repo, is_new_repo = repository_policy.acquire_repository()
404
add_cleanup(result_repo.lock_write().unlock)
405
fetch_spec_factory.source_repo = source_repository
406
fetch_spec_factory.target_repo = result_repo
407
if stacked or (len(result_repo._fallback_repositories) != 0):
408
target_repo_kind = fetch.TargetRepoKinds.STACKED
410
target_repo_kind = fetch.TargetRepoKinds.EMPTY
412
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
413
fetch_spec_factory.target_repo_kind = target_repo_kind
414
if source_repository is not None:
415
fetch_spec = fetch_spec_factory.make_fetch_spec()
416
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
418
if source_branch is None:
419
# this is for sprouting a controldir without a branch; is that
421
# Not especially, but it's part of the contract.
422
result_branch = result.create_branch()
424
result_branch = source_branch.sprout(result,
425
revision_id=revision_id, repository_policy=repository_policy,
426
repository=result_repo)
427
mutter("created new branch %r" % (result_branch,))
429
# Create/update the result working tree
430
if (create_tree_if_local and
431
isinstance(target_transport, local.LocalTransport) and
432
(result_repo is None or result_repo.make_working_trees())):
433
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
434
hardlink=hardlink, from_branch=result_branch)
437
if wt.path2id('') is None:
439
wt.set_root_id(self.open_workingtree.get_root_id())
440
except errors.NoWorkingTree:
446
if recurse == 'down':
449
basis = wt.basis_tree()
450
elif result_branch is not None:
451
basis = result_branch.basis_tree()
452
elif source_branch is not None:
453
basis = source_branch.basis_tree()
454
if basis is not None:
455
add_cleanup(basis.lock_read().unlock)
456
subtrees = basis.iter_references()
459
for path, file_id in subtrees:
460
target = urlutils.join(url, urlutils.escape(path))
461
sublocation = source_branch.reference_parent(file_id, path)
462
sublocation.bzrdir.sprout(target,
463
basis.get_reference_revision(file_id, path),
464
force_new_repo=force_new_repo, recurse=recurse,
468
def _find_source_repo(self, add_cleanup, source_branch):
469
"""Find the source branch and repo for a sprout operation.
471
This is helper intended for use by _sprout.
473
:returns: (source_branch, source_repository). Either or both may be
474
None. If not None, they will be read-locked (and their unlock(s)
475
scheduled via the add_cleanup param).
477
if source_branch is not None:
478
add_cleanup(source_branch.lock_read().unlock)
479
return source_branch, source_branch.repository
481
source_branch = self.open_branch()
482
source_repository = source_branch.repository
483
except errors.NotBranchError:
486
source_repository = self.open_repository()
487
except errors.NoRepositoryPresent:
488
source_repository = None
490
add_cleanup(source_repository.lock_read().unlock)
492
add_cleanup(source_branch.lock_read().unlock)
493
return source_branch, source_repository
332
495
def push_branch(self, source, revision_id=None, overwrite=False,
333
496
remember=False, create_prefix=False):
458
617
:param create_prefix: Create any missing directories leading up to
460
619
:param use_existing_dir: Use an existing directory if one exists.
461
:param no_tree: If set to true prevents creation of a working tree.
463
621
raise NotImplementedError(self.clone_on_transport)
466
class ControlComponentFormat(object):
467
"""A component that can live inside of a .bzr meta directory."""
469
upgrade_recommended = False
471
def get_format_string(self):
472
"""Return the format of this format, if usable in meta directories."""
473
raise NotImplementedError(self.get_format_string)
475
def get_format_description(self):
476
"""Return the short description for this format."""
477
raise NotImplementedError(self.get_format_description)
479
def is_supported(self):
480
"""Is this format supported?
482
Supported formats must be initializable and openable.
483
Unsupported formats may not support initialization or committing or
484
some other features depending on the reason for not being supported.
488
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
490
"""Give an error or warning on old formats.
492
:param allow_unsupported: If true, allow opening
493
formats that are strongly deprecated, and which may
494
have limited functionality.
496
:param recommend_upgrade: If true (default), warn
497
the user through the ui object that they may wish
498
to upgrade the object.
500
if not allow_unsupported and not self.is_supported():
501
# see open_downlevel to open legacy branches.
502
raise errors.UnsupportedFormatError(format=self)
503
if recommend_upgrade and self.upgrade_recommended:
504
ui.ui_factory.recommend_upgrade(
505
self.get_format_description(), basedir)
508
class ControlComponentFormatRegistry(registry.FormatRegistry):
509
"""A registry for control components (branch, workingtree, repository)."""
511
def __init__(self, other_registry=None):
512
super(ControlComponentFormatRegistry, self).__init__(other_registry)
513
self._extra_formats = []
515
def register(self, format):
516
"""Register a new format."""
517
super(ControlComponentFormatRegistry, self).register(
518
format.get_format_string(), format)
520
def remove(self, format):
521
"""Remove a registered format."""
522
super(ControlComponentFormatRegistry, self).remove(
523
format.get_format_string())
525
def register_extra(self, format):
526
"""Register a format that can not be used in a metadir.
528
This is mainly useful to allow custom repository formats, such as older
529
Bazaar formats and foreign formats, to be tested.
531
self._extra_formats.append(registry._ObjectGetter(format))
533
def remove_extra(self, format):
534
"""Remove an extra format.
536
self._extra_formats.remove(registry._ObjectGetter(format))
538
def register_extra_lazy(self, module_name, member_name):
539
"""Register a format lazily.
541
self._extra_formats.append(
542
registry._LazyObjectGetter(module_name, member_name))
544
def _get_extra(self):
545
"""Return all "extra" formats, not usable in meta directories."""
547
for getter in self._extra_formats:
555
"""Return all formats, even those not usable in metadirs.
558
for name in self.keys():
563
return result + self._get_extra()
565
def _get_all_modules(self):
566
"""Return a set of the modules providing objects."""
568
for name in self.keys():
569
modules.add(self._get_module(name))
570
for getter in self._extra_formats:
571
modules.add(getter.get_module())
575
class Converter(object):
576
"""Converts a disk format object from one format to another."""
578
def convert(self, to_convert, pb):
579
"""Perform the conversion of to_convert, giving feedback via pb.
581
:param to_convert: The disk object to convert.
582
:param pb: a progress bar to use for progress information.
585
def step(self, message):
586
"""Update the pb by a step."""
588
self.pb.update(message, self.count, self.total)
591
624
class ControlDirFormat(object):
592
625
"""An encapsulation of the initialization and open routines for a format.