484
485
raise NotImplementedError(self.clone_on_transport)
488
def find_bzrdirs(cls, transport, evaluate=None, list_current=None):
489
"""Find bzrdirs recursively from current location.
491
This is intended primarily as a building block for more sophisticated
492
functionality, like finding trees under a directory, or finding
493
branches that use a given repository.
495
:param evaluate: An optional callable that yields recurse, value,
496
where recurse controls whether this bzrdir is recursed into
497
and value is the value to yield. By default, all bzrdirs
498
are recursed into, and the return value is the bzrdir.
499
:param list_current: if supplied, use this function to list the current
500
directory, instead of Transport.list_dir
501
:return: a generator of found bzrdirs, or whatever evaluate returns.
503
if list_current is None:
504
def list_current(transport):
505
return transport.list_dir('')
507
def evaluate(bzrdir):
510
pending = [transport]
511
while len(pending) > 0:
512
current_transport = pending.pop()
515
bzrdir = cls.open_from_transport(current_transport)
516
except (errors.NotBranchError, errors.PermissionDenied):
519
recurse, value = evaluate(bzrdir)
522
subdirs = list_current(current_transport)
523
except (errors.NoSuchFile, errors.PermissionDenied):
526
for subdir in sorted(subdirs, reverse=True):
527
pending.append(current_transport.clone(subdir))
530
def find_branches(cls, transport):
531
"""Find all branches under a transport.
533
This will find all branches below the transport, including branches
534
inside other branches. Where possible, it will use
535
Repository.find_branches.
537
To list all the branches that use a particular Repository, see
538
Repository.find_branches
540
def evaluate(bzrdir):
542
repository = bzrdir.open_repository()
543
except errors.NoRepositoryPresent:
546
return False, ([], repository)
547
return True, (bzrdir.list_branches(), None)
549
for branches, repo in cls.find_bzrdirs(
550
transport, evaluate=evaluate):
552
ret.extend(repo.find_branches())
553
if branches is not None:
558
def create_branch_and_repo(cls, base, force_new_repo=False, format=None):
559
"""Create a new ControlDir, Branch and Repository at the url 'base'.
561
This will use the current default ControlDirFormat unless one is
562
specified, and use whatever
563
repository format that that uses via bzrdir.create_branch and
564
create_repository. If a shared repository is available that is used
567
The created Branch object is returned.
569
:param base: The URL to create the branch at.
570
:param force_new_repo: If True a new repository is always created.
571
:param format: If supplied, the format of branch to create. If not
572
supplied, the default is used.
574
bzrdir = cls.create(base, format)
575
bzrdir._find_or_create_repository(force_new_repo)
576
return bzrdir.create_branch()
579
def create_branch_convenience(cls, base, force_new_repo=False,
580
force_new_tree=None, format=None,
581
possible_transports=None):
582
"""Create a new ControlDir, Branch and Repository at the url 'base'.
584
This is a convenience function - it will use an existing repository
585
if possible, can be told explicitly whether to create a working tree or
588
This will use the current default ControlDirFormat unless one is
589
specified, and use whatever
590
repository format that that uses via bzrdir.create_branch and
591
create_repository. If a shared repository is available that is used
592
preferentially. Whatever repository is used, its tree creation policy
595
The created Branch object is returned.
596
If a working tree cannot be made due to base not being a file:// url,
597
no error is raised unless force_new_tree is True, in which case no
598
data is created on disk and NotLocalUrl is raised.
600
:param base: The URL to create the branch at.
601
:param force_new_repo: If True a new repository is always created.
602
:param force_new_tree: If True or False force creation of a tree or
603
prevent such creation respectively.
604
:param format: Override for the bzrdir format to create.
605
:param possible_transports: An optional reusable transports list.
608
# check for non local urls
609
t = _mod_transport.get_transport(base, possible_transports)
610
if not isinstance(t, local.LocalTransport):
611
raise errors.NotLocalUrl(base)
612
bzrdir = cls.create(base, format, possible_transports)
613
repo = bzrdir._find_or_create_repository(force_new_repo)
614
result = bzrdir.create_branch()
615
if force_new_tree or (repo.make_working_trees() and
616
force_new_tree is None):
618
bzrdir.create_workingtree()
619
except errors.NotLocalUrl:
624
def create_standalone_workingtree(cls, base, format=None):
625
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
627
'base' must be a local path or a file:// url.
629
This will use the current default ControlDirFormat unless one is
630
specified, and use whatever
631
repository format that that uses for bzrdirformat.create_workingtree,
632
create_branch and create_repository.
634
:param format: Override for the bzrdir format to create.
635
:return: The WorkingTree object.
637
from bzrlib.transport import local
638
t = _mod_transport.get_transport(base)
639
if not isinstance(t, local.LocalTransport):
640
raise errors.NotLocalUrl(base)
641
bzrdir = cls.create_branch_and_repo(base,
643
format=format).bzrdir
644
return bzrdir.create_workingtree()
647
def open_unsupported(cls, base):
648
"""Open a branch which is not supported."""
649
return cls.open(base, _unsupported=True)
652
def open(cls, base, _unsupported=False, possible_transports=None):
653
"""Open an existing bzrdir, rooted at 'base' (url).
655
:param _unsupported: a private parameter to the ControlDir class.
657
t = _mod_transport.get_transport(base, possible_transports)
658
return cls.open_from_transport(t, _unsupported=_unsupported)
661
def open_from_transport(cls, transport, _unsupported=False,
662
_server_formats=True):
663
"""Open a bzrdir within a particular directory.
665
:param transport: Transport containing the bzrdir.
666
:param _unsupported: private.
668
for hook in cls.hooks['pre_open']:
670
# Keep initial base since 'transport' may be modified while following
672
base = transport.base
673
def find_format(transport):
674
return transport, ControlDirFormat.find_format(
675
transport, _server_formats=_server_formats)
677
def redirected(transport, e, redirection_notice):
678
redirected_transport = transport._redirected_to(e.source, e.target)
679
if redirected_transport is None:
680
raise errors.NotBranchError(base)
681
note(gettext('{0} is{1} redirected to {2}').format(
682
transport.base, e.permanently, redirected_transport.base))
683
return redirected_transport
686
transport, format = _mod_transport.do_catching_redirections(
687
find_format, transport, redirected)
688
except errors.TooManyRedirections:
689
raise errors.NotBranchError(base)
691
format.check_support_status(_unsupported)
692
return format.open(transport, _found=True)
695
def open_containing(cls, url, possible_transports=None):
696
"""Open an existing branch which contains url.
698
:param url: url to search from.
700
See open_containing_from_transport for more detail.
702
transport = _mod_transport.get_transport(url, possible_transports)
703
return cls.open_containing_from_transport(transport)
706
def open_containing_from_transport(cls, a_transport):
707
"""Open an existing branch which contains a_transport.base.
709
This probes for a branch at a_transport, and searches upwards from there.
711
Basically we keep looking up until we find the control directory or
712
run into the root. If there isn't one, raises NotBranchError.
713
If there is one and it is either an unrecognised format or an unsupported
714
format, UnknownFormatError or UnsupportedFormatError are raised.
715
If there is one, it is returned, along with the unused portion of url.
717
:return: The ControlDir that contains the path, and a Unicode path
718
for the rest of the URL.
720
# this gets the normalised url back. I.e. '.' -> the full path.
721
url = a_transport.base
724
result = cls.open_from_transport(a_transport)
725
return result, urlutils.unescape(a_transport.relpath(url))
726
except errors.NotBranchError, e:
729
new_t = a_transport.clone('..')
730
except errors.InvalidURLJoin:
731
# reached the root, whatever that may be
732
raise errors.NotBranchError(path=url)
733
if new_t.base == a_transport.base:
734
# reached the root, whatever that may be
735
raise errors.NotBranchError(path=url)
739
def open_tree_or_branch(klass, location):
740
"""Return the branch and working tree at a location.
742
If there is no tree at the location, tree will be None.
743
If there is no branch at the location, an exception will be
745
:return: (tree, branch)
747
bzrdir = klass.open(location)
748
return bzrdir._get_tree_branch()
751
def open_containing_tree_or_branch(klass, location):
752
"""Return the branch and working tree contained by a location.
754
Returns (tree, branch, relpath).
755
If there is no tree at containing the location, tree will be None.
756
If there is no branch containing the location, an exception will be
758
relpath is the portion of the path that is contained by the branch.
760
bzrdir, relpath = klass.open_containing(location)
761
tree, branch = bzrdir._get_tree_branch()
762
return tree, branch, relpath
765
def open_containing_tree_branch_or_repository(klass, location):
766
"""Return the working tree, branch and repo contained by a location.
768
Returns (tree, branch, repository, relpath).
769
If there is no tree containing the location, tree will be None.
770
If there is no branch containing the location, branch will be None.
771
If there is no repository containing the location, repository will be
773
relpath is the portion of the path that is contained by the innermost
776
If no tree, branch or repository is found, a NotBranchError is raised.
778
bzrdir, relpath = klass.open_containing(location)
780
tree, branch = bzrdir._get_tree_branch()
781
except errors.NotBranchError:
783
repo = bzrdir.find_repository()
784
return None, None, repo, relpath
785
except (errors.NoRepositoryPresent):
786
raise errors.NotBranchError(location)
787
return tree, branch, branch.repository, relpath
790
def create(cls, base, format=None, possible_transports=None):
791
"""Create a new ControlDir at the url 'base'.
793
:param format: If supplied, the format of branch to create. If not
794
supplied, the default is used.
795
:param possible_transports: If supplied, a list of transports that
796
can be reused to share a remote connection.
798
if cls is not ControlDir:
799
raise AssertionError("ControlDir.create always creates the"
800
"default format, not one of %r" % cls)
801
t = _mod_transport.get_transport(base, possible_transports)
804
format = ControlDirFormat.get_default_format()
805
return format.initialize_on_transport(t)
808
class ControlDirHooks(hooks.Hooks):
809
"""Hooks for ControlDir operations."""
812
"""Create the default hooks."""
813
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
814
self.add_hook('pre_open',
815
"Invoked before attempting to open a ControlDir with the transport "
816
"that the open will use.", (1, 14))
817
self.add_hook('post_repo_init',
818
"Invoked after a repository has been initialized. "
819
"post_repo_init is called with a "
820
"bzrlib.controldir.RepoInitHookParams.",
823
# install the default hooks
824
ControlDir.hooks = ControlDirHooks()
487
827
class ControlComponentFormat(object):
488
828
"""A component that can live inside of a .bzr meta directory."""