~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-11 04:02:41 UTC
  • mfrom: (5017.2.2 tariff)
  • Revision ID: pqm@pqm.ubuntu.com-20100211040241-w6n021dz0uus341n
(mbp) add import-tariff tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 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 bzrlib.bzrdir.BzrDir.
22
 
 
23
 
"""
24
 
 
25
 
from bzrlib.lazy_import import lazy_import
26
 
lazy_import(globals(), """
27
 
import textwrap
28
 
 
29
 
from bzrlib import (
30
 
    errors,
31
 
    graph,
32
 
    registry,
33
 
    revision as _mod_revision,
34
 
    symbol_versioning,
35
 
    urlutils,
36
 
    )
37
 
from bzrlib.push import (
38
 
    PushResult,
39
 
    )
40
 
from bzrlib.trace import (
41
 
    mutter,
42
 
    )
43
 
from bzrlib.transport import (
44
 
    get_transport,
45
 
    local,
46
 
    )
47
 
 
48
 
""")
49
 
 
50
 
 
51
 
class ControlComponent(object):
52
 
    """Abstract base class for control directory components.
53
 
 
54
 
    This provides interfaces that are common across controldirs,
55
 
    repositories, branches, and workingtree control directories.
56
 
 
57
 
    They all expose two urls and transports: the *user* URL is the
58
 
    one that stops above the control directory (eg .bzr) and that
59
 
    should normally be used in messages, and the *control* URL is
60
 
    under that in eg .bzr/checkout and is used to read the control
61
 
    files.
62
 
 
63
 
    This can be used as a mixin and is intended to fit with
64
 
    foreign formats.
65
 
    """
66
 
 
67
 
    @property
68
 
    def control_transport(self):
69
 
        raise NotImplementedError
70
 
 
71
 
    @property
72
 
    def control_url(self):
73
 
        return self.control_transport.base
74
 
 
75
 
    @property
76
 
    def user_transport(self):
77
 
        raise NotImplementedError
78
 
 
79
 
    @property
80
 
    def user_url(self):
81
 
        return self.user_transport.base
82
 
 
83
 
 
84
 
class ControlDir(ControlComponent):
85
 
    """A control directory.
86
 
 
87
 
    While this represents a generic control directory, there are a few
88
 
    features that are present in this interface that are currently only
89
 
    supported by one of its implementations, BzrDir.
90
 
 
91
 
    These features (bound branches, stacked branches) are currently only
92
 
    supported by Bazaar, but could be supported by other version control
93
 
    systems as well. Implementations are required to raise the appropriate
94
 
    exceptions when an operation is requested that is not supported.
95
 
 
96
 
    This also makes life easier for API users who can rely on the
97
 
    implementation always allowing a particular feature to be requested but
98
 
    raising an exception when it is not supported, rather than requiring the
99
 
    API users to check for magic attributes to see what features are supported.
100
 
    """
101
 
 
102
 
    def can_convert_format(self):
103
 
        """Return true if this controldir is one whose format we can convert
104
 
        from."""
105
 
        return True
106
 
 
107
 
    def list_branches(self):
108
 
        """Return a sequence of all branches local to this control directory.
109
 
 
110
 
        """
111
 
        try:
112
 
            return [self.open_branch()]
113
 
        except (errors.NotBranchError, errors.NoRepositoryPresent):
114
 
            return []
115
 
 
116
 
    def is_control_filename(self, filename):
117
 
        """True if filename is the name of a path which is reserved for
118
 
        controldirs.
119
 
 
120
 
        :param filename: A filename within the root transport of this
121
 
            controldir.
122
 
 
123
 
        This is true IF and ONLY IF the filename is part of the namespace reserved
124
 
        for bzr control dirs. Currently this is the '.bzr' directory in the root
125
 
        of the root_transport. it is expected that plugins will need to extend
126
 
        this in the future - for instance to make bzr talk with svn working
127
 
        trees.
128
 
        """
129
 
        raise NotImplementedError(self.is_control_filename)
130
 
 
131
 
    def needs_format_conversion(self, format=None):
132
 
        """Return true if this controldir needs convert_format run on it.
133
 
 
134
 
        For instance, if the repository format is out of date but the
135
 
        branch and working tree are not, this should return True.
136
 
 
137
 
        :param format: Optional parameter indicating a specific desired
138
 
                       format we plan to arrive at.
139
 
        """
140
 
        raise NotImplementedError(self.needs_format_conversion)
141
 
 
142
 
    def destroy_repository(self):
143
 
        """Destroy the repository in this ControlDir."""
144
 
        raise NotImplementedError(self.destroy_repository)
145
 
 
146
 
    def create_branch(self, name=None):
147
 
        """Create a branch in this ControlDir.
148
 
 
149
 
        :param name: Name of the colocated branch to create, None for
150
 
            the default branch.
151
 
 
152
 
        The controldirs format will control what branch format is created.
153
 
        For more control see BranchFormatXX.create(a_controldir).
154
 
        """
155
 
        raise NotImplementedError(self.create_branch)
156
 
 
157
 
    def destroy_branch(self, name=None):
158
 
        """Destroy a branch in this ControlDir.
159
 
 
160
 
        :param name: Name of the branch to destroy, None for the default 
161
 
            branch.
162
 
        """
163
 
        raise NotImplementedError(self.destroy_branch)
164
 
 
165
 
    def create_workingtree(self, revision_id=None, from_branch=None,
166
 
        accelerator_tree=None, hardlink=False):
167
 
        """Create a working tree at this ControlDir.
168
 
 
169
 
        :param revision_id: create it as of this revision id.
170
 
        :param from_branch: override controldir branch 
171
 
            (for lightweight checkouts)
172
 
        :param accelerator_tree: A tree which can be used for retrieving file
173
 
            contents more quickly than the revision tree, i.e. a workingtree.
174
 
            The revision tree will be used for cases where accelerator_tree's
175
 
            content is different.
176
 
        """
177
 
        raise NotImplementedError(self.create_workingtree)
178
 
 
179
 
    def destroy_workingtree(self):
180
 
        """Destroy the working tree at this ControlDir.
181
 
 
182
 
        Formats that do not support this may raise UnsupportedOperation.
183
 
        """
184
 
        raise NotImplementedError(self.destroy_workingtree)
185
 
 
186
 
    def destroy_workingtree_metadata(self):
187
 
        """Destroy the control files for the working tree at this ControlDir.
188
 
 
189
 
        The contents of working tree files are not affected.
190
 
        Formats that do not support this may raise UnsupportedOperation.
191
 
        """
192
 
        raise NotImplementedError(self.destroy_workingtree_metadata)
193
 
 
194
 
    def get_branch_reference(self, name=None):
195
 
        """Return the referenced URL for the branch in this controldir.
196
 
 
197
 
        :param name: Optional colocated branch name
198
 
        :raises NotBranchError: If there is no Branch.
199
 
        :raises NoColocatedBranchSupport: If a branch name was specified
200
 
            but colocated branches are not supported.
201
 
        :return: The URL the branch in this controldir references if it is a
202
 
            reference branch, or None for regular branches.
203
 
        """
204
 
        if name is not None:
205
 
            raise errors.NoColocatedBranchSupport(self)
206
 
        return None
207
 
 
208
 
    def get_branch_transport(self, branch_format, name=None):
209
 
        """Get the transport for use by branch format in this ControlDir.
210
 
 
211
 
        Note that bzr dirs that do not support format strings will raise
212
 
        IncompatibleFormat if the branch format they are given has
213
 
        a format string, and vice versa.
214
 
 
215
 
        If branch_format is None, the transport is returned with no
216
 
        checking. If it is not None, then the returned transport is
217
 
        guaranteed to point to an existing directory ready for use.
218
 
        """
219
 
        raise NotImplementedError(self.get_branch_transport)
220
 
 
221
 
    def get_repository_transport(self, repository_format):
222
 
        """Get the transport for use by repository format in this ControlDir.
223
 
 
224
 
        Note that bzr dirs that do not support format strings will raise
225
 
        IncompatibleFormat if the repository format they are given has
226
 
        a format string, and vice versa.
227
 
 
228
 
        If repository_format is None, the transport is returned with no
229
 
        checking. If it is not None, then the returned transport is
230
 
        guaranteed to point to an existing directory ready for use.
231
 
        """
232
 
        raise NotImplementedError(self.get_repository_transport)
233
 
 
234
 
    def get_workingtree_transport(self, tree_format):
235
 
        """Get the transport for use by workingtree format in this ControlDir.
236
 
 
237
 
        Note that bzr dirs that do not support format strings will raise
238
 
        IncompatibleFormat if the workingtree format they are given has a
239
 
        format string, and vice versa.
240
 
 
241
 
        If workingtree_format is None, the transport is returned with no
242
 
        checking. If it is not None, then the returned transport is
243
 
        guaranteed to point to an existing directory ready for use.
244
 
        """
245
 
        raise NotImplementedError(self.get_workingtree_transport)
246
 
 
247
 
    def open_branch(self, name=None, unsupported=False,
248
 
                    ignore_fallbacks=False):
249
 
        """Open the branch object at this ControlDir if one is present.
250
 
 
251
 
        If unsupported is True, then no longer supported branch formats can
252
 
        still be opened.
253
 
 
254
 
        TODO: static convenience version of this?
255
 
        """
256
 
        raise NotImplementedError(self.open_branch)
257
 
 
258
 
    def open_repository(self, _unsupported=False):
259
 
        """Open the repository object at this ControlDir if one is present.
260
 
 
261
 
        This will not follow the Branch object pointer - it's strictly a direct
262
 
        open facility. Most client code should use open_branch().repository to
263
 
        get at a repository.
264
 
 
265
 
        :param _unsupported: a private parameter, not part of the api.
266
 
        TODO: static convenience version of this?
267
 
        """
268
 
        raise NotImplementedError(self.open_repository)
269
 
 
270
 
    def find_repository(self):
271
 
        """Find the repository that should be used.
272
 
 
273
 
        This does not require a branch as we use it to find the repo for
274
 
        new branches as well as to hook existing branches up to their
275
 
        repository.
276
 
        """
277
 
        raise NotImplementedError(self.find_repository)
278
 
 
279
 
    def open_workingtree(self, _unsupported=False,
280
 
                         recommend_upgrade=True, from_branch=None):
281
 
        """Open the workingtree object at this ControlDir if one is present.
282
 
 
283
 
        :param recommend_upgrade: Optional keyword parameter, when True (the
284
 
            default), emit through the ui module a recommendation that the user
285
 
            upgrade the working tree when the workingtree being opened is old
286
 
            (but still fully supported).
287
 
        :param from_branch: override controldir branch (for lightweight
288
 
            checkouts)
289
 
        """
290
 
        raise NotImplementedError(self.open_workingtree)
291
 
 
292
 
    def has_branch(self, name=None):
293
 
        """Tell if this controldir contains a branch.
294
 
 
295
 
        Note: if you're going to open the branch, you should just go ahead
296
 
        and try, and not ask permission first.  (This method just opens the
297
 
        branch and discards it, and that's somewhat expensive.)
298
 
        """
299
 
        try:
300
 
            self.open_branch(name)
301
 
            return True
302
 
        except errors.NotBranchError:
303
 
            return False
304
 
 
305
 
    def has_workingtree(self):
306
 
        """Tell if this controldir contains a working tree.
307
 
 
308
 
        This will still raise an exception if the controldir has a workingtree
309
 
        that is remote & inaccessible.
310
 
 
311
 
        Note: if you're going to open the working tree, you should just go ahead
312
 
        and try, and not ask permission first.  (This method just opens the
313
 
        workingtree and discards it, and that's somewhat expensive.)
314
 
        """
315
 
        try:
316
 
            self.open_workingtree(recommend_upgrade=False)
317
 
            return True
318
 
        except errors.NoWorkingTree:
319
 
            return False
320
 
 
321
 
    def cloning_metadir(self, require_stacking=False):
322
 
        """Produce a metadir suitable for cloning or sprouting with.
323
 
 
324
 
        These operations may produce workingtrees (yes, even though they're
325
 
        "cloning" something that doesn't have a tree), so a viable workingtree
326
 
        format must be selected.
327
 
 
328
 
        :require_stacking: If True, non-stackable formats will be upgraded
329
 
            to similar stackable formats.
330
 
        :returns: a ControlDirFormat with all component formats either set
331
 
            appropriately or set to None if that component should not be
332
 
            created.
333
 
        """
334
 
        raise NotImplementedError(self.cloning_metadir)
335
 
 
336
 
    def checkout_metadir(self):
337
 
        """Produce a metadir suitable for checkouts of this controldir."""
338
 
        return self.cloning_metadir()
339
 
 
340
 
    def sprout(self, url, revision_id=None, force_new_repo=False,
341
 
               recurse='down', possible_transports=None,
342
 
               accelerator_tree=None, hardlink=False, stacked=False,
343
 
               source_branch=None, create_tree_if_local=True):
344
 
        """Create a copy of this controldir prepared for use as a new line of
345
 
        development.
346
 
 
347
 
        If url's last component does not exist, it will be created.
348
 
 
349
 
        Attributes related to the identity of the source branch like
350
 
        branch nickname will be cleaned, a working tree is created
351
 
        whether one existed before or not; and a local branch is always
352
 
        created.
353
 
 
354
 
        if revision_id is not None, then the clone operation may tune
355
 
            itself to download less data.
356
 
        :param accelerator_tree: A tree which can be used for retrieving file
357
 
            contents more quickly than the revision tree, i.e. a workingtree.
358
 
            The revision tree will be used for cases where accelerator_tree's
359
 
            content is different.
360
 
        :param hardlink: If true, hard-link files from accelerator_tree,
361
 
            where possible.
362
 
        :param stacked: If true, create a stacked branch referring to the
363
 
            location of this control directory.
364
 
        :param create_tree_if_local: If true, a working-tree will be created
365
 
            when working locally.
366
 
        """
367
 
        target_transport = get_transport(url, possible_transports)
368
 
        target_transport.ensure_base()
369
 
        cloning_format = self.cloning_metadir(stacked)
370
 
        # Create/update the result branch
371
 
        result = cloning_format.initialize_on_transport(target_transport)
372
 
        # if a stacked branch wasn't requested, we don't create one
373
 
        # even if the origin was stacked
374
 
        stacked_branch_url = None
375
 
        if source_branch is not None:
376
 
            if stacked:
377
 
                stacked_branch_url = self.root_transport.base
378
 
            source_repository = source_branch.repository
379
 
        else:
380
 
            try:
381
 
                source_branch = self.open_branch()
382
 
                source_repository = source_branch.repository
383
 
                if stacked:
384
 
                    stacked_branch_url = self.root_transport.base
385
 
            except errors.NotBranchError:
386
 
                source_branch = None
387
 
                try:
388
 
                    source_repository = self.open_repository()
389
 
                except errors.NoRepositoryPresent:
390
 
                    source_repository = None
391
 
        repository_policy = result.determine_repository_policy(
392
 
            force_new_repo, stacked_branch_url, require_stacking=stacked)
393
 
        result_repo, is_new_repo = repository_policy.acquire_repository()
394
 
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
395
 
        if is_new_repo and revision_id is not None and not is_stacked:
396
 
            fetch_spec = graph.PendingAncestryResult(
397
 
                [revision_id], source_repository)
398
 
        else:
399
 
            fetch_spec = None
400
 
        if source_repository is not None:
401
 
            # Fetch while stacked to prevent unstacked fetch from
402
 
            # Branch.sprout.
403
 
            if fetch_spec is None:
404
 
                result_repo.fetch(source_repository, revision_id=revision_id)
405
 
            else:
406
 
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
407
 
 
408
 
        if source_branch is None:
409
 
            # this is for sprouting a controldir without a branch; is that
410
 
            # actually useful?
411
 
            # Not especially, but it's part of the contract.
412
 
            result_branch = result.create_branch()
413
 
        else:
414
 
            result_branch = source_branch.sprout(result,
415
 
                revision_id=revision_id, repository_policy=repository_policy)
416
 
        mutter("created new branch %r" % (result_branch,))
417
 
 
418
 
        # Create/update the result working tree
419
 
        if (create_tree_if_local and
420
 
            isinstance(target_transport, local.LocalTransport) and
421
 
            (result_repo is None or result_repo.make_working_trees())):
422
 
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
423
 
                hardlink=hardlink)
424
 
            wt.lock_write()
425
 
            try:
426
 
                if wt.path2id('') is None:
427
 
                    try:
428
 
                        wt.set_root_id(self.open_workingtree.get_root_id())
429
 
                    except errors.NoWorkingTree:
430
 
                        pass
431
 
            finally:
432
 
                wt.unlock()
433
 
        else:
434
 
            wt = None
435
 
        if recurse == 'down':
436
 
            if wt is not None:
437
 
                basis = wt.basis_tree()
438
 
                basis.lock_read()
439
 
                subtrees = basis.iter_references()
440
 
            elif result_branch is not None:
441
 
                basis = result_branch.basis_tree()
442
 
                basis.lock_read()
443
 
                subtrees = basis.iter_references()
444
 
            elif source_branch is not None:
445
 
                basis = source_branch.basis_tree()
446
 
                basis.lock_read()
447
 
                subtrees = basis.iter_references()
448
 
            else:
449
 
                subtrees = []
450
 
                basis = None
451
 
            try:
452
 
                for path, file_id in subtrees:
453
 
                    target = urlutils.join(url, urlutils.escape(path))
454
 
                    sublocation = source_branch.reference_parent(file_id, path)
455
 
                    sublocation.bzrdir.sprout(target,
456
 
                        basis.get_reference_revision(file_id, path),
457
 
                        force_new_repo=force_new_repo, recurse=recurse,
458
 
                        stacked=stacked)
459
 
            finally:
460
 
                if basis is not None:
461
 
                    basis.unlock()
462
 
        return result
463
 
 
464
 
    def push_branch(self, source, revision_id=None, overwrite=False, 
465
 
        remember=False, create_prefix=False):
466
 
        """Push the source branch into this ControlDir."""
467
 
        br_to = None
468
 
        # If we can open a branch, use its direct repository, otherwise see
469
 
        # if there is a repository without a branch.
470
 
        try:
471
 
            br_to = self.open_branch()
472
 
        except errors.NotBranchError:
473
 
            # Didn't find a branch, can we find a repository?
474
 
            repository_to = self.find_repository()
475
 
        else:
476
 
            # Found a branch, so we must have found a repository
477
 
            repository_to = br_to.repository
478
 
 
479
 
        push_result = PushResult()
480
 
        push_result.source_branch = source
481
 
        if br_to is None:
482
 
            # We have a repository but no branch, copy the revisions, and then
483
 
            # create a branch.
484
 
            repository_to.fetch(source.repository, revision_id=revision_id)
485
 
            br_to = source.clone(self, revision_id=revision_id)
486
 
            if source.get_push_location() is None or remember:
487
 
                source.set_push_location(br_to.base)
488
 
            push_result.stacked_on = None
489
 
            push_result.branch_push_result = None
490
 
            push_result.old_revno = None
491
 
            push_result.old_revid = _mod_revision.NULL_REVISION
492
 
            push_result.target_branch = br_to
493
 
            push_result.master_branch = None
494
 
            push_result.workingtree_updated = False
495
 
        else:
496
 
            # We have successfully opened the branch, remember if necessary:
497
 
            if source.get_push_location() is None or remember:
498
 
                source.set_push_location(br_to.base)
499
 
            try:
500
 
                tree_to = self.open_workingtree()
501
 
            except errors.NotLocalUrl:
502
 
                push_result.branch_push_result = source.push(br_to, 
503
 
                    overwrite, stop_revision=revision_id)
504
 
                push_result.workingtree_updated = False
505
 
            except errors.NoWorkingTree:
506
 
                push_result.branch_push_result = source.push(br_to,
507
 
                    overwrite, stop_revision=revision_id)
508
 
                push_result.workingtree_updated = None # Not applicable
509
 
            else:
510
 
                tree_to.lock_write()
511
 
                try:
512
 
                    push_result.branch_push_result = source.push(
513
 
                        tree_to.branch, overwrite, stop_revision=revision_id)
514
 
                    tree_to.update()
515
 
                finally:
516
 
                    tree_to.unlock()
517
 
                push_result.workingtree_updated = True
518
 
            push_result.old_revno = push_result.branch_push_result.old_revno
519
 
            push_result.old_revid = push_result.branch_push_result.old_revid
520
 
            push_result.target_branch = \
521
 
                push_result.branch_push_result.target_branch
522
 
        return push_result
523
 
 
524
 
    def _get_tree_branch(self, name=None):
525
 
        """Return the branch and tree, if any, for this bzrdir.
526
 
 
527
 
        :param name: Name of colocated branch to open.
528
 
 
529
 
        Return None for tree if not present or inaccessible.
530
 
        Raise NotBranchError if no branch is present.
531
 
        :return: (tree, branch)
532
 
        """
533
 
        try:
534
 
            tree = self.open_workingtree()
535
 
        except (errors.NoWorkingTree, errors.NotLocalUrl):
536
 
            tree = None
537
 
            branch = self.open_branch(name=name)
538
 
        else:
539
 
            if name is not None:
540
 
                branch = self.open_branch(name=name)
541
 
            else:
542
 
                branch = tree.branch
543
 
        return tree, branch
544
 
 
545
 
 
546
 
 
547
 
 
548
 
class ControlDirFormat(object):
549
 
    """An encapsulation of the initialization and open routines for a format.
550
 
 
551
 
    Formats provide three things:
552
 
     * An initialization routine,
553
 
     * a format string,
554
 
     * an open routine.
555
 
 
556
 
    Formats are placed in a dict by their format string for reference
557
 
    during controldir opening. These should be subclasses of ControlDirFormat
558
 
    for consistency.
559
 
 
560
 
    Once a format is deprecated, just deprecate the initialize and open
561
 
    methods on the format class. Do not deprecate the object, as the
562
 
    object will be created every system load.
563
 
 
564
 
    :cvar colocated_branches: Whether this formats supports colocated branches.
565
 
    """
566
 
 
567
 
    _default_format = None
568
 
    """The default format used for new control directories."""
569
 
 
570
 
    _formats = []
571
 
    """The registered control formats - .bzr, ....
572
 
 
573
 
    This is a list of ControlDirFormat objects.
574
 
    """
575
 
 
576
 
    _server_probers = []
577
 
    """The registered server format probers, e.g. RemoteBzrProber.
578
 
 
579
 
    This is a list of Prober-derived classes.
580
 
    """
581
 
 
582
 
    _probers = []
583
 
    """The registered format probers, e.g. BzrProber.
584
 
 
585
 
    This is a list of Prober-derived classes.
586
 
    """
587
 
 
588
 
    colocated_branches = False
589
 
    """Whether co-located branches are supported for this control dir format.
590
 
    """
591
 
 
592
 
    def get_format_description(self):
593
 
        """Return the short description for this format."""
594
 
        raise NotImplementedError(self.get_format_description)
595
 
 
596
 
    def get_converter(self, format=None):
597
 
        """Return the converter to use to convert controldirs needing converts.
598
 
 
599
 
        This returns a bzrlib.controldir.Converter object.
600
 
 
601
 
        This should return the best upgrader to step this format towards the
602
 
        current default format. In the case of plugins we can/should provide
603
 
        some means for them to extend the range of returnable converters.
604
 
 
605
 
        :param format: Optional format to override the default format of the
606
 
                       library.
607
 
        """
608
 
        raise NotImplementedError(self.get_converter)
609
 
 
610
 
    def is_supported(self):
611
 
        """Is this format supported?
612
 
 
613
 
        Supported formats must be initializable and openable.
614
 
        Unsupported formats may not support initialization or committing or
615
 
        some other features depending on the reason for not being supported.
616
 
        """
617
 
        return True
618
 
 
619
 
    def same_model(self, target_format):
620
 
        return (self.repository_format.rich_root_data ==
621
 
            target_format.rich_root_data)
622
 
 
623
 
    @classmethod
624
 
    def register_format(klass, format):
625
 
        """Register a format that does not use '.bzr' for its control dir.
626
 
 
627
 
        """
628
 
        klass._formats.append(format)
629
 
 
630
 
    @classmethod
631
 
    def register_prober(klass, prober):
632
 
        """Register a prober that can look for a control dir.
633
 
 
634
 
        """
635
 
        klass._probers.append(prober)
636
 
 
637
 
    @classmethod
638
 
    def unregister_prober(klass, prober):
639
 
        """Unregister a prober.
640
 
 
641
 
        """
642
 
        klass._probers.remove(prober)
643
 
 
644
 
    @classmethod
645
 
    def register_server_prober(klass, prober):
646
 
        """Register a control format prober for client-server environments.
647
 
 
648
 
        These probers will be used before ones registered with
649
 
        register_prober.  This gives implementations that decide to the
650
 
        chance to grab it before anything looks at the contents of the format
651
 
        file.
652
 
        """
653
 
        klass._server_probers.append(prober)
654
 
 
655
 
    def __str__(self):
656
 
        # Trim the newline
657
 
        return self.get_format_description().rstrip()
658
 
 
659
 
    @classmethod
660
 
    def unregister_format(klass, format):
661
 
        klass._formats.remove(format)
662
 
 
663
 
    @classmethod
664
 
    def known_formats(klass):
665
 
        """Return all the known formats.
666
 
        """
667
 
        return set(klass._formats)
668
 
 
669
 
    @classmethod
670
 
    def find_format(klass, transport, _server_formats=True):
671
 
        """Return the format present at transport."""
672
 
        if _server_formats:
673
 
            _probers = klass._server_probers + klass._probers
674
 
        else:
675
 
            _probers = klass._probers
676
 
        for prober_kls in _probers:
677
 
            prober = prober_kls()
678
 
            try:
679
 
                return prober.probe_transport(transport)
680
 
            except errors.NotBranchError:
681
 
                # this format does not find a control dir here.
682
 
                pass
683
 
        raise errors.NotBranchError(path=transport.base)
684
 
 
685
 
    def initialize(self, url, possible_transports=None):
686
 
        """Create a control dir at this url and return an opened copy.
687
 
 
688
 
        While not deprecated, this method is very specific and its use will
689
 
        lead to many round trips to setup a working environment. See
690
 
        initialize_on_transport_ex for a [nearly] all-in-one method.
691
 
 
692
 
        Subclasses should typically override initialize_on_transport
693
 
        instead of this method.
694
 
        """
695
 
        return self.initialize_on_transport(get_transport(url,
696
 
                                                          possible_transports))
697
 
    def initialize_on_transport(self, transport):
698
 
        """Initialize a new controldir in the base directory of a Transport."""
699
 
        raise NotImplementedError(self.initialize_on_transport)
700
 
 
701
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
702
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
703
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
704
 
        shared_repo=False, vfs_only=False):
705
 
        """Create this format on transport.
706
 
 
707
 
        The directory to initialize will be created.
708
 
 
709
 
        :param force_new_repo: Do not use a shared repository for the target,
710
 
                               even if one is available.
711
 
        :param create_prefix: Create any missing directories leading up to
712
 
            to_transport.
713
 
        :param use_existing_dir: Use an existing directory if one exists.
714
 
        :param stacked_on: A url to stack any created branch on, None to follow
715
 
            any target stacking policy.
716
 
        :param stack_on_pwd: If stack_on is relative, the location it is
717
 
            relative to.
718
 
        :param repo_format_name: If non-None, a repository will be
719
 
            made-or-found. Should none be found, or if force_new_repo is True
720
 
            the repo_format_name is used to select the format of repository to
721
 
            create.
722
 
        :param make_working_trees: Control the setting of make_working_trees
723
 
            for a new shared repository when one is made. None to use whatever
724
 
            default the format has.
725
 
        :param shared_repo: Control whether made repositories are shared or
726
 
            not.
727
 
        :param vfs_only: If True do not attempt to use a smart server
728
 
        :return: repo, controldir, require_stacking, repository_policy. repo is
729
 
            None if none was created or found, controldir is always valid.
730
 
            require_stacking is the result of examining the stacked_on
731
 
            parameter and any stacking policy found for the target.
732
 
        """
733
 
        raise NotImplementedError(self.initialize_on_transport_ex)
734
 
 
735
 
    def network_name(self):
736
 
        """A simple byte string uniquely identifying this format for RPC calls.
737
 
 
738
 
        Bzr control formats use this disk format string to identify the format
739
 
        over the wire. Its possible that other control formats have more
740
 
        complex detection requirements, so we permit them to use any unique and
741
 
        immutable string they desire.
742
 
        """
743
 
        raise NotImplementedError(self.network_name)
744
 
 
745
 
    def open(self, transport, _found=False):
746
 
        """Return an instance of this format for the dir transport points at.
747
 
        """
748
 
        raise NotImplementedError(self.open)
749
 
 
750
 
    @classmethod
751
 
    def _set_default_format(klass, format):
752
 
        """Set default format (for testing behavior of defaults only)"""
753
 
        klass._default_format = format
754
 
 
755
 
    @classmethod
756
 
    def get_default_format(klass):
757
 
        """Return the current default format."""
758
 
        return klass._default_format
759
 
 
760
 
 
761
 
class Prober(object):
762
 
    """Abstract class that can be used to detect a particular kind of 
763
 
    control directory.
764
 
 
765
 
    At the moment this just contains a single method to probe a particular 
766
 
    transport, but it may be extended in the future to e.g. avoid 
767
 
    multiple levels of probing for Subversion repositories.
768
 
    """
769
 
 
770
 
    def probe_transport(self, transport):
771
 
        """Return the controldir style format present in a directory.
772
 
 
773
 
        :raise UnknownFormatError: If a control dir was found but is
774
 
            in an unknown format.
775
 
        :raise NotBranchError: If no control directory was found.
776
 
        :return: A ControlDirFormat instance.
777
 
        """
778
 
        raise NotImplementedError(self.probe_transport)
779
 
 
780
 
 
781
 
class ControlDirFormatInfo(object):
782
 
 
783
 
    def __init__(self, native, deprecated, hidden, experimental):
784
 
        self.deprecated = deprecated
785
 
        self.native = native
786
 
        self.hidden = hidden
787
 
        self.experimental = experimental
788
 
 
789
 
 
790
 
class ControlDirFormatRegistry(registry.Registry):
791
 
    """Registry of user-selectable ControlDir subformats.
792
 
 
793
 
    Differs from ControlDirFormat._formats in that it provides sub-formats,
794
 
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
795
 
    """
796
 
 
797
 
    def __init__(self):
798
 
        """Create a ControlDirFormatRegistry."""
799
 
        self._aliases = set()
800
 
        self._registration_order = list()
801
 
        super(ControlDirFormatRegistry, self).__init__()
802
 
 
803
 
    def aliases(self):
804
 
        """Return a set of the format names which are aliases."""
805
 
        return frozenset(self._aliases)
806
 
 
807
 
    def register(self, key, factory, help, native=True, deprecated=False,
808
 
                 hidden=False, experimental=False, alias=False):
809
 
        """Register a ControlDirFormat factory.
810
 
 
811
 
        The factory must be a callable that takes one parameter: the key.
812
 
        It must produce an instance of the ControlDirFormat when called.
813
 
 
814
 
        This function mainly exists to prevent the info object from being
815
 
        supplied directly.
816
 
        """
817
 
        registry.Registry.register(self, key, factory, help,
818
 
            ControlDirFormatInfo(native, deprecated, hidden, experimental))
819
 
        if alias:
820
 
            self._aliases.add(key)
821
 
        self._registration_order.append(key)
822
 
 
823
 
    def register_lazy(self, key, module_name, member_name, help, native=True,
824
 
        deprecated=False, hidden=False, experimental=False, alias=False):
825
 
        registry.Registry.register_lazy(self, key, module_name, member_name,
826
 
            help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
827
 
        if alias:
828
 
            self._aliases.add(key)
829
 
        self._registration_order.append(key)
830
 
 
831
 
    def set_default(self, key):
832
 
        """Set the 'default' key to be a clone of the supplied key.
833
 
 
834
 
        This method must be called once and only once.
835
 
        """
836
 
        registry.Registry.register(self, 'default', self.get(key),
837
 
            self.get_help(key), info=self.get_info(key))
838
 
        self._aliases.add('default')
839
 
 
840
 
    def set_default_repository(self, key):
841
 
        """Set the FormatRegistry default and Repository default.
842
 
 
843
 
        This is a transitional method while Repository.set_default_format
844
 
        is deprecated.
845
 
        """
846
 
        if 'default' in self:
847
 
            self.remove('default')
848
 
        self.set_default(key)
849
 
        format = self.get('default')()
850
 
 
851
 
    def make_bzrdir(self, key):
852
 
        return self.get(key)()
853
 
 
854
 
    def help_topic(self, topic):
855
 
        output = ""
856
 
        default_realkey = None
857
 
        default_help = self.get_help('default')
858
 
        help_pairs = []
859
 
        for key in self._registration_order:
860
 
            if key == 'default':
861
 
                continue
862
 
            help = self.get_help(key)
863
 
            if help == default_help:
864
 
                default_realkey = key
865
 
            else:
866
 
                help_pairs.append((key, help))
867
 
 
868
 
        def wrapped(key, help, info):
869
 
            if info.native:
870
 
                help = '(native) ' + help
871
 
            return ':%s:\n%s\n\n' % (key,
872
 
                textwrap.fill(help, initial_indent='    ',
873
 
                    subsequent_indent='    ',
874
 
                    break_long_words=False))
875
 
        if default_realkey is not None:
876
 
            output += wrapped(default_realkey, '(default) %s' % default_help,
877
 
                              self.get_info('default'))
878
 
        deprecated_pairs = []
879
 
        experimental_pairs = []
880
 
        for key, help in help_pairs:
881
 
            info = self.get_info(key)
882
 
            if info.hidden:
883
 
                continue
884
 
            elif info.deprecated:
885
 
                deprecated_pairs.append((key, help))
886
 
            elif info.experimental:
887
 
                experimental_pairs.append((key, help))
888
 
            else:
889
 
                output += wrapped(key, help, info)
890
 
        output += "\nSee :doc:`formats-help` for more about storage formats."
891
 
        other_output = ""
892
 
        if len(experimental_pairs) > 0:
893
 
            other_output += "Experimental formats are shown below.\n\n"
894
 
            for key, help in experimental_pairs:
895
 
                info = self.get_info(key)
896
 
                other_output += wrapped(key, help, info)
897
 
        else:
898
 
            other_output += \
899
 
                "No experimental formats are available.\n\n"
900
 
        if len(deprecated_pairs) > 0:
901
 
            other_output += "\nDeprecated formats are shown below.\n\n"
902
 
            for key, help in deprecated_pairs:
903
 
                info = self.get_info(key)
904
 
                other_output += wrapped(key, help, info)
905
 
        else:
906
 
            other_output += \
907
 
                "\nNo deprecated formats are available.\n\n"
908
 
        other_output += \
909
 
                "\nSee :doc:`formats-help` for more about storage formats."
910
 
 
911
 
        if topic == 'other-formats':
912
 
            return other_output
913
 
        else:
914
 
            return output
915
 
 
916
 
 
917
 
# Please register new formats after old formats so that formats
918
 
# appear in chronological order and format descriptions can build
919
 
# on previous ones.
920
 
format_registry = ControlDirFormatRegistry()