380
375
when working locally.
381
376
:return: The created control directory
383
with cleanup.ExitStack() as stack:
384
fetch_spec_factory = fetch.FetchSpecFactory()
385
if revision_id is not None:
386
fetch_spec_factory.add_revision_ids([revision_id])
387
fetch_spec_factory.source_branch_stop_revision_id = revision_id
388
if possible_transports is None:
389
possible_transports = []
391
possible_transports = list(possible_transports) + [
393
target_transport = _mod_transport.get_transport(url,
395
target_transport.ensure_base()
396
cloning_format = self.cloning_metadir(stacked)
397
# Create/update the result branch
378
operation = cleanup.OperationWithCleanups(self._sprout)
379
return operation.run(url, revision_id=revision_id,
380
force_new_repo=force_new_repo, recurse=recurse,
381
possible_transports=possible_transports,
382
accelerator_tree=accelerator_tree, hardlink=hardlink,
383
stacked=stacked, source_branch=source_branch,
384
create_tree_if_local=create_tree_if_local)
386
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
387
recurse='down', possible_transports=None,
388
accelerator_tree=None, hardlink=False, stacked=False,
389
source_branch=None, create_tree_if_local=True, lossy=False):
390
add_cleanup = op.add_cleanup
391
fetch_spec_factory = fetch.FetchSpecFactory()
392
if revision_id is not None:
393
fetch_spec_factory.add_revision_ids([revision_id])
394
fetch_spec_factory.source_branch_stop_revision_id = revision_id
395
if possible_transports is None:
396
possible_transports = []
398
possible_transports = list(possible_transports) + [
400
target_transport = _mod_transport.get_transport(url,
402
target_transport.ensure_base()
403
cloning_format = self.cloning_metadir(stacked)
404
# Create/update the result branch
406
result = controldir.ControlDir.open_from_transport(target_transport)
407
except errors.NotBranchError:
408
result = cloning_format.initialize_on_transport(target_transport)
409
source_branch, source_repository = self._find_source_repo(
410
add_cleanup, source_branch)
411
fetch_spec_factory.source_branch = source_branch
412
# if a stacked branch wasn't requested, we don't create one
413
# even if the origin was stacked
414
if stacked and source_branch is not None:
415
stacked_branch_url = self.root_transport.base
417
stacked_branch_url = None
418
repository_policy = result.determine_repository_policy(
419
force_new_repo, stacked_branch_url, require_stacking=stacked)
420
result_repo, is_new_repo = repository_policy.acquire_repository(
421
possible_transports=possible_transports)
422
add_cleanup(result_repo.lock_write().unlock)
423
fetch_spec_factory.source_repo = source_repository
424
fetch_spec_factory.target_repo = result_repo
425
if stacked or (len(result_repo._fallback_repositories) != 0):
426
target_repo_kind = fetch.TargetRepoKinds.STACKED
428
target_repo_kind = fetch.TargetRepoKinds.EMPTY
430
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
431
fetch_spec_factory.target_repo_kind = target_repo_kind
432
if source_repository is not None:
433
fetch_spec = fetch_spec_factory.make_fetch_spec()
434
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
436
if source_branch is None:
437
# this is for sprouting a controldir without a branch; is that
439
# Not especially, but it's part of the contract.
440
result_branch = result.create_branch()
442
result_branch = source_branch.sprout(result,
443
revision_id=revision_id, repository_policy=repository_policy,
444
repository=result_repo)
445
mutter("created new branch %r" % (result_branch,))
447
# Create/update the result working tree
448
if (create_tree_if_local and not result.has_workingtree() and
449
isinstance(target_transport, local.LocalTransport) and
450
(result_repo is None or result_repo.make_working_trees())):
451
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
452
hardlink=hardlink, from_branch=result_branch)
399
result = controldir.ControlDir.open_from_transport(
401
except errors.NotBranchError:
402
result = cloning_format.initialize_on_transport(target_transport)
403
source_branch, source_repository = self._find_source_repo(
404
stack, source_branch)
405
fetch_spec_factory.source_branch = source_branch
406
# if a stacked branch wasn't requested, we don't create one
407
# even if the origin was stacked
408
if stacked and source_branch is not None:
409
stacked_branch_url = self.root_transport.base
411
stacked_branch_url = None
412
repository_policy = result.determine_repository_policy(
413
force_new_repo, stacked_branch_url, require_stacking=stacked)
414
result_repo, is_new_repo = repository_policy.acquire_repository(
415
possible_transports=possible_transports)
416
stack.enter_context(result_repo.lock_write())
417
fetch_spec_factory.source_repo = source_repository
418
fetch_spec_factory.target_repo = result_repo
419
if stacked or (len(result_repo._fallback_repositories) != 0):
420
target_repo_kind = fetch.TargetRepoKinds.STACKED
422
target_repo_kind = fetch.TargetRepoKinds.EMPTY
424
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
425
fetch_spec_factory.target_repo_kind = target_repo_kind
426
if source_repository is not None:
427
fetch_spec = fetch_spec_factory.make_fetch_spec()
428
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
430
if source_branch is None:
431
# this is for sprouting a controldir without a branch; is that
433
# Not especially, but it's part of the contract.
434
result_branch = result.create_branch()
436
result_branch = source_branch.sprout(
437
result, revision_id=revision_id,
438
repository_policy=repository_policy, repository=result_repo)
439
mutter("created new branch %r" % (result_branch,))
441
# Create/update the result working tree
442
if (create_tree_if_local and not result.has_workingtree()
443
and isinstance(target_transport, local.LocalTransport)
444
and (result_repo is None or result_repo.make_working_trees())
445
and result.open_branch(
447
possible_transports=possible_transports).name == result_branch.name):
448
wt = result.create_workingtree(
449
accelerator_tree=accelerator_tree, hardlink=hardlink,
450
from_branch=result_branch)
451
with wt.lock_write():
452
if not wt.is_versioned(''):
454
wt.set_root_id(self.open_workingtree.path2id(''))
455
except errors.NoWorkingTree:
459
if recurse == 'down':
463
basis = tree.basis_tree()
464
stack.enter_context(basis.lock_read())
465
elif result_branch is not None:
466
basis = tree = result_branch.basis_tree()
467
elif source_branch is not None:
468
basis = tree = source_branch.basis_tree()
470
stack.enter_context(tree.lock_read())
471
subtrees = tree.iter_references()
474
for path in subtrees:
475
target = urlutils.join(url, urlutils.escape(path))
476
sublocation = tree.reference_parent(
477
path, branch=result_branch,
478
possible_transports=possible_transports)
479
if sublocation is None:
481
'Ignoring nested tree %s, parent location unknown.',
484
sublocation.controldir.sprout(
485
target, basis.get_reference_revision(path),
486
force_new_repo=force_new_repo, recurse=recurse,
455
if not wt.is_versioned(''):
457
wt.set_root_id(self.open_workingtree.get_root_id())
458
except errors.NoWorkingTree:
464
if recurse == 'down':
467
basis = wt.basis_tree()
468
elif result_branch is not None:
469
basis = result_branch.basis_tree()
470
elif source_branch is not None:
471
basis = source_branch.basis_tree()
472
if basis is not None:
473
add_cleanup(basis.lock_read().unlock)
474
subtrees = basis.iter_references()
477
for path, file_id in subtrees:
478
target = urlutils.join(url, urlutils.escape(path))
479
sublocation = source_branch.reference_parent(path, file_id)
480
sublocation.controldir.sprout(target,
481
basis.get_reference_revision(path, file_id),
482
force_new_repo=force_new_repo, recurse=recurse,
490
486
def _available_backup_name(self, base):
491
487
"""Find a non-existing backup file name based on base.
1757
1728
def convert(self, to_convert, pb):
1758
1729
"""See Converter.convert()."""
1759
1730
self.controldir = to_convert
1760
with ui.ui_factory.nested_progress_bar() as self.pb:
1763
self.step('checking repository format')
1765
repo = self.controldir.open_repository()
1766
except errors.NoRepositoryPresent:
1769
repo_fmt = self.target_format.repository_format
1770
if not isinstance(repo._format, repo_fmt.__class__):
1771
from ..repository import CopyConverter
1772
ui.ui_factory.note(gettext('starting repository conversion'))
1773
if not repo_fmt.supports_overriding_transport:
1774
raise AssertionError(
1731
self.pb = ui.ui_factory.nested_progress_bar()
1734
self.step('checking repository format')
1736
repo = self.controldir.open_repository()
1737
except errors.NoRepositoryPresent:
1740
repo_fmt = self.target_format.repository_format
1741
if not isinstance(repo._format, repo_fmt.__class__):
1742
from ..repository import CopyConverter
1743
ui.ui_factory.note(gettext('starting repository conversion'))
1744
if not repo_fmt.supports_overriding_transport:
1745
raise AssertionError(
1775
1746
"Repository in metadir does not support "
1776
1747
"overriding transport")
1777
converter = CopyConverter(self.target_format.repository_format)
1778
converter.convert(repo, pb)
1779
for branch in self.controldir.list_branches():
1780
# TODO: conversions of Branch and Tree should be done by
1781
# InterXFormat lookups/some sort of registry.
1782
# Avoid circular imports
1748
converter = CopyConverter(self.target_format.repository_format)
1749
converter.convert(repo, pb)
1750
for branch in self.controldir.list_branches():
1751
# TODO: conversions of Branch and Tree should be done by
1752
# InterXFormat lookups/some sort of registry.
1753
# Avoid circular imports
1754
old = branch._format.__class__
1755
new = self.target_format.get_branch_format().__class__
1757
if (old == fullhistorybranch.BzrBranchFormat5 and
1758
new in (_mod_bzrbranch.BzrBranchFormat6,
1759
_mod_bzrbranch.BzrBranchFormat7,
1760
_mod_bzrbranch.BzrBranchFormat8)):
1761
branch_converter = _mod_bzrbranch.Converter5to6()
1762
elif (old == _mod_bzrbranch.BzrBranchFormat6 and
1763
new in (_mod_bzrbranch.BzrBranchFormat7,
1764
_mod_bzrbranch.BzrBranchFormat8)):
1765
branch_converter = _mod_bzrbranch.Converter6to7()
1766
elif (old == _mod_bzrbranch.BzrBranchFormat7 and
1767
new is _mod_bzrbranch.BzrBranchFormat8):
1768
branch_converter = _mod_bzrbranch.Converter7to8()
1770
raise errors.BadConversionTarget("No converter", new,
1772
branch_converter.convert(branch)
1773
branch = self.controldir.open_branch()
1783
1774
old = branch._format.__class__
1784
new = self.target_format.get_branch_format().__class__
1786
if (old == fullhistorybranch.BzrBranchFormat5
1787
and new in (_mod_bzrbranch.BzrBranchFormat6,
1788
_mod_bzrbranch.BzrBranchFormat7,
1789
_mod_bzrbranch.BzrBranchFormat8)):
1790
branch_converter = _mod_bzrbranch.Converter5to6()
1791
elif (old == _mod_bzrbranch.BzrBranchFormat6
1792
and new in (_mod_bzrbranch.BzrBranchFormat7,
1793
_mod_bzrbranch.BzrBranchFormat8)):
1794
branch_converter = _mod_bzrbranch.Converter6to7()
1795
elif (old == _mod_bzrbranch.BzrBranchFormat7
1796
and new is _mod_bzrbranch.BzrBranchFormat8):
1797
branch_converter = _mod_bzrbranch.Converter7to8()
1799
raise errors.BadConversionTarget("No converter", new,
1801
branch_converter.convert(branch)
1802
branch = self.controldir.open_branch()
1803
old = branch._format.__class__
1805
tree = self.controldir.open_workingtree(recommend_upgrade=False)
1806
except (errors.NoWorkingTree, errors.NotLocalUrl):
1809
# TODO: conversions of Branch and Tree should be done by
1810
# InterXFormat lookups
1811
if (isinstance(tree, workingtree_3.WorkingTree3)
1812
and not isinstance(tree, workingtree_4.DirStateWorkingTree)
1813
and isinstance(self.target_format.workingtree_format,
1814
workingtree_4.DirStateWorkingTreeFormat)):
1815
workingtree_4.Converter3to4().convert(tree)
1816
if (isinstance(tree, workingtree_4.DirStateWorkingTree)
1817
and not isinstance(tree, workingtree_4.WorkingTree5)
1818
and isinstance(self.target_format.workingtree_format,
1819
workingtree_4.WorkingTreeFormat5)):
1820
workingtree_4.Converter4to5().convert(tree)
1821
if (isinstance(tree, workingtree_4.DirStateWorkingTree)
1822
and not isinstance(tree, workingtree_4.WorkingTree6)
1823
and isinstance(self.target_format.workingtree_format,
1824
workingtree_4.WorkingTreeFormat6)):
1825
workingtree_4.Converter4or5to6().convert(tree)
1776
tree = self.controldir.open_workingtree(recommend_upgrade=False)
1777
except (errors.NoWorkingTree, errors.NotLocalUrl):
1780
# TODO: conversions of Branch and Tree should be done by
1781
# InterXFormat lookups
1782
if (isinstance(tree, workingtree_3.WorkingTree3) and
1783
not isinstance(tree, workingtree_4.DirStateWorkingTree) and
1784
isinstance(self.target_format.workingtree_format,
1785
workingtree_4.DirStateWorkingTreeFormat)):
1786
workingtree_4.Converter3to4().convert(tree)
1787
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1788
not isinstance(tree, workingtree_4.WorkingTree5) and
1789
isinstance(self.target_format.workingtree_format,
1790
workingtree_4.WorkingTreeFormat5)):
1791
workingtree_4.Converter4to5().convert(tree)
1792
if (isinstance(tree, workingtree_4.DirStateWorkingTree) and
1793
not isinstance(tree, workingtree_4.WorkingTree6) and
1794
isinstance(self.target_format.workingtree_format,
1795
workingtree_4.WorkingTreeFormat6)):
1796
workingtree_4.Converter4or5to6().convert(tree)
1826
1798
return to_convert