~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

(jameinel) Fix bug #397739,
 resolve 'lp:foo' locally as long as we have a launchpad-login to use
 bzr+ssh. (John A Meinel)

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
    fetch,
 
33
    revision as _mod_revision,
 
34
    transport as _mod_transport,
 
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
    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 create_repository(self, shared=False):
 
144
        """Create a new repository in this control directory.
 
145
 
 
146
        :param shared: If a shared repository should be created
 
147
        :return: The newly created repository
 
148
        """
 
149
        raise NotImplementedError(self.create_repository)
 
150
 
 
151
    def destroy_repository(self):
 
152
        """Destroy the repository in this ControlDir."""
 
153
        raise NotImplementedError(self.destroy_repository)
 
154
 
 
155
    def create_branch(self, name=None, repository=None):
 
156
        """Create a branch in this ControlDir.
 
157
 
 
158
        :param name: Name of the colocated branch to create, None for
 
159
            the default branch.
 
160
 
 
161
        The controldirs format will control what branch format is created.
 
162
        For more control see BranchFormatXX.create(a_controldir).
 
163
        """
 
164
        raise NotImplementedError(self.create_branch)
 
165
 
 
166
    def destroy_branch(self, name=None):
 
167
        """Destroy a branch in this ControlDir.
 
168
 
 
169
        :param name: Name of the branch to destroy, None for the default 
 
170
            branch.
 
171
        """
 
172
        raise NotImplementedError(self.destroy_branch)
 
173
 
 
174
    def create_workingtree(self, revision_id=None, from_branch=None,
 
175
        accelerator_tree=None, hardlink=False):
 
176
        """Create a working tree at this ControlDir.
 
177
 
 
178
        :param revision_id: create it as of this revision id.
 
179
        :param from_branch: override controldir branch 
 
180
            (for lightweight checkouts)
 
181
        :param accelerator_tree: A tree which can be used for retrieving file
 
182
            contents more quickly than the revision tree, i.e. a workingtree.
 
183
            The revision tree will be used for cases where accelerator_tree's
 
184
            content is different.
 
185
        """
 
186
        raise NotImplementedError(self.create_workingtree)
 
187
 
 
188
    def destroy_workingtree(self):
 
189
        """Destroy the working tree at this ControlDir.
 
190
 
 
191
        Formats that do not support this may raise UnsupportedOperation.
 
192
        """
 
193
        raise NotImplementedError(self.destroy_workingtree)
 
194
 
 
195
    def destroy_workingtree_metadata(self):
 
196
        """Destroy the control files for the working tree at this ControlDir.
 
197
 
 
198
        The contents of working tree files are not affected.
 
199
        Formats that do not support this may raise UnsupportedOperation.
 
200
        """
 
201
        raise NotImplementedError(self.destroy_workingtree_metadata)
 
202
 
 
203
    def get_branch_reference(self, name=None):
 
204
        """Return the referenced URL for the branch in this controldir.
 
205
 
 
206
        :param name: Optional colocated branch name
 
207
        :raises NotBranchError: If there is no Branch.
 
208
        :raises NoColocatedBranchSupport: If a branch name was specified
 
209
            but colocated branches are not supported.
 
210
        :return: The URL the branch in this controldir references if it is a
 
211
            reference branch, or None for regular branches.
 
212
        """
 
213
        if name is not None:
 
214
            raise errors.NoColocatedBranchSupport(self)
 
215
        return None
 
216
 
 
217
    def open_branch(self, name=None, unsupported=False,
 
218
                    ignore_fallbacks=False):
 
219
        """Open the branch object at this ControlDir if one is present.
 
220
 
 
221
        If unsupported is True, then no longer supported branch formats can
 
222
        still be opened.
 
223
 
 
224
        TODO: static convenience version of this?
 
225
        """
 
226
        raise NotImplementedError(self.open_branch)
 
227
 
 
228
    def open_repository(self, _unsupported=False):
 
229
        """Open the repository object at this ControlDir if one is present.
 
230
 
 
231
        This will not follow the Branch object pointer - it's strictly a direct
 
232
        open facility. Most client code should use open_branch().repository to
 
233
        get at a repository.
 
234
 
 
235
        :param _unsupported: a private parameter, not part of the api.
 
236
        TODO: static convenience version of this?
 
237
        """
 
238
        raise NotImplementedError(self.open_repository)
 
239
 
 
240
    def find_repository(self):
 
241
        """Find the repository that should be used.
 
242
 
 
243
        This does not require a branch as we use it to find the repo for
 
244
        new branches as well as to hook existing branches up to their
 
245
        repository.
 
246
        """
 
247
        raise NotImplementedError(self.find_repository)
 
248
 
 
249
    def open_workingtree(self, _unsupported=False,
 
250
                         recommend_upgrade=True, from_branch=None):
 
251
        """Open the workingtree object at this ControlDir if one is present.
 
252
 
 
253
        :param recommend_upgrade: Optional keyword parameter, when True (the
 
254
            default), emit through the ui module a recommendation that the user
 
255
            upgrade the working tree when the workingtree being opened is old
 
256
            (but still fully supported).
 
257
        :param from_branch: override controldir branch (for lightweight
 
258
            checkouts)
 
259
        """
 
260
        raise NotImplementedError(self.open_workingtree)
 
261
 
 
262
    def has_branch(self, name=None):
 
263
        """Tell if this controldir contains a branch.
 
264
 
 
265
        Note: if you're going to open the branch, you should just go ahead
 
266
        and try, and not ask permission first.  (This method just opens the
 
267
        branch and discards it, and that's somewhat expensive.)
 
268
        """
 
269
        try:
 
270
            self.open_branch(name)
 
271
            return True
 
272
        except errors.NotBranchError:
 
273
            return False
 
274
 
 
275
    def has_workingtree(self):
 
276
        """Tell if this controldir contains a working tree.
 
277
 
 
278
        This will still raise an exception if the controldir has a workingtree
 
279
        that is remote & inaccessible.
 
280
 
 
281
        Note: if you're going to open the working tree, you should just go ahead
 
282
        and try, and not ask permission first.  (This method just opens the
 
283
        workingtree and discards it, and that's somewhat expensive.)
 
284
        """
 
285
        try:
 
286
            self.open_workingtree(recommend_upgrade=False)
 
287
            return True
 
288
        except errors.NoWorkingTree:
 
289
            return False
 
290
 
 
291
    def cloning_metadir(self, require_stacking=False):
 
292
        """Produce a metadir suitable for cloning or sprouting with.
 
293
 
 
294
        These operations may produce workingtrees (yes, even though they're
 
295
        "cloning" something that doesn't have a tree), so a viable workingtree
 
296
        format must be selected.
 
297
 
 
298
        :require_stacking: If True, non-stackable formats will be upgraded
 
299
            to similar stackable formats.
 
300
        :returns: a ControlDirFormat with all component formats either set
 
301
            appropriately or set to None if that component should not be
 
302
            created.
 
303
        """
 
304
        raise NotImplementedError(self.cloning_metadir)
 
305
 
 
306
    def checkout_metadir(self):
 
307
        """Produce a metadir suitable for checkouts of this controldir."""
 
308
        return self.cloning_metadir()
 
309
 
 
310
    def sprout(self, url, revision_id=None, force_new_repo=False,
 
311
               recurse='down', possible_transports=None,
 
312
               accelerator_tree=None, hardlink=False, stacked=False,
 
313
               source_branch=None, create_tree_if_local=True):
 
314
        """Create a copy of this controldir prepared for use as a new line of
 
315
        development.
 
316
 
 
317
        If url's last component does not exist, it will be created.
 
318
 
 
319
        Attributes related to the identity of the source branch like
 
320
        branch nickname will be cleaned, a working tree is created
 
321
        whether one existed before or not; and a local branch is always
 
322
        created.
 
323
 
 
324
        if revision_id is not None, then the clone operation may tune
 
325
            itself to download less data.
 
326
        :param accelerator_tree: A tree which can be used for retrieving file
 
327
            contents more quickly than the revision tree, i.e. a workingtree.
 
328
            The revision tree will be used for cases where accelerator_tree's
 
329
            content is different.
 
330
        :param hardlink: If true, hard-link files from accelerator_tree,
 
331
            where possible.
 
332
        :param stacked: If true, create a stacked branch referring to the
 
333
            location of this control directory.
 
334
        :param create_tree_if_local: If true, a working-tree will be created
 
335
            when working locally.
 
336
        """
 
337
        operation = cleanup.OperationWithCleanups(self._sprout)
 
338
        return operation.run(url, revision_id=revision_id,
 
339
            force_new_repo=force_new_repo, recurse=recurse,
 
340
            possible_transports=possible_transports,
 
341
            accelerator_tree=accelerator_tree, hardlink=hardlink,
 
342
            stacked=stacked, source_branch=source_branch,
 
343
            create_tree_if_local=create_tree_if_local)
 
344
 
 
345
    def _sprout(self, op, url, revision_id=None, force_new_repo=False,
 
346
               recurse='down', possible_transports=None,
 
347
               accelerator_tree=None, hardlink=False, stacked=False,
 
348
               source_branch=None, create_tree_if_local=True):
 
349
        add_cleanup = op.add_cleanup
 
350
        fetch_spec_factory = fetch.FetchSpecFactory()
 
351
        if revision_id is not None:
 
352
            fetch_spec_factory.add_revision_ids([revision_id])
 
353
            fetch_spec_factory.source_branch_stop_revision_id = revision_id
 
354
        target_transport = _mod_transport.get_transport(url,
 
355
            possible_transports)
 
356
        target_transport.ensure_base()
 
357
        cloning_format = self.cloning_metadir(stacked)
 
358
        # Create/update the result branch
 
359
        result = cloning_format.initialize_on_transport(target_transport)
 
360
        source_branch, source_repository = self._find_source_repo(
 
361
            add_cleanup, source_branch)
 
362
        fetch_spec_factory.source_branch = source_branch
 
363
        # if a stacked branch wasn't requested, we don't create one
 
364
        # even if the origin was stacked
 
365
        if stacked and source_branch is not None:
 
366
            stacked_branch_url = self.root_transport.base
 
367
        else:
 
368
            stacked_branch_url = None
 
369
        repository_policy = result.determine_repository_policy(
 
370
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
371
        result_repo, is_new_repo = repository_policy.acquire_repository()
 
372
        add_cleanup(result_repo.lock_write().unlock)
 
373
        fetch_spec_factory.source_repo = source_repository
 
374
        fetch_spec_factory.target_repo = result_repo
 
375
        if stacked or (len(result_repo._fallback_repositories) != 0):
 
376
            target_repo_kind = fetch.TargetRepoKinds.STACKED
 
377
        elif is_new_repo:
 
378
            target_repo_kind = fetch.TargetRepoKinds.EMPTY
 
379
        else:
 
380
            target_repo_kind = fetch.TargetRepoKinds.PREEXISTING
 
381
        fetch_spec_factory.target_repo_kind = target_repo_kind
 
382
        if source_repository is not None:
 
383
            fetch_spec = fetch_spec_factory.make_fetch_spec()
 
384
            result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
385
 
 
386
        if source_branch is None:
 
387
            # this is for sprouting a controldir without a branch; is that
 
388
            # actually useful?
 
389
            # Not especially, but it's part of the contract.
 
390
            result_branch = result.create_branch()
 
391
        else:
 
392
            result_branch = source_branch.sprout(result,
 
393
                revision_id=revision_id, repository_policy=repository_policy,
 
394
                repository=result_repo)
 
395
        mutter("created new branch %r" % (result_branch,))
 
396
 
 
397
        # Create/update the result working tree
 
398
        if (create_tree_if_local and
 
399
            isinstance(target_transport, local.LocalTransport) and
 
400
            (result_repo is None or result_repo.make_working_trees())):
 
401
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
402
                hardlink=hardlink, from_branch=result_branch)
 
403
            wt.lock_write()
 
404
            try:
 
405
                if wt.path2id('') is None:
 
406
                    try:
 
407
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
408
                    except errors.NoWorkingTree:
 
409
                        pass
 
410
            finally:
 
411
                wt.unlock()
 
412
        else:
 
413
            wt = None
 
414
        if recurse == 'down':
 
415
            basis = None
 
416
            if wt is not None:
 
417
                basis = wt.basis_tree()
 
418
            elif result_branch is not None:
 
419
                basis = result_branch.basis_tree()
 
420
            elif source_branch is not None:
 
421
                basis = source_branch.basis_tree()
 
422
            if basis is not None:
 
423
                add_cleanup(basis.lock_read().unlock)
 
424
                subtrees = basis.iter_references()
 
425
            else:
 
426
                subtrees = []
 
427
            for path, file_id in subtrees:
 
428
                target = urlutils.join(url, urlutils.escape(path))
 
429
                sublocation = source_branch.reference_parent(file_id, path)
 
430
                sublocation.bzrdir.sprout(target,
 
431
                    basis.get_reference_revision(file_id, path),
 
432
                    force_new_repo=force_new_repo, recurse=recurse,
 
433
                    stacked=stacked)
 
434
        return result
 
435
 
 
436
    def _find_source_repo(self, add_cleanup, source_branch):
 
437
        """Find the source branch and repo for a sprout operation.
 
438
        
 
439
        This is helper intended for use by _sprout.
 
440
 
 
441
        :returns: (source_branch, source_repository).  Either or both may be
 
442
            None.  If not None, they will be read-locked (and their unlock(s)
 
443
            scheduled via the add_cleanup param).
 
444
        """
 
445
        if source_branch is not None:
 
446
            add_cleanup(source_branch.lock_read().unlock)
 
447
            return source_branch, source_branch.repository
 
448
        try:
 
449
            source_branch = self.open_branch()
 
450
            source_repository = source_branch.repository
 
451
        except errors.NotBranchError:
 
452
            source_branch = None
 
453
            try:
 
454
                source_repository = self.open_repository()
 
455
            except errors.NoRepositoryPresent:
 
456
                source_repository = None
 
457
            else:
 
458
                add_cleanup(source_repository.lock_read().unlock)
 
459
        else:
 
460
            add_cleanup(source_branch.lock_read().unlock)
 
461
        return source_branch, source_repository
 
462
 
 
463
    def push_branch(self, source, revision_id=None, overwrite=False, 
 
464
        remember=False, create_prefix=False):
 
465
        """Push the source branch into this ControlDir."""
 
466
        br_to = None
 
467
        # If we can open a branch, use its direct repository, otherwise see
 
468
        # if there is a repository without a branch.
 
469
        try:
 
470
            br_to = self.open_branch()
 
471
        except errors.NotBranchError:
 
472
            # Didn't find a branch, can we find a repository?
 
473
            repository_to = self.find_repository()
 
474
        else:
 
475
            # Found a branch, so we must have found a repository
 
476
            repository_to = br_to.repository
 
477
 
 
478
        push_result = PushResult()
 
479
        push_result.source_branch = source
 
480
        if br_to is None:
 
481
            # We have a repository but no branch, copy the revisions, and then
 
482
            # create a branch.
 
483
            if revision_id is None:
 
484
                # No revision supplied by the user, default to the branch
 
485
                # revision
 
486
                revision_id = source.last_revision()
 
487
            repository_to.fetch(source.repository, revision_id=revision_id)
 
488
            br_to = source.clone(self, revision_id=revision_id)
 
489
            if source.get_push_location() is None or remember:
 
490
                source.set_push_location(br_to.base)
 
491
            push_result.stacked_on = None
 
492
            push_result.branch_push_result = None
 
493
            push_result.old_revno = None
 
494
            push_result.old_revid = _mod_revision.NULL_REVISION
 
495
            push_result.target_branch = br_to
 
496
            push_result.master_branch = None
 
497
            push_result.workingtree_updated = False
 
498
        else:
 
499
            # We have successfully opened the branch, remember if necessary:
 
500
            if source.get_push_location() is None or remember:
 
501
                source.set_push_location(br_to.base)
 
502
            try:
 
503
                tree_to = self.open_workingtree()
 
504
            except errors.NotLocalUrl:
 
505
                push_result.branch_push_result = source.push(br_to, 
 
506
                    overwrite, stop_revision=revision_id)
 
507
                push_result.workingtree_updated = False
 
508
            except errors.NoWorkingTree:
 
509
                push_result.branch_push_result = source.push(br_to,
 
510
                    overwrite, stop_revision=revision_id)
 
511
                push_result.workingtree_updated = None # Not applicable
 
512
            else:
 
513
                tree_to.lock_write()
 
514
                try:
 
515
                    push_result.branch_push_result = source.push(
 
516
                        tree_to.branch, overwrite, stop_revision=revision_id)
 
517
                    tree_to.update()
 
518
                finally:
 
519
                    tree_to.unlock()
 
520
                push_result.workingtree_updated = True
 
521
            push_result.old_revno = push_result.branch_push_result.old_revno
 
522
            push_result.old_revid = push_result.branch_push_result.old_revid
 
523
            push_result.target_branch = \
 
524
                push_result.branch_push_result.target_branch
 
525
        return push_result
 
526
 
 
527
    def _get_tree_branch(self, name=None):
 
528
        """Return the branch and tree, if any, for this bzrdir.
 
529
 
 
530
        :param name: Name of colocated branch to open.
 
531
 
 
532
        Return None for tree if not present or inaccessible.
 
533
        Raise NotBranchError if no branch is present.
 
534
        :return: (tree, branch)
 
535
        """
 
536
        try:
 
537
            tree = self.open_workingtree()
 
538
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
539
            tree = None
 
540
            branch = self.open_branch(name=name)
 
541
        else:
 
542
            if name is not None:
 
543
                branch = self.open_branch(name=name)
 
544
            else:
 
545
                branch = tree.branch
 
546
        return tree, branch
 
547
 
 
548
    def get_config(self):
 
549
        """Get configuration for this ControlDir."""
 
550
        raise NotImplementedError(self.get_config)
 
551
 
 
552
    def check_conversion_target(self, target_format):
 
553
        """Check that a bzrdir as a whole can be converted to a new format."""
 
554
        raise NotImplementedError(self.check_conversion_target)
 
555
 
 
556
    def clone(self, url, revision_id=None, force_new_repo=False,
 
557
              preserve_stacking=False):
 
558
        """Clone this bzrdir and its contents to url verbatim.
 
559
 
 
560
        :param url: The url create the clone at.  If url's last component does
 
561
            not exist, it will be created.
 
562
        :param revision_id: The tip revision-id to use for any branch or
 
563
            working tree.  If not None, then the clone operation may tune
 
564
            itself to download less data.
 
565
        :param force_new_repo: Do not use a shared repository for the target
 
566
                               even if one is available.
 
567
        :param preserve_stacking: When cloning a stacked branch, stack the
 
568
            new branch on top of the other branch's stacked-on branch.
 
569
        """
 
570
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
571
                                       revision_id=revision_id,
 
572
                                       force_new_repo=force_new_repo,
 
573
                                       preserve_stacking=preserve_stacking)
 
574
 
 
575
    def clone_on_transport(self, transport, revision_id=None,
 
576
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
 
577
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
578
        """Clone this bzrdir and its contents to transport verbatim.
 
579
 
 
580
        :param transport: The transport for the location to produce the clone
 
581
            at.  If the target directory does not exist, it will be created.
 
582
        :param revision_id: The tip revision-id to use for any branch or
 
583
            working tree.  If not None, then the clone operation may tune
 
584
            itself to download less data.
 
585
        :param force_new_repo: Do not use a shared repository for the target,
 
586
                               even if one is available.
 
587
        :param preserve_stacking: When cloning a stacked branch, stack the
 
588
            new branch on top of the other branch's stacked-on branch.
 
589
        :param create_prefix: Create any missing directories leading up to
 
590
            to_transport.
 
591
        :param use_existing_dir: Use an existing directory if one exists.
 
592
        :param no_tree: If set to true prevents creation of a working tree.
 
593
        """
 
594
        raise NotImplementedError(self.clone_on_transport)
 
595
 
 
596
 
 
597
class ControlComponentFormat(object):
 
598
    """A component that can live inside of a .bzr meta directory."""
 
599
 
 
600
    def get_format_string(self):
 
601
        """Return the format of this format, if usable in meta directories."""
 
602
        raise NotImplementedError(self.get_format_string)
 
603
 
 
604
    def get_format_description(self):
 
605
        """Return the short description for this format."""
 
606
        raise NotImplementedError(self.get_format_description)
 
607
 
 
608
 
 
609
class ControlComponentFormatRegistry(registry.FormatRegistry):
 
610
    """A registry for control components (branch, workingtree, repository)."""
 
611
 
 
612
    def __init__(self, other_registry=None):
 
613
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
 
614
        self._extra_formats = []
 
615
 
 
616
    def register(self, format):
 
617
        """Register a new format."""
 
618
        super(ControlComponentFormatRegistry, self).register(
 
619
            format.get_format_string(), format)
 
620
 
 
621
    def remove(self, format):
 
622
        """Remove a registered format."""
 
623
        super(ControlComponentFormatRegistry, self).remove(
 
624
            format.get_format_string())
 
625
 
 
626
    def register_extra(self, format):
 
627
        """Register a format that can not be used in a metadir.
 
628
 
 
629
        This is mainly useful to allow custom repository formats, such as older
 
630
        Bazaar formats and foreign formats, to be tested.
 
631
        """
 
632
        self._extra_formats.append(registry._ObjectGetter(format))
 
633
 
 
634
    def remove_extra(self, format):
 
635
        """Remove an extra format.
 
636
        """
 
637
        self._extra_formats.remove(registry._ObjectGetter(format))
 
638
 
 
639
    def register_extra_lazy(self, module_name, member_name):
 
640
        """Register a format lazily.
 
641
        """
 
642
        self._extra_formats.append(
 
643
            registry._LazyObjectGetter(module_name, member_name))
 
644
 
 
645
    def _get_extra(self):
 
646
        """Return all "extra" formats, not usable in meta directories."""
 
647
        result = []
 
648
        for getter in self._extra_formats:
 
649
            f = getter.get_obj()
 
650
            if callable(f):
 
651
                f = f()
 
652
            result.append(f)
 
653
        return result
 
654
 
 
655
    def _get_all(self):
 
656
        """Return all formats, even those not usable in metadirs.
 
657
        """
 
658
        result = []
 
659
        for name in self.keys():
 
660
            fmt = self.get(name)
 
661
            if callable(fmt):
 
662
                fmt = fmt()
 
663
            result.append(fmt)
 
664
        return result + self._get_extra()
 
665
 
 
666
    def _get_all_modules(self):
 
667
        """Return a set of the modules providing objects."""
 
668
        modules = set()
 
669
        for name in self.keys():
 
670
            modules.add(self._get_module(name))
 
671
        for getter in self._extra_formats:
 
672
            modules.add(getter.get_module())
 
673
        return modules
 
674
 
 
675
 
 
676
class Converter(object):
 
677
    """Converts a disk format object from one format to another."""
 
678
 
 
679
    def convert(self, to_convert, pb):
 
680
        """Perform the conversion of to_convert, giving feedback via pb.
 
681
 
 
682
        :param to_convert: The disk object to convert.
 
683
        :param pb: a progress bar to use for progress information.
 
684
        """
 
685
 
 
686
    def step(self, message):
 
687
        """Update the pb by a step."""
 
688
        self.count +=1
 
689
        self.pb.update(message, self.count, self.total)
 
690
 
 
691
 
 
692
class ControlDirFormat(object):
 
693
    """An encapsulation of the initialization and open routines for a format.
 
694
 
 
695
    Formats provide three things:
 
696
     * An initialization routine,
 
697
     * a format string,
 
698
     * an open routine.
 
699
 
 
700
    Formats are placed in a dict by their format string for reference
 
701
    during controldir opening. These should be subclasses of ControlDirFormat
 
702
    for consistency.
 
703
 
 
704
    Once a format is deprecated, just deprecate the initialize and open
 
705
    methods on the format class. Do not deprecate the object, as the
 
706
    object will be created every system load.
 
707
 
 
708
    :cvar colocated_branches: Whether this formats supports colocated branches.
 
709
    :cvar supports_workingtrees: This control directory can co-exist with a
 
710
        working tree.
 
711
    """
 
712
 
 
713
    _default_format = None
 
714
    """The default format used for new control directories."""
 
715
 
 
716
    _server_probers = []
 
717
    """The registered server format probers, e.g. RemoteBzrProber.
 
718
 
 
719
    This is a list of Prober-derived classes.
 
720
    """
 
721
 
 
722
    _probers = []
 
723
    """The registered format probers, e.g. BzrProber.
 
724
 
 
725
    This is a list of Prober-derived classes.
 
726
    """
 
727
 
 
728
    colocated_branches = False
 
729
    """Whether co-located branches are supported for this control dir format.
 
730
    """
 
731
 
 
732
    supports_workingtrees = True
 
733
    """Whether working trees can exist in control directories of this format.
 
734
    """
 
735
 
 
736
    fixed_components = False
 
737
    """Whether components can not change format independent of the control dir.
 
738
    """
 
739
 
 
740
    def get_format_description(self):
 
741
        """Return the short description for this format."""
 
742
        raise NotImplementedError(self.get_format_description)
 
743
 
 
744
    def get_converter(self, format=None):
 
745
        """Return the converter to use to convert controldirs needing converts.
 
746
 
 
747
        This returns a bzrlib.controldir.Converter object.
 
748
 
 
749
        This should return the best upgrader to step this format towards the
 
750
        current default format. In the case of plugins we can/should provide
 
751
        some means for them to extend the range of returnable converters.
 
752
 
 
753
        :param format: Optional format to override the default format of the
 
754
                       library.
 
755
        """
 
756
        raise NotImplementedError(self.get_converter)
 
757
 
 
758
    def is_supported(self):
 
759
        """Is this format supported?
 
760
 
 
761
        Supported formats must be initializable and openable.
 
762
        Unsupported formats may not support initialization or committing or
 
763
        some other features depending on the reason for not being supported.
 
764
        """
 
765
        return True
 
766
 
 
767
    def same_model(self, target_format):
 
768
        return (self.repository_format.rich_root_data ==
 
769
            target_format.rich_root_data)
 
770
 
 
771
    @classmethod
 
772
    def register_format(klass, format):
 
773
        """Register a format that does not use '.bzr' for its control dir.
 
774
 
 
775
        """
 
776
        raise errors.BzrError("ControlDirFormat.register_format() has been "
 
777
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
778
 
 
779
    @classmethod
 
780
    def register_prober(klass, prober):
 
781
        """Register a prober that can look for a control dir.
 
782
 
 
783
        """
 
784
        klass._probers.append(prober)
 
785
 
 
786
    @classmethod
 
787
    def unregister_prober(klass, prober):
 
788
        """Unregister a prober.
 
789
 
 
790
        """
 
791
        klass._probers.remove(prober)
 
792
 
 
793
    @classmethod
 
794
    def register_server_prober(klass, prober):
 
795
        """Register a control format prober for client-server environments.
 
796
 
 
797
        These probers will be used before ones registered with
 
798
        register_prober.  This gives implementations that decide to the
 
799
        chance to grab it before anything looks at the contents of the format
 
800
        file.
 
801
        """
 
802
        klass._server_probers.append(prober)
 
803
 
 
804
    def __str__(self):
 
805
        # Trim the newline
 
806
        return self.get_format_description().rstrip()
 
807
 
 
808
    @classmethod
 
809
    def known_formats(klass):
 
810
        """Return all the known formats.
 
811
        """
 
812
        result = set()
 
813
        for prober_kls in klass._probers + klass._server_probers:
 
814
            result.update(prober_kls.known_formats())
 
815
        return result
 
816
 
 
817
    @classmethod
 
818
    def find_format(klass, transport, _server_formats=True):
 
819
        """Return the format present at transport."""
 
820
        if _server_formats:
 
821
            _probers = klass._server_probers + klass._probers
 
822
        else:
 
823
            _probers = klass._probers
 
824
        for prober_kls in _probers:
 
825
            prober = prober_kls()
 
826
            try:
 
827
                return prober.probe_transport(transport)
 
828
            except errors.NotBranchError:
 
829
                # this format does not find a control dir here.
 
830
                pass
 
831
        raise errors.NotBranchError(path=transport.base)
 
832
 
 
833
    def initialize(self, url, possible_transports=None):
 
834
        """Create a control dir at this url and return an opened copy.
 
835
 
 
836
        While not deprecated, this method is very specific and its use will
 
837
        lead to many round trips to setup a working environment. See
 
838
        initialize_on_transport_ex for a [nearly] all-in-one method.
 
839
 
 
840
        Subclasses should typically override initialize_on_transport
 
841
        instead of this method.
 
842
        """
 
843
        return self.initialize_on_transport(
 
844
            _mod_transport.get_transport(url, possible_transports))
 
845
 
 
846
    def initialize_on_transport(self, transport):
 
847
        """Initialize a new controldir in the base directory of a Transport."""
 
848
        raise NotImplementedError(self.initialize_on_transport)
 
849
 
 
850
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
 
851
        create_prefix=False, force_new_repo=False, stacked_on=None,
 
852
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
 
853
        shared_repo=False, vfs_only=False):
 
854
        """Create this format on transport.
 
855
 
 
856
        The directory to initialize will be created.
 
857
 
 
858
        :param force_new_repo: Do not use a shared repository for the target,
 
859
                               even if one is available.
 
860
        :param create_prefix: Create any missing directories leading up to
 
861
            to_transport.
 
862
        :param use_existing_dir: Use an existing directory if one exists.
 
863
        :param stacked_on: A url to stack any created branch on, None to follow
 
864
            any target stacking policy.
 
865
        :param stack_on_pwd: If stack_on is relative, the location it is
 
866
            relative to.
 
867
        :param repo_format_name: If non-None, a repository will be
 
868
            made-or-found. Should none be found, or if force_new_repo is True
 
869
            the repo_format_name is used to select the format of repository to
 
870
            create.
 
871
        :param make_working_trees: Control the setting of make_working_trees
 
872
            for a new shared repository when one is made. None to use whatever
 
873
            default the format has.
 
874
        :param shared_repo: Control whether made repositories are shared or
 
875
            not.
 
876
        :param vfs_only: If True do not attempt to use a smart server
 
877
        :return: repo, controldir, require_stacking, repository_policy. repo is
 
878
            None if none was created or found, controldir is always valid.
 
879
            require_stacking is the result of examining the stacked_on
 
880
            parameter and any stacking policy found for the target.
 
881
        """
 
882
        raise NotImplementedError(self.initialize_on_transport_ex)
 
883
 
 
884
    def network_name(self):
 
885
        """A simple byte string uniquely identifying this format for RPC calls.
 
886
 
 
887
        Bzr control formats use this disk format string to identify the format
 
888
        over the wire. Its possible that other control formats have more
 
889
        complex detection requirements, so we permit them to use any unique and
 
890
        immutable string they desire.
 
891
        """
 
892
        raise NotImplementedError(self.network_name)
 
893
 
 
894
    def open(self, transport, _found=False):
 
895
        """Return an instance of this format for the dir transport points at.
 
896
        """
 
897
        raise NotImplementedError(self.open)
 
898
 
 
899
    @classmethod
 
900
    def _set_default_format(klass, format):
 
901
        """Set default format (for testing behavior of defaults only)"""
 
902
        klass._default_format = format
 
903
 
 
904
    @classmethod
 
905
    def get_default_format(klass):
 
906
        """Return the current default format."""
 
907
        return klass._default_format
 
908
 
 
909
 
 
910
class Prober(object):
 
911
    """Abstract class that can be used to detect a particular kind of
 
912
    control directory.
 
913
 
 
914
    At the moment this just contains a single method to probe a particular
 
915
    transport, but it may be extended in the future to e.g. avoid
 
916
    multiple levels of probing for Subversion repositories.
 
917
 
 
918
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
919
    probers that detect .bzr/ directories and Bazaar smart servers,
 
920
    respectively.
 
921
 
 
922
    Probers should be registered using the register_server_prober or
 
923
    register_prober methods on ControlDirFormat.
 
924
    """
 
925
 
 
926
    def probe_transport(self, transport):
 
927
        """Return the controldir style format present in a directory.
 
928
 
 
929
        :raise UnknownFormatError: If a control dir was found but is
 
930
            in an unknown format.
 
931
        :raise NotBranchError: If no control directory was found.
 
932
        :return: A ControlDirFormat instance.
 
933
        """
 
934
        raise NotImplementedError(self.probe_transport)
 
935
 
 
936
    @classmethod
 
937
    def known_formats(cls):
 
938
        """Return the control dir formats known by this prober.
 
939
 
 
940
        Multiple probers can return the same formats, so this should
 
941
        return a set.
 
942
 
 
943
        :return: A set of known formats.
 
944
        """
 
945
        raise NotImplementedError(cls.known_formats)
 
946
 
 
947
 
 
948
class ControlDirFormatInfo(object):
 
949
 
 
950
    def __init__(self, native, deprecated, hidden, experimental):
 
951
        self.deprecated = deprecated
 
952
        self.native = native
 
953
        self.hidden = hidden
 
954
        self.experimental = experimental
 
955
 
 
956
 
 
957
class ControlDirFormatRegistry(registry.Registry):
 
958
    """Registry of user-selectable ControlDir subformats.
 
959
 
 
960
    Differs from ControlDirFormat._formats in that it provides sub-formats,
 
961
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
962
    """
 
963
 
 
964
    def __init__(self):
 
965
        """Create a ControlDirFormatRegistry."""
 
966
        self._aliases = set()
 
967
        self._registration_order = list()
 
968
        super(ControlDirFormatRegistry, self).__init__()
 
969
 
 
970
    def aliases(self):
 
971
        """Return a set of the format names which are aliases."""
 
972
        return frozenset(self._aliases)
 
973
 
 
974
    def register(self, key, factory, help, native=True, deprecated=False,
 
975
                 hidden=False, experimental=False, alias=False):
 
976
        """Register a ControlDirFormat factory.
 
977
 
 
978
        The factory must be a callable that takes one parameter: the key.
 
979
        It must produce an instance of the ControlDirFormat when called.
 
980
 
 
981
        This function mainly exists to prevent the info object from being
 
982
        supplied directly.
 
983
        """
 
984
        registry.Registry.register(self, key, factory, help,
 
985
            ControlDirFormatInfo(native, deprecated, hidden, experimental))
 
986
        if alias:
 
987
            self._aliases.add(key)
 
988
        self._registration_order.append(key)
 
989
 
 
990
    def register_lazy(self, key, module_name, member_name, help, native=True,
 
991
        deprecated=False, hidden=False, experimental=False, alias=False):
 
992
        registry.Registry.register_lazy(self, key, module_name, member_name,
 
993
            help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
 
994
        if alias:
 
995
            self._aliases.add(key)
 
996
        self._registration_order.append(key)
 
997
 
 
998
    def set_default(self, key):
 
999
        """Set the 'default' key to be a clone of the supplied key.
 
1000
 
 
1001
        This method must be called once and only once.
 
1002
        """
 
1003
        registry.Registry.register(self, 'default', self.get(key),
 
1004
            self.get_help(key), info=self.get_info(key))
 
1005
        self._aliases.add('default')
 
1006
 
 
1007
    def set_default_repository(self, key):
 
1008
        """Set the FormatRegistry default and Repository default.
 
1009
 
 
1010
        This is a transitional method while Repository.set_default_format
 
1011
        is deprecated.
 
1012
        """
 
1013
        if 'default' in self:
 
1014
            self.remove('default')
 
1015
        self.set_default(key)
 
1016
        format = self.get('default')()
 
1017
 
 
1018
    def make_bzrdir(self, key):
 
1019
        return self.get(key)()
 
1020
 
 
1021
    def help_topic(self, topic):
 
1022
        output = ""
 
1023
        default_realkey = None
 
1024
        default_help = self.get_help('default')
 
1025
        help_pairs = []
 
1026
        for key in self._registration_order:
 
1027
            if key == 'default':
 
1028
                continue
 
1029
            help = self.get_help(key)
 
1030
            if help == default_help:
 
1031
                default_realkey = key
 
1032
            else:
 
1033
                help_pairs.append((key, help))
 
1034
 
 
1035
        def wrapped(key, help, info):
 
1036
            if info.native:
 
1037
                help = '(native) ' + help
 
1038
            return ':%s:\n%s\n\n' % (key,
 
1039
                textwrap.fill(help, initial_indent='    ',
 
1040
                    subsequent_indent='    ',
 
1041
                    break_long_words=False))
 
1042
        if default_realkey is not None:
 
1043
            output += wrapped(default_realkey, '(default) %s' % default_help,
 
1044
                              self.get_info('default'))
 
1045
        deprecated_pairs = []
 
1046
        experimental_pairs = []
 
1047
        for key, help in help_pairs:
 
1048
            info = self.get_info(key)
 
1049
            if info.hidden:
 
1050
                continue
 
1051
            elif info.deprecated:
 
1052
                deprecated_pairs.append((key, help))
 
1053
            elif info.experimental:
 
1054
                experimental_pairs.append((key, help))
 
1055
            else:
 
1056
                output += wrapped(key, help, info)
 
1057
        output += "\nSee :doc:`formats-help` for more about storage formats."
 
1058
        other_output = ""
 
1059
        if len(experimental_pairs) > 0:
 
1060
            other_output += "Experimental formats are shown below.\n\n"
 
1061
            for key, help in experimental_pairs:
 
1062
                info = self.get_info(key)
 
1063
                other_output += wrapped(key, help, info)
 
1064
        else:
 
1065
            other_output += \
 
1066
                "No experimental formats are available.\n\n"
 
1067
        if len(deprecated_pairs) > 0:
 
1068
            other_output += "\nDeprecated formats are shown below.\n\n"
 
1069
            for key, help in deprecated_pairs:
 
1070
                info = self.get_info(key)
 
1071
                other_output += wrapped(key, help, info)
 
1072
        else:
 
1073
            other_output += \
 
1074
                "\nNo deprecated formats are available.\n\n"
 
1075
        other_output += \
 
1076
                "\nSee :doc:`formats-help` for more about storage formats."
 
1077
 
 
1078
        if topic == 'other-formats':
 
1079
            return other_output
 
1080
        else:
 
1081
            return output
 
1082
 
 
1083
 
 
1084
# Please register new formats after old formats so that formats
 
1085
# appear in chronological order and format descriptions can build
 
1086
# on previous ones.
 
1087
format_registry = ControlDirFormatRegistry()
 
1088
 
 
1089
network_format_registry = registry.FormatRegistry()
 
1090
"""Registry of formats indexed by their network name.
 
1091
 
 
1092
The network name for a ControlDirFormat is an identifier that can be used when
 
1093
referring to formats with smart server operations. See
 
1094
ControlDirFormat.network_name() for more detail.
 
1095
"""