488
484
raise NotImplementedError(self.clone_on_transport)
491
def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
492
"""Find control dirs recursively from current location.
494
This is intended primarily as a building block for more sophisticated
495
functionality, like finding trees under a directory, or finding
496
branches that use a given repository.
498
:param evaluate: An optional callable that yields recurse, value,
499
where recurse controls whether this controldir is recursed into
500
and value is the value to yield. By default, all bzrdirs
501
are recursed into, and the return value is the controldir.
502
:param list_current: if supplied, use this function to list the current
503
directory, instead of Transport.list_dir
504
:return: a generator of found bzrdirs, or whatever evaluate returns.
506
if list_current is None:
507
def list_current(transport):
508
return transport.list_dir('')
510
def evaluate(controldir):
511
return True, controldir
513
pending = [transport]
514
while len(pending) > 0:
515
current_transport = pending.pop()
518
controldir = klass.open_from_transport(current_transport)
519
except (errors.NotBranchError, errors.PermissionDenied):
522
recurse, value = evaluate(controldir)
525
subdirs = list_current(current_transport)
526
except (errors.NoSuchFile, errors.PermissionDenied):
529
for subdir in sorted(subdirs, reverse=True):
530
pending.append(current_transport.clone(subdir))
533
def find_branches(klass, transport):
534
"""Find all branches under a transport.
536
This will find all branches below the transport, including branches
537
inside other branches. Where possible, it will use
538
Repository.find_branches.
540
To list all the branches that use a particular Repository, see
541
Repository.find_branches
543
def evaluate(controldir):
545
repository = controldir.open_repository()
546
except errors.NoRepositoryPresent:
549
return False, ([], repository)
550
return True, (controldir.list_branches(), None)
552
for branches, repo in klass.find_bzrdirs(
553
transport, evaluate=evaluate):
555
ret.extend(repo.find_branches())
556
if branches is not None:
561
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
562
"""Create a new ControlDir, Branch and Repository at the url 'base'.
564
This will use the current default ControlDirFormat unless one is
565
specified, and use whatever
566
repository format that that uses via controldir.create_branch and
567
create_repository. If a shared repository is available that is used
570
The created Branch object is returned.
572
:param base: The URL to create the branch at.
573
:param force_new_repo: If True a new repository is always created.
574
:param format: If supplied, the format of branch to create. If not
575
supplied, the default is used.
577
controldir = klass.create(base, format)
578
controldir._find_or_create_repository(force_new_repo)
579
return controldir.create_branch()
582
def create_branch_convenience(klass, base, force_new_repo=False,
583
force_new_tree=None, format=None,
584
possible_transports=None):
585
"""Create a new ControlDir, Branch and Repository at the url 'base'.
587
This is a convenience function - it will use an existing repository
588
if possible, can be told explicitly whether to create a working tree or
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
595
preferentially. Whatever repository is used, its tree creation policy
598
The created Branch object is returned.
599
If a working tree cannot be made due to base not being a file:// url,
600
no error is raised unless force_new_tree is True, in which case no
601
data is created on disk and NotLocalUrl is raised.
603
:param base: The URL to create the branch at.
604
:param force_new_repo: If True a new repository is always created.
605
:param force_new_tree: If True or False force creation of a tree or
606
prevent such creation respectively.
607
:param format: Override for the controldir format to create.
608
:param possible_transports: An optional reusable transports list.
611
# check for non local urls
612
t = _mod_transport.get_transport(base, possible_transports)
613
if not isinstance(t, local.LocalTransport):
614
raise errors.NotLocalUrl(base)
615
controldir = klass.create(base, format, possible_transports)
616
repo = controldir._find_or_create_repository(force_new_repo)
617
result = controldir.create_branch()
618
if force_new_tree or (repo.make_working_trees() and
619
force_new_tree is None):
621
controldir.create_workingtree()
622
except errors.NotLocalUrl:
627
def create_standalone_workingtree(klass, base, format=None):
628
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
630
'base' must be a local path or a file:// url.
632
This will use the current default ControlDirFormat unless one is
633
specified, and use whatever
634
repository format that that uses for bzrdirformat.create_workingtree,
635
create_branch and create_repository.
637
:param format: Override for the controldir format to create.
638
:return: The WorkingTree object.
640
t = _mod_transport.get_transport(base)
641
if not isinstance(t, local.LocalTransport):
642
raise errors.NotLocalUrl(base)
643
controldir = klass.create_branch_and_repo(base,
645
format=format).bzrdir
646
return controldir.create_workingtree()
649
def open_unsupported(klass, base):
650
"""Open a branch which is not supported."""
651
return klass.open(base, _unsupported=True)
654
def open(klass, base, _unsupported=False, possible_transports=None):
655
"""Open an existing controldir, rooted at 'base' (url).
657
:param _unsupported: a private parameter to the ControlDir class.
659
t = _mod_transport.get_transport(base, possible_transports)
660
return klass.open_from_transport(t, _unsupported=_unsupported)
663
def open_from_transport(klass, transport, _unsupported=False,
664
_server_formats=True):
665
"""Open a controldir within a particular directory.
667
:param transport: Transport containing the controldir.
668
:param _unsupported: private.
670
for hook in klass.hooks['pre_open']:
672
# Keep initial base since 'transport' may be modified while following
674
base = transport.base
675
def find_format(transport):
676
return transport, ControlDirFormat.find_format(
677
transport, _server_formats=_server_formats)
679
def redirected(transport, e, redirection_notice):
680
redirected_transport = transport._redirected_to(e.source, e.target)
681
if redirected_transport is None:
682
raise errors.NotBranchError(base)
683
trace.note(gettext('{0} is{1} redirected to {2}').format(
684
transport.base, e.permanently, redirected_transport.base))
685
return redirected_transport
688
transport, format = _mod_transport.do_catching_redirections(
689
find_format, transport, redirected)
690
except errors.TooManyRedirections:
691
raise errors.NotBranchError(base)
693
format.check_support_status(_unsupported)
694
return format.open(transport, _found=True)
697
def open_containing(klass, url, possible_transports=None):
698
"""Open an existing branch which contains url.
700
:param url: url to search from.
702
See open_containing_from_transport for more detail.
704
transport = _mod_transport.get_transport(url, possible_transports)
705
return klass.open_containing_from_transport(transport)
708
def open_containing_from_transport(klass, a_transport):
709
"""Open an existing branch which contains a_transport.base.
711
This probes for a branch at a_transport, and searches upwards from there.
713
Basically we keep looking up until we find the control directory or
714
run into the root. If there isn't one, raises NotBranchError.
715
If there is one and it is either an unrecognised format or an unsupported
716
format, UnknownFormatError or UnsupportedFormatError are raised.
717
If there is one, it is returned, along with the unused portion of url.
719
:return: The ControlDir that contains the path, and a Unicode path
720
for the rest of the URL.
722
# this gets the normalised url back. I.e. '.' -> the full path.
723
url = a_transport.base
726
result = klass.open_from_transport(a_transport)
727
return result, urlutils.unescape(a_transport.relpath(url))
728
except errors.NotBranchError, e:
731
new_t = a_transport.clone('..')
732
except errors.InvalidURLJoin:
733
# reached the root, whatever that may be
734
raise errors.NotBranchError(path=url)
735
if new_t.base == a_transport.base:
736
# reached the root, whatever that may be
737
raise errors.NotBranchError(path=url)
741
def open_tree_or_branch(klass, location):
742
"""Return the branch and working tree at a location.
744
If there is no tree at the location, tree will be None.
745
If there is no branch at the location, an exception will be
747
:return: (tree, branch)
749
controldir = klass.open(location)
750
return controldir._get_tree_branch()
753
def open_containing_tree_or_branch(klass, location):
754
"""Return the branch and working tree contained by a location.
756
Returns (tree, branch, relpath).
757
If there is no tree at containing the location, tree will be None.
758
If there is no branch containing the location, an exception will be
760
relpath is the portion of the path that is contained by the branch.
762
controldir, relpath = klass.open_containing(location)
763
tree, branch = controldir._get_tree_branch()
764
return tree, branch, relpath
767
def open_containing_tree_branch_or_repository(klass, location):
768
"""Return the working tree, branch and repo contained by a location.
770
Returns (tree, branch, repository, relpath).
771
If there is no tree containing the location, tree will be None.
772
If there is no branch containing the location, branch will be None.
773
If there is no repository containing the location, repository will be
775
relpath is the portion of the path that is contained by the innermost
778
If no tree, branch or repository is found, a NotBranchError is raised.
780
controldir, relpath = klass.open_containing(location)
782
tree, branch = controldir._get_tree_branch()
783
except errors.NotBranchError:
785
repo = controldir.find_repository()
786
return None, None, repo, relpath
787
except (errors.NoRepositoryPresent):
788
raise errors.NotBranchError(location)
789
return tree, branch, branch.repository, relpath
792
def create(klass, base, format=None, possible_transports=None):
793
"""Create a new ControlDir at the url 'base'.
795
:param format: If supplied, the format of branch to create. If not
796
supplied, the default is used.
797
:param possible_transports: If supplied, a list of transports that
798
can be reused to share a remote connection.
800
if klass is not ControlDir:
801
raise AssertionError("ControlDir.create always creates the"
802
"default format, not one of %r" % klass)
803
t = _mod_transport.get_transport(base, possible_transports)
806
format = ControlDirFormat.get_default_format()
807
return format.initialize_on_transport(t)
810
class ControlDirHooks(hooks.Hooks):
811
"""Hooks for ControlDir operations."""
814
"""Create the default hooks."""
815
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
816
self.add_hook('pre_open',
817
"Invoked before attempting to open a ControlDir with the transport "
818
"that the open will use.", (1, 14))
819
self.add_hook('post_repo_init',
820
"Invoked after a repository has been initialized. "
821
"post_repo_init is called with a "
822
"bzrlib.controldir.RepoInitHookParams.",
825
# install the default hooks
826
ControlDir.hooks = ControlDirHooks()
829
487
class ControlComponentFormat(object):
830
488
"""A component that can live inside of a .bzr meta directory."""