513
464
raise NotImplementedError(self.clone_on_transport)
516
def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
517
"""Find control dirs recursively from current location.
519
This is intended primarily as a building block for more sophisticated
520
functionality, like finding trees under a directory, or finding
521
branches that use a given repository.
523
:param evaluate: An optional callable that yields recurse, value,
524
where recurse controls whether this controldir is recursed into
525
and value is the value to yield. By default, all bzrdirs
526
are recursed into, and the return value is the controldir.
527
:param list_current: if supplied, use this function to list the current
528
directory, instead of Transport.list_dir
529
:return: a generator of found bzrdirs, or whatever evaluate returns.
531
if list_current is None:
532
def list_current(transport):
533
return transport.list_dir('')
535
def evaluate(controldir):
536
return True, controldir
538
pending = [transport]
539
while len(pending) > 0:
540
current_transport = pending.pop()
543
controldir = klass.open_from_transport(current_transport)
544
except (errors.NotBranchError, errors.PermissionDenied):
547
recurse, value = evaluate(controldir)
550
subdirs = list_current(current_transport)
551
except (errors.NoSuchFile, errors.PermissionDenied):
554
for subdir in sorted(subdirs, reverse=True):
555
pending.append(current_transport.clone(subdir))
558
def find_branches(klass, transport):
559
"""Find all branches under a transport.
561
This will find all branches below the transport, including branches
562
inside other branches. Where possible, it will use
563
Repository.find_branches.
565
To list all the branches that use a particular Repository, see
566
Repository.find_branches
568
def evaluate(controldir):
570
repository = controldir.open_repository()
571
except errors.NoRepositoryPresent:
574
return False, ([], repository)
575
return True, (controldir.list_branches(), None)
577
for branches, repo in klass.find_bzrdirs(
578
transport, evaluate=evaluate):
580
ret.extend(repo.find_branches())
581
if branches is not None:
586
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
587
"""Create a new ControlDir, Branch and Repository at the url 'base'.
589
This will use the current default ControlDirFormat unless one is
590
specified, and use whatever
591
repository format that that uses via controldir.create_branch and
592
create_repository. If a shared repository is available that is used
595
The created Branch object is returned.
597
:param base: The URL to create the branch at.
598
:param force_new_repo: If True a new repository is always created.
599
:param format: If supplied, the format of branch to create. If not
600
supplied, the default is used.
602
controldir = klass.create(base, format)
603
controldir._find_or_create_repository(force_new_repo)
604
return controldir.create_branch()
607
def create_branch_convenience(klass, base, force_new_repo=False,
608
force_new_tree=None, format=None,
609
possible_transports=None):
610
"""Create a new ControlDir, Branch and Repository at the url 'base'.
612
This is a convenience function - it will use an existing repository
613
if possible, can be told explicitly whether to create a working tree or
616
This will use the current default ControlDirFormat unless one is
617
specified, and use whatever
618
repository format that that uses via ControlDir.create_branch and
619
create_repository. If a shared repository is available that is used
620
preferentially. Whatever repository is used, its tree creation policy
623
The created Branch object is returned.
624
If a working tree cannot be made due to base not being a file:// url,
625
no error is raised unless force_new_tree is True, in which case no
626
data is created on disk and NotLocalUrl is raised.
628
:param base: The URL to create the branch at.
629
:param force_new_repo: If True a new repository is always created.
630
:param force_new_tree: If True or False force creation of a tree or
631
prevent such creation respectively.
632
:param format: Override for the controldir format to create.
633
:param possible_transports: An optional reusable transports list.
636
# check for non local urls
637
t = _mod_transport.get_transport(base, possible_transports)
638
if not isinstance(t, local.LocalTransport):
639
raise errors.NotLocalUrl(base)
640
controldir = klass.create(base, format, possible_transports)
641
repo = controldir._find_or_create_repository(force_new_repo)
642
result = controldir.create_branch()
643
if force_new_tree or (repo.make_working_trees() and
644
force_new_tree is None):
646
controldir.create_workingtree()
647
except errors.NotLocalUrl:
652
def create_standalone_workingtree(klass, base, format=None):
653
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
655
'base' must be a local path or a file:// url.
657
This will use the current default ControlDirFormat unless one is
658
specified, and use whatever
659
repository format that that uses for bzrdirformat.create_workingtree,
660
create_branch and create_repository.
662
:param format: Override for the controldir format to create.
663
:return: The WorkingTree object.
665
t = _mod_transport.get_transport(base)
666
if not isinstance(t, local.LocalTransport):
667
raise errors.NotLocalUrl(base)
668
controldir = klass.create_branch_and_repo(base,
670
format=format).bzrdir
671
return controldir.create_workingtree()
674
def open_unsupported(klass, base):
675
"""Open a branch which is not supported."""
676
return klass.open(base, _unsupported=True)
679
def open(klass, base, possible_transports=None, probers=None,
681
"""Open an existing controldir, rooted at 'base' (url).
683
:param _unsupported: a private parameter to the ControlDir class.
685
t = _mod_transport.get_transport(base, possible_transports)
686
return klass.open_from_transport(t, probers=probers,
687
_unsupported=_unsupported)
690
def open_from_transport(klass, transport, _unsupported=False,
692
"""Open a controldir within a particular directory.
694
:param transport: Transport containing the controldir.
695
:param _unsupported: private.
697
for hook in klass.hooks['pre_open']:
699
# Keep initial base since 'transport' may be modified while following
701
base = transport.base
702
def find_format(transport):
703
return transport, ControlDirFormat.find_format(transport,
706
def redirected(transport, e, redirection_notice):
707
redirected_transport = transport._redirected_to(e.source, e.target)
708
if redirected_transport is None:
709
raise errors.NotBranchError(base)
710
trace.note(gettext('{0} is{1} redirected to {2}').format(
711
transport.base, e.permanently, redirected_transport.base))
712
return redirected_transport
715
transport, format = _mod_transport.do_catching_redirections(
716
find_format, transport, redirected)
717
except errors.TooManyRedirections:
718
raise errors.NotBranchError(base)
720
format.check_support_status(_unsupported)
721
return format.open(transport, _found=True)
724
def open_containing(klass, url, possible_transports=None):
725
"""Open an existing branch which contains url.
727
:param url: url to search from.
729
See open_containing_from_transport for more detail.
731
transport = _mod_transport.get_transport(url, possible_transports)
732
return klass.open_containing_from_transport(transport)
735
def open_containing_from_transport(klass, a_transport):
736
"""Open an existing branch which contains a_transport.base.
738
This probes for a branch at a_transport, and searches upwards from there.
740
Basically we keep looking up until we find the control directory or
741
run into the root. If there isn't one, raises NotBranchError.
742
If there is one and it is either an unrecognised format or an unsupported
743
format, UnknownFormatError or UnsupportedFormatError are raised.
744
If there is one, it is returned, along with the unused portion of url.
746
:return: The ControlDir that contains the path, and a Unicode path
747
for the rest of the URL.
749
# this gets the normalised url back. I.e. '.' -> the full path.
750
url = a_transport.base
753
result = klass.open_from_transport(a_transport)
754
return result, urlutils.unescape(a_transport.relpath(url))
755
except errors.NotBranchError, e:
757
except errors.PermissionDenied:
760
new_t = a_transport.clone('..')
761
except errors.InvalidURLJoin:
762
# reached the root, whatever that may be
763
raise errors.NotBranchError(path=url)
764
if new_t.base == a_transport.base:
765
# reached the root, whatever that may be
766
raise errors.NotBranchError(path=url)
770
def open_tree_or_branch(klass, location):
771
"""Return the branch and working tree at a location.
773
If there is no tree at the location, tree will be None.
774
If there is no branch at the location, an exception will be
776
:return: (tree, branch)
778
controldir = klass.open(location)
779
return controldir._get_tree_branch()
782
def open_containing_tree_or_branch(klass, location,
783
possible_transports=None):
784
"""Return the branch and working tree contained by a location.
786
Returns (tree, branch, relpath).
787
If there is no tree at containing the location, tree will be None.
788
If there is no branch containing the location, an exception will be
790
relpath is the portion of the path that is contained by the branch.
792
controldir, relpath = klass.open_containing(location,
793
possible_transports=possible_transports)
794
tree, branch = controldir._get_tree_branch()
795
return tree, branch, relpath
798
def open_containing_tree_branch_or_repository(klass, location):
799
"""Return the working tree, branch and repo contained by a location.
801
Returns (tree, branch, repository, relpath).
802
If there is no tree containing the location, tree will be None.
803
If there is no branch containing the location, branch will be None.
804
If there is no repository containing the location, repository will be
806
relpath is the portion of the path that is contained by the innermost
809
If no tree, branch or repository is found, a NotBranchError is raised.
811
controldir, relpath = klass.open_containing(location)
813
tree, branch = controldir._get_tree_branch()
814
except errors.NotBranchError:
816
repo = controldir.find_repository()
817
return None, None, repo, relpath
818
except (errors.NoRepositoryPresent):
819
raise errors.NotBranchError(location)
820
return tree, branch, branch.repository, relpath
823
def create(klass, base, format=None, possible_transports=None):
824
"""Create a new ControlDir at the url 'base'.
826
:param format: If supplied, the format of branch to create. If not
827
supplied, the default is used.
828
:param possible_transports: If supplied, a list of transports that
829
can be reused to share a remote connection.
831
if klass is not ControlDir:
832
raise AssertionError("ControlDir.create always creates the"
833
"default format, not one of %r" % klass)
834
t = _mod_transport.get_transport(base, possible_transports)
837
format = ControlDirFormat.get_default_format()
838
return format.initialize_on_transport(t)
841
class ControlDirHooks(hooks.Hooks):
842
"""Hooks for ControlDir operations."""
845
"""Create the default hooks."""
846
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
847
self.add_hook('pre_open',
848
"Invoked before attempting to open a ControlDir with the transport "
849
"that the open will use.", (1, 14))
850
self.add_hook('post_repo_init',
851
"Invoked after a repository has been initialized. "
852
"post_repo_init is called with a "
853
"bzrlib.controldir.RepoInitHookParams.",
856
# install the default hooks
857
ControlDir.hooks = ControlDirHooks()
860
467
class ControlComponentFormat(object):
861
"""A component that can live inside of a control directory."""
468
"""A component that can live inside of a .bzr meta directory."""
863
470
upgrade_recommended = False
472
def get_format_string(self):
473
"""Return the format of this format, if usable in meta directories."""
474
raise NotImplementedError(self.get_format_string)
865
476
def get_format_description(self):
866
477
"""Return the short description for this format."""
867
478
raise NotImplementedError(self.get_format_description)