/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

Support user.signingkey configuration variable in .git/config.

Merged from https://code.launchpad.net/~jelmer/brz/local-git-key/+merge/381000

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