334
327
:param create_tree_if_local: If true, a working-tree will be created
335
328
when working locally.
337
operation = cleanup.OperationWithCleanups(self._sprout)
338
return operation.run(url, revision_id=revision_id,
339
force_new_repo=force_new_repo, recurse=recurse,
340
possible_transports=possible_transports,
341
accelerator_tree=accelerator_tree, hardlink=hardlink,
342
stacked=stacked, source_branch=source_branch,
343
create_tree_if_local=create_tree_if_local)
345
def _sprout(self, op, url, revision_id=None, force_new_repo=False,
346
recurse='down', possible_transports=None,
347
accelerator_tree=None, hardlink=False, stacked=False,
348
source_branch=None, create_tree_if_local=True):
349
add_cleanup = op.add_cleanup
350
fetch_spec_factory = fetch.FetchSpecFactory()
351
if revision_id is not None:
352
fetch_spec_factory.add_revision_ids([revision_id])
353
fetch_spec_factory.source_branch_stop_revision_id = revision_id
354
target_transport = _mod_transport.get_transport(url,
356
target_transport.ensure_base()
357
cloning_format = self.cloning_metadir(stacked)
358
# Create/update the result branch
359
result = cloning_format.initialize_on_transport(target_transport)
360
source_branch, source_repository = self._find_source_repo(
361
add_cleanup, source_branch)
362
fetch_spec_factory.source_branch = source_branch
363
# if a stacked branch wasn't requested, we don't create one
364
# even if the origin was stacked
365
if stacked and source_branch is not None:
366
stacked_branch_url = self.root_transport.base
368
stacked_branch_url = None
369
repository_policy = result.determine_repository_policy(
370
force_new_repo, stacked_branch_url, require_stacking=stacked)
371
result_repo, is_new_repo = repository_policy.acquire_repository()
372
add_cleanup(result_repo.lock_write().unlock)
373
fetch_spec_factory.source_repo = source_repository
374
fetch_spec_factory.target_repo = result_repo
375
if stacked or (len(result_repo._fallback_repositories) != 0):
376
target_repo_kind = fetch.TargetRepoKinds.STACKED
378
target_repo_kind = fetch.TargetRepoKinds.EMPTY
380
target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
381
fetch_spec_factory.target_repo_kind = target_repo_kind
382
if source_repository is not None:
383
fetch_spec = fetch_spec_factory.make_fetch_spec()
384
result_repo.fetch(source_repository, fetch_spec=fetch_spec)
386
if source_branch is None:
387
# this is for sprouting a controldir without a branch; is that
389
# Not especially, but it's part of the contract.
390
result_branch = result.create_branch()
392
result_branch = source_branch.sprout(result,
393
revision_id=revision_id, repository_policy=repository_policy,
394
repository=result_repo)
395
mutter("created new branch %r" % (result_branch,))
397
# Create/update the result working tree
398
if (create_tree_if_local and
399
isinstance(target_transport, local.LocalTransport) and
400
(result_repo is None or result_repo.make_working_trees())):
401
wt = result.create_workingtree(accelerator_tree=accelerator_tree,
402
hardlink=hardlink, from_branch=result_branch)
405
if wt.path2id('') is None:
407
wt.set_root_id(self.open_workingtree.get_root_id())
408
except errors.NoWorkingTree:
414
if recurse == 'down':
417
basis = wt.basis_tree()
418
elif result_branch is not None:
419
basis = result_branch.basis_tree()
420
elif source_branch is not None:
421
basis = source_branch.basis_tree()
422
if basis is not None:
423
add_cleanup(basis.lock_read().unlock)
424
subtrees = basis.iter_references()
427
for path, file_id in subtrees:
428
target = urlutils.join(url, urlutils.escape(path))
429
sublocation = source_branch.reference_parent(file_id, path)
430
sublocation.bzrdir.sprout(target,
431
basis.get_reference_revision(file_id, path),
432
force_new_repo=force_new_repo, recurse=recurse,
436
def _find_source_repo(self, add_cleanup, source_branch):
437
"""Find the source branch and repo for a sprout operation.
439
This is helper intended for use by _sprout.
441
:returns: (source_branch, source_repository). Either or both may be
442
None. If not None, they will be read-locked (and their unlock(s)
443
scheduled via the add_cleanup param).
445
if source_branch is not None:
446
add_cleanup(source_branch.lock_read().unlock)
447
return source_branch, source_branch.repository
449
source_branch = self.open_branch()
450
source_repository = source_branch.repository
451
except errors.NotBranchError:
454
source_repository = self.open_repository()
455
except errors.NoRepositoryPresent:
456
source_repository = None
458
add_cleanup(source_repository.lock_read().unlock)
460
add_cleanup(source_branch.lock_read().unlock)
461
return source_branch, source_repository
330
raise NotImplementedError(self.sprout)
463
332
def push_branch(self, source, revision_id=None, overwrite=False,
464
333
remember=False, create_prefix=False):
601
476
"""Return the short description for this format."""
602
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)
605
508
class ControlComponentFormatRegistry(registry.FormatRegistry):
606
509
"""A registry for control components (branch, workingtree, repository)."""