~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Vincent Ladeuil
  • Date: 2011-01-20 21:15:10 UTC
  • mfrom: (5050.62.4 2.2)
  • mto: (5609.2.4 2.3)
  • mto: This revision was merged to the branch mainline in revision 5628.
  • Revision ID: v.ladeuil+lp@free.fr-20110120211510-9dl4tbl77dad86pl
Merge 2.2 into 2.3 including bugfix for #701940

Show diffs side-by-side

added added

removed removed

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