/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/controldir.py

  • Committer: Jelmer Vernooij
  • Date: 2020-02-18 01:57:45 UTC
  • mto: This revision was merged to the branch mainline in revision 7493.
  • Revision ID: jelmer@jelmer.uk-20200218015745-q2ss9tsk74h4nh61
drop use of future.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2010, 2011, 2012 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
"""ControlDir is the basic control directory class.
 
18
 
 
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.
 
22
 
 
23
"""
 
24
 
 
25
from .lazy_import import lazy_import
 
26
lazy_import(globals(), """
 
27
import textwrap
 
28
 
 
29
from breezy import (
 
30
    branch as _mod_branch,
 
31
    hooks,
 
32
    revision as _mod_revision,
 
33
    transport as _mod_transport,
 
34
    trace,
 
35
    ui,
 
36
    urlutils,
 
37
    )
 
38
from breezy.transport import local
 
39
from breezy.push import (
 
40
    PushResult,
 
41
    )
 
42
 
 
43
from breezy.i18n import gettext
 
44
""")
 
45
 
 
46
from . import (
 
47
    errors,
 
48
    registry,
 
49
    )
 
50
 
 
51
 
 
52
class MustHaveWorkingTree(errors.BzrError):
 
53
 
 
54
    _fmt = "Branching '%(url)s'(%(format)s) must create a working tree."
 
55
 
 
56
    def __init__(self, format, url):
 
57
        errors.BzrError.__init__(self, format=format, url=url)
 
58
 
 
59
 
 
60
class BranchReferenceLoop(errors.BzrError):
 
61
 
 
62
    _fmt = "Can not create branch reference that points at branch itself."
 
63
 
 
64
    def __init__(self, branch):
 
65
        errors.BzrError.__init__(self, branch=branch)
 
66
 
 
67
 
 
68
class ControlComponent(object):
 
69
    """Abstract base class for control directory components.
 
70
 
 
71
    This provides interfaces that are common across controldirs,
 
72
    repositories, branches, and workingtree control directories.
 
73
 
 
74
    They all expose two urls and transports: the *user* URL is the
 
75
    one that stops above the control directory (eg .bzr) and that
 
76
    should normally be used in messages, and the *control* URL is
 
77
    under that in eg .bzr/checkout and is used to read the control
 
78
    files.
 
79
 
 
80
    This can be used as a mixin and is intended to fit with
 
81
    foreign formats.
 
82
    """
 
83
 
 
84
    @property
 
85
    def control_transport(self):
 
86
        raise NotImplementedError
 
87
 
 
88
    @property
 
89
    def control_url(self):
 
90
        return self.control_transport.base
 
91
 
 
92
    @property
 
93
    def user_transport(self):
 
94
        raise NotImplementedError
 
95
 
 
96
    @property
 
97
    def user_url(self):
 
98
        return self.user_transport.base
 
99
 
 
100
 
 
101
class ControlDir(ControlComponent):
 
102
    """A control directory.
 
103
 
 
104
    While this represents a generic control directory, there are a few
 
105
    features that are present in this interface that are currently only
 
106
    supported by one of its implementations, BzrDir.
 
107
 
 
108
    These features (bound branches, stacked branches) are currently only
 
109
    supported by Bazaar, but could be supported by other version control
 
110
    systems as well. Implementations are required to raise the appropriate
 
111
    exceptions when an operation is requested that is not supported.
 
112
 
 
113
    This also makes life easier for API users who can rely on the
 
114
    implementation always allowing a particular feature to be requested but
 
115
    raising an exception when it is not supported, rather than requiring the
 
116
    API users to check for magic attributes to see what features are supported.
 
117
    """
 
118
 
 
119
    def can_convert_format(self):
 
120
        """Return true if this controldir is one whose format we can convert
 
121
        from."""
 
122
        return True
 
123
 
 
124
    def list_branches(self):
 
125
        """Return a sequence of all branches local to this control directory.
 
126
 
 
127
        """
 
128
        return list(self.get_branches().values())
 
129
 
 
130
    def get_branches(self):
 
131
        """Get all branches in this control directory, as a dictionary.
 
132
 
 
133
        :return: Dictionary mapping branch names to instances.
 
134
        """
 
135
        try:
 
136
            return {"": self.open_branch()}
 
137
        except (errors.NotBranchError, errors.NoRepositoryPresent):
 
138
            return {}
 
139
 
 
140
    def is_control_filename(self, filename):
 
141
        """True if filename is the name of a path which is reserved for
 
142
        controldirs.
 
143
 
 
144
        :param filename: A filename within the root transport of this
 
145
            controldir.
 
146
 
 
147
        This is true IF and ONLY IF the filename is part of the namespace reserved
 
148
        for bzr control dirs. Currently this is the '.bzr' directory in the root
 
149
        of the root_transport. it is expected that plugins will need to extend
 
150
        this in the future - for instance to make bzr talk with svn working
 
151
        trees.
 
152
        """
 
153
        return self._format.is_control_filename(filename)
 
154
 
 
155
    def needs_format_conversion(self, format=None):
 
156
        """Return true if this controldir needs convert_format run on it.
 
157
 
 
158
        For instance, if the repository format is out of date but the
 
159
        branch and working tree are not, this should return True.
 
160
 
 
161
        :param format: Optional parameter indicating a specific desired
 
162
                       format we plan to arrive at.
 
163
        """
 
164
        raise NotImplementedError(self.needs_format_conversion)
 
165
 
 
166
    def create_repository(self, shared=False):
 
167
        """Create a new repository in this control directory.
 
168
 
 
169
        :param shared: If a shared repository should be created
 
170
        :return: The newly created repository
 
171
        """
 
172
        raise NotImplementedError(self.create_repository)
 
173
 
 
174
    def destroy_repository(self):
 
175
        """Destroy the repository in this ControlDir."""
 
176
        raise NotImplementedError(self.destroy_repository)
 
177
 
 
178
    def create_branch(self, name=None, repository=None,
 
179
                      append_revisions_only=None):
 
180
        """Create a branch in this ControlDir.
 
181
 
 
182
        :param name: Name of the colocated branch to create, None for
 
183
            the user selected branch or "" for the active branch.
 
184
        :param append_revisions_only: Whether this branch should only allow
 
185
            appending new revisions to its history.
 
186
 
 
187
        The controldirs format will control what branch format is created.
 
188
        For more control see BranchFormatXX.create(a_controldir).
 
189
        """
 
190
        raise NotImplementedError(self.create_branch)
 
191
 
 
192
    def destroy_branch(self, name=None):
 
193
        """Destroy a branch in this ControlDir.
 
194
 
 
195
        :param name: Name of the branch to destroy, None for the
 
196
            user selected branch or "" for the active branch.
 
197
        :raise NotBranchError: When the branch does not exist
 
198
        """
 
199
        raise NotImplementedError(self.destroy_branch)
 
200
 
 
201
    def create_workingtree(self, revision_id=None, from_branch=None,
 
202
                           accelerator_tree=None, hardlink=False):
 
203
        """Create a working tree at this ControlDir.
 
204
 
 
205
        :param revision_id: create it as of this revision id.
 
206
        :param from_branch: override controldir branch
 
207
            (for lightweight checkouts)
 
208
        :param accelerator_tree: A tree which can be used for retrieving file
 
209
            contents more quickly than the revision tree, i.e. a workingtree.
 
210
            The revision tree will be used for cases where accelerator_tree's
 
211
            content is different.
 
212
        """
 
213
        raise NotImplementedError(self.create_workingtree)
 
214
 
 
215
    def destroy_workingtree(self):
 
216
        """Destroy the working tree at this ControlDir.
 
217
 
 
218
        Formats that do not support this may raise UnsupportedOperation.
 
219
        """
 
220
        raise NotImplementedError(self.destroy_workingtree)
 
221
 
 
222
    def destroy_workingtree_metadata(self):
 
223
        """Destroy the control files for the working tree at this ControlDir.
 
224
 
 
225
        The contents of working tree files are not affected.
 
226
        Formats that do not support this may raise UnsupportedOperation.
 
227
        """
 
228
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
229
 
 
230
    def find_branch_format(self, name=None):
 
231
        """Find the branch 'format' for this controldir.
 
232
 
 
233
        This might be a synthetic object for e.g. RemoteBranch and SVN.
 
234
        """
 
235
        raise NotImplementedError(self.find_branch_format)
 
236
 
 
237
    def get_branch_reference(self, name=None):
 
238
        """Return the referenced URL for the branch in this controldir.
 
239
 
 
240
        :param name: Optional colocated branch name
 
241
        :raises NotBranchError: If there is no Branch.
 
242
        :raises NoColocatedBranchSupport: If a branch name was specified
 
243
            but colocated branches are not supported.
 
244
        :return: The URL the branch in this controldir references if it is a
 
245
            reference branch, or None for regular branches.
 
246
        """
 
247
        if name is not None:
 
248
            raise errors.NoColocatedBranchSupport(self)
 
249
        return None
 
250
 
 
251
    def set_branch_reference(self, target_branch, name=None):
 
252
        """Set the referenced URL for the branch in this controldir.
 
253
 
 
254
        :param name: Optional colocated branch name
 
255
        :param target_branch: Branch to reference
 
256
        :raises NoColocatedBranchSupport: If a branch name was specified
 
257
            but colocated branches are not supported.
 
258
        :return: The referencing branch
 
259
        """
 
260
        raise NotImplementedError(self.set_branch_reference)
 
261
 
 
262
    def open_branch(self, name=None, unsupported=False,
 
263
                    ignore_fallbacks=False, possible_transports=None):
 
264
        """Open the branch object at this ControlDir if one is present.
 
265
 
 
266
        :param unsupported: if True, then no longer supported branch formats can
 
267
            still be opened.
 
268
        :param ignore_fallbacks: Whether to open fallback repositories
 
269
        :param possible_transports: Transports to use for opening e.g.
 
270
            fallback repositories.
 
271
        """
 
272
        raise NotImplementedError(self.open_branch)
 
273
 
 
274
    def open_repository(self, _unsupported=False):
 
275
        """Open the repository object at this ControlDir if one is present.
 
276
 
 
277
        This will not follow the Branch object pointer - it's strictly a direct
 
278
        open facility. Most client code should use open_branch().repository to
 
279
        get at a repository.
 
280
 
 
281
        :param _unsupported: a private parameter, not part of the api.
 
282
        """
 
283
        raise NotImplementedError(self.open_repository)
 
284
 
 
285
    def find_repository(self):
 
286
        """Find the repository that should be used.
 
287
 
 
288
        This does not require a branch as we use it to find the repo for
 
289
        new branches as well as to hook existing branches up to their
 
290
        repository.
 
291
        """
 
292
        raise NotImplementedError(self.find_repository)
 
293
 
 
294
    def open_workingtree(self, unsupported=False,
 
295
                         recommend_upgrade=True, from_branch=None):
 
296
        """Open the workingtree object at this ControlDir if one is present.
 
297
 
 
298
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
299
            default), emit through the ui module a recommendation that the user
 
300
            upgrade the working tree when the workingtree being opened is old
 
301
            (but still fully supported).
 
302
        :param from_branch: override controldir branch (for lightweight
 
303
            checkouts)
 
304
        """
 
305
        raise NotImplementedError(self.open_workingtree)
 
306
 
 
307
    def has_branch(self, name=None):
 
308
        """Tell if this controldir contains a branch.
 
309
 
 
310
        Note: if you're going to open the branch, you should just go ahead
 
311
        and try, and not ask permission first.  (This method just opens the
 
312
        branch and discards it, and that's somewhat expensive.)
 
313
        """
 
314
        try:
 
315
            self.open_branch(name, ignore_fallbacks=True)
 
316
            return True
 
317
        except errors.NotBranchError:
 
318
            return False
 
319
 
 
320
    def _get_selected_branch(self):
 
321
        """Return the name of the branch selected by the user.
 
322
 
 
323
        :return: Name of the branch selected by the user, or "".
 
324
        """
 
325
        branch = self.root_transport.get_segment_parameters().get("branch")
 
326
        if branch is None:
 
327
            branch = ""
 
328
        return urlutils.unescape(branch)
 
329
 
 
330
    def has_workingtree(self):
 
331
        """Tell if this controldir contains a working tree.
 
332
 
 
333
        This will still raise an exception if the controldir has a workingtree
 
334
        that is remote & inaccessible.
 
335
 
 
336
        Note: if you're going to open the working tree, you should just go ahead
 
337
        and try, and not ask permission first.  (This method just opens the
 
338
        workingtree and discards it, and that's somewhat expensive.)
 
339
        """
 
340
        try:
 
341
            self.open_workingtree(recommend_upgrade=False)
 
342
            return True
 
343
        except errors.NoWorkingTree:
 
344
            return False
 
345
 
 
346
    def cloning_metadir(self, require_stacking=False):
 
347
        """Produce a metadir suitable for cloning or sprouting with.
 
348
 
 
349
        These operations may produce workingtrees (yes, even though they're
 
350
        "cloning" something that doesn't have a tree), so a viable workingtree
 
351
        format must be selected.
 
352
 
 
353
        :require_stacking: If True, non-stackable formats will be upgraded
 
354
            to similar stackable formats.
 
355
        :returns: a ControlDirFormat with all component formats either set
 
356
            appropriately or set to None if that component should not be
 
357
            created.
 
358
        """
 
359
        raise NotImplementedError(self.cloning_metadir)
 
360
 
 
361
    def checkout_metadir(self):
 
362
        """Produce a metadir suitable for checkouts of this controldir.
 
363
 
 
364
        :returns: A ControlDirFormat with all component formats
 
365
            either set appropriately or set to None if that component
 
366
            should not be created.
 
367
        """
 
368
        return self.cloning_metadir()
 
369
 
 
370
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
371
               recurse='down', possible_transports=None,
 
372
               accelerator_tree=None, hardlink=False, stacked=False,
 
373
               source_branch=None, create_tree_if_local=True,
 
374
               lossy=False):
 
375
        """Create a copy of this controldir prepared for use as a new line of
 
376
        development.
 
377
 
 
378
        If url's last component does not exist, it will be created.
 
379
 
 
380
        Attributes related to the identity of the source branch like
 
381
        branch nickname will be cleaned, a working tree is created
 
382
        whether one existed before or not; and a local branch is always
 
383
        created.
 
384
 
 
385
        :param revision_id: if revision_id is not None, then the clone
 
386
            operation may tune itself to download less data.
 
387
        :param accelerator_tree: A tree which can be used for retrieving file
 
388
            contents more quickly than the revision tree, i.e. a workingtree.
 
389
            The revision tree will be used for cases where accelerator_tree's
 
390
            content is different.
 
391
        :param hardlink: If true, hard-link files from accelerator_tree,
 
392
            where possible.
 
393
        :param stacked: If true, create a stacked branch referring to the
 
394
            location of this control directory.
 
395
        :param create_tree_if_local: If true, a working-tree will be created
 
396
            when working locally.
 
397
        """
 
398
        raise NotImplementedError(self.sprout)
 
399
 
 
400
    def push_branch(self, source, revision_id=None, overwrite=False,
 
401
                    remember=False, create_prefix=False, lossy=False):
 
402
        """Push the source branch into this ControlDir."""
 
403
        br_to = None
 
404
        # If we can open a branch, use its direct repository, otherwise see
 
405
        # if there is a repository without a branch.
 
406
        try:
 
407
            br_to = self.open_branch()
 
408
        except errors.NotBranchError:
 
409
            # Didn't find a branch, can we find a repository?
 
410
            repository_to = self.find_repository()
 
411
        else:
 
412
            # Found a branch, so we must have found a repository
 
413
            repository_to = br_to.repository
 
414
 
 
415
        push_result = PushResult()
 
416
        push_result.source_branch = source
 
417
        if br_to is None:
 
418
            # We have a repository but no branch, copy the revisions, and then
 
419
            # create a branch.
 
420
            if revision_id is None:
 
421
                # No revision supplied by the user, default to the branch
 
422
                # revision
 
423
                revision_id = source.last_revision()
 
424
            repository_to.fetch(source.repository, revision_id=revision_id)
 
425
            br_to = source.sprout(self, revision_id=revision_id, lossy=lossy)
 
426
            if source.get_push_location() is None or remember:
 
427
                # FIXME: Should be done only if we succeed ? -- vila 2012-01-18
 
428
                source.set_push_location(br_to.base)
 
429
            push_result.stacked_on = None
 
430
            push_result.branch_push_result = None
 
431
            push_result.old_revno = None
 
432
            push_result.old_revid = _mod_revision.NULL_REVISION
 
433
            push_result.target_branch = br_to
 
434
            push_result.master_branch = None
 
435
            push_result.workingtree_updated = False
 
436
        else:
 
437
            # We have successfully opened the branch, remember if necessary:
 
438
            if source.get_push_location() is None or remember:
 
439
                # FIXME: Should be done only if we succeed ? -- vila 2012-01-18
 
440
                source.set_push_location(br_to.base)
 
441
            try:
 
442
                tree_to = self.open_workingtree()
 
443
            except errors.NotLocalUrl:
 
444
                push_result.branch_push_result = source.push(
 
445
                    br_to, overwrite, stop_revision=revision_id, lossy=lossy)
 
446
                push_result.workingtree_updated = False
 
447
            except errors.NoWorkingTree:
 
448
                push_result.branch_push_result = source.push(
 
449
                    br_to, overwrite, stop_revision=revision_id, lossy=lossy)
 
450
                push_result.workingtree_updated = None  # Not applicable
 
451
            else:
 
452
                with tree_to.lock_write():
 
453
                    push_result.branch_push_result = source.push(
 
454
                        tree_to.branch, overwrite, stop_revision=revision_id,
 
455
                        lossy=lossy)
 
456
                    tree_to.update()
 
457
                push_result.workingtree_updated = True
 
458
            push_result.old_revno = push_result.branch_push_result.old_revno
 
459
            push_result.old_revid = push_result.branch_push_result.old_revid
 
460
            push_result.target_branch = \
 
461
                push_result.branch_push_result.target_branch
 
462
        return push_result
 
463
 
 
464
    def _get_tree_branch(self, name=None):
 
465
        """Return the branch and tree, if any, for this controldir.
 
466
 
 
467
        :param name: Name of colocated branch to open.
 
468
 
 
469
        Return None for tree if not present or inaccessible.
 
470
        Raise NotBranchError if no branch is present.
 
471
        :return: (tree, branch)
 
472
        """
 
473
        try:
 
474
            tree = self.open_workingtree()
 
475
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
476
            tree = None
 
477
            branch = self.open_branch(name=name)
 
478
        else:
 
479
            if name is not None:
 
480
                branch = self.open_branch(name=name)
 
481
            else:
 
482
                branch = tree.branch
 
483
        return tree, branch
 
484
 
 
485
    def get_config(self):
 
486
        """Get configuration for this ControlDir."""
 
487
        raise NotImplementedError(self.get_config)
 
488
 
 
489
    def check_conversion_target(self, target_format):
 
490
        """Check that a controldir as a whole can be converted to a new format."""
 
491
        raise NotImplementedError(self.check_conversion_target)
 
492
 
 
493
    def clone(self, url, revision_id=None, force_new_repo=False,
 
494
              preserve_stacking=False):
 
495
        """Clone this controldir and its contents to url verbatim.
 
496
 
 
497
        :param url: The url create the clone at.  If url's last component does
 
498
            not exist, it will be created.
 
499
        :param revision_id: The tip revision-id to use for any branch or
 
500
            working tree.  If not None, then the clone operation may tune
 
501
            itself to download less data.
 
502
        :param force_new_repo: Do not use a shared repository for the target
 
503
                               even if one is available.
 
504
        :param preserve_stacking: When cloning a stacked branch, stack the
 
505
            new branch on top of the other branch's stacked-on branch.
 
506
        """
 
507
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
508
                                       revision_id=revision_id,
 
509
                                       force_new_repo=force_new_repo,
 
510
                                       preserve_stacking=preserve_stacking)
 
511
 
 
512
    def clone_on_transport(self, transport, revision_id=None,
 
513
                           force_new_repo=False, preserve_stacking=False, stacked_on=None,
 
514
                           create_prefix=False, use_existing_dir=True, no_tree=False):
 
515
        """Clone this controldir and its contents to transport verbatim.
 
516
 
 
517
        :param transport: The transport for the location to produce the clone
 
518
            at.  If the target directory does not exist, it will be created.
 
519
        :param revision_id: The tip revision-id to use for any branch or
 
520
            working tree.  If not None, then the clone operation may tune
 
521
            itself to download less data.
 
522
        :param force_new_repo: Do not use a shared repository for the target,
 
523
                               even if one is available.
 
524
        :param preserve_stacking: When cloning a stacked branch, stack the
 
525
            new branch on top of the other branch's stacked-on branch.
 
526
        :param create_prefix: Create any missing directories leading up to
 
527
            to_transport.
 
528
        :param use_existing_dir: Use an existing directory if one exists.
 
529
        :param no_tree: If set to true prevents creation of a working tree.
 
530
        """
 
531
        raise NotImplementedError(self.clone_on_transport)
 
532
 
 
533
    @classmethod
 
534
    def find_controldirs(klass, transport, evaluate=None, list_current=None):
 
535
        """Find control dirs recursively from current location.
 
536
 
 
537
        This is intended primarily as a building block for more sophisticated
 
538
        functionality, like finding trees under a directory, or finding
 
539
        branches that use a given repository.
 
540
 
 
541
        :param evaluate: An optional callable that yields recurse, value,
 
542
            where recurse controls whether this controldir is recursed into
 
543
            and value is the value to yield.  By default, all bzrdirs
 
544
            are recursed into, and the return value is the controldir.
 
545
        :param list_current: if supplied, use this function to list the current
 
546
            directory, instead of Transport.list_dir
 
547
        :return: a generator of found bzrdirs, or whatever evaluate returns.
 
548
        """
 
549
        if list_current is None:
 
550
            def list_current(transport):
 
551
                return transport.list_dir('')
 
552
        if evaluate is None:
 
553
            def evaluate(controldir):
 
554
                return True, controldir
 
555
 
 
556
        pending = [transport]
 
557
        while len(pending) > 0:
 
558
            current_transport = pending.pop()
 
559
            recurse = True
 
560
            try:
 
561
                controldir = klass.open_from_transport(current_transport)
 
562
            except (errors.NotBranchError, errors.PermissionDenied,
 
563
                    errors.UnknownFormatError):
 
564
                pass
 
565
            else:
 
566
                recurse, value = evaluate(controldir)
 
567
                yield value
 
568
            try:
 
569
                subdirs = list_current(current_transport)
 
570
            except (errors.NoSuchFile, errors.PermissionDenied):
 
571
                continue
 
572
            if recurse:
 
573
                for subdir in sorted(subdirs, reverse=True):
 
574
                    pending.append(current_transport.clone(subdir))
 
575
 
 
576
    @classmethod
 
577
    def find_branches(klass, transport):
 
578
        """Find all branches under a transport.
 
579
 
 
580
        This will find all branches below the transport, including branches
 
581
        inside other branches.  Where possible, it will use
 
582
        Repository.find_branches.
 
583
 
 
584
        To list all the branches that use a particular Repository, see
 
585
        Repository.find_branches
 
586
        """
 
587
        def evaluate(controldir):
 
588
            try:
 
589
                repository = controldir.open_repository()
 
590
            except errors.NoRepositoryPresent:
 
591
                pass
 
592
            else:
 
593
                return False, ([], repository)
 
594
            return True, (controldir.list_branches(), None)
 
595
        ret = []
 
596
        for branches, repo in klass.find_controldirs(
 
597
                transport, evaluate=evaluate):
 
598
            if repo is not None:
 
599
                ret.extend(repo.find_branches())
 
600
            if branches is not None:
 
601
                ret.extend(branches)
 
602
        return ret
 
603
 
 
604
    @classmethod
 
605
    def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
 
606
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
607
 
 
608
        This will use the current default ControlDirFormat unless one is
 
609
        specified, and use whatever
 
610
        repository format that that uses via controldir.create_branch and
 
611
        create_repository. If a shared repository is available that is used
 
612
        preferentially.
 
613
 
 
614
        The created Branch object is returned.
 
615
 
 
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 format: If supplied, the format of branch to create.  If not
 
619
            supplied, the default is used.
 
620
        """
 
621
        controldir = klass.create(base, format)
 
622
        controldir._find_or_create_repository(force_new_repo)
 
623
        return controldir.create_branch()
 
624
 
 
625
    @classmethod
 
626
    def create_branch_convenience(klass, base, force_new_repo=False,
 
627
                                  force_new_tree=None, format=None,
 
628
                                  possible_transports=None):
 
629
        """Create a new ControlDir, Branch and Repository at the url 'base'.
 
630
 
 
631
        This is a convenience function - it will use an existing repository
 
632
        if possible, can be told explicitly whether to create a working tree or
 
633
        not.
 
634
 
 
635
        This will use the current default ControlDirFormat unless one is
 
636
        specified, and use whatever
 
637
        repository format that that uses via ControlDir.create_branch and
 
638
        create_repository. If a shared repository is available that is used
 
639
        preferentially. Whatever repository is used, its tree creation policy
 
640
        is followed.
 
641
 
 
642
        The created Branch object is returned.
 
643
        If a working tree cannot be made due to base not being a file:// url,
 
644
        no error is raised unless force_new_tree is True, in which case no
 
645
        data is created on disk and NotLocalUrl is raised.
 
646
 
 
647
        :param base: The URL to create the branch at.
 
648
        :param force_new_repo: If True a new repository is always created.
 
649
        :param force_new_tree: If True or False force creation of a tree or
 
650
                               prevent such creation respectively.
 
651
        :param format: Override for the controldir format to create.
 
652
        :param possible_transports: An optional reusable transports list.
 
653
        """
 
654
        if force_new_tree:
 
655
            # check for non local urls
 
656
            t = _mod_transport.get_transport(base, possible_transports)
 
657
            if not isinstance(t, local.LocalTransport):
 
658
                raise errors.NotLocalUrl(base)
 
659
        controldir = klass.create(base, format, possible_transports)
 
660
        repo = controldir._find_or_create_repository(force_new_repo)
 
661
        result = controldir.create_branch()
 
662
        if force_new_tree or (repo.make_working_trees() and
 
663
                              force_new_tree is None):
 
664
            try:
 
665
                controldir.create_workingtree()
 
666
            except errors.NotLocalUrl:
 
667
                pass
 
668
        return result
 
669
 
 
670
    @classmethod
 
671
    def create_standalone_workingtree(klass, base, format=None):
 
672
        """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
 
673
 
 
674
        'base' must be a local path or a file:// url.
 
675
 
 
676
        This will use the current default ControlDirFormat unless one is
 
677
        specified, and use whatever
 
678
        repository format that that uses for bzrdirformat.create_workingtree,
 
679
        create_branch and create_repository.
 
680
 
 
681
        :param format: Override for the controldir format to create.
 
682
        :return: The WorkingTree object.
 
683
        """
 
684
        t = _mod_transport.get_transport(base)
 
685
        if not isinstance(t, local.LocalTransport):
 
686
            raise errors.NotLocalUrl(base)
 
687
        controldir = klass.create_branch_and_repo(base,
 
688
                                                  force_new_repo=True,
 
689
                                                  format=format).controldir
 
690
        return controldir.create_workingtree()
 
691
 
 
692
    @classmethod
 
693
    def open_unsupported(klass, base):
 
694
        """Open a branch which is not supported."""
 
695
        return klass.open(base, _unsupported=True)
 
696
 
 
697
    @classmethod
 
698
    def open(klass, base, possible_transports=None, probers=None,
 
699
             _unsupported=False):
 
700
        """Open an existing controldir, rooted at 'base' (url).
 
701
 
 
702
        :param _unsupported: a private parameter to the ControlDir class.
 
703
        """
 
704
        t = _mod_transport.get_transport(base, possible_transports)
 
705
        return klass.open_from_transport(t, probers=probers,
 
706
                                         _unsupported=_unsupported)
 
707
 
 
708
    @classmethod
 
709
    def open_from_transport(klass, transport, _unsupported=False,
 
710
                            probers=None):
 
711
        """Open a controldir within a particular directory.
 
712
 
 
713
        :param transport: Transport containing the controldir.
 
714
        :param _unsupported: private.
 
715
        """
 
716
        for hook in klass.hooks['pre_open']:
 
717
            hook(transport)
 
718
        # Keep initial base since 'transport' may be modified while following
 
719
        # the redirections.
 
720
        base = transport.base
 
721
 
 
722
        def find_format(transport):
 
723
            return transport, ControlDirFormat.find_format(transport,
 
724
                                                           probers=probers)
 
725
 
 
726
        def redirected(transport, e, redirection_notice):
 
727
            redirected_transport = transport._redirected_to(e.source, e.target)
 
728
            if redirected_transport is None:
 
729
                raise errors.NotBranchError(base)
 
730
            trace.note(gettext('{0} is{1} redirected to {2}').format(
 
731
                transport.base, e.permanently, redirected_transport.base))
 
732
            return redirected_transport
 
733
 
 
734
        try:
 
735
            transport, format = _mod_transport.do_catching_redirections(
 
736
                find_format, transport, redirected)
 
737
        except errors.TooManyRedirections:
 
738
            raise errors.NotBranchError(base)
 
739
 
 
740
        format.check_support_status(_unsupported)
 
741
        return format.open(transport, _found=True)
 
742
 
 
743
    @classmethod
 
744
    def open_containing(klass, url, possible_transports=None):
 
745
        """Open an existing branch which contains url.
 
746
 
 
747
        :param url: url to search from.
 
748
 
 
749
        See open_containing_from_transport for more detail.
 
750
        """
 
751
        transport = _mod_transport.get_transport(url, possible_transports)
 
752
        return klass.open_containing_from_transport(transport)
 
753
 
 
754
    @classmethod
 
755
    def open_containing_from_transport(klass, a_transport):
 
756
        """Open an existing branch which contains a_transport.base.
 
757
 
 
758
        This probes for a branch at a_transport, and searches upwards from there.
 
759
 
 
760
        Basically we keep looking up until we find the control directory or
 
761
        run into the root.  If there isn't one, raises NotBranchError.
 
762
        If there is one and it is either an unrecognised format or an unsupported
 
763
        format, UnknownFormatError or UnsupportedFormatError are raised.
 
764
        If there is one, it is returned, along with the unused portion of url.
 
765
 
 
766
        :return: The ControlDir that contains the path, and a Unicode path
 
767
                for the rest of the URL.
 
768
        """
 
769
        # this gets the normalised url back. I.e. '.' -> the full path.
 
770
        url = a_transport.base
 
771
        while True:
 
772
            try:
 
773
                result = klass.open_from_transport(a_transport)
 
774
                return result, urlutils.unescape(a_transport.relpath(url))
 
775
            except errors.NotBranchError:
 
776
                pass
 
777
            except errors.PermissionDenied:
 
778
                pass
 
779
            try:
 
780
                new_t = a_transport.clone('..')
 
781
            except urlutils.InvalidURLJoin:
 
782
                # reached the root, whatever that may be
 
783
                raise errors.NotBranchError(path=url)
 
784
            if new_t.base == a_transport.base:
 
785
                # reached the root, whatever that may be
 
786
                raise errors.NotBranchError(path=url)
 
787
            a_transport = new_t
 
788
 
 
789
    @classmethod
 
790
    def open_tree_or_branch(klass, location):
 
791
        """Return the branch and working tree at a location.
 
792
 
 
793
        If there is no tree at the location, tree will be None.
 
794
        If there is no branch at the location, an exception will be
 
795
        raised
 
796
        :return: (tree, branch)
 
797
        """
 
798
        controldir = klass.open(location)
 
799
        return controldir._get_tree_branch()
 
800
 
 
801
    @classmethod
 
802
    def open_containing_tree_or_branch(klass, location,
 
803
                                       possible_transports=None):
 
804
        """Return the branch and working tree contained by a location.
 
805
 
 
806
        Returns (tree, branch, relpath).
 
807
        If there is no tree at containing the location, tree will be None.
 
808
        If there is no branch containing the location, an exception will be
 
809
        raised
 
810
        relpath is the portion of the path that is contained by the branch.
 
811
        """
 
812
        controldir, relpath = klass.open_containing(location,
 
813
                                                    possible_transports=possible_transports)
 
814
        tree, branch = controldir._get_tree_branch()
 
815
        return tree, branch, relpath
 
816
 
 
817
    @classmethod
 
818
    def open_containing_tree_branch_or_repository(klass, location):
 
819
        """Return the working tree, branch and repo contained by a location.
 
820
 
 
821
        Returns (tree, branch, repository, relpath).
 
822
        If there is no tree containing the location, tree will be None.
 
823
        If there is no branch containing the location, branch will be None.
 
824
        If there is no repository containing the location, repository will be
 
825
        None.
 
826
        relpath is the portion of the path that is contained by the innermost
 
827
        ControlDir.
 
828
 
 
829
        If no tree, branch or repository is found, a NotBranchError is raised.
 
830
        """
 
831
        controldir, relpath = klass.open_containing(location)
 
832
        try:
 
833
            tree, branch = controldir._get_tree_branch()
 
834
        except errors.NotBranchError:
 
835
            try:
 
836
                repo = controldir.find_repository()
 
837
                return None, None, repo, relpath
 
838
            except (errors.NoRepositoryPresent):
 
839
                raise errors.NotBranchError(location)
 
840
        return tree, branch, branch.repository, relpath
 
841
 
 
842
    @classmethod
 
843
    def create(klass, base, format=None, possible_transports=None):
 
844
        """Create a new ControlDir at the url 'base'.
 
845
 
 
846
        :param format: If supplied, the format of branch to create.  If not
 
847
            supplied, the default is used.
 
848
        :param possible_transports: If supplied, a list of transports that
 
849
            can be reused to share a remote connection.
 
850
        """
 
851
        if klass is not ControlDir:
 
852
            raise AssertionError("ControlDir.create always creates the"
 
853
                                 "default format, not one of %r" % klass)
 
854
        t = _mod_transport.get_transport(base, possible_transports)
 
855
        t.ensure_base()
 
856
        if format is None:
 
857
            format = ControlDirFormat.get_default_format()
 
858
        return format.initialize_on_transport(t)
 
859
 
 
860
 
 
861
class ControlDirHooks(hooks.Hooks):
 
862
    """Hooks for ControlDir operations."""
 
863
 
 
864
    def __init__(self):
 
865
        """Create the default hooks."""
 
866
        hooks.Hooks.__init__(self, "breezy.controldir", "ControlDir.hooks")
 
867
        self.add_hook('pre_open',
 
868
                      "Invoked before attempting to open a ControlDir with the transport "
 
869
                      "that the open will use.", (1, 14))
 
870
        self.add_hook('post_repo_init',
 
871
                      "Invoked after a repository has been initialized. "
 
872
                      "post_repo_init is called with a "
 
873
                      "breezy.controldir.RepoInitHookParams.",
 
874
                      (2, 2))
 
875
 
 
876
 
 
877
# install the default hooks
 
878
ControlDir.hooks = ControlDirHooks()
 
879
 
 
880
 
 
881
class ControlComponentFormat(object):
 
882
    """A component that can live inside of a control directory."""
 
883
 
 
884
    upgrade_recommended = False
 
885
 
 
886
    def get_format_description(self):
 
887
        """Return the short description for this format."""
 
888
        raise NotImplementedError(self.get_format_description)
 
889
 
 
890
    def is_supported(self):
 
891
        """Is this format supported?
 
892
 
 
893
        Supported formats must be initializable and openable.
 
894
        Unsupported formats may not support initialization or committing or
 
895
        some other features depending on the reason for not being supported.
 
896
        """
 
897
        return True
 
898
 
 
899
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
900
                             basedir=None):
 
901
        """Give an error or warning on old formats.
 
902
 
 
903
        :param allow_unsupported: If true, allow opening
 
904
            formats that are strongly deprecated, and which may
 
905
            have limited functionality.
 
906
 
 
907
        :param recommend_upgrade: If true (default), warn
 
908
            the user through the ui object that they may wish
 
909
            to upgrade the object.
 
910
        """
 
911
        if not allow_unsupported and not self.is_supported():
 
912
            # see open_downlevel to open legacy branches.
 
913
            raise errors.UnsupportedFormatError(format=self)
 
914
        if recommend_upgrade and self.upgrade_recommended:
 
915
            ui.ui_factory.recommend_upgrade(
 
916
                self.get_format_description(), basedir)
 
917
 
 
918
    @classmethod
 
919
    def get_format_string(cls):
 
920
        raise NotImplementedError(cls.get_format_string)
 
921
 
 
922
 
 
923
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
924
    """A registry for control components (branch, workingtree, repository)."""
 
925
 
 
926
    def __init__(self, other_registry=None):
 
927
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
928
        self._extra_formats = []
 
929
 
 
930
    def register(self, format):
 
931
        """Register a new format."""
 
932
        super(ControlComponentFormatRegistry, self).register(
 
933
            format.get_format_string(), format)
 
934
 
 
935
    def remove(self, format):
 
936
        """Remove a registered format."""
 
937
        super(ControlComponentFormatRegistry, self).remove(
 
938
            format.get_format_string())
 
939
 
 
940
    def register_extra(self, format):
 
941
        """Register a format that can not be used in a metadir.
 
942
 
 
943
        This is mainly useful to allow custom repository formats, such as older
 
944
        Bazaar formats and foreign formats, to be tested.
 
945
        """
 
946
        self._extra_formats.append(registry._ObjectGetter(format))
 
947
 
 
948
    def remove_extra(self, format):
 
949
        """Remove an extra format.
 
950
        """
 
951
        self._extra_formats.remove(registry._ObjectGetter(format))
 
952
 
 
953
    def register_extra_lazy(self, module_name, member_name):
 
954
        """Register a format lazily.
 
955
        """
 
956
        self._extra_formats.append(
 
957
            registry._LazyObjectGetter(module_name, member_name))
 
958
 
 
959
    def _get_extra(self):
 
960
        """Return getters for extra formats, not usable in meta directories."""
 
961
        return [getter.get_obj for getter in self._extra_formats]
 
962
 
 
963
    def _get_all_lazy(self):
 
964
        """Return getters for all formats, even those not usable in metadirs."""
 
965
        result = [self._dict[name].get_obj for name in self.keys()]
 
966
        result.extend(self._get_extra())
 
967
        return result
 
968
 
 
969
    def _get_all(self):
 
970
        """Return all formats, even those not usable in metadirs."""
 
971
        result = []
 
972
        for getter in self._get_all_lazy():
 
973
            fmt = getter()
 
974
            if callable(fmt):
 
975
                fmt = fmt()
 
976
            result.append(fmt)
 
977
        return result
 
978
 
 
979
    def _get_all_modules(self):
 
980
        """Return a set of the modules providing objects."""
 
981
        modules = set()
 
982
        for name in self.keys():
 
983
            modules.add(self._get_module(name))
 
984
        for getter in self._extra_formats:
 
985
            modules.add(getter.get_module())
 
986
        return modules
 
987
 
 
988
 
 
989
class Converter(object):
 
990
    """Converts a disk format object from one format to another."""
 
991
 
 
992
    def convert(self, to_convert, pb):
 
993
        """Perform the conversion of to_convert, giving feedback via pb.
 
994
 
 
995
        :param to_convert: The disk object to convert.
 
996
        :param pb: a progress bar to use for progress information.
 
997
        """
 
998
 
 
999
    def step(self, message):
 
1000
        """Update the pb by a step."""
 
1001
        self.count += 1
 
1002
        self.pb.update(message, self.count, self.total)
 
1003
 
 
1004
 
 
1005
class ControlDirFormat(object):
 
1006
    """An encapsulation of the initialization and open routines for a format.
 
1007
 
 
1008
    Formats provide three things:
 
1009
     * An initialization routine,
 
1010
     * a format string,
 
1011
     * an open routine.
 
1012
 
 
1013
    Formats are placed in a dict by their format string for reference
 
1014
    during controldir opening. These should be subclasses of ControlDirFormat
 
1015
    for consistency.
 
1016
 
 
1017
    Once a format is deprecated, just deprecate the initialize and open
 
1018
    methods on the format class. Do not deprecate the object, as the
 
1019
    object will be created every system load.
 
1020
 
 
1021
    :cvar colocated_branches: Whether this formats supports colocated branches.
 
1022
    :cvar supports_workingtrees: This control directory can co-exist with a
 
1023
        working tree.
 
1024
    """
 
1025
 
 
1026
    _default_format = None
 
1027
    """The default format used for new control directories."""
 
1028
 
 
1029
    _probers = []
 
1030
    """The registered format probers, e.g. BzrProber.
 
1031
 
 
1032
    This is a list of Prober-derived classes.
 
1033
    """
 
1034
 
 
1035
    colocated_branches = False
 
1036
    """Whether co-located branches are supported for this control dir format.
 
1037
    """
 
1038
 
 
1039
    supports_workingtrees = True
 
1040
    """Whether working trees can exist in control directories of this format.
 
1041
    """
 
1042
 
 
1043
    fixed_components = False
 
1044
    """Whether components can not change format independent of the control dir.
 
1045
    """
 
1046
 
 
1047
    upgrade_recommended = False
 
1048
    """Whether an upgrade from this format is recommended."""
 
1049
 
 
1050
    def get_format_description(self):
 
1051
        """Return the short description for this format."""
 
1052
        raise NotImplementedError(self.get_format_description)
 
1053
 
 
1054
    def get_converter(self, format=None):
 
1055
        """Return the converter to use to convert controldirs needing converts.
 
1056
 
 
1057
        This returns a breezy.controldir.Converter object.
 
1058
 
 
1059
        This should return the best upgrader to step this format towards the
 
1060
        current default format. In the case of plugins we can/should provide
 
1061
        some means for them to extend the range of returnable converters.
 
1062
 
 
1063
        :param format: Optional format to override the default format of the
 
1064
                       library.
 
1065
        """
 
1066
        raise NotImplementedError(self.get_converter)
 
1067
 
 
1068
    def is_supported(self):
 
1069
        """Is this format supported?
 
1070
 
 
1071
        Supported formats must be openable.
 
1072
        Unsupported formats may not support initialization or committing or
 
1073
        some other features depending on the reason for not being supported.
 
1074
        """
 
1075
        return True
 
1076
 
 
1077
    def is_initializable(self):
 
1078
        """Whether new control directories of this format can be initialized.
 
1079
        """
 
1080
        return self.is_supported()
 
1081
 
 
1082
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1083
                             basedir=None):
 
1084
        """Give an error or warning on old formats.
 
1085
 
 
1086
        :param allow_unsupported: If true, allow opening
 
1087
            formats that are strongly deprecated, and which may
 
1088
            have limited functionality.
 
1089
 
 
1090
        :param recommend_upgrade: If true (default), warn
 
1091
            the user through the ui object that they may wish
 
1092
            to upgrade the object.
 
1093
        """
 
1094
        if not allow_unsupported and not self.is_supported():
 
1095
            # see open_downlevel to open legacy branches.
 
1096
            raise errors.UnsupportedFormatError(format=self)
 
1097
        if recommend_upgrade and self.upgrade_recommended:
 
1098
            ui.ui_factory.recommend_upgrade(
 
1099
                self.get_format_description(), basedir)
 
1100
 
 
1101
    def same_model(self, target_format):
 
1102
        return (self.repository_format.rich_root_data ==
 
1103
                target_format.rich_root_data)
 
1104
 
 
1105
    @classmethod
 
1106
    def register_prober(klass, prober):
 
1107
        """Register a prober that can look for a control dir.
 
1108
 
 
1109
        """
 
1110
        klass._probers.append(prober)
 
1111
 
 
1112
    @classmethod
 
1113
    def unregister_prober(klass, prober):
 
1114
        """Unregister a prober.
 
1115
 
 
1116
        """
 
1117
        klass._probers.remove(prober)
 
1118
 
 
1119
    def __str__(self):
 
1120
        # Trim the newline
 
1121
        return self.get_format_description().rstrip()
 
1122
 
 
1123
    @classmethod
 
1124
    def all_probers(klass):
 
1125
        return klass._probers
 
1126
 
 
1127
    @classmethod
 
1128
    def known_formats(klass):
 
1129
        """Return all the known formats.
 
1130
        """
 
1131
        result = []
 
1132
        for prober_kls in klass.all_probers():
 
1133
            result.extend(prober_kls.known_formats())
 
1134
        return result
 
1135
 
 
1136
    @classmethod
 
1137
    def find_format(klass, transport, probers=None):
 
1138
        """Return the format present at transport."""
 
1139
        if probers is None:
 
1140
            probers = sorted(
 
1141
                klass.all_probers(),
 
1142
                key=lambda prober: prober.priority(transport))
 
1143
        for prober_kls in probers:
 
1144
            prober = prober_kls()
 
1145
            try:
 
1146
                return prober.probe_transport(transport)
 
1147
            except errors.NotBranchError:
 
1148
                # this format does not find a control dir here.
 
1149
                pass
 
1150
        raise errors.NotBranchError(path=transport.base)
 
1151
 
 
1152
    def initialize(self, url, possible_transports=None):
 
1153
        """Create a control dir at this url and return an opened copy.
 
1154
 
 
1155
        While not deprecated, this method is very specific and its use will
 
1156
        lead to many round trips to setup a working environment. See
 
1157
        initialize_on_transport_ex for a [nearly] all-in-one method.
 
1158
 
 
1159
        Subclasses should typically override initialize_on_transport
 
1160
        instead of this method.
 
1161
        """
 
1162
        return self.initialize_on_transport(
 
1163
            _mod_transport.get_transport(url, possible_transports))
 
1164
 
 
1165
    def initialize_on_transport(self, transport):
 
1166
        """Initialize a new controldir in the base directory of a Transport."""
 
1167
        raise NotImplementedError(self.initialize_on_transport)
 
1168
 
 
1169
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
 
1170
                                   create_prefix=False, force_new_repo=False, stacked_on=None,
 
1171
                                   stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
 
1172
                                   shared_repo=False, vfs_only=False):
 
1173
        """Create this format on transport.
 
1174
 
 
1175
        The directory to initialize will be created.
 
1176
 
 
1177
        :param force_new_repo: Do not use a shared repository for the target,
 
1178
                               even if one is available.
 
1179
        :param create_prefix: Create any missing directories leading up to
 
1180
            to_transport.
 
1181
        :param use_existing_dir: Use an existing directory if one exists.
 
1182
        :param stacked_on: A url to stack any created branch on, None to follow
 
1183
            any target stacking policy.
 
1184
        :param stack_on_pwd: If stack_on is relative, the location it is
 
1185
            relative to.
 
1186
        :param repo_format_name: If non-None, a repository will be
 
1187
            made-or-found. Should none be found, or if force_new_repo is True
 
1188
            the repo_format_name is used to select the format of repository to
 
1189
            create.
 
1190
        :param make_working_trees: Control the setting of make_working_trees
 
1191
            for a new shared repository when one is made. None to use whatever
 
1192
            default the format has.
 
1193
        :param shared_repo: Control whether made repositories are shared or
 
1194
            not.
 
1195
        :param vfs_only: If True do not attempt to use a smart server
 
1196
        :return: repo, controldir, require_stacking, repository_policy. repo is
 
1197
            None if none was created or found, controldir is always valid.
 
1198
            require_stacking is the result of examining the stacked_on
 
1199
            parameter and any stacking policy found for the target.
 
1200
        """
 
1201
        raise NotImplementedError(self.initialize_on_transport_ex)
 
1202
 
 
1203
    def network_name(self):
 
1204
        """A simple byte string uniquely identifying this format for RPC calls.
 
1205
 
 
1206
        Bzr control formats use this disk format string to identify the format
 
1207
        over the wire. Its possible that other control formats have more
 
1208
        complex detection requirements, so we permit them to use any unique and
 
1209
        immutable string they desire.
 
1210
        """
 
1211
        raise NotImplementedError(self.network_name)
 
1212
 
 
1213
    def open(self, transport, _found=False):
 
1214
        """Return an instance of this format for the dir transport points at.
 
1215
        """
 
1216
        raise NotImplementedError(self.open)
 
1217
 
 
1218
    @classmethod
 
1219
    def _set_default_format(klass, format):
 
1220
        """Set default format (for testing behavior of defaults only)"""
 
1221
        klass._default_format = format
 
1222
 
 
1223
    @classmethod
 
1224
    def get_default_format(klass):
 
1225
        """Return the current default format."""
 
1226
        return klass._default_format
 
1227
 
 
1228
    def supports_transport(self, transport):
 
1229
        """Check if this format can be opened over a particular transport.
 
1230
        """
 
1231
        raise NotImplementedError(self.supports_transport)
 
1232
 
 
1233
    @classmethod
 
1234
    def is_control_filename(klass, filename):
 
1235
        """True if filename is the name of a path which is reserved for
 
1236
        controldirs.
 
1237
 
 
1238
        :param filename: A filename within the root transport of this
 
1239
            controldir.
 
1240
 
 
1241
        This is true IF and ONLY IF the filename is part of the namespace reserved
 
1242
        for bzr control dirs. Currently this is the '.bzr' directory in the root
 
1243
        of the root_transport. it is expected that plugins will need to extend
 
1244
        this in the future - for instance to make bzr talk with svn working
 
1245
        trees.
 
1246
        """
 
1247
        raise NotImplementedError(self.is_control_filename)
 
1248
 
 
1249
 
 
1250
class Prober(object):
 
1251
    """Abstract class that can be used to detect a particular kind of
 
1252
    control directory.
 
1253
 
 
1254
    At the moment this just contains a single method to probe a particular
 
1255
    transport, but it may be extended in the future to e.g. avoid
 
1256
    multiple levels of probing for Subversion repositories.
 
1257
 
 
1258
    See BzrProber and RemoteBzrProber in breezy.bzrdir for the
 
1259
    probers that detect .bzr/ directories and Bazaar smart servers,
 
1260
    respectively.
 
1261
 
 
1262
    Probers should be registered using the register_prober methods on
 
1263
    ControlDirFormat.
 
1264
    """
 
1265
 
 
1266
    def probe_transport(self, transport):
 
1267
        """Return the controldir style format present in a directory.
 
1268
 
 
1269
        :raise UnknownFormatError: If a control dir was found but is
 
1270
            in an unknown format.
 
1271
        :raise NotBranchError: If no control directory was found.
 
1272
        :return: A ControlDirFormat instance.
 
1273
        """
 
1274
        raise NotImplementedError(self.probe_transport)
 
1275
 
 
1276
    @classmethod
 
1277
    def known_formats(klass):
 
1278
        """Return the control dir formats known by this prober.
 
1279
 
 
1280
        Multiple probers can return the same formats, so this should
 
1281
        return a set.
 
1282
 
 
1283
        :return: A set of known formats.
 
1284
        """
 
1285
        raise NotImplementedError(klass.known_formats)
 
1286
 
 
1287
    @classmethod
 
1288
    def priority(klass, transport):
 
1289
        """Priority of this prober.
 
1290
 
 
1291
        A lower value means the prober gets checked first.
 
1292
 
 
1293
        Other conventions:
 
1294
 
 
1295
        -10: This is a "server" prober
 
1296
        0: No priority set
 
1297
        10: This is a regular file-based prober
 
1298
        100: This is a prober for an unsupported format
 
1299
        """
 
1300
        return 0
 
1301
 
 
1302
 
 
1303
class ControlDirFormatInfo(object):
 
1304
 
 
1305
    def __init__(self, native, deprecated, hidden, experimental):
 
1306
        self.deprecated = deprecated
 
1307
        self.native = native
 
1308
        self.hidden = hidden
 
1309
        self.experimental = experimental
 
1310
 
 
1311
 
 
1312
class ControlDirFormatRegistry(registry.Registry):
 
1313
    """Registry of user-selectable ControlDir subformats.
 
1314
 
 
1315
    Differs from ControlDirFormat._formats in that it provides sub-formats,
 
1316
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
1317
    """
 
1318
 
 
1319
    def __init__(self):
 
1320
        """Create a ControlDirFormatRegistry."""
 
1321
        self._registration_order = list()
 
1322
        super(ControlDirFormatRegistry, self).__init__()
 
1323
 
 
1324
    def register(self, key, factory, help, native=True, deprecated=False,
 
1325
                 hidden=False, experimental=False):
 
1326
        """Register a ControlDirFormat factory.
 
1327
 
 
1328
        The factory must be a callable that takes one parameter: the key.
 
1329
        It must produce an instance of the ControlDirFormat when called.
 
1330
 
 
1331
        This function mainly exists to prevent the info object from being
 
1332
        supplied directly.
 
1333
        """
 
1334
        registry.Registry.register(self, key, factory, help,
 
1335
                                   ControlDirFormatInfo(native, deprecated, hidden, experimental))
 
1336
        self._registration_order.append(key)
 
1337
 
 
1338
    def register_alias(self, key, target, hidden=False):
 
1339
        """Register a format alias.
 
1340
 
 
1341
        :param key: Alias name
 
1342
        :param target: Target format
 
1343
        :param hidden: Whether the alias is hidden
 
1344
        """
 
1345
        info = self.get_info(target)
 
1346
        registry.Registry.register_alias(self, key, target,
 
1347
                                         ControlDirFormatInfo(
 
1348
                                             native=info.native, deprecated=info.deprecated,
 
1349
                                             hidden=hidden, experimental=info.experimental))
 
1350
 
 
1351
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
1352
                      deprecated=False, hidden=False, experimental=False):
 
1353
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
1354
                                        help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
 
1355
        self._registration_order.append(key)
 
1356
 
 
1357
    def set_default(self, key):
 
1358
        """Set the 'default' key to be a clone of the supplied key.
 
1359
 
 
1360
        This method must be called once and only once.
 
1361
        """
 
1362
        self.register_alias('default', key)
 
1363
 
 
1364
    def set_default_repository(self, key):
 
1365
        """Set the FormatRegistry default and Repository default.
 
1366
 
 
1367
        This is a transitional method while Repository.set_default_format
 
1368
        is deprecated.
 
1369
        """
 
1370
        if 'default' in self:
 
1371
            self.remove('default')
 
1372
        self.set_default(key)
 
1373
        format = self.get('default')()
 
1374
 
 
1375
    def make_controldir(self, key):
 
1376
        return self.get(key)()
 
1377
 
 
1378
    def help_topic(self, topic):
 
1379
        output = ""
 
1380
        default_realkey = None
 
1381
        default_help = self.get_help('default')
 
1382
        help_pairs = []
 
1383
        for key in self._registration_order:
 
1384
            if key == 'default':
 
1385
                continue
 
1386
            help = self.get_help(key)
 
1387
            if help == default_help:
 
1388
                default_realkey = key
 
1389
            else:
 
1390
                help_pairs.append((key, help))
 
1391
 
 
1392
        def wrapped(key, help, info):
 
1393
            if info.native:
 
1394
                help = '(native) ' + help
 
1395
            return ':%s:\n%s\n\n' % (key,
 
1396
                                     textwrap.fill(help, initial_indent='    ',
 
1397
                                                   subsequent_indent='    ',
 
1398
                                                   break_long_words=False))
 
1399
        if default_realkey is not None:
 
1400
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
1401
                              self.get_info('default'))
 
1402
        deprecated_pairs = []
 
1403
        experimental_pairs = []
 
1404
        for key, help in help_pairs:
 
1405
            info = self.get_info(key)
 
1406
            if info.hidden:
 
1407
                continue
 
1408
            elif info.deprecated:
 
1409
                deprecated_pairs.append((key, help))
 
1410
            elif info.experimental:
 
1411
                experimental_pairs.append((key, help))
 
1412
            else:
 
1413
                output += wrapped(key, help, info)
 
1414
        output += "\nSee :doc:`formats-help` for more about storage formats."
 
1415
        other_output = ""
 
1416
        if len(experimental_pairs) > 0:
 
1417
            other_output += "Experimental formats are shown below.\n\n"
 
1418
            for key, help in experimental_pairs:
 
1419
                info = self.get_info(key)
 
1420
                other_output += wrapped(key, help, info)
 
1421
        else:
 
1422
            other_output += \
 
1423
                "No experimental formats are available.\n\n"
 
1424
        if len(deprecated_pairs) > 0:
 
1425
            other_output += "\nDeprecated formats are shown below.\n\n"
 
1426
            for key, help in deprecated_pairs:
 
1427
                info = self.get_info(key)
 
1428
                other_output += wrapped(key, help, info)
 
1429
        else:
 
1430
            other_output += \
 
1431
                "\nNo deprecated formats are available.\n\n"
 
1432
        other_output += \
 
1433
            "\nSee :doc:`formats-help` for more about storage formats."
 
1434
 
 
1435
        if topic == 'other-formats':
 
1436
            return other_output
 
1437
        else:
 
1438
            return output
 
1439
 
 
1440
 
 
1441
class RepoInitHookParams(object):
 
1442
    """Object holding parameters passed to `*_repo_init` hooks.
 
1443
 
 
1444
    There are 4 fields that hooks may wish to access:
 
1445
 
 
1446
    :ivar repository: Repository created
 
1447
    :ivar format: Repository format
 
1448
    :ivar bzrdir: The controldir for the repository
 
1449
    :ivar shared: The repository is shared
 
1450
    """
 
1451
 
 
1452
    def __init__(self, repository, format, controldir, shared):
 
1453
        """Create a group of RepoInitHook parameters.
 
1454
 
 
1455
        :param repository: Repository created
 
1456
        :param format: Repository format
 
1457
        :param controldir: The controldir for the repository
 
1458
        :param shared: The repository is shared
 
1459
        """
 
1460
        self.repository = repository
 
1461
        self.format = format
 
1462
        self.controldir = controldir
 
1463
        self.shared = shared
 
1464
 
 
1465
    def __eq__(self, other):
 
1466
        return self.__dict__ == other.__dict__
 
1467
 
 
1468
    def __repr__(self):
 
1469
        if self.repository:
 
1470
            return "<%s for %s>" % (self.__class__.__name__,
 
1471
                                    self.repository)
 
1472
        else:
 
1473
            return "<%s for %s>" % (self.__class__.__name__,
 
1474
                                    self.controldir)
 
1475
 
 
1476
 
 
1477
def is_control_filename(filename):
 
1478
    """Check if filename is used for control directories."""
 
1479
    # TODO(jelmer): Instead, have a function that returns all control
 
1480
    # filenames.
 
1481
    for key, format in format_registry.items():
 
1482
        if format().is_control_filename(filename):
 
1483
            return True
 
1484
    else:
 
1485
        return False
 
1486
 
 
1487
 
 
1488
class RepositoryAcquisitionPolicy(object):
 
1489
    """Abstract base class for repository acquisition policies.
 
1490
 
 
1491
    A repository acquisition policy decides how a ControlDir acquires a repository
 
1492
    for a branch that is being created.  The most basic policy decision is
 
1493
    whether to create a new repository or use an existing one.
 
1494
    """
 
1495
 
 
1496
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
1497
        """Constructor.
 
1498
 
 
1499
        :param stack_on: A location to stack on
 
1500
        :param stack_on_pwd: If stack_on is relative, the location it is
 
1501
            relative to.
 
1502
        :param require_stacking: If True, it is a failure to not stack.
 
1503
        """
 
1504
        self._stack_on = stack_on
 
1505
        self._stack_on_pwd = stack_on_pwd
 
1506
        self._require_stacking = require_stacking
 
1507
 
 
1508
    def configure_branch(self, branch):
 
1509
        """Apply any configuration data from this policy to the branch.
 
1510
 
 
1511
        Default implementation sets repository stacking.
 
1512
        """
 
1513
        if self._stack_on is None:
 
1514
            return
 
1515
        if self._stack_on_pwd is None:
 
1516
            stack_on = self._stack_on
 
1517
        else:
 
1518
            try:
 
1519
                stack_on = urlutils.rebase_url(self._stack_on,
 
1520
                                               self._stack_on_pwd,
 
1521
                                               branch.user_url)
 
1522
            except urlutils.InvalidRebaseURLs:
 
1523
                stack_on = self._get_full_stack_on()
 
1524
        try:
 
1525
            branch.set_stacked_on_url(stack_on)
 
1526
        except (_mod_branch.UnstackableBranchFormat,
 
1527
                errors.UnstackableRepositoryFormat):
 
1528
            if self._require_stacking:
 
1529
                raise
 
1530
 
 
1531
    def requires_stacking(self):
 
1532
        """Return True if this policy requires stacking."""
 
1533
        return self._stack_on is not None and self._require_stacking
 
1534
 
 
1535
    def _get_full_stack_on(self):
 
1536
        """Get a fully-qualified URL for the stack_on location."""
 
1537
        if self._stack_on is None:
 
1538
            return None
 
1539
        if self._stack_on_pwd is None:
 
1540
            return self._stack_on
 
1541
        else:
 
1542
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
1543
 
 
1544
    def _add_fallback(self, repository, possible_transports=None):
 
1545
        """Add a fallback to the supplied repository, if stacking is set."""
 
1546
        stack_on = self._get_full_stack_on()
 
1547
        if stack_on is None:
 
1548
            return
 
1549
        try:
 
1550
            stacked_dir = ControlDir.open(
 
1551
                stack_on, possible_transports=possible_transports)
 
1552
        except errors.JailBreak:
 
1553
            # We keep the stacking details, but we are in the server code so
 
1554
            # actually stacking is not needed.
 
1555
            return
 
1556
        try:
 
1557
            stacked_repo = stacked_dir.open_branch().repository
 
1558
        except errors.NotBranchError:
 
1559
            stacked_repo = stacked_dir.open_repository()
 
1560
        try:
 
1561
            repository.add_fallback_repository(stacked_repo)
 
1562
        except errors.UnstackableRepositoryFormat:
 
1563
            if self._require_stacking:
 
1564
                raise
 
1565
        else:
 
1566
            self._require_stacking = True
 
1567
 
 
1568
    def acquire_repository(self, make_working_trees=None, shared=False,
 
1569
                           possible_transports=None):
 
1570
        """Acquire a repository for this controlrdir.
 
1571
 
 
1572
        Implementations may create a new repository or use a pre-exising
 
1573
        repository.
 
1574
 
 
1575
        :param make_working_trees: If creating a repository, set
 
1576
            make_working_trees to this value (if non-None)
 
1577
        :param shared: If creating a repository, make it shared if True
 
1578
        :return: A repository, is_new_flag (True if the repository was
 
1579
            created).
 
1580
        """
 
1581
        raise NotImplementedError(
 
1582
            RepositoryAcquisitionPolicy.acquire_repository)
 
1583
 
 
1584
 
 
1585
# Please register new formats after old formats so that formats
 
1586
# appear in chronological order and format descriptions can build
 
1587
# on previous ones.
 
1588
format_registry = ControlDirFormatRegistry()
 
1589
 
 
1590
network_format_registry = registry.FormatRegistry()
 
1591
"""Registry of formats indexed by their network name.
 
1592
 
 
1593
The network name for a ControlDirFormat is an identifier that can be used when
 
1594
referring to formats with smart server operations. See
 
1595
ControlDirFormat.network_name() for more detail.
 
1596
"""