542
466
branch = tree.branch
543
467
return tree, branch
469
def get_config(self):
470
"""Get configuration for this ControlDir."""
471
raise NotImplementedError(self.get_config)
473
def check_conversion_target(self, target_format):
474
"""Check that a controldir as a whole can be converted to a new format."""
475
raise NotImplementedError(self.check_conversion_target)
477
def clone(self, url, revision_id=None, force_new_repo=False,
478
preserve_stacking=False):
479
"""Clone this controldir and its contents to url verbatim.
481
:param url: The url create the clone at. If url's last component does
482
not exist, it will be created.
483
:param revision_id: The tip revision-id to use for any branch or
484
working tree. If not None, then the clone operation may tune
485
itself to download less data.
486
:param force_new_repo: Do not use a shared repository for the target
487
even if one is available.
488
:param preserve_stacking: When cloning a stacked branch, stack the
489
new branch on top of the other branch's stacked-on branch.
491
return self.clone_on_transport(_mod_transport.get_transport(url),
492
revision_id=revision_id,
493
force_new_repo=force_new_repo,
494
preserve_stacking=preserve_stacking)
496
def clone_on_transport(self, transport, revision_id=None,
497
force_new_repo=False, preserve_stacking=False, stacked_on=None,
498
create_prefix=False, use_existing_dir=True, no_tree=False):
499
"""Clone this controldir and its contents to transport verbatim.
501
:param transport: The transport for the location to produce the clone
502
at. If the target directory does not exist, it will be created.
503
:param revision_id: The tip revision-id to use for any branch or
504
working tree. If not None, then the clone operation may tune
505
itself to download less data.
506
:param force_new_repo: Do not use a shared repository for the target,
507
even if one is available.
508
:param preserve_stacking: When cloning a stacked branch, stack the
509
new branch on top of the other branch's stacked-on branch.
510
:param create_prefix: Create any missing directories leading up to
512
:param use_existing_dir: Use an existing directory if one exists.
513
:param no_tree: If set to true prevents creation of a working tree.
515
raise NotImplementedError(self.clone_on_transport)
518
def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
519
"""Find control dirs recursively from current location.
521
This is intended primarily as a building block for more sophisticated
522
functionality, like finding trees under a directory, or finding
523
branches that use a given repository.
525
:param evaluate: An optional callable that yields recurse, value,
526
where recurse controls whether this controldir is recursed into
527
and value is the value to yield. By default, all bzrdirs
528
are recursed into, and the return value is the controldir.
529
:param list_current: if supplied, use this function to list the current
530
directory, instead of Transport.list_dir
531
:return: a generator of found bzrdirs, or whatever evaluate returns.
533
if list_current is None:
534
def list_current(transport):
535
return transport.list_dir('')
537
def evaluate(controldir):
538
return True, controldir
540
pending = [transport]
541
while len(pending) > 0:
542
current_transport = pending.pop()
545
controldir = klass.open_from_transport(current_transport)
546
except (errors.NotBranchError, errors.PermissionDenied):
549
recurse, value = evaluate(controldir)
552
subdirs = list_current(current_transport)
553
except (errors.NoSuchFile, errors.PermissionDenied):
556
for subdir in sorted(subdirs, reverse=True):
557
pending.append(current_transport.clone(subdir))
560
def find_branches(klass, transport):
561
"""Find all branches under a transport.
563
This will find all branches below the transport, including branches
564
inside other branches. Where possible, it will use
565
Repository.find_branches.
567
To list all the branches that use a particular Repository, see
568
Repository.find_branches
570
def evaluate(controldir):
572
repository = controldir.open_repository()
573
except errors.NoRepositoryPresent:
576
return False, ([], repository)
577
return True, (controldir.list_branches(), None)
579
for branches, repo in klass.find_bzrdirs(
580
transport, evaluate=evaluate):
582
ret.extend(repo.find_branches())
583
if branches is not None:
588
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
589
"""Create a new ControlDir, Branch and Repository at the url 'base'.
591
This will use the current default ControlDirFormat unless one is
592
specified, and use whatever
593
repository format that that uses via controldir.create_branch and
594
create_repository. If a shared repository is available that is used
597
The created Branch object is returned.
599
:param base: The URL to create the branch at.
600
:param force_new_repo: If True a new repository is always created.
601
:param format: If supplied, the format of branch to create. If not
602
supplied, the default is used.
604
controldir = klass.create(base, format)
605
controldir._find_or_create_repository(force_new_repo)
606
return controldir.create_branch()
609
def create_branch_convenience(klass, base, force_new_repo=False,
610
force_new_tree=None, format=None,
611
possible_transports=None):
612
"""Create a new ControlDir, Branch and Repository at the url 'base'.
614
This is a convenience function - it will use an existing repository
615
if possible, can be told explicitly whether to create a working tree or
618
This will use the current default ControlDirFormat unless one is
619
specified, and use whatever
620
repository format that that uses via ControlDir.create_branch and
621
create_repository. If a shared repository is available that is used
622
preferentially. Whatever repository is used, its tree creation policy
625
The created Branch object is returned.
626
If a working tree cannot be made due to base not being a file:// url,
627
no error is raised unless force_new_tree is True, in which case no
628
data is created on disk and NotLocalUrl is raised.
630
:param base: The URL to create the branch at.
631
:param force_new_repo: If True a new repository is always created.
632
:param force_new_tree: If True or False force creation of a tree or
633
prevent such creation respectively.
634
:param format: Override for the controldir format to create.
635
:param possible_transports: An optional reusable transports list.
638
# check for non local urls
639
t = _mod_transport.get_transport(base, possible_transports)
640
if not isinstance(t, local.LocalTransport):
641
raise errors.NotLocalUrl(base)
642
controldir = klass.create(base, format, possible_transports)
643
repo = controldir._find_or_create_repository(force_new_repo)
644
result = controldir.create_branch()
645
if force_new_tree or (repo.make_working_trees() and
646
force_new_tree is None):
648
controldir.create_workingtree()
649
except errors.NotLocalUrl:
654
def create_standalone_workingtree(klass, base, format=None):
655
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
657
'base' must be a local path or a file:// url.
659
This will use the current default ControlDirFormat unless one is
660
specified, and use whatever
661
repository format that that uses for bzrdirformat.create_workingtree,
662
create_branch and create_repository.
664
:param format: Override for the controldir format to create.
665
:return: The WorkingTree object.
667
t = _mod_transport.get_transport(base)
668
if not isinstance(t, local.LocalTransport):
669
raise errors.NotLocalUrl(base)
670
controldir = klass.create_branch_and_repo(base,
672
format=format).bzrdir
673
return controldir.create_workingtree()
676
def open_unsupported(klass, base):
677
"""Open a branch which is not supported."""
678
return klass.open(base, _unsupported=True)
681
def open(klass, base, possible_transports=None, probers=None,
683
"""Open an existing controldir, rooted at 'base' (url).
685
:param _unsupported: a private parameter to the ControlDir class.
687
t = _mod_transport.get_transport(base, possible_transports)
688
return klass.open_from_transport(t, probers=probers,
689
_unsupported=_unsupported)
692
def open_from_transport(klass, transport, _unsupported=False,
694
"""Open a controldir within a particular directory.
696
:param transport: Transport containing the controldir.
697
:param _unsupported: private.
699
for hook in klass.hooks['pre_open']:
701
# Keep initial base since 'transport' may be modified while following
703
base = transport.base
704
def find_format(transport):
705
return transport, ControlDirFormat.find_format(transport,
708
def redirected(transport, e, redirection_notice):
709
redirected_transport = transport._redirected_to(e.source, e.target)
710
if redirected_transport is None:
711
raise errors.NotBranchError(base)
712
trace.note(gettext('{0} is{1} redirected to {2}').format(
713
transport.base, e.permanently, redirected_transport.base))
714
return redirected_transport
717
transport, format = _mod_transport.do_catching_redirections(
718
find_format, transport, redirected)
719
except errors.TooManyRedirections:
720
raise errors.NotBranchError(base)
722
format.check_support_status(_unsupported)
723
return format.open(transport, _found=True)
726
def open_containing(klass, url, possible_transports=None):
727
"""Open an existing branch which contains url.
729
:param url: url to search from.
731
See open_containing_from_transport for more detail.
733
transport = _mod_transport.get_transport(url, possible_transports)
734
return klass.open_containing_from_transport(transport)
737
def open_containing_from_transport(klass, a_transport):
738
"""Open an existing branch which contains a_transport.base.
740
This probes for a branch at a_transport, and searches upwards from there.
742
Basically we keep looking up until we find the control directory or
743
run into the root. If there isn't one, raises NotBranchError.
744
If there is one and it is either an unrecognised format or an unsupported
745
format, UnknownFormatError or UnsupportedFormatError are raised.
746
If there is one, it is returned, along with the unused portion of url.
748
:return: The ControlDir that contains the path, and a Unicode path
749
for the rest of the URL.
751
# this gets the normalised url back. I.e. '.' -> the full path.
752
url = a_transport.base
755
result = klass.open_from_transport(a_transport)
756
return result, urlutils.unescape(a_transport.relpath(url))
757
except errors.NotBranchError, e:
759
except errors.PermissionDenied:
762
new_t = a_transport.clone('..')
763
except errors.InvalidURLJoin:
764
# reached the root, whatever that may be
765
raise errors.NotBranchError(path=url)
766
if new_t.base == a_transport.base:
767
# reached the root, whatever that may be
768
raise errors.NotBranchError(path=url)
772
def open_tree_or_branch(klass, location):
773
"""Return the branch and working tree at a location.
775
If there is no tree at the location, tree will be None.
776
If there is no branch at the location, an exception will be
778
:return: (tree, branch)
780
controldir = klass.open(location)
781
return controldir._get_tree_branch()
784
def open_containing_tree_or_branch(klass, location,
785
possible_transports=None):
786
"""Return the branch and working tree contained by a location.
788
Returns (tree, branch, relpath).
789
If there is no tree at containing the location, tree will be None.
790
If there is no branch containing the location, an exception will be
792
relpath is the portion of the path that is contained by the branch.
794
controldir, relpath = klass.open_containing(location,
795
possible_transports=possible_transports)
796
tree, branch = controldir._get_tree_branch()
797
return tree, branch, relpath
800
def open_containing_tree_branch_or_repository(klass, location):
801
"""Return the working tree, branch and repo contained by a location.
803
Returns (tree, branch, repository, relpath).
804
If there is no tree containing the location, tree will be None.
805
If there is no branch containing the location, branch will be None.
806
If there is no repository containing the location, repository will be
808
relpath is the portion of the path that is contained by the innermost
811
If no tree, branch or repository is found, a NotBranchError is raised.
813
controldir, relpath = klass.open_containing(location)
815
tree, branch = controldir._get_tree_branch()
816
except errors.NotBranchError:
818
repo = controldir.find_repository()
819
return None, None, repo, relpath
820
except (errors.NoRepositoryPresent):
821
raise errors.NotBranchError(location)
822
return tree, branch, branch.repository, relpath
825
def create(klass, base, format=None, possible_transports=None):
826
"""Create a new ControlDir at the url 'base'.
828
:param format: If supplied, the format of branch to create. If not
829
supplied, the default is used.
830
:param possible_transports: If supplied, a list of transports that
831
can be reused to share a remote connection.
833
if klass is not ControlDir:
834
raise AssertionError("ControlDir.create always creates the"
835
"default format, not one of %r" % klass)
836
t = _mod_transport.get_transport(base, possible_transports)
839
format = ControlDirFormat.get_default_format()
840
return format.initialize_on_transport(t)
843
class ControlDirHooks(hooks.Hooks):
844
"""Hooks for ControlDir operations."""
847
"""Create the default hooks."""
848
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
849
self.add_hook('pre_open',
850
"Invoked before attempting to open a ControlDir with the transport "
851
"that the open will use.", (1, 14))
852
self.add_hook('post_repo_init',
853
"Invoked after a repository has been initialized. "
854
"post_repo_init is called with a "
855
"bzrlib.controldir.RepoInitHookParams.",
858
# install the default hooks
859
ControlDir.hooks = ControlDirHooks()
862
class ControlComponentFormat(object):
863
"""A component that can live inside of a control directory."""
865
upgrade_recommended = False
867
def get_format_description(self):
868
"""Return the short description for this format."""
869
raise NotImplementedError(self.get_format_description)
871
def is_supported(self):
872
"""Is this format supported?
874
Supported formats must be initializable and openable.
875
Unsupported formats may not support initialization or committing or
876
some other features depending on the reason for not being supported.
880
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
882
"""Give an error or warning on old formats.
884
:param allow_unsupported: If true, allow opening
885
formats that are strongly deprecated, and which may
886
have limited functionality.
888
:param recommend_upgrade: If true (default), warn
889
the user through the ui object that they may wish
890
to upgrade the object.
892
if not allow_unsupported and not self.is_supported():
893
# see open_downlevel to open legacy branches.
894
raise errors.UnsupportedFormatError(format=self)
895
if recommend_upgrade and self.upgrade_recommended:
896
ui.ui_factory.recommend_upgrade(
897
self.get_format_description(), basedir)
900
def get_format_string(cls):
901
raise NotImplementedError(cls.get_format_string)
904
class ControlComponentFormatRegistry(registry.FormatRegistry):
905
"""A registry for control components (branch, workingtree, repository)."""
907
def __init__(self, other_registry=None):
908
super(ControlComponentFormatRegistry, self).__init__(other_registry)
909
self._extra_formats = []
911
def register(self, format):
912
"""Register a new format."""
913
super(ControlComponentFormatRegistry, self).register(
914
format.get_format_string(), format)
916
def remove(self, format):
917
"""Remove a registered format."""
918
super(ControlComponentFormatRegistry, self).remove(
919
format.get_format_string())
921
def register_extra(self, format):
922
"""Register a format that can not be used in a metadir.
924
This is mainly useful to allow custom repository formats, such as older
925
Bazaar formats and foreign formats, to be tested.
927
self._extra_formats.append(registry._ObjectGetter(format))
929
def remove_extra(self, format):
930
"""Remove an extra format.
932
self._extra_formats.remove(registry._ObjectGetter(format))
934
def register_extra_lazy(self, module_name, member_name):
935
"""Register a format lazily.
937
self._extra_formats.append(
938
registry._LazyObjectGetter(module_name, member_name))
940
def _get_extra(self):
941
"""Return all "extra" formats, not usable in meta directories."""
943
for getter in self._extra_formats:
951
"""Return all formats, even those not usable in metadirs.
954
for name in self.keys():
959
return result + self._get_extra()
961
def _get_all_modules(self):
962
"""Return a set of the modules providing objects."""
964
for name in self.keys():
965
modules.add(self._get_module(name))
966
for getter in self._extra_formats:
967
modules.add(getter.get_module())
971
class Converter(object):
972
"""Converts a disk format object from one format to another."""
974
def convert(self, to_convert, pb):
975
"""Perform the conversion of to_convert, giving feedback via pb.
977
:param to_convert: The disk object to convert.
978
:param pb: a progress bar to use for progress information.
981
def step(self, message):
982
"""Update the pb by a step."""
984
self.pb.update(message, self.count, self.total)
548
987
class ControlDirFormat(object):