464
499
raise NotImplementedError(self.clone_on_transport)
502
def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
503
"""Find control dirs recursively from current location.
505
This is intended primarily as a building block for more sophisticated
506
functionality, like finding trees under a directory, or finding
507
branches that use a given repository.
509
:param evaluate: An optional callable that yields recurse, value,
510
where recurse controls whether this controldir is recursed into
511
and value is the value to yield. By default, all bzrdirs
512
are recursed into, and the return value is the controldir.
513
:param list_current: if supplied, use this function to list the current
514
directory, instead of Transport.list_dir
515
:return: a generator of found bzrdirs, or whatever evaluate returns.
517
if list_current is None:
518
def list_current(transport):
519
return transport.list_dir('')
521
def evaluate(controldir):
522
return True, controldir
524
pending = [transport]
525
while len(pending) > 0:
526
current_transport = pending.pop()
529
controldir = klass.open_from_transport(current_transport)
530
except (errors.NotBranchError, errors.PermissionDenied):
533
recurse, value = evaluate(controldir)
536
subdirs = list_current(current_transport)
537
except (errors.NoSuchFile, errors.PermissionDenied):
540
for subdir in sorted(subdirs, reverse=True):
541
pending.append(current_transport.clone(subdir))
544
def find_branches(klass, transport):
545
"""Find all branches under a transport.
547
This will find all branches below the transport, including branches
548
inside other branches. Where possible, it will use
549
Repository.find_branches.
551
To list all the branches that use a particular Repository, see
552
Repository.find_branches
554
def evaluate(controldir):
556
repository = controldir.open_repository()
557
except errors.NoRepositoryPresent:
560
return False, ([], repository)
561
return True, (controldir.list_branches(), None)
563
for branches, repo in klass.find_bzrdirs(
564
transport, evaluate=evaluate):
566
ret.extend(repo.find_branches())
567
if branches is not None:
572
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
573
"""Create a new ControlDir, Branch and Repository at the url 'base'.
575
This will use the current default ControlDirFormat unless one is
576
specified, and use whatever
577
repository format that that uses via controldir.create_branch and
578
create_repository. If a shared repository is available that is used
581
The created Branch object is returned.
583
:param base: The URL to create the branch at.
584
:param force_new_repo: If True a new repository is always created.
585
:param format: If supplied, the format of branch to create. If not
586
supplied, the default is used.
588
controldir = klass.create(base, format)
589
controldir._find_or_create_repository(force_new_repo)
590
return controldir.create_branch()
593
def create_branch_convenience(klass, base, force_new_repo=False,
594
force_new_tree=None, format=None,
595
possible_transports=None):
596
"""Create a new ControlDir, Branch and Repository at the url 'base'.
598
This is a convenience function - it will use an existing repository
599
if possible, can be told explicitly whether to create a working tree or
602
This will use the current default ControlDirFormat unless one is
603
specified, and use whatever
604
repository format that that uses via ControlDir.create_branch and
605
create_repository. If a shared repository is available that is used
606
preferentially. Whatever repository is used, its tree creation policy
609
The created Branch object is returned.
610
If a working tree cannot be made due to base not being a file:// url,
611
no error is raised unless force_new_tree is True, in which case no
612
data is created on disk and NotLocalUrl is raised.
614
:param base: The URL to create the branch at.
615
:param force_new_repo: If True a new repository is always created.
616
:param force_new_tree: If True or False force creation of a tree or
617
prevent such creation respectively.
618
:param format: Override for the controldir format to create.
619
:param possible_transports: An optional reusable transports list.
622
# check for non local urls
623
t = _mod_transport.get_transport(base, possible_transports)
624
if not isinstance(t, local.LocalTransport):
625
raise errors.NotLocalUrl(base)
626
controldir = klass.create(base, format, possible_transports)
627
repo = controldir._find_or_create_repository(force_new_repo)
628
result = controldir.create_branch()
629
if force_new_tree or (repo.make_working_trees() and
630
force_new_tree is None):
632
controldir.create_workingtree()
633
except errors.NotLocalUrl:
638
def create_standalone_workingtree(klass, base, format=None):
639
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
641
'base' must be a local path or a file:// url.
643
This will use the current default ControlDirFormat unless one is
644
specified, and use whatever
645
repository format that that uses for bzrdirformat.create_workingtree,
646
create_branch and create_repository.
648
:param format: Override for the controldir format to create.
649
:return: The WorkingTree object.
651
t = _mod_transport.get_transport(base)
652
if not isinstance(t, local.LocalTransport):
653
raise errors.NotLocalUrl(base)
654
controldir = klass.create_branch_and_repo(base,
656
format=format).bzrdir
657
return controldir.create_workingtree()
660
def open_unsupported(klass, base):
661
"""Open a branch which is not supported."""
662
return klass.open(base, _unsupported=True)
665
def open(klass, base, _unsupported=False, possible_transports=None):
666
"""Open an existing controldir, rooted at 'base' (url).
668
:param _unsupported: a private parameter to the ControlDir class.
670
t = _mod_transport.get_transport(base, possible_transports)
671
return klass.open_from_transport(t, _unsupported=_unsupported)
674
def open_from_transport(klass, transport, _unsupported=False,
675
_server_formats=True):
676
"""Open a controldir within a particular directory.
678
:param transport: Transport containing the controldir.
679
:param _unsupported: private.
681
for hook in klass.hooks['pre_open']:
683
# Keep initial base since 'transport' may be modified while following
685
base = transport.base
686
def find_format(transport):
687
return transport, ControlDirFormat.find_format(
688
transport, _server_formats=_server_formats)
690
def redirected(transport, e, redirection_notice):
691
redirected_transport = transport._redirected_to(e.source, e.target)
692
if redirected_transport is None:
693
raise errors.NotBranchError(base)
694
trace.note(gettext('{0} is{1} redirected to {2}').format(
695
transport.base, e.permanently, redirected_transport.base))
696
return redirected_transport
699
transport, format = _mod_transport.do_catching_redirections(
700
find_format, transport, redirected)
701
except errors.TooManyRedirections:
702
raise errors.NotBranchError(base)
704
format.check_support_status(_unsupported)
705
return format.open(transport, _found=True)
708
def open_containing(klass, url, possible_transports=None):
709
"""Open an existing branch which contains url.
711
:param url: url to search from.
713
See open_containing_from_transport for more detail.
715
transport = _mod_transport.get_transport(url, possible_transports)
716
return klass.open_containing_from_transport(transport)
719
def open_containing_from_transport(klass, a_transport):
720
"""Open an existing branch which contains a_transport.base.
722
This probes for a branch at a_transport, and searches upwards from there.
724
Basically we keep looking up until we find the control directory or
725
run into the root. If there isn't one, raises NotBranchError.
726
If there is one and it is either an unrecognised format or an unsupported
727
format, UnknownFormatError or UnsupportedFormatError are raised.
728
If there is one, it is returned, along with the unused portion of url.
730
:return: The ControlDir that contains the path, and a Unicode path
731
for the rest of the URL.
733
# this gets the normalised url back. I.e. '.' -> the full path.
734
url = a_transport.base
737
result = klass.open_from_transport(a_transport)
738
return result, urlutils.unescape(a_transport.relpath(url))
739
except errors.NotBranchError, e:
742
new_t = a_transport.clone('..')
743
except errors.InvalidURLJoin:
744
# reached the root, whatever that may be
745
raise errors.NotBranchError(path=url)
746
if new_t.base == a_transport.base:
747
# reached the root, whatever that may be
748
raise errors.NotBranchError(path=url)
752
def open_tree_or_branch(klass, location):
753
"""Return the branch and working tree at a location.
755
If there is no tree at the location, tree will be None.
756
If there is no branch at the location, an exception will be
758
:return: (tree, branch)
760
controldir = klass.open(location)
761
return controldir._get_tree_branch()
764
def open_containing_tree_or_branch(klass, location):
765
"""Return the branch and working tree contained by a location.
767
Returns (tree, branch, relpath).
768
If there is no tree at containing the location, tree will be None.
769
If there is no branch containing the location, an exception will be
771
relpath is the portion of the path that is contained by the branch.
773
controldir, relpath = klass.open_containing(location)
774
tree, branch = controldir._get_tree_branch()
775
return tree, branch, relpath
778
def open_containing_tree_branch_or_repository(klass, location):
779
"""Return the working tree, branch and repo contained by a location.
781
Returns (tree, branch, repository, relpath).
782
If there is no tree containing the location, tree will be None.
783
If there is no branch containing the location, branch will be None.
784
If there is no repository containing the location, repository will be
786
relpath is the portion of the path that is contained by the innermost
789
If no tree, branch or repository is found, a NotBranchError is raised.
791
controldir, relpath = klass.open_containing(location)
793
tree, branch = controldir._get_tree_branch()
794
except errors.NotBranchError:
796
repo = controldir.find_repository()
797
return None, None, repo, relpath
798
except (errors.NoRepositoryPresent):
799
raise errors.NotBranchError(location)
800
return tree, branch, branch.repository, relpath
803
def create(klass, base, format=None, possible_transports=None):
804
"""Create a new ControlDir at the url 'base'.
806
:param format: If supplied, the format of branch to create. If not
807
supplied, the default is used.
808
:param possible_transports: If supplied, a list of transports that
809
can be reused to share a remote connection.
811
if klass is not ControlDir:
812
raise AssertionError("ControlDir.create always creates the"
813
"default format, not one of %r" % klass)
814
t = _mod_transport.get_transport(base, possible_transports)
817
format = ControlDirFormat.get_default_format()
818
return format.initialize_on_transport(t)
821
class ControlDirHooks(hooks.Hooks):
822
"""Hooks for ControlDir operations."""
825
"""Create the default hooks."""
826
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
827
self.add_hook('pre_open',
828
"Invoked before attempting to open a ControlDir with the transport "
829
"that the open will use.", (1, 14))
830
self.add_hook('post_repo_init',
831
"Invoked after a repository has been initialized. "
832
"post_repo_init is called with a "
833
"bzrlib.controldir.RepoInitHookParams.",
836
# install the default hooks
837
ControlDir.hooks = ControlDirHooks()
467
840
class ControlComponentFormat(object):
468
841
"""A component that can live inside of a .bzr meta directory."""
470
843
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)
476
845
def get_format_description(self):
477
846
"""Return the short description for this format."""
478
847
raise NotImplementedError(self.get_format_description)