1
# Copyright (C) 2010, 2011, 2012 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""ControlDir is the basic control directory class.
19
The ControlDir class is the base for the control directory used
20
by all bzr and foreign formats. For the ".bzr" implementation,
21
see breezy.bzrdir.BzrDir.
25
from __future__ import absolute_import
27
from .lazy_import import lazy_import
28
lazy_import(globals(), """
32
branch as _mod_branch,
34
revision as _mod_revision,
35
transport as _mod_transport,
40
from breezy.transport import local
41
from breezy.push import (
45
from breezy.i18n import gettext
54
class MustHaveWorkingTree(errors.BzrError):
56
_fmt = "Branching '%(url)s'(%(format)s) must create a working tree."
58
def __init__(self, format, url):
59
errors.BzrError.__init__(self, format=format, url=url)
62
class ControlComponent(object):
63
"""Abstract base class for control directory components.
65
This provides interfaces that are common across controldirs,
66
repositories, branches, and workingtree control directories.
68
They all expose two urls and transports: the *user* URL is the
69
one that stops above the control directory (eg .bzr) and that
70
should normally be used in messages, and the *control* URL is
71
under that in eg .bzr/checkout and is used to read the control
74
This can be used as a mixin and is intended to fit with
79
def control_transport(self):
80
raise NotImplementedError
83
def control_url(self):
84
return self.control_transport.base
87
def user_transport(self):
88
raise NotImplementedError
92
return self.user_transport.base
95
class ControlDir(ControlComponent):
96
"""A control directory.
98
While this represents a generic control directory, there are a few
99
features that are present in this interface that are currently only
100
supported by one of its implementations, BzrDir.
102
These features (bound branches, stacked branches) are currently only
103
supported by Bazaar, but could be supported by other version control
104
systems as well. Implementations are required to raise the appropriate
105
exceptions when an operation is requested that is not supported.
107
This also makes life easier for API users who can rely on the
108
implementation always allowing a particular feature to be requested but
109
raising an exception when it is not supported, rather than requiring the
110
API users to check for magic attributes to see what features are supported.
113
def can_convert_format(self):
114
"""Return true if this controldir is one whose format we can convert
118
def list_branches(self):
119
"""Return a sequence of all branches local to this control directory.
122
return list(self.get_branches().values())
124
def get_branches(self):
125
"""Get all branches in this control directory, as a dictionary.
127
:return: Dictionary mapping branch names to instances.
130
return { "": self.open_branch() }
131
except (errors.NotBranchError, errors.NoRepositoryPresent):
134
def is_control_filename(self, filename):
135
"""True if filename is the name of a path which is reserved for
138
:param filename: A filename within the root transport of this
141
This is true IF and ONLY IF the filename is part of the namespace reserved
142
for bzr control dirs. Currently this is the '.bzr' directory in the root
143
of the root_transport. it is expected that plugins will need to extend
144
this in the future - for instance to make bzr talk with svn working
147
raise NotImplementedError(self.is_control_filename)
149
def needs_format_conversion(self, format=None):
150
"""Return true if this controldir needs convert_format run on it.
152
For instance, if the repository format is out of date but the
153
branch and working tree are not, this should return True.
155
:param format: Optional parameter indicating a specific desired
156
format we plan to arrive at.
158
raise NotImplementedError(self.needs_format_conversion)
160
def create_repository(self, shared=False):
161
"""Create a new repository in this control directory.
163
:param shared: If a shared repository should be created
164
:return: The newly created repository
166
raise NotImplementedError(self.create_repository)
168
def destroy_repository(self):
169
"""Destroy the repository in this ControlDir."""
170
raise NotImplementedError(self.destroy_repository)
172
def create_branch(self, name=None, repository=None,
173
append_revisions_only=None):
174
"""Create a branch in this ControlDir.
176
:param name: Name of the colocated branch to create, None for
177
the user selected branch or "" for the active branch.
178
:param append_revisions_only: Whether this branch should only allow
179
appending new revisions to its history.
181
The controldirs format will control what branch format is created.
182
For more control see BranchFormatXX.create(a_controldir).
184
raise NotImplementedError(self.create_branch)
186
def destroy_branch(self, name=None):
187
"""Destroy a branch in this ControlDir.
189
:param name: Name of the branch to destroy, None for the
190
user selected branch or "" for the active branch.
191
:raise NotBranchError: When the branch does not exist
193
raise NotImplementedError(self.destroy_branch)
195
def create_workingtree(self, revision_id=None, from_branch=None,
196
accelerator_tree=None, hardlink=False):
197
"""Create a working tree at this ControlDir.
199
:param revision_id: create it as of this revision id.
200
:param from_branch: override controldir branch
201
(for lightweight checkouts)
202
:param accelerator_tree: A tree which can be used for retrieving file
203
contents more quickly than the revision tree, i.e. a workingtree.
204
The revision tree will be used for cases where accelerator_tree's
205
content is different.
207
raise NotImplementedError(self.create_workingtree)
209
def destroy_workingtree(self):
210
"""Destroy the working tree at this ControlDir.
212
Formats that do not support this may raise UnsupportedOperation.
214
raise NotImplementedError(self.destroy_workingtree)
216
def destroy_workingtree_metadata(self):
217
"""Destroy the control files for the working tree at this ControlDir.
219
The contents of working tree files are not affected.
220
Formats that do not support this may raise UnsupportedOperation.
222
raise NotImplementedError(self.destroy_workingtree_metadata)
224
def find_branch_format(self, name=None):
225
"""Find the branch 'format' for this controldir.
227
This might be a synthetic object for e.g. RemoteBranch and SVN.
229
raise NotImplementedError(self.find_branch_format)
231
def get_branch_reference(self, name=None):
232
"""Return the referenced URL for the branch in this controldir.
234
:param name: Optional colocated branch name
235
:raises NotBranchError: If there is no Branch.
236
:raises NoColocatedBranchSupport: If a branch name was specified
237
but colocated branches are not supported.
238
:return: The URL the branch in this controldir references if it is a
239
reference branch, or None for regular branches.
242
raise errors.NoColocatedBranchSupport(self)
245
def set_branch_reference(self, target_branch, name=None):
246
"""Set the referenced URL for the branch in this controldir.
248
:param name: Optional colocated branch name
249
:param target_branch: Branch to reference
250
:raises NoColocatedBranchSupport: If a branch name was specified
251
but colocated branches are not supported.
252
:return: The referencing branch
254
raise NotImplementedError(self.set_branch_reference)
256
def open_branch(self, name=None, unsupported=False,
257
ignore_fallbacks=False, possible_transports=None):
258
"""Open the branch object at this ControlDir if one is present.
260
:param unsupported: if True, then no longer supported branch formats can
262
:param ignore_fallbacks: Whether to open fallback repositories
263
:param possible_transports: Transports to use for opening e.g.
264
fallback repositories.
266
raise NotImplementedError(self.open_branch)
268
def open_repository(self, _unsupported=False):
269
"""Open the repository object at this ControlDir if one is present.
271
This will not follow the Branch object pointer - it's strictly a direct
272
open facility. Most client code should use open_branch().repository to
275
:param _unsupported: a private parameter, not part of the api.
277
raise NotImplementedError(self.open_repository)
279
def find_repository(self):
280
"""Find the repository that should be used.
282
This does not require a branch as we use it to find the repo for
283
new branches as well as to hook existing branches up to their
286
raise NotImplementedError(self.find_repository)
288
def open_workingtree(self, unsupported=False,
289
recommend_upgrade=True, from_branch=None):
290
"""Open the workingtree object at this ControlDir if one is present.
292
:param recommend_upgrade: Optional keyword parameter, when True (the
293
default), emit through the ui module a recommendation that the user
294
upgrade the working tree when the workingtree being opened is old
295
(but still fully supported).
296
:param from_branch: override controldir branch (for lightweight
299
raise NotImplementedError(self.open_workingtree)
301
def has_branch(self, name=None):
302
"""Tell if this controldir contains a branch.
304
Note: if you're going to open the branch, you should just go ahead
305
and try, and not ask permission first. (This method just opens the
306
branch and discards it, and that's somewhat expensive.)
309
self.open_branch(name, ignore_fallbacks=True)
311
except errors.NotBranchError:
314
def _get_selected_branch(self):
315
"""Return the name of the branch selected by the user.
317
:return: Name of the branch selected by the user, or "".
319
branch = self.root_transport.get_segment_parameters().get("branch")
322
return urlutils.unescape(branch)
324
def has_workingtree(self):
325
"""Tell if this controldir contains a working tree.
327
This will still raise an exception if the controldir has a workingtree
328
that is remote & inaccessible.
330
Note: if you're going to open the working tree, you should just go ahead
331
and try, and not ask permission first. (This method just opens the
332
workingtree and discards it, and that's somewhat expensive.)
335
self.open_workingtree(recommend_upgrade=False)
337
except errors.NoWorkingTree:
340
def cloning_metadir(self, require_stacking=False):
341
"""Produce a metadir suitable for cloning or sprouting with.
343
These operations may produce workingtrees (yes, even though they're
344
"cloning" something that doesn't have a tree), so a viable workingtree
345
format must be selected.
347
:require_stacking: If True, non-stackable formats will be upgraded
348
to similar stackable formats.
349
:returns: a ControlDirFormat with all component formats either set
350
appropriately or set to None if that component should not be
353
raise NotImplementedError(self.cloning_metadir)
355
def checkout_metadir(self):
356
"""Produce a metadir suitable for checkouts of this controldir.
358
:returns: A ControlDirFormat with all component formats
359
either set appropriately or set to None if that component
360
should not be created.
362
return self.cloning_metadir()
364
def sprout(self, url, revision_id=None, force_new_repo=False,
365
recurse='down', possible_transports=None,
366
accelerator_tree=None, hardlink=False, stacked=False,
367
source_branch=None, create_tree_if_local=True):
368
"""Create a copy of this controldir prepared for use as a new line of
371
If url's last component does not exist, it will be created.
373
Attributes related to the identity of the source branch like
374
branch nickname will be cleaned, a working tree is created
375
whether one existed before or not; and a local branch is always
378
:param revision_id: if revision_id is not None, then the clone
379
operation may tune itself to download less data.
380
:param accelerator_tree: A tree which can be used for retrieving file
381
contents more quickly than the revision tree, i.e. a workingtree.
382
The revision tree will be used for cases where accelerator_tree's
383
content is different.
384
:param hardlink: If true, hard-link files from accelerator_tree,
386
:param stacked: If true, create a stacked branch referring to the
387
location of this control directory.
388
:param create_tree_if_local: If true, a working-tree will be created
389
when working locally.
391
raise NotImplementedError(self.sprout)
393
def push_branch(self, source, revision_id=None, overwrite=False,
394
remember=False, create_prefix=False):
395
"""Push the source branch into this ControlDir."""
397
# If we can open a branch, use its direct repository, otherwise see
398
# if there is a repository without a branch.
400
br_to = self.open_branch()
401
except errors.NotBranchError:
402
# Didn't find a branch, can we find a repository?
403
repository_to = self.find_repository()
405
# Found a branch, so we must have found a repository
406
repository_to = br_to.repository
408
push_result = PushResult()
409
push_result.source_branch = source
411
# We have a repository but no branch, copy the revisions, and then
413
if revision_id is None:
414
# No revision supplied by the user, default to the branch
416
revision_id = source.last_revision()
417
repository_to.fetch(source.repository, revision_id=revision_id)
418
br_to = source.clone(self, revision_id=revision_id)
419
if source.get_push_location() is None or remember:
420
# FIXME: Should be done only if we succeed ? -- vila 2012-01-18
421
source.set_push_location(br_to.base)
422
push_result.stacked_on = None
423
push_result.branch_push_result = None
424
push_result.old_revno = None
425
push_result.old_revid = _mod_revision.NULL_REVISION
426
push_result.target_branch = br_to
427
push_result.master_branch = None
428
push_result.workingtree_updated = False
430
# We have successfully opened the branch, remember if necessary:
431
if source.get_push_location() is None or remember:
432
# FIXME: Should be done only if we succeed ? -- vila 2012-01-18
433
source.set_push_location(br_to.base)
435
tree_to = self.open_workingtree()
436
except errors.NotLocalUrl:
437
push_result.branch_push_result = source.push(br_to,
438
overwrite, stop_revision=revision_id)
439
push_result.workingtree_updated = False
440
except errors.NoWorkingTree:
441
push_result.branch_push_result = source.push(br_to,
442
overwrite, stop_revision=revision_id)
443
push_result.workingtree_updated = None # Not applicable
447
push_result.branch_push_result = source.push(
448
tree_to.branch, overwrite, stop_revision=revision_id)
452
push_result.workingtree_updated = True
453
push_result.old_revno = push_result.branch_push_result.old_revno
454
push_result.old_revid = push_result.branch_push_result.old_revid
455
push_result.target_branch = \
456
push_result.branch_push_result.target_branch
459
def _get_tree_branch(self, name=None):
460
"""Return the branch and tree, if any, for this controldir.
462
:param name: Name of colocated branch to open.
464
Return None for tree if not present or inaccessible.
465
Raise NotBranchError if no branch is present.
466
:return: (tree, branch)
469
tree = self.open_workingtree()
470
except (errors.NoWorkingTree, errors.NotLocalUrl):
472
branch = self.open_branch(name=name)
475
branch = self.open_branch(name=name)
480
def get_config(self):
481
"""Get configuration for this ControlDir."""
482
raise NotImplementedError(self.get_config)
484
def check_conversion_target(self, target_format):
485
"""Check that a controldir as a whole can be converted to a new format."""
486
raise NotImplementedError(self.check_conversion_target)
488
def clone(self, url, revision_id=None, force_new_repo=False,
489
preserve_stacking=False):
490
"""Clone this controldir and its contents to url verbatim.
492
:param url: The url create the clone at. If url's last component does
493
not exist, it will be created.
494
:param revision_id: The tip revision-id to use for any branch or
495
working tree. If not None, then the clone operation may tune
496
itself to download less data.
497
:param force_new_repo: Do not use a shared repository for the target
498
even if one is available.
499
:param preserve_stacking: When cloning a stacked branch, stack the
500
new branch on top of the other branch's stacked-on branch.
502
return self.clone_on_transport(_mod_transport.get_transport(url),
503
revision_id=revision_id,
504
force_new_repo=force_new_repo,
505
preserve_stacking=preserve_stacking)
507
def clone_on_transport(self, transport, revision_id=None,
508
force_new_repo=False, preserve_stacking=False, stacked_on=None,
509
create_prefix=False, use_existing_dir=True, no_tree=False):
510
"""Clone this controldir and its contents to transport verbatim.
512
:param transport: The transport for the location to produce the clone
513
at. If the target directory does not exist, it will be created.
514
:param revision_id: The tip revision-id to use for any branch or
515
working tree. If not None, then the clone operation may tune
516
itself to download less data.
517
:param force_new_repo: Do not use a shared repository for the target,
518
even if one is available.
519
:param preserve_stacking: When cloning a stacked branch, stack the
520
new branch on top of the other branch's stacked-on branch.
521
:param create_prefix: Create any missing directories leading up to
523
:param use_existing_dir: Use an existing directory if one exists.
524
:param no_tree: If set to true prevents creation of a working tree.
526
raise NotImplementedError(self.clone_on_transport)
529
def find_controldirs(klass, transport, evaluate=None, list_current=None):
530
"""Find control dirs recursively from current location.
532
This is intended primarily as a building block for more sophisticated
533
functionality, like finding trees under a directory, or finding
534
branches that use a given repository.
536
:param evaluate: An optional callable that yields recurse, value,
537
where recurse controls whether this controldir is recursed into
538
and value is the value to yield. By default, all bzrdirs
539
are recursed into, and the return value is the controldir.
540
:param list_current: if supplied, use this function to list the current
541
directory, instead of Transport.list_dir
542
:return: a generator of found bzrdirs, or whatever evaluate returns.
544
if list_current is None:
545
def list_current(transport):
546
return transport.list_dir('')
548
def evaluate(controldir):
549
return True, controldir
551
pending = [transport]
552
while len(pending) > 0:
553
current_transport = pending.pop()
556
controldir = klass.open_from_transport(current_transport)
557
except (errors.NotBranchError, errors.PermissionDenied):
560
recurse, value = evaluate(controldir)
563
subdirs = list_current(current_transport)
564
except (errors.NoSuchFile, errors.PermissionDenied):
567
for subdir in sorted(subdirs, reverse=True):
568
pending.append(current_transport.clone(subdir))
571
def find_branches(klass, transport):
572
"""Find all branches under a transport.
574
This will find all branches below the transport, including branches
575
inside other branches. Where possible, it will use
576
Repository.find_branches.
578
To list all the branches that use a particular Repository, see
579
Repository.find_branches
581
def evaluate(controldir):
583
repository = controldir.open_repository()
584
except errors.NoRepositoryPresent:
587
return False, ([], repository)
588
return True, (controldir.list_branches(), None)
590
for branches, repo in klass.find_controldirs(
591
transport, evaluate=evaluate):
593
ret.extend(repo.find_branches())
594
if branches is not None:
599
def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
600
"""Create a new ControlDir, Branch and Repository at the url 'base'.
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
608
The created Branch object is returned.
610
:param base: The URL to create the branch at.
611
:param force_new_repo: If True a new repository is always created.
612
:param format: If supplied, the format of branch to create. If not
613
supplied, the default is used.
615
controldir = klass.create(base, format)
616
controldir._find_or_create_repository(force_new_repo)
617
return controldir.create_branch()
620
def create_branch_convenience(klass, base, force_new_repo=False,
621
force_new_tree=None, format=None,
622
possible_transports=None):
623
"""Create a new ControlDir, Branch and Repository at the url 'base'.
625
This is a convenience function - it will use an existing repository
626
if possible, can be told explicitly whether to create a working tree or
629
This will use the current default ControlDirFormat unless one is
630
specified, and use whatever
631
repository format that that uses via ControlDir.create_branch and
632
create_repository. If a shared repository is available that is used
633
preferentially. Whatever repository is used, its tree creation policy
636
The created Branch object is returned.
637
If a working tree cannot be made due to base not being a file:// url,
638
no error is raised unless force_new_tree is True, in which case no
639
data is created on disk and NotLocalUrl is raised.
641
:param base: The URL to create the branch at.
642
:param force_new_repo: If True a new repository is always created.
643
:param force_new_tree: If True or False force creation of a tree or
644
prevent such creation respectively.
645
:param format: Override for the controldir format to create.
646
:param possible_transports: An optional reusable transports list.
649
# check for non local urls
650
t = _mod_transport.get_transport(base, possible_transports)
651
if not isinstance(t, local.LocalTransport):
652
raise errors.NotLocalUrl(base)
653
controldir = klass.create(base, format, possible_transports)
654
repo = controldir._find_or_create_repository(force_new_repo)
655
result = controldir.create_branch()
656
if force_new_tree or (repo.make_working_trees() and
657
force_new_tree is None):
659
controldir.create_workingtree()
660
except errors.NotLocalUrl:
665
def create_standalone_workingtree(klass, base, format=None):
666
"""Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
668
'base' must be a local path or a file:// url.
670
This will use the current default ControlDirFormat unless one is
671
specified, and use whatever
672
repository format that that uses for bzrdirformat.create_workingtree,
673
create_branch and create_repository.
675
:param format: Override for the controldir format to create.
676
:return: The WorkingTree object.
678
t = _mod_transport.get_transport(base)
679
if not isinstance(t, local.LocalTransport):
680
raise errors.NotLocalUrl(base)
681
controldir = klass.create_branch_and_repo(base,
683
format=format).controldir
684
return controldir.create_workingtree()
687
def open_unsupported(klass, base):
688
"""Open a branch which is not supported."""
689
return klass.open(base, _unsupported=True)
692
def open(klass, base, possible_transports=None, probers=None,
694
"""Open an existing controldir, rooted at 'base' (url).
696
:param _unsupported: a private parameter to the ControlDir class.
698
t = _mod_transport.get_transport(base, possible_transports)
699
return klass.open_from_transport(t, probers=probers,
700
_unsupported=_unsupported)
703
def open_from_transport(klass, transport, _unsupported=False,
705
"""Open a controldir within a particular directory.
707
:param transport: Transport containing the controldir.
708
:param _unsupported: private.
710
for hook in klass.hooks['pre_open']:
712
# Keep initial base since 'transport' may be modified while following
714
base = transport.base
715
def find_format(transport):
716
return transport, ControlDirFormat.find_format(transport,
719
def redirected(transport, e, redirection_notice):
720
redirected_transport = transport._redirected_to(e.source, e.target)
721
if redirected_transport is None:
722
raise errors.NotBranchError(base)
723
trace.note(gettext('{0} is{1} redirected to {2}').format(
724
transport.base, e.permanently, redirected_transport.base))
725
return redirected_transport
728
transport, format = _mod_transport.do_catching_redirections(
729
find_format, transport, redirected)
730
except errors.TooManyRedirections:
731
raise errors.NotBranchError(base)
733
format.check_support_status(_unsupported)
734
return format.open(transport, _found=True)
737
def open_containing(klass, url, possible_transports=None):
738
"""Open an existing branch which contains url.
740
:param url: url to search from.
742
See open_containing_from_transport for more detail.
744
transport = _mod_transport.get_transport(url, possible_transports)
745
return klass.open_containing_from_transport(transport)
748
def open_containing_from_transport(klass, a_transport):
749
"""Open an existing branch which contains a_transport.base.
751
This probes for a branch at a_transport, and searches upwards from there.
753
Basically we keep looking up until we find the control directory or
754
run into the root. If there isn't one, raises NotBranchError.
755
If there is one and it is either an unrecognised format or an unsupported
756
format, UnknownFormatError or UnsupportedFormatError are raised.
757
If there is one, it is returned, along with the unused portion of url.
759
:return: The ControlDir that contains the path, and a Unicode path
760
for the rest of the URL.
762
# this gets the normalised url back. I.e. '.' -> the full path.
763
url = a_transport.base
766
result = klass.open_from_transport(a_transport)
767
return result, urlutils.unescape(a_transport.relpath(url))
768
except errors.NotBranchError as e:
770
except errors.PermissionDenied:
773
new_t = a_transport.clone('..')
774
except urlutils.InvalidURLJoin:
775
# reached the root, whatever that may be
776
raise errors.NotBranchError(path=url)
777
if new_t.base == a_transport.base:
778
# reached the root, whatever that may be
779
raise errors.NotBranchError(path=url)
783
def open_tree_or_branch(klass, location):
784
"""Return the branch and working tree at a location.
786
If there is no tree at the location, tree will be None.
787
If there is no branch at the location, an exception will be
789
:return: (tree, branch)
791
controldir = klass.open(location)
792
return controldir._get_tree_branch()
795
def open_containing_tree_or_branch(klass, location,
796
possible_transports=None):
797
"""Return the branch and working tree contained by a location.
799
Returns (tree, branch, relpath).
800
If there is no tree at containing the location, tree will be None.
801
If there is no branch containing the location, an exception will be
803
relpath is the portion of the path that is contained by the branch.
805
controldir, relpath = klass.open_containing(location,
806
possible_transports=possible_transports)
807
tree, branch = controldir._get_tree_branch()
808
return tree, branch, relpath
811
def open_containing_tree_branch_or_repository(klass, location):
812
"""Return the working tree, branch and repo contained by a location.
814
Returns (tree, branch, repository, relpath).
815
If there is no tree containing the location, tree will be None.
816
If there is no branch containing the location, branch will be None.
817
If there is no repository containing the location, repository will be
819
relpath is the portion of the path that is contained by the innermost
822
If no tree, branch or repository is found, a NotBranchError is raised.
824
controldir, relpath = klass.open_containing(location)
826
tree, branch = controldir._get_tree_branch()
827
except errors.NotBranchError:
829
repo = controldir.find_repository()
830
return None, None, repo, relpath
831
except (errors.NoRepositoryPresent):
832
raise errors.NotBranchError(location)
833
return tree, branch, branch.repository, relpath
836
def create(klass, base, format=None, possible_transports=None):
837
"""Create a new ControlDir at the url 'base'.
839
:param format: If supplied, the format of branch to create. If not
840
supplied, the default is used.
841
:param possible_transports: If supplied, a list of transports that
842
can be reused to share a remote connection.
844
if klass is not ControlDir:
845
raise AssertionError("ControlDir.create always creates the"
846
"default format, not one of %r" % klass)
847
t = _mod_transport.get_transport(base, possible_transports)
850
format = ControlDirFormat.get_default_format()
851
return format.initialize_on_transport(t)
854
class ControlDirHooks(hooks.Hooks):
855
"""Hooks for ControlDir operations."""
858
"""Create the default hooks."""
859
hooks.Hooks.__init__(self, "breezy.controldir", "ControlDir.hooks")
860
self.add_hook('pre_open',
861
"Invoked before attempting to open a ControlDir with the transport "
862
"that the open will use.", (1, 14))
863
self.add_hook('post_repo_init',
864
"Invoked after a repository has been initialized. "
865
"post_repo_init is called with a "
866
"breezy.controldir.RepoInitHookParams.",
869
# install the default hooks
870
ControlDir.hooks = ControlDirHooks()
873
class ControlComponentFormat(object):
874
"""A component that can live inside of a control directory."""
876
upgrade_recommended = False
878
def get_format_description(self):
879
"""Return the short description for this format."""
880
raise NotImplementedError(self.get_format_description)
882
def is_supported(self):
883
"""Is this format supported?
885
Supported formats must be initializable and openable.
886
Unsupported formats may not support initialization or committing or
887
some other features depending on the reason for not being supported.
891
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
893
"""Give an error or warning on old formats.
895
:param allow_unsupported: If true, allow opening
896
formats that are strongly deprecated, and which may
897
have limited functionality.
899
:param recommend_upgrade: If true (default), warn
900
the user through the ui object that they may wish
901
to upgrade the object.
903
if not allow_unsupported and not self.is_supported():
904
# see open_downlevel to open legacy branches.
905
raise errors.UnsupportedFormatError(format=self)
906
if recommend_upgrade and self.upgrade_recommended:
907
ui.ui_factory.recommend_upgrade(
908
self.get_format_description(), basedir)
911
def get_format_string(cls):
912
raise NotImplementedError(cls.get_format_string)
915
class ControlComponentFormatRegistry(registry.FormatRegistry):
916
"""A registry for control components (branch, workingtree, repository)."""
918
def __init__(self, other_registry=None):
919
super(ControlComponentFormatRegistry, self).__init__(other_registry)
920
self._extra_formats = []
922
def register(self, format):
923
"""Register a new format."""
924
super(ControlComponentFormatRegistry, self).register(
925
format.get_format_string(), format)
927
def remove(self, format):
928
"""Remove a registered format."""
929
super(ControlComponentFormatRegistry, self).remove(
930
format.get_format_string())
932
def register_extra(self, format):
933
"""Register a format that can not be used in a metadir.
935
This is mainly useful to allow custom repository formats, such as older
936
Bazaar formats and foreign formats, to be tested.
938
self._extra_formats.append(registry._ObjectGetter(format))
940
def remove_extra(self, format):
941
"""Remove an extra format.
943
self._extra_formats.remove(registry._ObjectGetter(format))
945
def register_extra_lazy(self, module_name, member_name):
946
"""Register a format lazily.
948
self._extra_formats.append(
949
registry._LazyObjectGetter(module_name, member_name))
951
def _get_extra(self):
952
"""Return all "extra" formats, not usable in meta directories."""
954
for getter in self._extra_formats:
962
"""Return all formats, even those not usable in metadirs.
965
for name in self.keys():
970
return result + self._get_extra()
972
def _get_all_modules(self):
973
"""Return a set of the modules providing objects."""
975
for name in self.keys():
976
modules.add(self._get_module(name))
977
for getter in self._extra_formats:
978
modules.add(getter.get_module())
982
class Converter(object):
983
"""Converts a disk format object from one format to another."""
985
def convert(self, to_convert, pb):
986
"""Perform the conversion of to_convert, giving feedback via pb.
988
:param to_convert: The disk object to convert.
989
:param pb: a progress bar to use for progress information.
992
def step(self, message):
993
"""Update the pb by a step."""
995
self.pb.update(message, self.count, self.total)
998
class ControlDirFormat(object):
999
"""An encapsulation of the initialization and open routines for a format.
1001
Formats provide three things:
1002
* An initialization routine,
1006
Formats are placed in a dict by their format string for reference
1007
during controldir opening. These should be subclasses of ControlDirFormat
1010
Once a format is deprecated, just deprecate the initialize and open
1011
methods on the format class. Do not deprecate the object, as the
1012
object will be created every system load.
1014
:cvar colocated_branches: Whether this formats supports colocated branches.
1015
:cvar supports_workingtrees: This control directory can co-exist with a
1019
_default_format = None
1020
"""The default format used for new control directories."""
1022
_server_probers = []
1023
"""The registered server format probers, e.g. RemoteBzrProber.
1025
This is a list of Prober-derived classes.
1029
"""The registered format probers, e.g. BzrProber.
1031
This is a list of Prober-derived classes.
1034
colocated_branches = False
1035
"""Whether co-located branches are supported for this control dir format.
1038
supports_workingtrees = True
1039
"""Whether working trees can exist in control directories of this format.
1042
fixed_components = False
1043
"""Whether components can not change format independent of the control dir.
1046
upgrade_recommended = False
1047
"""Whether an upgrade from this format is recommended."""
1049
def get_format_description(self):
1050
"""Return the short description for this format."""
1051
raise NotImplementedError(self.get_format_description)
1053
def get_converter(self, format=None):
1054
"""Return the converter to use to convert controldirs needing converts.
1056
This returns a breezy.controldir.Converter object.
1058
This should return the best upgrader to step this format towards the
1059
current default format. In the case of plugins we can/should provide
1060
some means for them to extend the range of returnable converters.
1062
:param format: Optional format to override the default format of the
1065
raise NotImplementedError(self.get_converter)
1067
def is_supported(self):
1068
"""Is this format supported?
1070
Supported formats must be openable.
1071
Unsupported formats may not support initialization or committing or
1072
some other features depending on the reason for not being supported.
1076
def is_initializable(self):
1077
"""Whether new control directories of this format can be initialized.
1079
return self.is_supported()
1081
def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1083
"""Give an error or warning on old formats.
1085
:param allow_unsupported: If true, allow opening
1086
formats that are strongly deprecated, and which may
1087
have limited functionality.
1089
:param recommend_upgrade: If true (default), warn
1090
the user through the ui object that they may wish
1091
to upgrade the object.
1093
if not allow_unsupported and not self.is_supported():
1094
# see open_downlevel to open legacy branches.
1095
raise errors.UnsupportedFormatError(format=self)
1096
if recommend_upgrade and self.upgrade_recommended:
1097
ui.ui_factory.recommend_upgrade(
1098
self.get_format_description(), basedir)
1100
def same_model(self, target_format):
1101
return (self.repository_format.rich_root_data ==
1102
target_format.rich_root_data)
1105
def register_prober(klass, prober):
1106
"""Register a prober that can look for a control dir.
1109
klass._probers.append(prober)
1112
def unregister_prober(klass, prober):
1113
"""Unregister a prober.
1116
klass._probers.remove(prober)
1119
def register_server_prober(klass, prober):
1120
"""Register a control format prober for client-server environments.
1122
These probers will be used before ones registered with
1123
register_prober. This gives implementations that decide to the
1124
chance to grab it before anything looks at the contents of the format
1127
klass._server_probers.append(prober)
1131
return self.get_format_description().rstrip()
1134
def all_probers(klass):
1135
return klass._server_probers + klass._probers
1138
def known_formats(klass):
1139
"""Return all the known formats.
1142
for prober_kls in klass.all_probers():
1143
result.update(prober_kls.known_formats())
1147
def find_format(klass, transport, probers=None):
1148
"""Return the format present at transport."""
1150
probers = klass.all_probers()
1151
for prober_kls in probers:
1152
prober = prober_kls()
1154
return prober.probe_transport(transport)
1155
except errors.NotBranchError:
1156
# this format does not find a control dir here.
1158
raise errors.NotBranchError(path=transport.base)
1160
def initialize(self, url, possible_transports=None):
1161
"""Create a control dir at this url and return an opened copy.
1163
While not deprecated, this method is very specific and its use will
1164
lead to many round trips to setup a working environment. See
1165
initialize_on_transport_ex for a [nearly] all-in-one method.
1167
Subclasses should typically override initialize_on_transport
1168
instead of this method.
1170
return self.initialize_on_transport(
1171
_mod_transport.get_transport(url, possible_transports))
1173
def initialize_on_transport(self, transport):
1174
"""Initialize a new controldir in the base directory of a Transport."""
1175
raise NotImplementedError(self.initialize_on_transport)
1177
def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1178
create_prefix=False, force_new_repo=False, stacked_on=None,
1179
stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1180
shared_repo=False, vfs_only=False):
1181
"""Create this format on transport.
1183
The directory to initialize will be created.
1185
:param force_new_repo: Do not use a shared repository for the target,
1186
even if one is available.
1187
:param create_prefix: Create any missing directories leading up to
1189
:param use_existing_dir: Use an existing directory if one exists.
1190
:param stacked_on: A url to stack any created branch on, None to follow
1191
any target stacking policy.
1192
:param stack_on_pwd: If stack_on is relative, the location it is
1194
:param repo_format_name: If non-None, a repository will be
1195
made-or-found. Should none be found, or if force_new_repo is True
1196
the repo_format_name is used to select the format of repository to
1198
:param make_working_trees: Control the setting of make_working_trees
1199
for a new shared repository when one is made. None to use whatever
1200
default the format has.
1201
:param shared_repo: Control whether made repositories are shared or
1203
:param vfs_only: If True do not attempt to use a smart server
1204
:return: repo, controldir, require_stacking, repository_policy. repo is
1205
None if none was created or found, controldir is always valid.
1206
require_stacking is the result of examining the stacked_on
1207
parameter and any stacking policy found for the target.
1209
raise NotImplementedError(self.initialize_on_transport_ex)
1211
def network_name(self):
1212
"""A simple byte string uniquely identifying this format for RPC calls.
1214
Bzr control formats use this disk format string to identify the format
1215
over the wire. Its possible that other control formats have more
1216
complex detection requirements, so we permit them to use any unique and
1217
immutable string they desire.
1219
raise NotImplementedError(self.network_name)
1221
def open(self, transport, _found=False):
1222
"""Return an instance of this format for the dir transport points at.
1224
raise NotImplementedError(self.open)
1227
def _set_default_format(klass, format):
1228
"""Set default format (for testing behavior of defaults only)"""
1229
klass._default_format = format
1232
def get_default_format(klass):
1233
"""Return the current default format."""
1234
return klass._default_format
1236
def supports_transport(self, transport):
1237
"""Check if this format can be opened over a particular transport.
1239
raise NotImplementedError(self.supports_transport)
1242
class Prober(object):
1243
"""Abstract class that can be used to detect a particular kind of
1246
At the moment this just contains a single method to probe a particular
1247
transport, but it may be extended in the future to e.g. avoid
1248
multiple levels of probing for Subversion repositories.
1250
See BzrProber and RemoteBzrProber in breezy.bzrdir for the
1251
probers that detect .bzr/ directories and Bazaar smart servers,
1254
Probers should be registered using the register_server_prober or
1255
register_prober methods on ControlDirFormat.
1258
def probe_transport(self, transport):
1259
"""Return the controldir style format present in a directory.
1261
:raise UnknownFormatError: If a control dir was found but is
1262
in an unknown format.
1263
:raise NotBranchError: If no control directory was found.
1264
:return: A ControlDirFormat instance.
1266
raise NotImplementedError(self.probe_transport)
1269
def known_formats(klass):
1270
"""Return the control dir formats known by this prober.
1272
Multiple probers can return the same formats, so this should
1275
:return: A set of known formats.
1277
raise NotImplementedError(klass.known_formats)
1280
class ControlDirFormatInfo(object):
1282
def __init__(self, native, deprecated, hidden, experimental):
1283
self.deprecated = deprecated
1284
self.native = native
1285
self.hidden = hidden
1286
self.experimental = experimental
1289
class ControlDirFormatRegistry(registry.Registry):
1290
"""Registry of user-selectable ControlDir subformats.
1292
Differs from ControlDirFormat._formats in that it provides sub-formats,
1293
e.g. BzrDirMeta1 with weave repository. Also, it's more user-oriented.
1297
"""Create a ControlDirFormatRegistry."""
1298
self._aliases = set()
1299
self._registration_order = list()
1300
super(ControlDirFormatRegistry, self).__init__()
1303
"""Return a set of the format names which are aliases."""
1304
return frozenset(self._aliases)
1306
def register(self, key, factory, help, native=True, deprecated=False,
1307
hidden=False, experimental=False, alias=False):
1308
"""Register a ControlDirFormat factory.
1310
The factory must be a callable that takes one parameter: the key.
1311
It must produce an instance of the ControlDirFormat when called.
1313
This function mainly exists to prevent the info object from being
1316
registry.Registry.register(self, key, factory, help,
1317
ControlDirFormatInfo(native, deprecated, hidden, experimental))
1319
self._aliases.add(key)
1320
self._registration_order.append(key)
1322
def register_lazy(self, key, module_name, member_name, help, native=True,
1323
deprecated=False, hidden=False, experimental=False, alias=False):
1324
registry.Registry.register_lazy(self, key, module_name, member_name,
1325
help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
1327
self._aliases.add(key)
1328
self._registration_order.append(key)
1330
def set_default(self, key):
1331
"""Set the 'default' key to be a clone of the supplied key.
1333
This method must be called once and only once.
1335
registry.Registry.register(self, 'default', self.get(key),
1336
self.get_help(key), info=self.get_info(key))
1337
self._aliases.add('default')
1339
def set_default_repository(self, key):
1340
"""Set the FormatRegistry default and Repository default.
1342
This is a transitional method while Repository.set_default_format
1345
if 'default' in self:
1346
self.remove('default')
1347
self.set_default(key)
1348
format = self.get('default')()
1350
def make_controldir(self, key):
1351
return self.get(key)()
1353
def help_topic(self, topic):
1355
default_realkey = None
1356
default_help = self.get_help('default')
1358
for key in self._registration_order:
1359
if key == 'default':
1361
help = self.get_help(key)
1362
if help == default_help:
1363
default_realkey = key
1365
help_pairs.append((key, help))
1367
def wrapped(key, help, info):
1369
help = '(native) ' + help
1370
return ':%s:\n%s\n\n' % (key,
1371
textwrap.fill(help, initial_indent=' ',
1372
subsequent_indent=' ',
1373
break_long_words=False))
1374
if default_realkey is not None:
1375
output += wrapped(default_realkey, '(default) %s' % default_help,
1376
self.get_info('default'))
1377
deprecated_pairs = []
1378
experimental_pairs = []
1379
for key, help in help_pairs:
1380
info = self.get_info(key)
1383
elif info.deprecated:
1384
deprecated_pairs.append((key, help))
1385
elif info.experimental:
1386
experimental_pairs.append((key, help))
1388
output += wrapped(key, help, info)
1389
output += "\nSee :doc:`formats-help` for more about storage formats."
1391
if len(experimental_pairs) > 0:
1392
other_output += "Experimental formats are shown below.\n\n"
1393
for key, help in experimental_pairs:
1394
info = self.get_info(key)
1395
other_output += wrapped(key, help, info)
1398
"No experimental formats are available.\n\n"
1399
if len(deprecated_pairs) > 0:
1400
other_output += "\nDeprecated formats are shown below.\n\n"
1401
for key, help in deprecated_pairs:
1402
info = self.get_info(key)
1403
other_output += wrapped(key, help, info)
1406
"\nNo deprecated formats are available.\n\n"
1408
"\nSee :doc:`formats-help` for more about storage formats."
1410
if topic == 'other-formats':
1416
class RepoInitHookParams(object):
1417
"""Object holding parameters passed to `*_repo_init` hooks.
1419
There are 4 fields that hooks may wish to access:
1421
:ivar repository: Repository created
1422
:ivar format: Repository format
1423
:ivar bzrdir: The controldir for the repository
1424
:ivar shared: The repository is shared
1427
def __init__(self, repository, format, controldir, shared):
1428
"""Create a group of RepoInitHook parameters.
1430
:param repository: Repository created
1431
:param format: Repository format
1432
:param controldir: The controldir for the repository
1433
:param shared: The repository is shared
1435
self.repository = repository
1436
self.format = format
1437
self.controldir = controldir
1438
self.shared = shared
1440
def __eq__(self, other):
1441
return self.__dict__ == other.__dict__
1445
return "<%s for %s>" % (self.__class__.__name__,
1448
return "<%s for %s>" % (self.__class__.__name__,
1452
def is_control_filename(filename):
1453
"""Check if filename is used for control directories."""
1454
# TODO(jelmer): Allow registration by other VCSes
1455
return filename == '.bzr'
1458
class RepositoryAcquisitionPolicy(object):
1459
"""Abstract base class for repository acquisition policies.
1461
A repository acquisition policy decides how a ControlDir acquires a repository
1462
for a branch that is being created. The most basic policy decision is
1463
whether to create a new repository or use an existing one.
1465
def __init__(self, stack_on, stack_on_pwd, require_stacking):
1468
:param stack_on: A location to stack on
1469
:param stack_on_pwd: If stack_on is relative, the location it is
1471
:param require_stacking: If True, it is a failure to not stack.
1473
self._stack_on = stack_on
1474
self._stack_on_pwd = stack_on_pwd
1475
self._require_stacking = require_stacking
1477
def configure_branch(self, branch):
1478
"""Apply any configuration data from this policy to the branch.
1480
Default implementation sets repository stacking.
1482
if self._stack_on is None:
1484
if self._stack_on_pwd is None:
1485
stack_on = self._stack_on
1488
stack_on = urlutils.rebase_url(self._stack_on,
1491
except urlutils.InvalidRebaseURLs:
1492
stack_on = self._get_full_stack_on()
1494
branch.set_stacked_on_url(stack_on)
1495
except (_mod_branch.UnstackableBranchFormat,
1496
errors.UnstackableRepositoryFormat):
1497
if self._require_stacking:
1500
def requires_stacking(self):
1501
"""Return True if this policy requires stacking."""
1502
return self._stack_on is not None and self._require_stacking
1504
def _get_full_stack_on(self):
1505
"""Get a fully-qualified URL for the stack_on location."""
1506
if self._stack_on is None:
1508
if self._stack_on_pwd is None:
1509
return self._stack_on
1511
return urlutils.join(self._stack_on_pwd, self._stack_on)
1513
def _add_fallback(self, repository, possible_transports=None):
1514
"""Add a fallback to the supplied repository, if stacking is set."""
1515
stack_on = self._get_full_stack_on()
1516
if stack_on is None:
1519
stacked_dir = ControlDir.open(
1520
stack_on, possible_transports=possible_transports)
1521
except errors.JailBreak:
1522
# We keep the stacking details, but we are in the server code so
1523
# actually stacking is not needed.
1526
stacked_repo = stacked_dir.open_branch().repository
1527
except errors.NotBranchError:
1528
stacked_repo = stacked_dir.open_repository()
1530
repository.add_fallback_repository(stacked_repo)
1531
except errors.UnstackableRepositoryFormat:
1532
if self._require_stacking:
1535
self._require_stacking = True
1537
def acquire_repository(self, make_working_trees=None, shared=False,
1538
possible_transports=None):
1539
"""Acquire a repository for this controlrdir.
1541
Implementations may create a new repository or use a pre-exising
1544
:param make_working_trees: If creating a repository, set
1545
make_working_trees to this value (if non-None)
1546
:param shared: If creating a repository, make it shared if True
1547
:return: A repository, is_new_flag (True if the repository was
1550
raise NotImplementedError(RepositoryAcquisitionPolicy.acquire_repository)
1553
# Please register new formats after old formats so that formats
1554
# appear in chronological order and format descriptions can build
1556
format_registry = ControlDirFormatRegistry()
1558
network_format_registry = registry.FormatRegistry()
1559
"""Registry of formats indexed by their network name.
1561
The network name for a ControlDirFormat is an identifier that can be used when
1562
referring to formats with smart server operations. See
1563
ControlDirFormat.network_name() for more detail.