~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/controldir.py

(jelmer) Fix bug #1010339,
 use encoding_type='exact' for bzr testament (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
"""
24
24
 
25
 
from __future__ import absolute_import
26
 
 
27
25
from bzrlib.lazy_import import lazy_import
28
26
lazy_import(globals(), """
29
27
import textwrap
30
28
 
31
29
from bzrlib import (
32
30
    errors,
33
 
    hooks,
34
31
    revision as _mod_revision,
35
32
    transport as _mod_transport,
36
 
    trace,
37
33
    ui,
38
 
    urlutils,
39
34
    )
40
 
from bzrlib.transport import local
41
35
from bzrlib.push import (
42
36
    PushResult,
43
37
    )
44
38
 
45
 
from bzrlib.i18n import gettext
46
39
""")
47
40
 
48
41
from bzrlib import registry
81
74
        return self.user_transport.base
82
75
 
83
76
 
 
77
 
84
78
class ControlDir(ControlComponent):
85
79
    """A control directory.
86
80
 
108
102
        """Return a sequence of all branches local to this control directory.
109
103
 
110
104
        """
111
 
        return self.get_branches().values()
112
 
 
113
 
    def get_branches(self):
114
 
        """Get all branches in this control directory, as a dictionary.
115
 
        
116
 
        :return: Dictionary mapping branch names to instances.
117
 
        """
118
105
        try:
119
 
           return { "": self.open_branch() }
 
106
            return [self.open_branch()]
120
107
        except (errors.NotBranchError, errors.NoRepositoryPresent):
121
 
           return {}
 
108
            return []
122
109
 
123
110
    def is_control_filename(self, filename):
124
111
        """True if filename is the name of a path which is reserved for
158
145
        """Destroy the repository in this ControlDir."""
159
146
        raise NotImplementedError(self.destroy_repository)
160
147
 
161
 
    def create_branch(self, name=None, repository=None,
162
 
                      append_revisions_only=None):
 
148
    def create_branch(self, name=None, repository=None):
163
149
        """Create a branch in this ControlDir.
164
150
 
165
151
        :param name: Name of the colocated branch to create, None for
166
 
            the user selected branch or "" for the active branch.
167
 
        :param append_revisions_only: Whether this branch should only allow
168
 
            appending new revisions to its history.
 
152
            the default branch.
169
153
 
170
154
        The controldirs format will control what branch format is created.
171
155
        For more control see BranchFormatXX.create(a_controldir).
175
159
    def destroy_branch(self, name=None):
176
160
        """Destroy a branch in this ControlDir.
177
161
 
178
 
        :param name: Name of the branch to destroy, None for the 
179
 
            user selected branch or "" for the active branch.
180
 
        :raise NotBranchError: When the branch does not exist
 
162
        :param name: Name of the branch to destroy, None for the default 
 
163
            branch.
181
164
        """
182
165
        raise NotImplementedError(self.destroy_branch)
183
166
 
210
193
        """
211
194
        raise NotImplementedError(self.destroy_workingtree_metadata)
212
195
 
213
 
    def find_branch_format(self, name=None):
214
 
        """Find the branch 'format' for this controldir.
215
 
 
216
 
        This might be a synthetic object for e.g. RemoteBranch and SVN.
217
 
        """
218
 
        raise NotImplementedError(self.find_branch_format)
219
 
 
220
196
    def get_branch_reference(self, name=None):
221
197
        """Return the referenced URL for the branch in this controldir.
222
198
 
231
207
            raise errors.NoColocatedBranchSupport(self)
232
208
        return None
233
209
 
234
 
    def set_branch_reference(self, target_branch, name=None):
235
 
        """Set the referenced URL for the branch in this controldir.
236
 
 
237
 
        :param name: Optional colocated branch name
238
 
        :param target_branch: Branch to reference
239
 
        :raises NoColocatedBranchSupport: If a branch name was specified
240
 
            but colocated branches are not supported.
241
 
        :return: The referencing branch
242
 
        """
243
 
        raise NotImplementedError(self.set_branch_reference)
244
 
 
245
210
    def open_branch(self, name=None, unsupported=False,
246
 
                    ignore_fallbacks=False, possible_transports=None):
 
211
                    ignore_fallbacks=False):
247
212
        """Open the branch object at this ControlDir if one is present.
248
213
 
249
 
        :param unsupported: if True, then no longer supported branch formats can
250
 
            still be opened.
251
 
        :param ignore_fallbacks: Whether to open fallback repositories
252
 
        :param possible_transports: Transports to use for opening e.g.
253
 
            fallback repositories.
 
214
        If unsupported is True, then no longer supported branch formats can
 
215
        still be opened.
 
216
 
 
217
        TODO: static convenience version of this?
254
218
        """
255
219
        raise NotImplementedError(self.open_branch)
256
220
 
262
226
        get at a repository.
263
227
 
264
228
        :param _unsupported: a private parameter, not part of the api.
 
229
 
 
230
        TODO: static convenience version of this?
265
231
        """
266
232
        raise NotImplementedError(self.open_repository)
267
233
 
274
240
        """
275
241
        raise NotImplementedError(self.find_repository)
276
242
 
277
 
    def open_workingtree(self, unsupported=False,
 
243
    def open_workingtree(self, _unsupported=False,
278
244
                         recommend_upgrade=True, from_branch=None):
279
245
        """Open the workingtree object at this ControlDir if one is present.
280
246
 
295
261
        branch and discards it, and that's somewhat expensive.)
296
262
        """
297
263
        try:
298
 
            self.open_branch(name, ignore_fallbacks=True)
 
264
            self.open_branch(name)
299
265
            return True
300
266
        except errors.NotBranchError:
301
267
            return False
302
268
 
303
 
    def _get_selected_branch(self):
304
 
        """Return the name of the branch selected by the user.
305
 
 
306
 
        :return: Name of the branch selected by the user, or "".
307
 
        """
308
 
        branch = self.root_transport.get_segment_parameters().get("branch")
309
 
        if branch is None:
310
 
            branch = ""
311
 
        return urlutils.unescape(branch)
312
 
 
313
269
    def has_workingtree(self):
314
270
        """Tell if this controldir contains a working tree.
315
271
 
342
298
        raise NotImplementedError(self.cloning_metadir)
343
299
 
344
300
    def checkout_metadir(self):
345
 
        """Produce a metadir suitable for checkouts of this controldir.
346
 
 
347
 
        :returns: A ControlDirFormat with all component formats
348
 
            either set appropriately or set to None if that component
349
 
            should not be created.
350
 
        """
 
301
        """Produce a metadir suitable for checkouts of this controldir."""
351
302
        return self.cloning_metadir()
352
303
 
353
304
    def sprout(self, url, revision_id=None, force_new_repo=False,
444
395
        return push_result
445
396
 
446
397
    def _get_tree_branch(self, name=None):
447
 
        """Return the branch and tree, if any, for this controldir.
 
398
        """Return the branch and tree, if any, for this bzrdir.
448
399
 
449
400
        :param name: Name of colocated branch to open.
450
401
 
469
420
        raise NotImplementedError(self.get_config)
470
421
 
471
422
    def check_conversion_target(self, target_format):
472
 
        """Check that a controldir as a whole can be converted to a new format."""
 
423
        """Check that a bzrdir as a whole can be converted to a new format."""
473
424
        raise NotImplementedError(self.check_conversion_target)
474
425
 
475
426
    def clone(self, url, revision_id=None, force_new_repo=False,
476
427
              preserve_stacking=False):
477
 
        """Clone this controldir and its contents to url verbatim.
 
428
        """Clone this bzrdir and its contents to url verbatim.
478
429
 
479
430
        :param url: The url create the clone at.  If url's last component does
480
431
            not exist, it will be created.
494
445
    def clone_on_transport(self, transport, revision_id=None,
495
446
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
496
447
        create_prefix=False, use_existing_dir=True, no_tree=False):
497
 
        """Clone this controldir and its contents to transport verbatim.
 
448
        """Clone this bzrdir and its contents to transport verbatim.
498
449
 
499
450
        :param transport: The transport for the location to produce the clone
500
451
            at.  If the target directory does not exist, it will be created.
512
463
        """
513
464
        raise NotImplementedError(self.clone_on_transport)
514
465
 
515
 
    @classmethod
516
 
    def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
517
 
        """Find control dirs recursively from current location.
518
 
 
519
 
        This is intended primarily as a building block for more sophisticated
520
 
        functionality, like finding trees under a directory, or finding
521
 
        branches that use a given repository.
522
 
 
523
 
        :param evaluate: An optional callable that yields recurse, value,
524
 
            where recurse controls whether this controldir is recursed into
525
 
            and value is the value to yield.  By default, all bzrdirs
526
 
            are recursed into, and the return value is the controldir.
527
 
        :param list_current: if supplied, use this function to list the current
528
 
            directory, instead of Transport.list_dir
529
 
        :return: a generator of found bzrdirs, or whatever evaluate returns.
530
 
        """
531
 
        if list_current is None:
532
 
            def list_current(transport):
533
 
                return transport.list_dir('')
534
 
        if evaluate is None:
535
 
            def evaluate(controldir):
536
 
                return True, controldir
537
 
 
538
 
        pending = [transport]
539
 
        while len(pending) > 0:
540
 
            current_transport = pending.pop()
541
 
            recurse = True
542
 
            try:
543
 
                controldir = klass.open_from_transport(current_transport)
544
 
            except (errors.NotBranchError, errors.PermissionDenied):
545
 
                pass
546
 
            else:
547
 
                recurse, value = evaluate(controldir)
548
 
                yield value
549
 
            try:
550
 
                subdirs = list_current(current_transport)
551
 
            except (errors.NoSuchFile, errors.PermissionDenied):
552
 
                continue
553
 
            if recurse:
554
 
                for subdir in sorted(subdirs, reverse=True):
555
 
                    pending.append(current_transport.clone(subdir))
556
 
 
557
 
    @classmethod
558
 
    def find_branches(klass, transport):
559
 
        """Find all branches under a transport.
560
 
 
561
 
        This will find all branches below the transport, including branches
562
 
        inside other branches.  Where possible, it will use
563
 
        Repository.find_branches.
564
 
 
565
 
        To list all the branches that use a particular Repository, see
566
 
        Repository.find_branches
567
 
        """
568
 
        def evaluate(controldir):
569
 
            try:
570
 
                repository = controldir.open_repository()
571
 
            except errors.NoRepositoryPresent:
572
 
                pass
573
 
            else:
574
 
                return False, ([], repository)
575
 
            return True, (controldir.list_branches(), None)
576
 
        ret = []
577
 
        for branches, repo in klass.find_bzrdirs(
578
 
                transport, evaluate=evaluate):
579
 
            if repo is not None:
580
 
                ret.extend(repo.find_branches())
581
 
            if branches is not None:
582
 
                ret.extend(branches)
583
 
        return ret
584
 
 
585
 
    @classmethod
586
 
    def create_branch_and_repo(klass, base, force_new_repo=False, format=None):
587
 
        """Create a new ControlDir, Branch and Repository at the url 'base'.
588
 
 
589
 
        This will use the current default ControlDirFormat unless one is
590
 
        specified, and use whatever
591
 
        repository format that that uses via controldir.create_branch and
592
 
        create_repository. If a shared repository is available that is used
593
 
        preferentially.
594
 
 
595
 
        The created Branch object is returned.
596
 
 
597
 
        :param base: The URL to create the branch at.
598
 
        :param force_new_repo: If True a new repository is always created.
599
 
        :param format: If supplied, the format of branch to create.  If not
600
 
            supplied, the default is used.
601
 
        """
602
 
        controldir = klass.create(base, format)
603
 
        controldir._find_or_create_repository(force_new_repo)
604
 
        return controldir.create_branch()
605
 
 
606
 
    @classmethod
607
 
    def create_branch_convenience(klass, base, force_new_repo=False,
608
 
                                  force_new_tree=None, format=None,
609
 
                                  possible_transports=None):
610
 
        """Create a new ControlDir, Branch and Repository at the url 'base'.
611
 
 
612
 
        This is a convenience function - it will use an existing repository
613
 
        if possible, can be told explicitly whether to create a working tree or
614
 
        not.
615
 
 
616
 
        This will use the current default ControlDirFormat unless one is
617
 
        specified, and use whatever
618
 
        repository format that that uses via ControlDir.create_branch and
619
 
        create_repository. If a shared repository is available that is used
620
 
        preferentially. Whatever repository is used, its tree creation policy
621
 
        is followed.
622
 
 
623
 
        The created Branch object is returned.
624
 
        If a working tree cannot be made due to base not being a file:// url,
625
 
        no error is raised unless force_new_tree is True, in which case no
626
 
        data is created on disk and NotLocalUrl is raised.
627
 
 
628
 
        :param base: The URL to create the branch at.
629
 
        :param force_new_repo: If True a new repository is always created.
630
 
        :param force_new_tree: If True or False force creation of a tree or
631
 
                               prevent such creation respectively.
632
 
        :param format: Override for the controldir format to create.
633
 
        :param possible_transports: An optional reusable transports list.
634
 
        """
635
 
        if force_new_tree:
636
 
            # check for non local urls
637
 
            t = _mod_transport.get_transport(base, possible_transports)
638
 
            if not isinstance(t, local.LocalTransport):
639
 
                raise errors.NotLocalUrl(base)
640
 
        controldir = klass.create(base, format, possible_transports)
641
 
        repo = controldir._find_or_create_repository(force_new_repo)
642
 
        result = controldir.create_branch()
643
 
        if force_new_tree or (repo.make_working_trees() and
644
 
                              force_new_tree is None):
645
 
            try:
646
 
                controldir.create_workingtree()
647
 
            except errors.NotLocalUrl:
648
 
                pass
649
 
        return result
650
 
 
651
 
    @classmethod
652
 
    def create_standalone_workingtree(klass, base, format=None):
653
 
        """Create a new ControlDir, WorkingTree, Branch and Repository at 'base'.
654
 
 
655
 
        'base' must be a local path or a file:// url.
656
 
 
657
 
        This will use the current default ControlDirFormat unless one is
658
 
        specified, and use whatever
659
 
        repository format that that uses for bzrdirformat.create_workingtree,
660
 
        create_branch and create_repository.
661
 
 
662
 
        :param format: Override for the controldir format to create.
663
 
        :return: The WorkingTree object.
664
 
        """
665
 
        t = _mod_transport.get_transport(base)
666
 
        if not isinstance(t, local.LocalTransport):
667
 
            raise errors.NotLocalUrl(base)
668
 
        controldir = klass.create_branch_and_repo(base,
669
 
                                               force_new_repo=True,
670
 
                                               format=format).bzrdir
671
 
        return controldir.create_workingtree()
672
 
 
673
 
    @classmethod
674
 
    def open_unsupported(klass, base):
675
 
        """Open a branch which is not supported."""
676
 
        return klass.open(base, _unsupported=True)
677
 
 
678
 
    @classmethod
679
 
    def open(klass, base, possible_transports=None, probers=None,
680
 
             _unsupported=False):
681
 
        """Open an existing controldir, rooted at 'base' (url).
682
 
 
683
 
        :param _unsupported: a private parameter to the ControlDir class.
684
 
        """
685
 
        t = _mod_transport.get_transport(base, possible_transports)
686
 
        return klass.open_from_transport(t, probers=probers,
687
 
                _unsupported=_unsupported)
688
 
 
689
 
    @classmethod
690
 
    def open_from_transport(klass, transport, _unsupported=False,
691
 
                            probers=None):
692
 
        """Open a controldir within a particular directory.
693
 
 
694
 
        :param transport: Transport containing the controldir.
695
 
        :param _unsupported: private.
696
 
        """
697
 
        for hook in klass.hooks['pre_open']:
698
 
            hook(transport)
699
 
        # Keep initial base since 'transport' may be modified while following
700
 
        # the redirections.
701
 
        base = transport.base
702
 
        def find_format(transport):
703
 
            return transport, ControlDirFormat.find_format(transport,
704
 
                probers=probers)
705
 
 
706
 
        def redirected(transport, e, redirection_notice):
707
 
            redirected_transport = transport._redirected_to(e.source, e.target)
708
 
            if redirected_transport is None:
709
 
                raise errors.NotBranchError(base)
710
 
            trace.note(gettext('{0} is{1} redirected to {2}').format(
711
 
                 transport.base, e.permanently, redirected_transport.base))
712
 
            return redirected_transport
713
 
 
714
 
        try:
715
 
            transport, format = _mod_transport.do_catching_redirections(
716
 
                find_format, transport, redirected)
717
 
        except errors.TooManyRedirections:
718
 
            raise errors.NotBranchError(base)
719
 
 
720
 
        format.check_support_status(_unsupported)
721
 
        return format.open(transport, _found=True)
722
 
 
723
 
    @classmethod
724
 
    def open_containing(klass, url, possible_transports=None):
725
 
        """Open an existing branch which contains url.
726
 
 
727
 
        :param url: url to search from.
728
 
 
729
 
        See open_containing_from_transport for more detail.
730
 
        """
731
 
        transport = _mod_transport.get_transport(url, possible_transports)
732
 
        return klass.open_containing_from_transport(transport)
733
 
 
734
 
    @classmethod
735
 
    def open_containing_from_transport(klass, a_transport):
736
 
        """Open an existing branch which contains a_transport.base.
737
 
 
738
 
        This probes for a branch at a_transport, and searches upwards from there.
739
 
 
740
 
        Basically we keep looking up until we find the control directory or
741
 
        run into the root.  If there isn't one, raises NotBranchError.
742
 
        If there is one and it is either an unrecognised format or an unsupported
743
 
        format, UnknownFormatError or UnsupportedFormatError are raised.
744
 
        If there is one, it is returned, along with the unused portion of url.
745
 
 
746
 
        :return: The ControlDir that contains the path, and a Unicode path
747
 
                for the rest of the URL.
748
 
        """
749
 
        # this gets the normalised url back. I.e. '.' -> the full path.
750
 
        url = a_transport.base
751
 
        while True:
752
 
            try:
753
 
                result = klass.open_from_transport(a_transport)
754
 
                return result, urlutils.unescape(a_transport.relpath(url))
755
 
            except errors.NotBranchError, e:
756
 
                pass
757
 
            except errors.PermissionDenied:
758
 
                pass
759
 
            try:
760
 
                new_t = a_transport.clone('..')
761
 
            except errors.InvalidURLJoin:
762
 
                # reached the root, whatever that may be
763
 
                raise errors.NotBranchError(path=url)
764
 
            if new_t.base == a_transport.base:
765
 
                # reached the root, whatever that may be
766
 
                raise errors.NotBranchError(path=url)
767
 
            a_transport = new_t
768
 
 
769
 
    @classmethod
770
 
    def open_tree_or_branch(klass, location):
771
 
        """Return the branch and working tree at a location.
772
 
 
773
 
        If there is no tree at the location, tree will be None.
774
 
        If there is no branch at the location, an exception will be
775
 
        raised
776
 
        :return: (tree, branch)
777
 
        """
778
 
        controldir = klass.open(location)
779
 
        return controldir._get_tree_branch()
780
 
 
781
 
    @classmethod
782
 
    def open_containing_tree_or_branch(klass, location,
783
 
            possible_transports=None):
784
 
        """Return the branch and working tree contained by a location.
785
 
 
786
 
        Returns (tree, branch, relpath).
787
 
        If there is no tree at containing the location, tree will be None.
788
 
        If there is no branch containing the location, an exception will be
789
 
        raised
790
 
        relpath is the portion of the path that is contained by the branch.
791
 
        """
792
 
        controldir, relpath = klass.open_containing(location,
793
 
            possible_transports=possible_transports)
794
 
        tree, branch = controldir._get_tree_branch()
795
 
        return tree, branch, relpath
796
 
 
797
 
    @classmethod
798
 
    def open_containing_tree_branch_or_repository(klass, location):
799
 
        """Return the working tree, branch and repo contained by a location.
800
 
 
801
 
        Returns (tree, branch, repository, relpath).
802
 
        If there is no tree containing the location, tree will be None.
803
 
        If there is no branch containing the location, branch will be None.
804
 
        If there is no repository containing the location, repository will be
805
 
        None.
806
 
        relpath is the portion of the path that is contained by the innermost
807
 
        ControlDir.
808
 
 
809
 
        If no tree, branch or repository is found, a NotBranchError is raised.
810
 
        """
811
 
        controldir, relpath = klass.open_containing(location)
812
 
        try:
813
 
            tree, branch = controldir._get_tree_branch()
814
 
        except errors.NotBranchError:
815
 
            try:
816
 
                repo = controldir.find_repository()
817
 
                return None, None, repo, relpath
818
 
            except (errors.NoRepositoryPresent):
819
 
                raise errors.NotBranchError(location)
820
 
        return tree, branch, branch.repository, relpath
821
 
 
822
 
    @classmethod
823
 
    def create(klass, base, format=None, possible_transports=None):
824
 
        """Create a new ControlDir at the url 'base'.
825
 
 
826
 
        :param format: If supplied, the format of branch to create.  If not
827
 
            supplied, the default is used.
828
 
        :param possible_transports: If supplied, a list of transports that
829
 
            can be reused to share a remote connection.
830
 
        """
831
 
        if klass is not ControlDir:
832
 
            raise AssertionError("ControlDir.create always creates the"
833
 
                "default format, not one of %r" % klass)
834
 
        t = _mod_transport.get_transport(base, possible_transports)
835
 
        t.ensure_base()
836
 
        if format is None:
837
 
            format = ControlDirFormat.get_default_format()
838
 
        return format.initialize_on_transport(t)
839
 
 
840
 
 
841
 
class ControlDirHooks(hooks.Hooks):
842
 
    """Hooks for ControlDir operations."""
843
 
 
844
 
    def __init__(self):
845
 
        """Create the default hooks."""
846
 
        hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
847
 
        self.add_hook('pre_open',
848
 
            "Invoked before attempting to open a ControlDir with the transport "
849
 
            "that the open will use.", (1, 14))
850
 
        self.add_hook('post_repo_init',
851
 
            "Invoked after a repository has been initialized. "
852
 
            "post_repo_init is called with a "
853
 
            "bzrlib.controldir.RepoInitHookParams.",
854
 
            (2, 2))
855
 
 
856
 
# install the default hooks
857
 
ControlDir.hooks = ControlDirHooks()
858
 
 
859
466
 
860
467
class ControlComponentFormat(object):
861
 
    """A component that can live inside of a control directory."""
 
468
    """A component that can live inside of a .bzr meta directory."""
862
469
 
863
470
    upgrade_recommended = False
864
471
 
 
472
    def get_format_string(self):
 
473
        """Return the format of this format, if usable in meta directories."""
 
474
        raise NotImplementedError(self.get_format_string)
 
475
 
865
476
    def get_format_description(self):
866
477
        """Return the short description for this format."""
867
478
        raise NotImplementedError(self.get_format_description)
894
505
            ui.ui_factory.recommend_upgrade(
895
506
                self.get_format_description(), basedir)
896
507
 
897
 
    @classmethod
898
 
    def get_format_string(cls):
899
 
        raise NotImplementedError(cls.get_format_string)
900
 
 
901
508
 
902
509
class ControlComponentFormatRegistry(registry.FormatRegistry):
903
510
    """A registry for control components (branch, workingtree, repository)."""
1054
661
    def is_supported(self):
1055
662
        """Is this format supported?
1056
663
 
1057
 
        Supported formats must be openable.
 
664
        Supported formats must be initializable and openable.
1058
665
        Unsupported formats may not support initialization or committing or
1059
666
        some other features depending on the reason for not being supported.
1060
667
        """
1061
668
        return True
1062
669
 
1063
 
    def is_initializable(self):
1064
 
        """Whether new control directories of this format can be initialized.
1065
 
        """
1066
 
        return self.is_supported()
1067
 
 
1068
670
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1069
671
        basedir=None):
1070
672
        """Give an error or warning on old formats.
1126
728
        return self.get_format_description().rstrip()
1127
729
 
1128
730
    @classmethod
1129
 
    def all_probers(klass):
1130
 
        return klass._server_probers + klass._probers
1131
 
 
1132
 
    @classmethod
1133
731
    def known_formats(klass):
1134
732
        """Return all the known formats.
1135
733
        """
1136
734
        result = set()
1137
 
        for prober_kls in klass.all_probers():
 
735
        for prober_kls in klass._probers + klass._server_probers:
1138
736
            result.update(prober_kls.known_formats())
1139
737
        return result
1140
738
 
1141
739
    @classmethod
1142
 
    def find_format(klass, transport, probers=None):
 
740
    def find_format(klass, transport, _server_formats=True):
1143
741
        """Return the format present at transport."""
1144
 
        if probers is None:
1145
 
            probers = klass.all_probers()
1146
 
        for prober_kls in probers:
 
742
        if _server_formats:
 
743
            _probers = klass._server_probers + klass._probers
 
744
        else:
 
745
            _probers = klass._probers
 
746
        for prober_kls in _probers:
1147
747
            prober = prober_kls()
1148
748
            try:
1149
749
                return prober.probe_transport(transport)
1228
828
        """Return the current default format."""
1229
829
        return klass._default_format
1230
830
 
1231
 
    def supports_transport(self, transport):
1232
 
        """Check if this format can be opened over a particular transport.
1233
 
        """
1234
 
        raise NotImplementedError(self.supports_transport)
1235
 
 
1236
831
 
1237
832
class Prober(object):
1238
833
    """Abstract class that can be used to detect a particular kind of
1261
856
        raise NotImplementedError(self.probe_transport)
1262
857
 
1263
858
    @classmethod
1264
 
    def known_formats(klass):
 
859
    def known_formats(cls):
1265
860
        """Return the control dir formats known by this prober.
1266
861
 
1267
862
        Multiple probers can return the same formats, so this should
1269
864
 
1270
865
        :return: A set of known formats.
1271
866
        """
1272
 
        raise NotImplementedError(klass.known_formats)
 
867
        raise NotImplementedError(cls.known_formats)
1273
868
 
1274
869
 
1275
870
class ControlDirFormatInfo(object):
1408
1003
            return output
1409
1004
 
1410
1005
 
1411
 
class RepoInitHookParams(object):
1412
 
    """Object holding parameters passed to `*_repo_init` hooks.
1413
 
 
1414
 
    There are 4 fields that hooks may wish to access:
1415
 
 
1416
 
    :ivar repository: Repository created
1417
 
    :ivar format: Repository format
1418
 
    :ivar bzrdir: The controldir for the repository
1419
 
    :ivar shared: The repository is shared
1420
 
    """
1421
 
 
1422
 
    def __init__(self, repository, format, controldir, shared):
1423
 
        """Create a group of RepoInitHook parameters.
1424
 
 
1425
 
        :param repository: Repository created
1426
 
        :param format: Repository format
1427
 
        :param controldir: The controldir for the repository
1428
 
        :param shared: The repository is shared
1429
 
        """
1430
 
        self.repository = repository
1431
 
        self.format = format
1432
 
        self.bzrdir = controldir
1433
 
        self.shared = shared
1434
 
 
1435
 
    def __eq__(self, other):
1436
 
        return self.__dict__ == other.__dict__
1437
 
 
1438
 
    def __repr__(self):
1439
 
        if self.repository:
1440
 
            return "<%s for %s>" % (self.__class__.__name__,
1441
 
                self.repository)
1442
 
        else:
1443
 
            return "<%s for %s>" % (self.__class__.__name__,
1444
 
                self.bzrdir)
1445
 
 
1446
 
 
1447
1006
# Please register new formats after old formats so that formats
1448
1007
# appear in chronological order and format descriptions can build
1449
1008
# on previous ones.