464
501
raise NotImplementedError(self.clone_on_transport)
504
def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
505
"""Find control dirs recursively from current location.
507
This is intended primarily as a building block for more sophisticated
508
functionality, like finding trees under a directory, or finding
509
branches that use a given repository.
511
:param evaluate: An optional callable that yields recurse, value,
512
where recurse controls whether this controldir is recursed into
513
and value is the value to yield. By default, all bzrdirs
514
are recursed into, and the return value is the controldir.
515
:param list_current: if supplied, use this function to list the current
516
directory, instead of Transport.list_dir
517
:return: a generator of found bzrdirs, or whatever evaluate returns.
519
if list_current is None:
520
def list_current(transport):
521
return transport.list_dir('')
523
def evaluate(controldir):
524
return True, controldir
526
pending = [transport]
527
while len(pending) > 0:
528
current_transport = pending.pop()
531
controldir = klass.open_from_transport(current_transport)
532
except (errors.NotBranchError, errors.PermissionDenied):
535
recurse, value = evaluate(controldir)
538
subdirs = list_current(current_transport)
539
except (errors.NoSuchFile, errors.PermissionDenied):
542
for subdir in sorted(subdirs, reverse=True):
543
pending.append(current_transport.clone(subdir))
546
def find_branches(klass, transport):
547
"""Find all branches under a transport.
549
This will find all branches below the transport, including branches
550
inside other branches. Where possible, it will use
551
Repository.find_branches.
553
To list all the branches that use a particular Repository, see
554
Repository.find_branches
556
def evaluate(controldir):
558
repository = controldir.open_repository()
559
except errors.NoRepositoryPresent:
562
return False, ([], repository)
563
return True, (controldir.list_branches(), None)
565
for branches, repo in klass.find_bzrdirs(
566
transport, evaluate=evaluate):
568
ret.extend(repo.find_branches())
569
if branches is not None:
574
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
575
"""Create a new ControlDir, Branch and Repository at the url 'base'.
577
This will use the current default ControlDirFormat unless one is
578
specified, and use whatever
579
repository format that that uses via controldir.create_branch and
580
create_repository. If a shared repository is available that is used
583
The created Branch object is returned.
585
:param base: The URL to create the branch at.
586
:param force_new_repo: If True a new repository is always created.
587
:param format: If supplied, the format of branch to create. If not
588
supplied, the default is used.
590
controldir = klass.create(base, format)
591
controldir._find_or_create_repository(force_new_repo)
592
return controldir.create_branch()
595
def create_branch_convenience(klass, base, force_new_repo=False,
596
force_new_tree=None, format=None,
597
possible_transports=None):
598
"""Create a new ControlDir, Branch and Repository at the url 'base'.
600
This is a convenience function - it will use an existing repository
601
if possible, can be told explicitly whether to create a working tree or
604
This will use the current default ControlDirFormat unless one is
605
specified, and use whatever
606
repository format that that uses via ControlDir.create_branch and
607
create_repository. If a shared repository is available that is used
608
preferentially. Whatever repository is used, its tree creation policy
611
The created Branch object is returned.
612
If a working tree cannot be made due to base not being a file:// url,
613
no error is raised unless force_new_tree is True, in which case no
614
data is created on disk and NotLocalUrl is raised.
616
:param base: The URL to create the branch at.
617
:param force_new_repo: If True a new repository is always created.
618
:param force_new_tree: If True or False force creation of a tree or
619
prevent such creation respectively.
620
:param format: Override for the controldir format to create.
621
:param possible_transports: An optional reusable transports list.
624
# check for non local urls
625
t = _mod_transport.get_transport(base, possible_transports)
626
if not isinstance(t, local.LocalTransport):
627
raise errors.NotLocalUrl(base)
628
controldir = klass.create(base, format, possible_transports)
629
repo = controldir._find_or_create_repository(force_new_repo)
630
result = controldir.create_branch()
631
if force_new_tree or (repo.make_working_trees() and
632
force_new_tree is None):
634
controldir.create_workingtree()
635
except errors.NotLocalUrl:
640
def create_standalone_workingtree(klass, base, format=None):
641
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
643
'base' must be a local path or a file:// url.
645
This will use the current default ControlDirFormat unless one is
646
specified, and use whatever
647
repository format that that uses for bzrdirformat.create_workingtree,
648
create_branch and create_repository.
650
:param format: Override for the controldir format to create.
651
:return: The WorkingTree object.
653
t = _mod_transport.get_transport(base)
654
if not isinstance(t, local.LocalTransport):
655
raise errors.NotLocalUrl(base)
656
controldir = klass.create_branch_and_repo(base,
658
format=format).bzrdir
659
return controldir.create_workingtree()
662
def open_unsupported(klass, base):
663
"""Open a branch which is not supported."""
664
return klass.open(base, _unsupported=True)
667
def open(klass, base, _unsupported=False, possible_transports=None):
668
"""Open an existing controldir, rooted at 'base' (url).
670
:param _unsupported: a private parameter to the ControlDir class.
672
t = _mod_transport.get_transport(base, possible_transports)
673
return klass.open_from_transport(t, _unsupported=_unsupported)
676
def open_from_transport(klass, transport, _unsupported=False,
677
_server_formats=True):
678
"""Open a controldir within a particular directory.
680
:param transport: Transport containing the controldir.
681
:param _unsupported: private.
683
for hook in klass.hooks['pre_open']:
685
# Keep initial base since 'transport' may be modified while following
687
base = transport.base
688
def find_format(transport):
689
return transport, ControlDirFormat.find_format(
690
transport, _server_formats=_server_formats)
692
def redirected(transport, e, redirection_notice):
693
redirected_transport = transport._redirected_to(e.source, e.target)
694
if redirected_transport is None:
695
raise errors.NotBranchError(base)
696
trace.note(gettext('{0} is{1} redirected to {2}').format(
697
transport.base, e.permanently, redirected_transport.base))
698
return redirected_transport
701
transport, format = _mod_transport.do_catching_redirections(
702
find_format, transport, redirected)
703
except errors.TooManyRedirections:
704
raise errors.NotBranchError(base)
706
format.check_support_status(_unsupported)
707
return format.open(transport, _found=True)
710
def open_containing(klass, url, possible_transports=None):
711
"""Open an existing branch which contains url.
713
:param url: url to search from.
715
See open_containing_from_transport for more detail.
717
transport = _mod_transport.get_transport(url, possible_transports)
718
return klass.open_containing_from_transport(transport)
721
def open_containing_from_transport(klass, a_transport):
722
"""Open an existing branch which contains a_transport.base.
724
This probes for a branch at a_transport, and searches upwards from there.
726
Basically we keep looking up until we find the control directory or
727
run into the root. If there isn't one, raises NotBranchError.
728
If there is one and it is either an unrecognised format or an unsupported
729
format, UnknownFormatError or UnsupportedFormatError are raised.
730
If there is one, it is returned, along with the unused portion of url.
732
:return: The ControlDir that contains the path, and a Unicode path
733
for the rest of the URL.
735
# this gets the normalised url back. I.e. '.' -> the full path.
736
url = a_transport.base
739
result = klass.open_from_transport(a_transport)
740
return result, urlutils.unescape(a_transport.relpath(url))
741
except errors.NotBranchError, e:
743
except errors.PermissionDenied:
746
new_t = a_transport.clone('..')
747
except errors.InvalidURLJoin:
748
# reached the root, whatever that may be
749
raise errors.NotBranchError(path=url)
750
if new_t.base == a_transport.base:
751
# reached the root, whatever that may be
752
raise errors.NotBranchError(path=url)
756
def open_tree_or_branch(klass, location):
757
"""Return the branch and working tree at a location.
759
If there is no tree at the location, tree will be None.
760
If there is no branch at the location, an exception will be
762
:return: (tree, branch)
764
controldir = klass.open(location)
765
return controldir._get_tree_branch()
768
def open_containing_tree_or_branch(klass, location):
769
"""Return the branch and working tree contained by a location.
771
Returns (tree, branch, relpath).
772
If there is no tree at containing the location, tree will be None.
773
If there is no branch containing the location, an exception will be
775
relpath is the portion of the path that is contained by the branch.
777
controldir, relpath = klass.open_containing(location)
778
tree, branch = controldir._get_tree_branch()
779
return tree, branch, relpath
782
def open_containing_tree_branch_or_repository(klass, location):
783
"""Return the working tree, branch and repo contained by a location.
785
Returns (tree, branch, repository, relpath).
786
If there is no tree containing the location, tree will be None.
787
If there is no branch containing the location, branch will be None.
788
If there is no repository containing the location, repository will be
790
relpath is the portion of the path that is contained by the innermost
793
If no tree, branch or repository is found, a NotBranchError is raised.
795
controldir, relpath = klass.open_containing(location)
797
tree, branch = controldir._get_tree_branch()
798
except errors.NotBranchError:
800
repo = controldir.find_repository()
801
return None, None, repo, relpath
802
except (errors.NoRepositoryPresent):
803
raise errors.NotBranchError(location)
804
return tree, branch, branch.repository, relpath
807
def create(klass, base, format=None, possible_transports=None):
808
"""Create a new ControlDir at the url 'base'.
810
:param format: If supplied, the format of branch to create. If not
811
supplied, the default is used.
812
:param possible_transports: If supplied, a list of transports that
813
can be reused to share a remote connection.
815
if klass is not ControlDir:
816
raise AssertionError("ControlDir.create always creates the"
817
"default format, not one of %r" % klass)
818
t = _mod_transport.get_transport(base, possible_transports)
821
format = ControlDirFormat.get_default_format()
822
return format.initialize_on_transport(t)
825
class ControlDirHooks(hooks.Hooks):
826
"""Hooks for ControlDir operations."""
829
"""Create the default hooks."""
830
hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
831
self.add_hook('pre_open',
832
"Invoked before attempting to open a ControlDir with the transport "
833
"that the open will use.", (1, 14))
834
self.add_hook('post_repo_init',
835
"Invoked after a repository has been initialized. "
836
"post_repo_init is called with a "
837
"bzrlib.controldir.RepoInitHookParams.",
840
# install the default hooks
841
ControlDir.hooks = ControlDirHooks()
467
844
class ControlComponentFormat(object):
468
845
"""A component that can live inside of a .bzr meta directory."""
470
847
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
849
def get_format_description(self):
477
850
"""Return the short description for this format."""
478
851
raise NotImplementedError(self.get_format_description)