232
233
t = _mod_transport.get_transport(url)
237
def find_bzrdirs(transport, evaluate=None, list_current=None):
238
"""Find bzrdirs recursively from current location.
240
This is intended primarily as a building block for more sophisticated
241
functionality, like finding trees under a directory, or finding
242
branches that use a given repository.
244
:param evaluate: An optional callable that yields recurse, value,
245
where recurse controls whether this bzrdir is recursed into
246
and value is the value to yield. By default, all bzrdirs
247
are recursed into, and the return value is the bzrdir.
248
:param list_current: if supplied, use this function to list the current
249
directory, instead of Transport.list_dir
250
:return: a generator of found bzrdirs, or whatever evaluate returns.
252
if list_current is None:
253
def list_current(transport):
254
return transport.list_dir('')
256
def evaluate(bzrdir):
259
pending = [transport]
260
while len(pending) > 0:
261
current_transport = pending.pop()
264
bzrdir = BzrDir.open_from_transport(current_transport)
265
except (errors.NotBranchError, errors.PermissionDenied):
268
recurse, value = evaluate(bzrdir)
271
subdirs = list_current(current_transport)
272
except (errors.NoSuchFile, errors.PermissionDenied):
275
for subdir in sorted(subdirs, reverse=True):
276
pending.append(current_transport.clone(subdir))
279
def find_branches(transport):
280
"""Find all branches under a transport.
282
This will find all branches below the transport, including branches
283
inside other branches. Where possible, it will use
284
Repository.find_branches.
286
To list all the branches that use a particular Repository, see
287
Repository.find_branches
289
def evaluate(bzrdir):
291
repository = bzrdir.open_repository()
292
except errors.NoRepositoryPresent:
295
return False, ([], repository)
296
return True, (bzrdir.list_branches(), None)
298
for branches, repo in BzrDir.find_bzrdirs(transport,
301
ret.extend(repo.find_branches())
302
if branches is not None:
307
def create_branch_and_repo(base, force_new_repo=False, format=None):
308
"""Create a new BzrDir, Branch and Repository at the url 'base'.
310
This will use the current default BzrDirFormat unless one is
311
specified, and use whatever
312
repository format that that uses via bzrdir.create_branch and
313
create_repository. If a shared repository is available that is used
316
The created Branch object is returned.
318
:param base: The URL to create the branch at.
319
:param force_new_repo: If True a new repository is always created.
320
:param format: If supplied, the format of branch to create. If not
321
supplied, the default is used.
323
bzrdir = BzrDir.create(base, format)
324
bzrdir._find_or_create_repository(force_new_repo)
325
return bzrdir.create_branch()
235
327
def determine_repository_policy(self, force_new_repo=False, stack_on=None,
236
328
stack_on_pwd=None, require_stacking=False):
237
329
"""Return an object representing a policy to use.
548
def create_branch_convenience(base, force_new_repo=False,
549
force_new_tree=None, format=None,
550
possible_transports=None):
551
"""Create a new BzrDir, Branch and Repository at the url 'base'.
553
This is a convenience function - it will use an existing repository
554
if possible, can be told explicitly whether to create a working tree or
557
This will use the current default BzrDirFormat unless one is
558
specified, and use whatever
559
repository format that that uses via bzrdir.create_branch and
560
create_repository. If a shared repository is available that is used
561
preferentially. Whatever repository is used, its tree creation policy
564
The created Branch object is returned.
565
If a working tree cannot be made due to base not being a file:// url,
566
no error is raised unless force_new_tree is True, in which case no
567
data is created on disk and NotLocalUrl is raised.
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 force_new_tree: If True or False force creation of a tree or
572
prevent such creation respectively.
573
:param format: Override for the bzrdir format to create.
574
:param possible_transports: An optional reusable transports list.
577
# check for non local urls
578
t = _mod_transport.get_transport(base, possible_transports)
579
if not isinstance(t, local.LocalTransport):
580
raise errors.NotLocalUrl(base)
581
bzrdir = BzrDir.create(base, format, possible_transports)
582
repo = bzrdir._find_or_create_repository(force_new_repo)
583
result = bzrdir.create_branch()
584
if force_new_tree or (repo.make_working_trees() and
585
force_new_tree is None):
587
bzrdir.create_workingtree()
588
except errors.NotLocalUrl:
593
def create_standalone_workingtree(base, format=None):
594
"""Create a new BzrDir, WorkingTree, Branch and Repository at 'base'.
596
'base' must be a local path or a file:// url.
598
This will use the current default BzrDirFormat unless one is
599
specified, and use whatever
600
repository format that that uses for bzrdirformat.create_workingtree,
601
create_branch and create_repository.
603
:param format: Override for the bzrdir format to create.
604
:return: The WorkingTree object.
606
t = _mod_transport.get_transport(base)
607
if not isinstance(t, local.LocalTransport):
608
raise errors.NotLocalUrl(base)
609
bzrdir = BzrDir.create_branch_and_repo(base,
611
format=format).bzrdir
612
return bzrdir.create_workingtree()
455
614
@deprecated_method(deprecated_in((2, 3, 0)))
456
615
def generate_backup_name(self, base):
457
616
return self._available_backup_name(base)
654
813
# add new tests for it to the appropriate place.
655
814
return filename == '.bzr' or filename.startswith('.bzr/')
817
def open_unsupported(base):
818
"""Open a branch which is not supported."""
819
return BzrDir.open(base, _unsupported=True)
822
def open(base, _unsupported=False, possible_transports=None):
823
"""Open an existing bzrdir, rooted at 'base' (url).
825
:param _unsupported: a private parameter to the BzrDir class.
827
t = _mod_transport.get_transport(base, possible_transports)
828
return BzrDir.open_from_transport(t, _unsupported=_unsupported)
831
def open_from_transport(transport, _unsupported=False,
832
_server_formats=True):
833
"""Open a bzrdir within a particular directory.
835
:param transport: Transport containing the bzrdir.
836
:param _unsupported: private.
838
for hook in BzrDir.hooks['pre_open']:
840
# Keep initial base since 'transport' may be modified while following
842
base = transport.base
843
def find_format(transport):
844
return transport, controldir.ControlDirFormat.find_format(
845
transport, _server_formats=_server_formats)
847
def redirected(transport, e, redirection_notice):
848
redirected_transport = transport._redirected_to(e.source, e.target)
849
if redirected_transport is None:
850
raise errors.NotBranchError(base)
851
note(gettext('{0} is{1} redirected to {2}').format(
852
transport.base, e.permanently, redirected_transport.base))
853
return redirected_transport
856
transport, format = do_catching_redirections(find_format,
859
except errors.TooManyRedirections:
860
raise errors.NotBranchError(base)
862
format.check_support_status(_unsupported)
863
return format.open(transport, _found=True)
866
def open_containing(url, possible_transports=None):
867
"""Open an existing branch which contains url.
869
:param url: url to search from.
871
See open_containing_from_transport for more detail.
873
transport = _mod_transport.get_transport(url, possible_transports)
874
return BzrDir.open_containing_from_transport(transport)
877
def open_containing_from_transport(a_transport):
878
"""Open an existing branch which contains a_transport.base.
880
This probes for a branch at a_transport, and searches upwards from there.
882
Basically we keep looking up until we find the control directory or
883
run into the root. If there isn't one, raises NotBranchError.
884
If there is one and it is either an unrecognised format or an unsupported
885
format, UnknownFormatError or UnsupportedFormatError are raised.
886
If there is one, it is returned, along with the unused portion of url.
888
:return: The BzrDir that contains the path, and a Unicode path
889
for the rest of the URL.
891
# this gets the normalised url back. I.e. '.' -> the full path.
892
url = a_transport.base
895
result = BzrDir.open_from_transport(a_transport)
896
return result, urlutils.unescape(a_transport.relpath(url))
897
except errors.NotBranchError, e:
900
new_t = a_transport.clone('..')
901
except errors.InvalidURLJoin:
902
# reached the root, whatever that may be
903
raise errors.NotBranchError(path=url)
904
if new_t.base == a_transport.base:
905
# reached the root, whatever that may be
906
raise errors.NotBranchError(path=url)
910
def open_tree_or_branch(klass, location):
911
"""Return the branch and working tree at a location.
913
If there is no tree at the location, tree will be None.
914
If there is no branch at the location, an exception will be
916
:return: (tree, branch)
918
bzrdir = klass.open(location)
919
return bzrdir._get_tree_branch()
922
def open_containing_tree_or_branch(klass, location):
923
"""Return the branch and working tree contained by a location.
925
Returns (tree, branch, relpath).
926
If there is no tree at containing the location, tree will be None.
927
If there is no branch containing the location, an exception will be
929
relpath is the portion of the path that is contained by the branch.
931
bzrdir, relpath = klass.open_containing(location)
932
tree, branch = bzrdir._get_tree_branch()
933
return tree, branch, relpath
936
def open_containing_tree_branch_or_repository(klass, location):
937
"""Return the working tree, branch and repo contained by a location.
939
Returns (tree, branch, repository, relpath).
940
If there is no tree containing the location, tree will be None.
941
If there is no branch containing the location, branch will be None.
942
If there is no repository containing the location, repository will be
944
relpath is the portion of the path that is contained by the innermost
947
If no tree, branch or repository is found, a NotBranchError is raised.
949
bzrdir, relpath = klass.open_containing(location)
951
tree, branch = bzrdir._get_tree_branch()
952
except errors.NotBranchError:
954
repo = bzrdir.find_repository()
955
return None, None, repo, relpath
956
except (errors.NoRepositoryPresent):
957
raise errors.NotBranchError(location)
958
return tree, branch, branch.repository, relpath
657
960
def _cloning_metadir(self):
658
961
"""Produce a metadir suitable for cloning with.
757
1078
raise NotImplementedError(self.get_workingtree_transport)
760
def create(cls, base, format=None, possible_transports=None):
761
"""Create a new BzrDir at the url 'base'.
763
:param format: If supplied, the format of branch to create. If not
764
supplied, the default is used.
765
:param possible_transports: If supplied, a list of transports that
766
can be reused to share a remote connection.
1081
class BzrDirHooks(hooks.Hooks):
1082
"""Hooks for BzrDir operations."""
1085
"""Create the default hooks."""
1086
hooks.Hooks.__init__(self, "bzrlib.bzrdir", "BzrDir.hooks")
1087
self.add_hook('pre_open',
1088
"Invoked before attempting to open a BzrDir with the transport "
1089
"that the open will use.", (1, 14))
1090
self.add_hook('post_repo_init',
1091
"Invoked after a repository has been initialized. "
1092
"post_repo_init is called with a "
1093
"bzrlib.bzrdir.RepoInitHookParams.",
1096
# install the default hooks
1097
BzrDir.hooks = BzrDirHooks()
1100
class RepoInitHookParams(object):
1101
"""Object holding parameters passed to `*_repo_init` hooks.
1103
There are 4 fields that hooks may wish to access:
1105
:ivar repository: Repository created
1106
:ivar format: Repository format
1107
:ivar bzrdir: The bzrdir for the repository
1108
:ivar shared: The repository is shared
1111
def __init__(self, repository, format, a_bzrdir, shared):
1112
"""Create a group of RepoInitHook parameters.
1114
:param repository: Repository created
1115
:param format: Repository format
1116
:param bzrdir: The bzrdir for the repository
1117
:param shared: The repository is shared
768
if cls is not BzrDir:
769
raise AssertionError("BzrDir.create always creates the "
770
"default format, not one of %r" % cls)
771
return controldir.ControlDir.create(base, format=format,
772
possible_transports=possible_transports)
1119
self.repository = repository
1120
self.format = format
1121
self.bzrdir = a_bzrdir
1122
self.shared = shared
1124
def __eq__(self, other):
1125
return self.__dict__ == other.__dict__
1129
return "<%s for %s>" % (self.__class__.__name__,
1132
return "<%s for %s>" % (self.__class__.__name__,
775
1136
class BzrDirMeta1(BzrDir):
1706
2056
return to_convert
1709
class ConvertMetaToColo(controldir.Converter):
1710
"""Add colocated branch support."""
1712
def __init__(self, target_format):
1713
"""Create a converter.that upgrades a metadir to the colo format.
1715
:param target_format: The final metadir format that is desired.
1717
self.target_format = target_format
1719
def convert(self, to_convert, pb):
1720
"""See Converter.convert()."""
1721
to_convert.transport.put_bytes('branch-format',
1722
self.target_format.get_format_string())
1723
return BzrDir.open_from_transport(to_convert.root_transport)
1726
class ConvertMetaRemoveColo(controldir.Converter):
1727
"""Remove colocated branch support from a bzrdir."""
1729
def __init__(self, target_format):
1730
"""Create a converter.that downgrades a colocated branch metadir
1731
to a regular metadir.
1733
:param target_format: The final metadir format that is desired.
1735
self.target_format = target_format
1737
def convert(self, to_convert, pb):
1738
"""See Converter.convert()."""
1739
to_convert.control_files.lock_write()
1741
branches = to_convert.list_branches()
1742
if len(branches) > 1:
1743
raise errors.BzrError("remove all but a single "
1744
"colocated branch when downgrading")
1746
to_convert.control_files.unlock()
1747
to_convert.transport.put_bytes('branch-format',
1748
self.target_format.get_format_string())
1749
return BzrDir.open_from_transport(to_convert.root_transport)
1752
2059
controldir.ControlDirFormat.register_server_prober(RemoteBzrProber)