/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/controldir.py

  • Committer: Breezy landing bot
  • Author(s): Colin Watson
  • Date: 2020-11-16 21:47:08 UTC
  • mfrom: (7521.1.1 remove-lp-workaround)
  • Revision ID: breezy.the.bot@gmail.com-20201116214708-jos209mgxi41oy15
Remove breezy.git workaround for bazaar.launchpad.net.

Merged from https://code.launchpad.net/~cjwatson/brz/remove-lp-workaround/+merge/393710

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
The ControlDir class is the base for the control directory used
20
20
by all bzr and foreign formats. For the ".bzr" implementation,
21
 
see bzrlib.bzrdir.BzrDir.
 
21
see breezy.bzrdir.BzrDir.
22
22
 
23
23
"""
24
24
 
25
 
from __future__ import absolute_import
26
 
 
27
 
from bzrlib.lazy_import import lazy_import
 
25
from .lazy_import import lazy_import
28
26
lazy_import(globals(), """
29
27
import textwrap
30
28
 
31
 
from bzrlib import (
32
 
    errors,
 
29
from breezy import (
 
30
    branch as _mod_branch,
33
31
    hooks,
34
32
    revision as _mod_revision,
35
33
    transport as _mod_transport,
37
35
    ui,
38
36
    urlutils,
39
37
    )
40
 
from bzrlib.transport import local
41
 
from bzrlib.push import (
 
38
from breezy.transport import local
 
39
from breezy.push import (
42
40
    PushResult,
43
41
    )
44
42
 
45
 
from bzrlib.i18n import gettext
 
43
from breezy.i18n import gettext
46
44
""")
47
45
 
48
 
from bzrlib import registry
 
46
from . import (
 
47
    errors,
 
48
    registry,
 
49
    )
 
50
 
 
51
 
 
52
class MustHaveWorkingTree(errors.BzrError):
 
53
 
 
54
    _fmt = "Branching '%(url)s'(%(format)s) must create a working tree."
 
55
 
 
56
    def __init__(self, format, url):
 
57
        errors.BzrError.__init__(self, format=format, url=url)
 
58
 
 
59
 
 
60
class BranchReferenceLoop(errors.BzrError):
 
61
 
 
62
    _fmt = "Can not create branch reference that points at branch itself."
 
63
 
 
64
    def __init__(self, branch):
 
65
        errors.BzrError.__init__(self, branch=branch)
49
66
 
50
67
 
51
68
class ControlComponent(object):
108
125
        """Return a sequence of all branches local to this control directory.
109
126
 
110
127
        """
111
 
        return self.get_branches().values()
 
128
        return list(self.get_branches().values())
 
129
 
 
130
    def branch_names(self):
 
131
        """List all branch names in this control directory.
 
132
 
 
133
        :return: List of branch names
 
134
        """
 
135
        try:
 
136
            self.get_branch_reference()
 
137
        except (errors.NotBranchError, errors.NoRepositoryPresent):
 
138
            return []
 
139
        else:
 
140
            return [""]
112
141
 
113
142
    def get_branches(self):
114
143
        """Get all branches in this control directory, as a dictionary.
115
 
        
 
144
 
116
145
        :return: Dictionary mapping branch names to instances.
117
146
        """
118
147
        try:
119
 
           return { "": self.open_branch() }
 
148
            return {"": self.open_branch()}
120
149
        except (errors.NotBranchError, errors.NoRepositoryPresent):
121
 
           return {}
 
150
            return {}
122
151
 
123
152
    def is_control_filename(self, filename):
124
153
        """True if filename is the name of a path which is reserved for
133
162
        this in the future - for instance to make bzr talk with svn working
134
163
        trees.
135
164
        """
136
 
        raise NotImplementedError(self.is_control_filename)
 
165
        return self._format.is_control_filename(filename)
137
166
 
138
167
    def needs_format_conversion(self, format=None):
139
168
        """Return true if this controldir needs convert_format run on it.
175
204
    def destroy_branch(self, name=None):
176
205
        """Destroy a branch in this ControlDir.
177
206
 
178
 
        :param name: Name of the branch to destroy, None for the 
 
207
        :param name: Name of the branch to destroy, None for the
179
208
            user selected branch or "" for the active branch.
180
209
        :raise NotBranchError: When the branch does not exist
181
210
        """
182
211
        raise NotImplementedError(self.destroy_branch)
183
212
 
184
213
    def create_workingtree(self, revision_id=None, from_branch=None,
185
 
        accelerator_tree=None, hardlink=False):
 
214
                           accelerator_tree=None, hardlink=False):
186
215
        """Create a working tree at this ControlDir.
187
216
 
188
217
        :param revision_id: create it as of this revision id.
189
 
        :param from_branch: override controldir branch 
 
218
        :param from_branch: override controldir branch
190
219
            (for lightweight checkouts)
191
220
        :param accelerator_tree: A tree which can be used for retrieving file
192
221
            contents more quickly than the revision tree, i.e. a workingtree.
353
382
    def sprout(self, url, revision_id=None, force_new_repo=False,
354
383
               recurse='down', possible_transports=None,
355
384
               accelerator_tree=None, hardlink=False, stacked=False,
356
 
               source_branch=None, create_tree_if_local=True):
 
385
               source_branch=None, create_tree_if_local=True,
 
386
               lossy=False):
357
387
        """Create a copy of this controldir prepared for use as a new line of
358
388
        development.
359
389
 
379
409
        """
380
410
        raise NotImplementedError(self.sprout)
381
411
 
382
 
    def push_branch(self, source, revision_id=None, overwrite=False, 
383
 
        remember=False, create_prefix=False):
 
412
    def push_branch(self, source, revision_id=None, overwrite=False,
 
413
                    remember=False, create_prefix=False, lossy=False,
 
414
                    tag_selector=None):
384
415
        """Push the source branch into this ControlDir."""
385
416
        br_to = None
386
417
        # If we can open a branch, use its direct repository, otherwise see
404
435
                # revision
405
436
                revision_id = source.last_revision()
406
437
            repository_to.fetch(source.repository, revision_id=revision_id)
407
 
            br_to = source.clone(self, revision_id=revision_id)
 
438
            br_to = source.sprout(
 
439
                self, revision_id=revision_id, lossy=lossy,
 
440
                tag_selector=tag_selector)
408
441
            if source.get_push_location() is None or remember:
409
442
                # FIXME: Should be done only if we succeed ? -- vila 2012-01-18
410
443
                source.set_push_location(br_to.base)
423
456
            try:
424
457
                tree_to = self.open_workingtree()
425
458
            except errors.NotLocalUrl:
426
 
                push_result.branch_push_result = source.push(br_to, 
427
 
                    overwrite, stop_revision=revision_id)
 
459
                push_result.branch_push_result = source.push(
 
460
                    br_to, overwrite, stop_revision=revision_id, lossy=lossy,
 
461
                    tag_selector=tag_selector)
428
462
                push_result.workingtree_updated = False
429
463
            except errors.NoWorkingTree:
430
 
                push_result.branch_push_result = source.push(br_to,
431
 
                    overwrite, stop_revision=revision_id)
432
 
                push_result.workingtree_updated = None # Not applicable
 
464
                push_result.branch_push_result = source.push(
 
465
                    br_to, overwrite, stop_revision=revision_id, lossy=lossy,
 
466
                    tag_selector=tag_selector)
 
467
                push_result.workingtree_updated = None  # Not applicable
433
468
            else:
434
 
                tree_to.lock_write()
435
 
                try:
 
469
                with tree_to.lock_write():
436
470
                    push_result.branch_push_result = source.push(
437
 
                        tree_to.branch, overwrite, stop_revision=revision_id)
 
471
                        tree_to.branch, overwrite, stop_revision=revision_id,
 
472
                        lossy=lossy, tag_selector=tag_selector)
438
473
                    tree_to.update()
439
 
                finally:
440
 
                    tree_to.unlock()
441
474
                push_result.workingtree_updated = True
442
475
            push_result.old_revno = push_result.branch_push_result.old_revno
443
476
            push_result.old_revid = push_result.branch_push_result.old_revid
475
508
        raise NotImplementedError(self.check_conversion_target)
476
509
 
477
510
    def clone(self, url, revision_id=None, force_new_repo=False,
478
 
              preserve_stacking=False):
 
511
              preserve_stacking=False, tag_selector=None):
479
512
        """Clone this controldir and its contents to url verbatim.
480
513
 
481
514
        :param url: The url create the clone at.  If url's last component does
491
524
        return self.clone_on_transport(_mod_transport.get_transport(url),
492
525
                                       revision_id=revision_id,
493
526
                                       force_new_repo=force_new_repo,
494
 
                                       preserve_stacking=preserve_stacking)
 
527
                                       preserve_stacking=preserve_stacking,
 
528
                                       tag_selector=tag_selector)
495
529
 
496
530
    def clone_on_transport(self, transport, revision_id=None,
497
 
        force_new_repo=False, preserve_stacking=False, stacked_on=None,
498
 
        create_prefix=False, use_existing_dir=True, no_tree=False):
 
531
                           force_new_repo=False, preserve_stacking=False, stacked_on=None,
 
532
                           create_prefix=False, use_existing_dir=True, no_tree=False,
 
533
                           tag_selector=None):
499
534
        """Clone this controldir and its contents to transport verbatim.
500
535
 
501
536
        :param transport: The transport for the location to produce the clone
515
550
        raise NotImplementedError(self.clone_on_transport)
516
551
 
517
552
    @classmethod
518
 
    def find_bzrdirs(klass, transport, evaluate=None, list_current=None):
 
553
    def find_controldirs(klass, transport, evaluate=None, list_current=None):
519
554
        """Find control dirs recursively from current location.
520
555
 
521
556
        This is intended primarily as a building block for more sophisticated
543
578
            recurse = True
544
579
            try:
545
580
                controldir = klass.open_from_transport(current_transport)
546
 
            except (errors.NotBranchError, errors.PermissionDenied):
 
581
            except (errors.NotBranchError, errors.PermissionDenied,
 
582
                    errors.UnknownFormatError):
547
583
                pass
548
584
            else:
549
585
                recurse, value = evaluate(controldir)
576
612
                return False, ([], repository)
577
613
            return True, (controldir.list_branches(), None)
578
614
        ret = []
579
 
        for branches, repo in klass.find_bzrdirs(
 
615
        for branches, repo in klass.find_controldirs(
580
616
                transport, evaluate=evaluate):
581
617
            if repo is not None:
582
618
                ret.extend(repo.find_branches())
668
704
        if not isinstance(t, local.LocalTransport):
669
705
            raise errors.NotLocalUrl(base)
670
706
        controldir = klass.create_branch_and_repo(base,
671
 
                                               force_new_repo=True,
672
 
                                               format=format).bzrdir
 
707
                                                  force_new_repo=True,
 
708
                                                  format=format).controldir
673
709
        return controldir.create_workingtree()
674
710
 
675
711
    @classmethod
686
722
        """
687
723
        t = _mod_transport.get_transport(base, possible_transports)
688
724
        return klass.open_from_transport(t, probers=probers,
689
 
                _unsupported=_unsupported)
 
725
                                         _unsupported=_unsupported)
690
726
 
691
727
    @classmethod
692
728
    def open_from_transport(klass, transport, _unsupported=False,
701
737
        # Keep initial base since 'transport' may be modified while following
702
738
        # the redirections.
703
739
        base = transport.base
 
740
 
704
741
        def find_format(transport):
705
742
            return transport, ControlDirFormat.find_format(transport,
706
 
                probers=probers)
 
743
                                                           probers=probers)
707
744
 
708
745
        def redirected(transport, e, redirection_notice):
709
746
            redirected_transport = transport._redirected_to(e.source, e.target)
710
747
            if redirected_transport is None:
711
748
                raise errors.NotBranchError(base)
712
749
            trace.note(gettext('{0} is{1} redirected to {2}').format(
713
 
                 transport.base, e.permanently, redirected_transport.base))
 
750
                transport.base, e.permanently, redirected_transport.base))
714
751
            return redirected_transport
715
752
 
716
753
        try:
754
791
            try:
755
792
                result = klass.open_from_transport(a_transport)
756
793
                return result, urlutils.unescape(a_transport.relpath(url))
757
 
            except errors.NotBranchError, e:
 
794
            except errors.NotBranchError:
758
795
                pass
759
796
            except errors.PermissionDenied:
760
797
                pass
761
798
            try:
762
799
                new_t = a_transport.clone('..')
763
 
            except errors.InvalidURLJoin:
 
800
            except urlutils.InvalidURLJoin:
764
801
                # reached the root, whatever that may be
765
802
                raise errors.NotBranchError(path=url)
766
803
            if new_t.base == a_transport.base:
769
806
            a_transport = new_t
770
807
 
771
808
    @classmethod
772
 
    def open_tree_or_branch(klass, location):
 
809
    def open_tree_or_branch(klass, location, name=None):
773
810
        """Return the branch and working tree at a location.
774
811
 
775
812
        If there is no tree at the location, tree will be None.
778
815
        :return: (tree, branch)
779
816
        """
780
817
        controldir = klass.open(location)
781
 
        return controldir._get_tree_branch()
 
818
        return controldir._get_tree_branch(name=name)
782
819
 
783
820
    @classmethod
784
821
    def open_containing_tree_or_branch(klass, location,
785
 
            possible_transports=None):
 
822
                                       possible_transports=None):
786
823
        """Return the branch and working tree contained by a location.
787
824
 
788
825
        Returns (tree, branch, relpath).
792
829
        relpath is the portion of the path that is contained by the branch.
793
830
        """
794
831
        controldir, relpath = klass.open_containing(location,
795
 
            possible_transports=possible_transports)
 
832
                                                    possible_transports=possible_transports)
796
833
        tree, branch = controldir._get_tree_branch()
797
834
        return tree, branch, relpath
798
835
 
832
869
        """
833
870
        if klass is not ControlDir:
834
871
            raise AssertionError("ControlDir.create always creates the"
835
 
                "default format, not one of %r" % klass)
 
872
                                 "default format, not one of %r" % klass)
836
873
        t = _mod_transport.get_transport(base, possible_transports)
837
874
        t.ensure_base()
838
875
        if format is None:
845
882
 
846
883
    def __init__(self):
847
884
        """Create the default hooks."""
848
 
        hooks.Hooks.__init__(self, "bzrlib.controldir", "ControlDir.hooks")
 
885
        hooks.Hooks.__init__(self, "breezy.controldir", "ControlDir.hooks")
849
886
        self.add_hook('pre_open',
850
 
            "Invoked before attempting to open a ControlDir with the transport "
851
 
            "that the open will use.", (1, 14))
 
887
                      "Invoked before attempting to open a ControlDir with the transport "
 
888
                      "that the open will use.", (1, 14))
852
889
        self.add_hook('post_repo_init',
853
 
            "Invoked after a repository has been initialized. "
854
 
            "post_repo_init is called with a "
855
 
            "bzrlib.controldir.RepoInitHookParams.",
856
 
            (2, 2))
 
890
                      "Invoked after a repository has been initialized. "
 
891
                      "post_repo_init is called with a "
 
892
                      "breezy.controldir.RepoInitHookParams.",
 
893
                      (2, 2))
 
894
 
857
895
 
858
896
# install the default hooks
859
897
ControlDir.hooks = ControlDirHooks()
878
916
        return True
879
917
 
880
918
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
881
 
        basedir=None):
 
919
                             basedir=None):
882
920
        """Give an error or warning on old formats.
883
921
 
884
922
        :param allow_unsupported: If true, allow opening
938
976
            registry._LazyObjectGetter(module_name, member_name))
939
977
 
940
978
    def _get_extra(self):
941
 
        """Return all "extra" formats, not usable in meta directories."""
942
 
        result = []
943
 
        for getter in self._extra_formats:
944
 
            f = getter.get_obj()
945
 
            if callable(f):
946
 
                f = f()
947
 
            result.append(f)
 
979
        """Return getters for extra formats, not usable in meta directories."""
 
980
        return [getter.get_obj for getter in self._extra_formats]
 
981
 
 
982
    def _get_all_lazy(self):
 
983
        """Return getters for all formats, even those not usable in metadirs."""
 
984
        result = [self._dict[name].get_obj for name in self.keys()]
 
985
        result.extend(self._get_extra())
948
986
        return result
949
987
 
950
988
    def _get_all(self):
951
 
        """Return all formats, even those not usable in metadirs.
952
 
        """
 
989
        """Return all formats, even those not usable in metadirs."""
953
990
        result = []
954
 
        for name in self.keys():
955
 
            fmt = self.get(name)
 
991
        for getter in self._get_all_lazy():
 
992
            fmt = getter()
956
993
            if callable(fmt):
957
994
                fmt = fmt()
958
995
            result.append(fmt)
959
 
        return result + self._get_extra()
 
996
        return result
960
997
 
961
998
    def _get_all_modules(self):
962
999
        """Return a set of the modules providing objects."""
980
1017
 
981
1018
    def step(self, message):
982
1019
        """Update the pb by a step."""
983
 
        self.count +=1
 
1020
        self.count += 1
984
1021
        self.pb.update(message, self.count, self.total)
985
1022
 
986
1023
 
1008
1045
    _default_format = None
1009
1046
    """The default format used for new control directories."""
1010
1047
 
1011
 
    _server_probers = []
1012
 
    """The registered server format probers, e.g. RemoteBzrProber.
1013
 
 
1014
 
    This is a list of Prober-derived classes.
1015
 
    """
1016
 
 
1017
1048
    _probers = []
1018
1049
    """The registered format probers, e.g. BzrProber.
1019
1050
 
1042
1073
    def get_converter(self, format=None):
1043
1074
        """Return the converter to use to convert controldirs needing converts.
1044
1075
 
1045
 
        This returns a bzrlib.controldir.Converter object.
 
1076
        This returns a breezy.controldir.Converter object.
1046
1077
 
1047
1078
        This should return the best upgrader to step this format towards the
1048
1079
        current default format. In the case of plugins we can/should provide
1068
1099
        return self.is_supported()
1069
1100
 
1070
1101
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
1071
 
        basedir=None):
 
1102
                             basedir=None):
1072
1103
        """Give an error or warning on old formats.
1073
1104
 
1074
1105
        :param allow_unsupported: If true, allow opening
1088
1119
 
1089
1120
    def same_model(self, target_format):
1090
1121
        return (self.repository_format.rich_root_data ==
1091
 
            target_format.rich_root_data)
1092
 
 
1093
 
    @classmethod
1094
 
    def register_format(klass, format):
1095
 
        """Register a format that does not use '.bzr' for its control dir.
1096
 
 
1097
 
        """
1098
 
        raise errors.BzrError("ControlDirFormat.register_format() has been "
1099
 
            "removed in Bazaar 2.4. Please upgrade your plugins.")
 
1122
                target_format.rich_root_data)
1100
1123
 
1101
1124
    @classmethod
1102
1125
    def register_prober(klass, prober):
1112
1135
        """
1113
1136
        klass._probers.remove(prober)
1114
1137
 
1115
 
    @classmethod
1116
 
    def register_server_prober(klass, prober):
1117
 
        """Register a control format prober for client-server environments.
1118
 
 
1119
 
        These probers will be used before ones registered with
1120
 
        register_prober.  This gives implementations that decide to the
1121
 
        chance to grab it before anything looks at the contents of the format
1122
 
        file.
1123
 
        """
1124
 
        klass._server_probers.append(prober)
1125
 
 
1126
1138
    def __str__(self):
1127
1139
        # Trim the newline
1128
1140
        return self.get_format_description().rstrip()
1129
1141
 
1130
1142
    @classmethod
1131
1143
    def all_probers(klass):
1132
 
        return klass._server_probers + klass._probers
 
1144
        return klass._probers
1133
1145
 
1134
1146
    @classmethod
1135
1147
    def known_formats(klass):
1136
1148
        """Return all the known formats.
1137
1149
        """
1138
 
        result = set()
 
1150
        result = []
1139
1151
        for prober_kls in klass.all_probers():
1140
 
            result.update(prober_kls.known_formats())
 
1152
            result.extend(prober_kls.known_formats())
1141
1153
        return result
1142
1154
 
1143
1155
    @classmethod
1144
1156
    def find_format(klass, transport, probers=None):
1145
1157
        """Return the format present at transport."""
1146
1158
        if probers is None:
1147
 
            probers = klass.all_probers()
 
1159
            probers = sorted(
 
1160
                klass.all_probers(),
 
1161
                key=lambda prober: prober.priority(transport))
1148
1162
        for prober_kls in probers:
1149
1163
            prober = prober_kls()
1150
1164
            try:
1172
1186
        raise NotImplementedError(self.initialize_on_transport)
1173
1187
 
1174
1188
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
1175
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
1176
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
1177
 
        shared_repo=False, vfs_only=False):
 
1189
                                   create_prefix=False, force_new_repo=False, stacked_on=None,
 
1190
                                   stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
 
1191
                                   shared_repo=False, vfs_only=False):
1178
1192
        """Create this format on transport.
1179
1193
 
1180
1194
        The directory to initialize will be created.
1235
1249
        """
1236
1250
        raise NotImplementedError(self.supports_transport)
1237
1251
 
 
1252
    @classmethod
 
1253
    def is_control_filename(klass, filename):
 
1254
        """True if filename is the name of a path which is reserved for
 
1255
        controldirs.
 
1256
 
 
1257
        :param filename: A filename within the root transport of this
 
1258
            controldir.
 
1259
 
 
1260
        This is true IF and ONLY IF the filename is part of the namespace reserved
 
1261
        for bzr control dirs. Currently this is the '.bzr' directory in the root
 
1262
        of the root_transport. it is expected that plugins will need to extend
 
1263
        this in the future - for instance to make bzr talk with svn working
 
1264
        trees.
 
1265
        """
 
1266
        raise NotImplementedError(self.is_control_filename)
 
1267
 
1238
1268
 
1239
1269
class Prober(object):
1240
1270
    """Abstract class that can be used to detect a particular kind of
1244
1274
    transport, but it may be extended in the future to e.g. avoid
1245
1275
    multiple levels of probing for Subversion repositories.
1246
1276
 
1247
 
    See BzrProber and RemoteBzrProber in bzrlib.bzrdir for the
 
1277
    See BzrProber and RemoteBzrProber in breezy.bzrdir for the
1248
1278
    probers that detect .bzr/ directories and Bazaar smart servers,
1249
1279
    respectively.
1250
1280
 
1251
 
    Probers should be registered using the register_server_prober or
1252
 
    register_prober methods on ControlDirFormat.
 
1281
    Probers should be registered using the register_prober methods on
 
1282
    ControlDirFormat.
1253
1283
    """
1254
1284
 
1255
1285
    def probe_transport(self, transport):
1273
1303
        """
1274
1304
        raise NotImplementedError(klass.known_formats)
1275
1305
 
 
1306
    @classmethod
 
1307
    def priority(klass, transport):
 
1308
        """Priority of this prober.
 
1309
 
 
1310
        A lower value means the prober gets checked first.
 
1311
 
 
1312
        Other conventions:
 
1313
 
 
1314
        -10: This is a "server" prober
 
1315
        0: No priority set
 
1316
        10: This is a regular file-based prober
 
1317
        100: This is a prober for an unsupported format
 
1318
        """
 
1319
        return 0
 
1320
 
1276
1321
 
1277
1322
class ControlDirFormatInfo(object):
1278
1323
 
1292
1337
 
1293
1338
    def __init__(self):
1294
1339
        """Create a ControlDirFormatRegistry."""
1295
 
        self._aliases = set()
1296
1340
        self._registration_order = list()
1297
1341
        super(ControlDirFormatRegistry, self).__init__()
1298
1342
 
1299
 
    def aliases(self):
1300
 
        """Return a set of the format names which are aliases."""
1301
 
        return frozenset(self._aliases)
1302
 
 
1303
1343
    def register(self, key, factory, help, native=True, deprecated=False,
1304
 
                 hidden=False, experimental=False, alias=False):
 
1344
                 hidden=False, experimental=False):
1305
1345
        """Register a ControlDirFormat factory.
1306
1346
 
1307
1347
        The factory must be a callable that takes one parameter: the key.
1311
1351
        supplied directly.
1312
1352
        """
1313
1353
        registry.Registry.register(self, key, factory, help,
1314
 
            ControlDirFormatInfo(native, deprecated, hidden, experimental))
1315
 
        if alias:
1316
 
            self._aliases.add(key)
 
1354
                                   ControlDirFormatInfo(native, deprecated, hidden, experimental))
1317
1355
        self._registration_order.append(key)
1318
1356
 
 
1357
    def register_alias(self, key, target, hidden=False):
 
1358
        """Register a format alias.
 
1359
 
 
1360
        :param key: Alias name
 
1361
        :param target: Target format
 
1362
        :param hidden: Whether the alias is hidden
 
1363
        """
 
1364
        info = self.get_info(target)
 
1365
        registry.Registry.register_alias(self, key, target,
 
1366
                                         ControlDirFormatInfo(
 
1367
                                             native=info.native, deprecated=info.deprecated,
 
1368
                                             hidden=hidden, experimental=info.experimental))
 
1369
 
1319
1370
    def register_lazy(self, key, module_name, member_name, help, native=True,
1320
 
        deprecated=False, hidden=False, experimental=False, alias=False):
 
1371
                      deprecated=False, hidden=False, experimental=False):
1321
1372
        registry.Registry.register_lazy(self, key, module_name, member_name,
1322
 
            help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
1323
 
        if alias:
1324
 
            self._aliases.add(key)
 
1373
                                        help, ControlDirFormatInfo(native, deprecated, hidden, experimental))
1325
1374
        self._registration_order.append(key)
1326
1375
 
1327
1376
    def set_default(self, key):
1329
1378
 
1330
1379
        This method must be called once and only once.
1331
1380
        """
1332
 
        registry.Registry.register(self, 'default', self.get(key),
1333
 
            self.get_help(key), info=self.get_info(key))
1334
 
        self._aliases.add('default')
 
1381
        self.register_alias('default', key)
1335
1382
 
1336
1383
    def set_default_repository(self, key):
1337
1384
        """Set the FormatRegistry default and Repository default.
1344
1391
        self.set_default(key)
1345
1392
        format = self.get('default')()
1346
1393
 
1347
 
    def make_bzrdir(self, key):
 
1394
    def make_controldir(self, key):
1348
1395
        return self.get(key)()
1349
1396
 
1350
1397
    def help_topic(self, topic):
1365
1412
            if info.native:
1366
1413
                help = '(native) ' + help
1367
1414
            return ':%s:\n%s\n\n' % (key,
1368
 
                textwrap.fill(help, initial_indent='    ',
1369
 
                    subsequent_indent='    ',
1370
 
                    break_long_words=False))
 
1415
                                     textwrap.fill(help, initial_indent='    ',
 
1416
                                                   subsequent_indent='    ',
 
1417
                                                   break_long_words=False))
1371
1418
        if default_realkey is not None:
1372
1419
            output += wrapped(default_realkey, '(default) %s' % default_help,
1373
1420
                              self.get_info('default'))
1402
1449
            other_output += \
1403
1450
                "\nNo deprecated formats are available.\n\n"
1404
1451
        other_output += \
1405
 
                "\nSee :doc:`formats-help` for more about storage formats."
 
1452
            "\nSee :doc:`formats-help` for more about storage formats."
1406
1453
 
1407
1454
        if topic == 'other-formats':
1408
1455
            return other_output
1431
1478
        """
1432
1479
        self.repository = repository
1433
1480
        self.format = format
1434
 
        self.bzrdir = controldir
 
1481
        self.controldir = controldir
1435
1482
        self.shared = shared
1436
1483
 
1437
1484
    def __eq__(self, other):
1440
1487
    def __repr__(self):
1441
1488
        if self.repository:
1442
1489
            return "<%s for %s>" % (self.__class__.__name__,
1443
 
                self.repository)
 
1490
                                    self.repository)
1444
1491
        else:
1445
1492
            return "<%s for %s>" % (self.__class__.__name__,
1446
 
                self.bzrdir)
 
1493
                                    self.controldir)
 
1494
 
 
1495
 
 
1496
def is_control_filename(filename):
 
1497
    """Check if filename is used for control directories."""
 
1498
    # TODO(jelmer): Instead, have a function that returns all control
 
1499
    # filenames.
 
1500
    for key, format in format_registry.items():
 
1501
        if format().is_control_filename(filename):
 
1502
            return True
 
1503
    else:
 
1504
        return False
 
1505
 
 
1506
 
 
1507
class RepositoryAcquisitionPolicy(object):
 
1508
    """Abstract base class for repository acquisition policies.
 
1509
 
 
1510
    A repository acquisition policy decides how a ControlDir acquires a repository
 
1511
    for a branch that is being created.  The most basic policy decision is
 
1512
    whether to create a new repository or use an existing one.
 
1513
    """
 
1514
 
 
1515
    def __init__(self, stack_on, stack_on_pwd, require_stacking):
 
1516
        """Constructor.
 
1517
 
 
1518
        :param stack_on: A location to stack on
 
1519
        :param stack_on_pwd: If stack_on is relative, the location it is
 
1520
            relative to.
 
1521
        :param require_stacking: If True, it is a failure to not stack.
 
1522
        """
 
1523
        self._stack_on = stack_on
 
1524
        self._stack_on_pwd = stack_on_pwd
 
1525
        self._require_stacking = require_stacking
 
1526
 
 
1527
    def configure_branch(self, branch):
 
1528
        """Apply any configuration data from this policy to the branch.
 
1529
 
 
1530
        Default implementation sets repository stacking.
 
1531
        """
 
1532
        if self._stack_on is None:
 
1533
            return
 
1534
        if self._stack_on_pwd is None:
 
1535
            stack_on = self._stack_on
 
1536
        else:
 
1537
            try:
 
1538
                stack_on = urlutils.rebase_url(self._stack_on,
 
1539
                                               self._stack_on_pwd,
 
1540
                                               branch.user_url)
 
1541
            except urlutils.InvalidRebaseURLs:
 
1542
                stack_on = self._get_full_stack_on()
 
1543
        try:
 
1544
            branch.set_stacked_on_url(stack_on)
 
1545
        except (_mod_branch.UnstackableBranchFormat,
 
1546
                errors.UnstackableRepositoryFormat):
 
1547
            if self._require_stacking:
 
1548
                raise
 
1549
 
 
1550
    def requires_stacking(self):
 
1551
        """Return True if this policy requires stacking."""
 
1552
        return self._stack_on is not None and self._require_stacking
 
1553
 
 
1554
    def _get_full_stack_on(self):
 
1555
        """Get a fully-qualified URL for the stack_on location."""
 
1556
        if self._stack_on is None:
 
1557
            return None
 
1558
        if self._stack_on_pwd is None:
 
1559
            return self._stack_on
 
1560
        else:
 
1561
            return urlutils.join(self._stack_on_pwd, self._stack_on)
 
1562
 
 
1563
    def _add_fallback(self, repository, possible_transports=None):
 
1564
        """Add a fallback to the supplied repository, if stacking is set."""
 
1565
        stack_on = self._get_full_stack_on()
 
1566
        if stack_on is None:
 
1567
            return
 
1568
        try:
 
1569
            stacked_dir = ControlDir.open(
 
1570
                stack_on, possible_transports=possible_transports)
 
1571
        except errors.JailBreak:
 
1572
            # We keep the stacking details, but we are in the server code so
 
1573
            # actually stacking is not needed.
 
1574
            return
 
1575
        try:
 
1576
            stacked_repo = stacked_dir.open_branch().repository
 
1577
        except errors.NotBranchError:
 
1578
            stacked_repo = stacked_dir.open_repository()
 
1579
        try:
 
1580
            repository.add_fallback_repository(stacked_repo)
 
1581
        except errors.UnstackableRepositoryFormat:
 
1582
            if self._require_stacking:
 
1583
                raise
 
1584
        else:
 
1585
            self._require_stacking = True
 
1586
 
 
1587
    def acquire_repository(self, make_working_trees=None, shared=False,
 
1588
                           possible_transports=None):
 
1589
        """Acquire a repository for this controlrdir.
 
1590
 
 
1591
        Implementations may create a new repository or use a pre-exising
 
1592
        repository.
 
1593
 
 
1594
        :param make_working_trees: If creating a repository, set
 
1595
            make_working_trees to this value (if non-None)
 
1596
        :param shared: If creating a repository, make it shared if True
 
1597
        :return: A repository, is_new_flag (True if the repository was
 
1598
            created).
 
1599
        """
 
1600
        raise NotImplementedError(
 
1601
            RepositoryAcquisitionPolicy.acquire_repository)
1447
1602
 
1448
1603
 
1449
1604
# Please register new formats after old formats so that formats