~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

  • Committer: Vincent Ladeuil
  • Date: 2010-10-07 06:08:01 UTC
  • mto: This revision was merged to the branch mainline in revision 5491.
  • Revision ID: v.ladeuil+lp@free.fr-20101007060801-wfdhizfhfmctl8qa
Fix some typos and propose a release planning.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010, 2011 Canonical Ltd
 
1
# Copyright (C) 2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
28
28
 
29
29
from bzrlib import (
30
30
    errors,
31
 
    hooks,
 
31
    graph,
 
32
    registry,
32
33
    revision as _mod_revision,
33
 
    transport as _mod_transport,
34
 
    trace,
35
 
    ui,
 
34
    symbol_versioning,
36
35
    urlutils,
37
36
    )
38
 
from bzrlib.transport import local
39
37
from bzrlib.push import (
40
38
    PushResult,
41
39
    )
 
40
from bzrlib.trace import (
 
41
    mutter,
 
42
    )
 
43
from bzrlib.transport import (
 
44
    get_transport,
 
45
    local,
 
46
    )
42
47
 
43
 
from bzrlib.i18n import gettext
44
48
""")
45
49
 
46
 
from bzrlib import registry
47
 
 
48
50
 
49
51
class ControlComponent(object):
50
52
    """Abstract base class for control directory components.
137
139
        """
138
140
        raise NotImplementedError(self.needs_format_conversion)
139
141
 
140
 
    def create_repository(self, shared=False):
141
 
        """Create a new repository in this control directory.
142
 
 
143
 
        :param shared: If a shared repository should be created
144
 
        :return: The newly created repository
145
 
        """
146
 
        raise NotImplementedError(self.create_repository)
147
 
 
148
142
    def destroy_repository(self):
149
143
        """Destroy the repository in this ControlDir."""
150
144
        raise NotImplementedError(self.destroy_repository)
151
145
 
152
 
    def create_branch(self, name=None, repository=None,
153
 
                      append_revisions_only=None):
 
146
    def create_branch(self, name=None):
154
147
        """Create a branch in this ControlDir.
155
148
 
156
149
        :param name: Name of the colocated branch to create, None for
157
150
            the default branch.
158
 
        :param append_revisions_only: Whether this branch should only allow
159
 
            appending new revisions to its history.
160
151
 
161
152
        The controldirs format will control what branch format is created.
162
153
        For more control see BranchFormatXX.create(a_controldir).
200
191
        """
201
192
        raise NotImplementedError(self.destroy_workingtree_metadata)
202
193
 
203
 
    def find_branch_format(self, name=None):
204
 
        """Find the branch 'format' for this controldir.
205
 
 
206
 
        This might be a synthetic object for e.g. RemoteBranch and SVN.
207
 
        """
208
 
        raise NotImplementedError(self.find_branch_format)
209
 
 
210
194
    def get_branch_reference(self, name=None):
211
195
        """Return the referenced URL for the branch in this controldir.
212
196
 
221
205
            raise errors.NoColocatedBranchSupport(self)
222
206
        return None
223
207
 
 
208
    def get_branch_transport(self, branch_format, name=None):
 
209
        """Get the transport for use by branch format in this ControlDir.
 
210
 
 
211
        Note that bzr dirs that do not support format strings will raise
 
212
        IncompatibleFormat if the branch format they are given has
 
213
        a format string, and vice versa.
 
214
 
 
215
        If branch_format is None, the transport is returned with no
 
216
        checking. If it is not None, then the returned transport is
 
217
        guaranteed to point to an existing directory ready for use.
 
218
        """
 
219
        raise NotImplementedError(self.get_branch_transport)
 
220
 
 
221
    def get_repository_transport(self, repository_format):
 
222
        """Get the transport for use by repository format in this ControlDir.
 
223
 
 
224
        Note that bzr dirs that do not support format strings will raise
 
225
        IncompatibleFormat if the repository format they are given has
 
226
        a format string, and vice versa.
 
227
 
 
228
        If repository_format is None, the transport is returned with no
 
229
        checking. If it is not None, then the returned transport is
 
230
        guaranteed to point to an existing directory ready for use.
 
231
        """
 
232
        raise NotImplementedError(self.get_repository_transport)
 
233
 
 
234
    def get_workingtree_transport(self, tree_format):
 
235
        """Get the transport for use by workingtree format in this ControlDir.
 
236
 
 
237
        Note that bzr dirs that do not support format strings will raise
 
238
        IncompatibleFormat if the workingtree format they are given has a
 
239
        format string, and vice versa.
 
240
 
 
241
        If workingtree_format is None, the transport is returned with no
 
242
        checking. If it is not None, then the returned transport is
 
243
        guaranteed to point to an existing directory ready for use.
 
244
        """
 
245
        raise NotImplementedError(self.get_workingtree_transport)
 
246
 
224
247
    def open_branch(self, name=None, unsupported=False,
225
248
                    ignore_fallbacks=False):
226
249
        """Open the branch object at this ControlDir if one is present.
240
263
        get at a repository.
241
264
 
242
265
        :param _unsupported: a private parameter, not part of the api.
243
 
 
244
266
        TODO: static convenience version of this?
245
267
        """
246
268
        raise NotImplementedError(self.open_repository)
280
302
        except errors.NotBranchError:
281
303
            return False
282
304
 
283
 
    def _get_selected_branch(self):
284
 
        """Return the name of the branch selected by the user.
285
 
 
286
 
        :return: Name of the branch selected by the user, or None.
287
 
        """
288
 
        branch = self.root_transport.get_segment_parameters().get("branch")
289
 
        if branch is not None:
290
 
            branch = urlutils.unescape(branch)
291
 
        return branch
292
 
 
293
305
    def has_workingtree(self):
294
306
        """Tell if this controldir contains a working tree.
295
307
 
339
351
        whether one existed before or not; and a local branch is always
340
352
        created.
341
353
 
342
 
        :param revision_id: if revision_id is not None, then the clone
343
 
            operation may tune itself to download less data.
 
354
        if revision_id is not None, then the clone operation may tune
 
355
            itself to download less data.
344
356
        :param accelerator_tree: A tree which can be used for retrieving file
345
357
            contents more quickly than the revision tree, i.e. a workingtree.
346
358
            The revision tree will be used for cases where accelerator_tree's
352
364
        :param create_tree_if_local: If true, a working-tree will be created
353
365
            when working locally.
354
366
        """
355
 
        raise NotImplementedError(self.sprout)
 
367
        target_transport = get_transport(url, possible_transports)
 
368
        target_transport.ensure_base()
 
369
        cloning_format = self.cloning_metadir(stacked)
 
370
        # Create/update the result branch
 
371
        result = cloning_format.initialize_on_transport(target_transport)
 
372
        # if a stacked branch wasn't requested, we don't create one
 
373
        # even if the origin was stacked
 
374
        stacked_branch_url = None
 
375
        if source_branch is not None:
 
376
            if stacked:
 
377
                stacked_branch_url = self.root_transport.base
 
378
            source_repository = source_branch.repository
 
379
        else:
 
380
            try:
 
381
                source_branch = self.open_branch()
 
382
                source_repository = source_branch.repository
 
383
                if stacked:
 
384
                    stacked_branch_url = self.root_transport.base
 
385
            except errors.NotBranchError:
 
386
                source_branch = None
 
387
                try:
 
388
                    source_repository = self.open_repository()
 
389
                except errors.NoRepositoryPresent:
 
390
                    source_repository = None
 
391
        repository_policy = result.determine_repository_policy(
 
392
            force_new_repo, stacked_branch_url, require_stacking=stacked)
 
393
        result_repo, is_new_repo = repository_policy.acquire_repository()
 
394
        is_stacked = stacked or (len(result_repo._fallback_repositories) != 0)
 
395
        if is_new_repo and revision_id is not None and not is_stacked:
 
396
            fetch_spec = graph.PendingAncestryResult(
 
397
                [revision_id], source_repository)
 
398
        else:
 
399
            fetch_spec = None
 
400
        if source_repository is not None:
 
401
            # Fetch while stacked to prevent unstacked fetch from
 
402
            # Branch.sprout.
 
403
            if fetch_spec is None:
 
404
                result_repo.fetch(source_repository, revision_id=revision_id)
 
405
            else:
 
406
                result_repo.fetch(source_repository, fetch_spec=fetch_spec)
 
407
 
 
408
        if source_branch is None:
 
409
            # this is for sprouting a controldir without a branch; is that
 
410
            # actually useful?
 
411
            # Not especially, but it's part of the contract.
 
412
            result_branch = result.create_branch()
 
413
        else:
 
414
            result_branch = source_branch.sprout(result,
 
415
                revision_id=revision_id, repository_policy=repository_policy)
 
416
        mutter("created new branch %r" % (result_branch,))
 
417
 
 
418
        # Create/update the result working tree
 
419
        if (create_tree_if_local and
 
420
            isinstance(target_transport, local.LocalTransport) and
 
421
            (result_repo is None or result_repo.make_working_trees())):
 
422
            wt = result.create_workingtree(accelerator_tree=accelerator_tree,
 
423
                hardlink=hardlink)
 
424
            wt.lock_write()
 
425
            try:
 
426
                if wt.path2id('') is None:
 
427
                    try:
 
428
                        wt.set_root_id(self.open_workingtree.get_root_id())
 
429
                    except errors.NoWorkingTree:
 
430
                        pass
 
431
            finally:
 
432
                wt.unlock()
 
433
        else:
 
434
            wt = None
 
435
        if recurse == 'down':
 
436
            if wt is not None:
 
437
                basis = wt.basis_tree()
 
438
                basis.lock_read()
 
439
                subtrees = basis.iter_references()
 
440
            elif result_branch is not None:
 
441
                basis = result_branch.basis_tree()
 
442
                basis.lock_read()
 
443
                subtrees = basis.iter_references()
 
444
            elif source_branch is not None:
 
445
                basis = source_branch.basis_tree()
 
446
                basis.lock_read()
 
447
                subtrees = basis.iter_references()
 
448
            else:
 
449
                subtrees = []
 
450
                basis = None
 
451
            try:
 
452
                for path, file_id in subtrees:
 
453
                    target = urlutils.join(url, urlutils.escape(path))
 
454
                    sublocation = source_branch.reference_parent(file_id, path)
 
455
                    sublocation.bzrdir.sprout(target,
 
456
                        basis.get_reference_revision(file_id, path),
 
457
                        force_new_repo=force_new_repo, recurse=recurse,
 
458
                        stacked=stacked)
 
459
            finally:
 
460
                if basis is not None:
 
461
                    basis.unlock()
 
462
        return result
356
463
 
357
464
    def push_branch(self, source, revision_id=None, overwrite=False, 
358
465
        remember=False, create_prefix=False):
374
481
        if br_to is None:
375
482
            # We have a repository but no branch, copy the revisions, and then
376
483
            # create a branch.
377
 
            if revision_id is None:
378
 
                # No revision supplied by the user, default to the branch
379
 
                # revision
380
 
                revision_id = source.last_revision()
381
484
            repository_to.fetch(source.repository, revision_id=revision_id)
382
485
            br_to = source.clone(self, revision_id=revision_id)
383
486
            if source.get_push_location() is None or remember:
419
522
        return push_result
420
523
 
421
524
    def _get_tree_branch(self, name=None):
422
 
        """Return the branch and tree, if any, for this controldir.
 
525
        """Return the branch and tree, if any, for this bzrdir.
423
526
 
424
527
        :param name: Name of colocated branch to open.
425
528
 
444
547
        raise NotImplementedError(self.get_config)
445
548
 
446
549
    def check_conversion_target(self, target_format):
447
 
        """Check that a controldir as a whole can be converted to a new format."""
 
550
        """Check that a bzrdir as a whole can be converted to a new format."""
448
551
        raise NotImplementedError(self.check_conversion_target)
449
552
 
450
553
    def clone(self, url, revision_id=None, force_new_repo=False,
451
554
              preserve_stacking=False):
452
 
        """Clone this controldir and its contents to url verbatim.
 
555
        """Clone this bzrdir and its contents to url verbatim.
453
556
 
454
557
        :param url: The url create the clone at.  If url's last component does
455
558
            not exist, it will be created.
461
564
        :param preserve_stacking: When cloning a stacked branch, stack the
462
565
            new branch on top of the other branch's stacked-on branch.
463
566
        """
464
 
        return self.clone_on_transport(_mod_transport.get_transport(url),
 
567
        return self.clone_on_transport(get_transport(url),
465
568
                                       revision_id=revision_id,
466
569
                                       force_new_repo=force_new_repo,
467
570
                                       preserve_stacking=preserve_stacking)
468
571
 
469
572
    def clone_on_transport(self, transport, revision_id=None,
470
573
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
471
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
472
 
        """Clone this controldir and its contents to transport verbatim.
 
574
        create_prefix=False, use_existing_dir=True):
 
575
        """Clone this bzrdir and its contents to transport verbatim.
473
576
 
474
577
        :param transport: The transport for the location to produce the clone
475
578
            at.  If the target directory does not exist, it will be created.
483
586
        :param create_prefix: Create any missing directories leading up to
484
587
            to_transport.
485
588
        :param use_existing_dir: Use an existing directory if one exists.
486
 
        :param no_tree: If set to true prevents creation of a working tree.
487
589
        """
488
590
        raise NotImplementedError(self.clone_on_transport)
489
591
 
490
 
    @classmethod
491
 
    def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
492
 
        """Find control dirs recursively from current location.
493
 
 
494
 
        This is intended primarily as a building block for more sophisticated
495
 
        functionality, like finding trees under a directory, or finding
496
 
        branches that use a given repository.
497
 
 
498
 
        :param evaluate: An optional callable that yields recurse, value,
499
 
            where recurse controls whether this controldir is recursed into
500
 
            and value is the value to yield.  By default, all bzrdirs
501
 
            are recursed into, and the return value is the controldir.
502
 
        :param list_current: if supplied, use this function to list the current
503
 
            directory, instead of Transport.list_dir
504
 
        :return: a generator of found bzrdirs, or whatever evaluate returns.
505
 
        """
506
 
        if list_current is None:
507
 
            def list_current(transport):
508
 
                return transport.list_dir('')
509
 
        if evaluate is None:
510
 
            def evaluate(controldir):
511
 
                return True, controldir
512
 
 
513
 
        pending = [transport]
514
 
        while len(pending) > 0:
515
 
            current_transport = pending.pop()
516
 
            recurse = True
517
 
            try:
518
 
                controldir = klass.open_from_transport(current_transport)
519
 
            except (errors.NotBranchError, errors.PermissionDenied):
520
 
                pass
521
 
            else:
522
 
                recurse, value = evaluate(controldir)
523
 
                yield value
524
 
            try:
525
 
                subdirs = list_current(current_transport)
526
 
            except (errors.NoSuchFile, errors.PermissionDenied):
527
 
                continue
528
 
            if recurse:
529
 
                for subdir in sorted(subdirs, reverse=True):
530
 
                    pending.append(current_transport.clone(subdir))
531
 
 
532
 
    @classmethod
533
 
    def find_branches(klass, transport):
534
 
        """Find all branches under a transport.
535
 
 
536
 
        This will find all branches below the transport, including branches
537
 
        inside other branches.  Where possible, it will use
538
 
        Repository.find_branches.
539
 
 
540
 
        To list all the branches that use a particular Repository, see
541
 
        Repository.find_branches
542
 
        """
543
 
        def evaluate(controldir):
544
 
            try:
545
 
                repository = controldir.open_repository()
546
 
            except errors.NoRepositoryPresent:
547
 
                pass
548
 
            else:
549
 
                return False, ([], repository)
550
 
            return True, (controldir.list_branches(), None)
551
 
        ret = []
552
 
        for branches, repo in klass.find_bzrdirs(
553
 
                transport, evaluate=evaluate):
554
 
            if repo is not None:
555
 
                ret.extend(repo.find_branches())
556
 
            if branches is not None:
557
 
                ret.extend(branches)
558
 
        return ret
559
 
 
560
 
    @classmethod
561
 
    def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
562
 
        """Create a new ControlDir, Branch and Repository at the url 'base'.
563
 
 
564
 
        This will use the current default ControlDirFormat unless one is
565
 
        specified, and use whatever
566
 
        repository format that that uses via controldir.create_branch and
567
 
        create_repository. If a shared repository is available that is used
568
 
        preferentially.
569
 
 
570
 
        The created Branch object is returned.
571
 
 
572
 
        :param base: The URL to create the branch at.
573
 
        :param force_new_repo: If True a new repository is always created.
574
 
        :param format: If supplied, the format of branch to create.  If not
575
 
            supplied, the default is used.
576
 
        """
577
 
        controldir = klass.create(base, format)
578
 
        controldir._find_or_create_repository(force_new_repo)
579
 
        return controldir.create_branch()
580
 
 
581
 
    @classmethod
582
 
    def create_branch_convenience(klass, base, force_new_repo=False,
583
 
                                  force_new_tree=None, format=None,
584
 
                                  possible_transports=None):
585
 
        """Create a new ControlDir, Branch and Repository at the url 'base'.
586
 
 
587
 
        This is a convenience function - it will use an existing repository
588
 
        if possible, can be told explicitly whether to create a working tree or
589
 
        not.
590
 
 
591
 
        This will use the current default ControlDirFormat unless one is
592
 
        specified, and use whatever
593
 
        repository format that that uses via ControlDir.create_branch and
594
 
        create_repository. If a shared repository is available that is used
595
 
        preferentially. Whatever repository is used, its tree creation policy
596
 
        is followed.
597
 
 
598
 
        The created Branch object is returned.
599
 
        If a working tree cannot be made due to base not being a file:// url,
600
 
        no error is raised unless force_new_tree is True, in which case no
601
 
        data is created on disk and NotLocalUrl is raised.
602
 
 
603
 
        :param base: The URL to create the branch at.
604
 
        :param force_new_repo: If True a new repository is always created.
605
 
        :param force_new_tree: If True or False force creation of a tree or
606
 
                               prevent such creation respectively.
607
 
        :param format: Override for the controldir format to create.
608
 
        :param possible_transports: An optional reusable transports list.
609
 
        """
610
 
        if force_new_tree:
611
 
            # check for non local urls
612
 
            t = _mod_transport.get_transport(base, possible_transports)
613
 
            if not isinstance(t, local.LocalTransport):
614
 
                raise errors.NotLocalUrl(base)
615
 
        controldir = klass.create(base, format, possible_transports)
616
 
        repo = controldir._find_or_create_repository(force_new_repo)
617
 
        result = controldir.create_branch()
618
 
        if force_new_tree or (repo.make_working_trees() and
619
 
                              force_new_tree is None):
620
 
            try:
621
 
                controldir.create_workingtree()
622
 
            except errors.NotLocalUrl:
623
 
                pass
624
 
        return result
625
 
 
626
 
    @classmethod
627
 
    def create_standalone_workingtree(klass, base, format=None):
628
 
        """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
629
 
 
630
 
        'base' must be a local path or a file:// url.
631
 
 
632
 
        This will use the current default ControlDirFormat unless one is
633
 
        specified, and use whatever
634
 
        repository format that that uses for bzrdirformat.create_workingtree,
635
 
        create_branch and create_repository.
636
 
 
637
 
        :param format: Override for the controldir format to create.
638
 
        :return: The WorkingTree object.
639
 
        """
640
 
        t = _mod_transport.get_transport(base)
641
 
        if not isinstance(t, local.LocalTransport):
642
 
            raise errors.NotLocalUrl(base)
643
 
        controldir = klass.create_branch_and_repo(base,
644
 
                                               force_new_repo=True,
645
 
                                               format=format).bzrdir
646
 
        return controldir.create_workingtree()
647
 
 
648
 
    @classmethod
649
 
    def open_unsupported(klass, base):
650
 
        """Open a branch which is not supported."""
651
 
        return klass.open(base, _unsupported=True)
652
 
 
653
 
    @classmethod
654
 
    def open(klass, base, _unsupported=False, possible_transports=None):
655
 
        """Open an existing controldir, rooted at 'base' (url).
656
 
 
657
 
        :param _unsupported: a private parameter to the ControlDir class.
658
 
        """
659
 
        t = _mod_transport.get_transport(base, possible_transports)
660
 
        return klass.open_from_transport(t, _unsupported=_unsupported)
661
 
 
662
 
    @classmethod
663
 
    def open_from_transport(klass, transport, _unsupported=False,
664
 
                            _server_formats=True):
665
 
        """Open a controldir within a particular directory.
666
 
 
667
 
        :param transport: Transport containing the controldir.
668
 
        :param _unsupported: private.
669
 
        """
670
 
        for hook in klass.hooks['pre_open']:
671
 
            hook(transport)
672
 
        # Keep initial base since 'transport' may be modified while following
673
 
        # the redirections.
674
 
        base = transport.base
675
 
        def find_format(transport):
676
 
            return transport, ControlDirFormat.find_format(
677
 
                transport, _server_formats=_server_formats)
678
 
 
679
 
        def redirected(transport, e, redirection_notice):
680
 
            redirected_transport = transport._redirected_to(e.source, e.target)
681
 
            if redirected_transport is None:
682
 
                raise errors.NotBranchError(base)
683
 
            trace.note(gettext('{0} is{1} redirected to {2}').format(
684
 
                 transport.base, e.permanently, redirected_transport.base))
685
 
            return redirected_transport
686
 
 
687
 
        try:
688
 
            transport, format = _mod_transport.do_catching_redirections(
689
 
                find_format, transport, redirected)
690
 
        except errors.TooManyRedirections:
691
 
            raise errors.NotBranchError(base)
692
 
 
693
 
        format.check_support_status(_unsupported)
694
 
        return format.open(transport, _found=True)
695
 
 
696
 
    @classmethod
697
 
    def open_containing(klass, url, possible_transports=None):
698
 
        """Open an existing branch which contains url.
699
 
 
700
 
        :param url: url to search from.
701
 
 
702
 
        See open_containing_from_transport for more detail.
703
 
        """
704
 
        transport = _mod_transport.get_transport(url, possible_transports)
705
 
        return klass.open_containing_from_transport(transport)
706
 
 
707
 
    @classmethod
708
 
    def open_containing_from_transport(klass, a_transport):
709
 
        """Open an existing branch which contains a_transport.base.
710
 
 
711
 
        This probes for a branch at a_transport, and searches upwards from there.
712
 
 
713
 
        Basically we keep looking up until we find the control directory or
714
 
        run into the root.  If there isn't one, raises NotBranchError.
715
 
        If there is one and it is either an unrecognised format or an unsupported
716
 
        format, UnknownFormatError or UnsupportedFormatError are raised.
717
 
        If there is one, it is returned, along with the unused portion of url.
718
 
 
719
 
        :return: The ControlDir that contains the path, and a Unicode path
720
 
                for the rest of the URL.
721
 
        """
722
 
        # this gets the normalised url back. I.e. '.' -> the full path.
723
 
        url = a_transport.base
724
 
        while True:
725
 
            try:
726
 
                result = klass.open_from_transport(a_transport)
727
 
                return result, urlutils.unescape(a_transport.relpath(url))
728
 
            except errors.NotBranchError, e:
729
 
                pass
730
 
            try:
731
 
                new_t = a_transport.clone('..')
732
 
            except errors.InvalidURLJoin:
733
 
                # reached the root, whatever that may be
734
 
                raise errors.NotBranchError(path=url)
735
 
            if new_t.base == a_transport.base:
736
 
                # reached the root, whatever that may be
737
 
                raise errors.NotBranchError(path=url)
738
 
            a_transport = new_t
739
 
 
740
 
    @classmethod
741
 
    def open_tree_or_branch(klass, location):
742
 
        """Return the branch and working tree at a location.
743
 
 
744
 
        If there is no tree at the location, tree will be None.
745
 
        If there is no branch at the location, an exception will be
746
 
        raised
747
 
        :return: (tree, branch)
748
 
        """
749
 
        controldir = klass.open(location)
750
 
        return controldir._get_tree_branch()
751
 
 
752
 
    @classmethod
753
 
    def open_containing_tree_or_branch(klass, location):
754
 
        """Return the branch and working tree contained by a location.
755
 
 
756
 
        Returns (tree, branch, relpath).
757
 
        If there is no tree at containing the location, tree will be None.
758
 
        If there is no branch containing the location, an exception will be
759
 
        raised
760
 
        relpath is the portion of the path that is contained by the branch.
761
 
        """
762
 
        controldir, relpath = klass.open_containing(location)
763
 
        tree, branch = controldir._get_tree_branch()
764
 
        return tree, branch, relpath
765
 
 
766
 
    @classmethod
767
 
    def open_containing_tree_branch_or_repository(klass, location):
768
 
        """Return the working tree, branch and repo contained by a location.
769
 
 
770
 
        Returns (tree, branch, repository, relpath).
771
 
        If there is no tree containing the location, tree will be None.
772
 
        If there is no branch containing the location, branch will be None.
773
 
        If there is no repository containing the location, repository will be
774
 
        None.
775
 
        relpath is the portion of the path that is contained by the innermost
776
 
        ControlDir.
777
 
 
778
 
        If no tree, branch or repository is found, a NotBranchError is raised.
779
 
        """
780
 
        controldir, relpath = klass.open_containing(location)
781
 
        try:
782
 
            tree, branch = controldir._get_tree_branch()
783
 
        except errors.NotBranchError:
784
 
            try:
785
 
                repo = controldir.find_repository()
786
 
                return None, None, repo, relpath
787
 
            except (errors.NoRepositoryPresent):
788
 
                raise errors.NotBranchError(location)
789
 
        return tree, branch, branch.repository, relpath
790
 
 
791
 
    @classmethod
792
 
    def create(klass, base, format=None, possible_transports=None):
793
 
        """Create a new ControlDir at the url 'base'.
794
 
 
795
 
        :param format: If supplied, the format of branch to create.  If not
796
 
            supplied, the default is used.
797
 
        :param possible_transports: If supplied, a list of transports that
798
 
            can be reused to share a remote connection.
799
 
        """
800
 
        if klass is not ControlDir:
801
 
            raise AssertionError("ControlDir.create always creates the"
802
 
                "default format, not one of %r" % klass)
803
 
        t = _mod_transport.get_transport(base, possible_transports)
804
 
        t.ensure_base()
805
 
        if format is None:
806
 
            format = ControlDirFormat.get_default_format()
807
 
        return format.initialize_on_transport(t)
808
 
 
809
 
 
810
 
class ControlDirHooks(hooks.Hooks):
811
 
    """Hooks for ControlDir operations."""
812
 
 
813
 
    def __init__(self):
814
 
        """Create the default hooks."""
815
 
        hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
816
 
        self.add_hook('pre_open',
817
 
            "Invoked before attempting to open a ControlDir with the transport "
818
 
            "that the open will use.", (1, 14))
819
 
        self.add_hook('post_repo_init',
820
 
            "Invoked after a repository has been initialized. "
821
 
            "post_repo_init is called with a "
822
 
            "bzrlib.controldir.RepoInitHookParams.",
823
 
            (2, 2))
824
 
 
825
 
# install the default hooks
826
 
ControlDir.hooks = ControlDirHooks()
827
 
 
828
 
 
829
 
class ControlComponentFormat(object):
830
 
    """A component that can live inside of a .bzr meta directory."""
831
 
 
832
 
    upgrade_recommended = False
833
 
 
834
 
    def get_format_string(self):
835
 
        """Return the format of this format, if usable in meta directories."""
836
 
        raise NotImplementedError(self.get_format_string)
837
 
 
838
 
    def get_format_description(self):
839
 
        """Return the short description for this format."""
840
 
        raise NotImplementedError(self.get_format_description)
841
 
 
842
 
    def is_supported(self):
843
 
        """Is this format supported?
844
 
 
845
 
        Supported formats must be initializable and openable.
846
 
        Unsupported formats may not support initialization or committing or
847
 
        some other features depending on the reason for not being supported.
848
 
        """
849
 
        return True
850
 
 
851
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
852
 
        basedir=None):
853
 
        """Give an error or warning on old formats.
854
 
 
855
 
        :param allow_unsupported: If true, allow opening
856
 
            formats that are strongly deprecated, and which may
857
 
            have limited functionality.
858
 
 
859
 
        :param recommend_upgrade: If true (default), warn
860
 
            the user through the ui object that they may wish
861
 
            to upgrade the object.
862
 
        """
863
 
        if not allow_unsupported and not self.is_supported():
864
 
            # see open_downlevel to open legacy branches.
865
 
            raise errors.UnsupportedFormatError(format=self)
866
 
        if recommend_upgrade and self.upgrade_recommended:
867
 
            ui.ui_factory.recommend_upgrade(
868
 
                self.get_format_description(), basedir)
869
 
 
870
 
 
871
 
class ControlComponentFormatRegistry(registry.FormatRegistry):
872
 
    """A registry for control components (branch, workingtree, repository)."""
873
 
 
874
 
    def __init__(self, other_registry=None):
875
 
        super(ControlComponentFormatRegistry, self).__init__(other_registry)
876
 
        self._extra_formats = []
877
 
 
878
 
    def register(self, format):
879
 
        """Register a new format."""
880
 
        super(ControlComponentFormatRegistry, self).register(
881
 
            format.get_format_string(), format)
882
 
 
883
 
    def remove(self, format):
884
 
        """Remove a registered format."""
885
 
        super(ControlComponentFormatRegistry, self).remove(
886
 
            format.get_format_string())
887
 
 
888
 
    def register_extra(self, format):
889
 
        """Register a format that can not be used in a metadir.
890
 
 
891
 
        This is mainly useful to allow custom repository formats, such as older
892
 
        Bazaar formats and foreign formats, to be tested.
893
 
        """
894
 
        self._extra_formats.append(registry._ObjectGetter(format))
895
 
 
896
 
    def remove_extra(self, format):
897
 
        """Remove an extra format.
898
 
        """
899
 
        self._extra_formats.remove(registry._ObjectGetter(format))
900
 
 
901
 
    def register_extra_lazy(self, module_name, member_name):
902
 
        """Register a format lazily.
903
 
        """
904
 
        self._extra_formats.append(
905
 
            registry._LazyObjectGetter(module_name, member_name))
906
 
 
907
 
    def _get_extra(self):
908
 
        """Return all "extra" formats, not usable in meta directories."""
909
 
        result = []
910
 
        for getter in self._extra_formats:
911
 
            f = getter.get_obj()
912
 
            if callable(f):
913
 
                f = f()
914
 
            result.append(f)
915
 
        return result
916
 
 
917
 
    def _get_all(self):
918
 
        """Return all formats, even those not usable in metadirs.
919
 
        """
920
 
        result = []
921
 
        for name in self.keys():
922
 
            fmt = self.get(name)
923
 
            if callable(fmt):
924
 
                fmt = fmt()
925
 
            result.append(fmt)
926
 
        return result + self._get_extra()
927
 
 
928
 
    def _get_all_modules(self):
929
 
        """Return a set of the modules providing objects."""
930
 
        modules = set()
931
 
        for name in self.keys():
932
 
            modules.add(self._get_module(name))
933
 
        for getter in self._extra_formats:
934
 
            modules.add(getter.get_module())
935
 
        return modules
936
 
 
937
 
 
938
 
class Converter(object):
939
 
    """Converts a disk format object from one format to another."""
940
 
 
941
 
    def convert(self, to_convert, pb):
942
 
        """Perform the conversion of to_convert, giving feedback via pb.
943
 
 
944
 
        :param to_convert: The disk object to convert.
945
 
        :param pb: a progress bar to use for progress information.
946
 
        """
947
 
 
948
 
    def step(self, message):
949
 
        """Update the pb by a step."""
950
 
        self.count +=1
951
 
        self.pb.update(message, self.count, self.total)
952
 
 
953
592
 
954
593
class ControlDirFormat(object):
955
594
    """An encapsulation of the initialization and open routines for a format.
975
614
    _default_format = None
976
615
    """The default format used for new control directories."""
977
616
 
 
617
    _formats = []
 
618
    """The registered control formats - .bzr, ....
 
619
 
 
620
    This is a list of ControlDirFormat objects.
 
621
    """
 
622
 
978
623
    _server_probers = []
979
624
    """The registered server format probers, e.g. RemoteBzrProber.
980
625
 
992
637
    """
993
638
 
994
639
    supports_workingtrees = True
995
 
    """Whether working trees can exist in control directories of this format.
996
 
    """
997
 
 
998
 
    fixed_components = False
999
 
    """Whether components can not change format independent of the control dir.
1000
 
    """
1001
 
 
1002
 
    upgrade_recommended = False
1003
 
    """Whether an upgrade from this format is recommended."""
1004
640
 
1005
641
    def get_format_description(self):
1006
642
        """Return the short description for this format."""
1023
659
    def is_supported(self):
1024
660
        """Is this format supported?
1025
661
 
1026
 
        Supported formats must be openable.
 
662
        Supported formats must be initializable and openable.
1027
663
        Unsupported formats may not support initialization or committing or
1028
664
        some other features depending on the reason for not being supported.
1029
665
        """
1030
666
        return True
1031
667
 
1032
 
    def is_initializable(self):
1033
 
        """Whether new control directories of this format can be initialized.
1034
 
        """
1035
 
        return self.is_supported()
1036
 
 
1037
 
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1038
 
        basedir=None):
1039
 
        """Give an error or warning on old formats.
1040
 
 
1041
 
        :param allow_unsupported: If true, allow opening
1042
 
            formats that are strongly deprecated, and which may
1043
 
            have limited functionality.
1044
 
 
1045
 
        :param recommend_upgrade: If true (default), warn
1046
 
            the user through the ui object that they may wish
1047
 
            to upgrade the object.
1048
 
        """
1049
 
        if not allow_unsupported and not self.is_supported():
1050
 
            # see open_downlevel to open legacy branches.
1051
 
            raise errors.UnsupportedFormatError(format=self)
1052
 
        if recommend_upgrade and self.upgrade_recommended:
1053
 
            ui.ui_factory.recommend_upgrade(
1054
 
                self.get_format_description(), basedir)
1055
 
 
1056
668
    def same_model(self, target_format):
1057
669
        return (self.repository_format.rich_root_data ==
1058
670
            target_format.rich_root_data)
1062
674
        """Register a format that does not use '.bzr' for its control dir.
1063
675
 
1064
676
        """
1065
 
        raise errors.BzrError("ControlDirFormat.register_format() has been "
1066
 
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
677
        klass._formats.append(format)
1067
678
 
1068
679
    @classmethod
1069
680
    def register_prober(klass, prober):
1095
706
        return self.get_format_description().rstrip()
1096
707
 
1097
708
    @classmethod
 
709
    def unregister_format(klass, format):
 
710
        klass._formats.remove(format)
 
711
 
 
712
    @classmethod
1098
713
    def known_formats(klass):
1099
714
        """Return all the known formats.
1100
715
        """
1101
 
        result = set()
1102
 
        for prober_kls in klass._probers + klass._server_probers:
1103
 
            result.update(prober_kls.known_formats())
1104
 
        return result
 
716
        return set(klass._formats)
1105
717
 
1106
718
    @classmethod
1107
719
    def find_format(klass, transport, _server_formats=True):
1129
741
        Subclasses should typically override initialize_on_transport
1130
742
        instead of this method.
1131
743
        """
1132
 
        return self.initialize_on_transport(
1133
 
            _mod_transport.get_transport(url, possible_transports))
1134
 
 
 
744
        return self.initialize_on_transport(get_transport(url,
 
745
                                                          possible_transports))
1135
746
    def initialize_on_transport(self, transport):
1136
747
        """Initialize a new controldir in the base directory of a Transport."""
1137
748
        raise NotImplementedError(self.initialize_on_transport)
1195
806
        """Return the current default format."""
1196
807
        return klass._default_format
1197
808
 
1198
 
    def supports_transport(self, transport):
1199
 
        """Check if this format can be opened over a particular transport.
1200
 
        """
1201
 
        raise NotImplementedError(self.supports_transport)
1202
 
 
1203
809
 
1204
810
class Prober(object):
1205
 
    """Abstract class that can be used to detect a particular kind of
 
811
    """Abstract class that can be used to detect a particular kind of 
1206
812
    control directory.
1207
813
 
1208
 
    At the moment this just contains a single method to probe a particular
1209
 
    transport, but it may be extended in the future to e.g. avoid
 
814
    At the moment this just contains a single method to probe a particular 
 
815
    transport, but it may be extended in the future to e.g. avoid 
1210
816
    multiple levels of probing for Subversion repositories.
1211
 
 
1212
 
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
1213
 
    probers that detect .bzr/ directories and Bazaar smart servers,
1214
 
    respectively.
1215
 
 
1216
 
    Probers should be registered using the register_server_prober or
1217
 
    register_prober methods on ControlDirFormat.
1218
817
    """
1219
818
 
1220
819
    def probe_transport(self, transport):
1227
826
        """
1228
827
        raise NotImplementedError(self.probe_transport)
1229
828
 
1230
 
    @classmethod
1231
 
    def known_formats(klass):
1232
 
        """Return the control dir formats known by this prober.
1233
 
 
1234
 
        Multiple probers can return the same formats, so this should
1235
 
        return a set.
1236
 
 
1237
 
        :return: A set of known formats.
1238
 
        """
1239
 
        raise NotImplementedError(klass.known_formats)
1240
 
 
1241
829
 
1242
830
class ControlDirFormatInfo(object):
1243
831
 
1252
840
    """Registry of user-selectable ControlDir subformats.
1253
841
 
1254
842
    Differs from ControlDirFormat._formats in that it provides sub-formats,
1255
 
    e.g. BzrDirMeta1 with weave repository.  Also, it's more user-oriented.
 
843
    e.g. ControlDirMeta1 with weave repository.  Also, it's more user-oriented.
1256
844
    """
1257
845
 
1258
846
    def __init__(self):
1375
963
            return output
1376
964
 
1377
965
 
1378
 
class RepoInitHookParams(object):
1379
 
    """Object holding parameters passed to `*_repo_init` hooks.
1380
 
 
1381
 
    There are 4 fields that hooks may wish to access:
1382
 
 
1383
 
    :ivar repository: Repository created
1384
 
    :ivar format: Repository format
1385
 
    :ivar bzrdir: The controldir for the repository
1386
 
    :ivar shared: The repository is shared
1387
 
    """
1388
 
 
1389
 
    def __init__(self, repository, format, controldir, shared):
1390
 
        """Create a group of RepoInitHook parameters.
1391
 
 
1392
 
        :param repository: Repository created
1393
 
        :param format: Repository format
1394
 
        :param controldir: The controldir for the repository
1395
 
        :param shared: The repository is shared
1396
 
        """
1397
 
        self.repository = repository
1398
 
        self.format = format
1399
 
        self.bzrdir = controldir
1400
 
        self.shared = shared
1401
 
 
1402
 
    def __eq__(self, other):
1403
 
        return self.__dict__ == other.__dict__
1404
 
 
1405
 
    def __repr__(self):
1406
 
        if self.repository:
1407
 
            return "<%s for %s>" % (self.__class__.__name__,
1408
 
                self.repository)
1409
 
        else:
1410
 
            return "<%s for %s>" % (self.__class__.__name__,
1411
 
                self.bzrdir)
1412
 
 
1413
 
 
1414
966
# Please register new formats after old formats so that formats
1415
967
# appear in chronological order and format descriptions can build
1416
968
# on previous ones.