~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

(vila) Provide a config section matcher respecting the file order. (Vincent
 Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
786
786
    def __repr__(self):
787
787
        return "<%s at %r>" % (self.__class__.__name__, self.user_url)
788
788
 
 
789
    def update_feature_flags(self, updated_flags):
 
790
        """Update the features required by this bzrdir.
 
791
 
 
792
        :param updated_flags: Dictionary mapping feature names to necessities
 
793
            A necessity can be None to indicate the feature should be removed
 
794
        """
 
795
        self.control_files.lock_write()
 
796
        try:
 
797
            self._format._update_feature_flags(updated_flags)
 
798
            self.transport.put_bytes('branch-format', self._format.as_string())
 
799
        finally:
 
800
            self.control_files.unlock()
 
801
 
789
802
 
790
803
class BzrDirMeta1(BzrDir):
791
804
    """A .bzr meta version 1 control object.
796
809
    present within a BzrDir.
797
810
    """
798
811
 
 
812
    def __init__(self, _transport, _format):
 
813
        super(BzrDirMeta1, self).__init__(_transport, _format)
 
814
        self.control_files = lockable_files.LockableFiles(self.control_transport,
 
815
            self._format._lock_file_name, self._format._lock_class)
 
816
 
799
817
    def can_convert_format(self):
800
818
        """See BzrDir.can_convert_format()."""
801
819
        return True
993
1011
    BzrDirMeta1.
994
1012
    """
995
1013
 
996
 
    def __init__(self, _transport, _format):
997
 
        super(BzrDirMeta1Colo, self).__init__(_transport, _format)
998
 
        self.control_files = lockable_files.LockableFiles(self.control_transport,
999
 
            self._format._lock_file_name, self._format._lock_class)
1000
 
 
1001
1014
    def _get_branch_path(self, name):
1002
1015
        """Obtain the branch path to use.
1003
1016
 
1102
1115
        return self.transport.clone(path)
1103
1116
 
1104
1117
 
1105
 
class BzrDirMetaComponentFormat(controldir.ControlComponentFormat):
 
1118
class BzrFormat(object):
1106
1119
    """Base class for all formats of things living in metadirs.
1107
1120
 
1108
1121
    This class manages the format string that is stored in the 'format'
1113
1126
    (i.e. different from .bzr/branch-format) derive from this class,
1114
1127
    as well as the relevant base class for their kind
1115
1128
    (BranchFormat, WorkingTreeFormat, RepositoryFormat).
 
1129
 
 
1130
    Each format is identified by a "format" or "branch-format" file with a
 
1131
    single line containing the base format name and then an optional list of
 
1132
    feature flags.
 
1133
 
 
1134
    Feature flags are supported as of bzr 2.5. Setting feature flags on formats
 
1135
    will render them inaccessible to older versions of bzr.
 
1136
 
 
1137
    :ivar features: Dictionary mapping feature names to their necessity
1116
1138
    """
1117
1139
 
 
1140
    _present_features = set()
 
1141
 
 
1142
    def __init__(self):
 
1143
        self.features = {}
 
1144
 
 
1145
    @classmethod
 
1146
    def register_feature(cls, name):
 
1147
        """Register a feature as being present.
 
1148
 
 
1149
        :param name: Name of the feature
 
1150
        """
 
1151
        if " " in name:
 
1152
            raise ValueError("spaces are not allowed in feature names")
 
1153
        if name in cls._present_features:
 
1154
            raise errors.FeatureAlreadyRegistered(name)
 
1155
        cls._present_features.add(name)
 
1156
 
 
1157
    @classmethod
 
1158
    def unregister_feature(cls, name):
 
1159
        """Unregister a feature."""
 
1160
        cls._present_features.remove(name)
 
1161
 
 
1162
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1163
            basedir=None):
 
1164
        for name, necessity in self.features.iteritems():
 
1165
            if name in self._present_features:
 
1166
                continue
 
1167
            if necessity == "optional":
 
1168
                mutter("ignoring optional missing feature %s", name)
 
1169
                continue
 
1170
            elif necessity == "required":
 
1171
                raise errors.MissingFeature(name)
 
1172
            else:
 
1173
                mutter("treating unknown necessity as require for %s",
 
1174
                       name)
 
1175
                raise errors.MissingFeature(name)
 
1176
 
1118
1177
    @classmethod
1119
1178
    def get_format_string(cls):
1120
1179
        """Return the ASCII format string that identifies this format."""
1121
1180
        raise NotImplementedError(cls.get_format_string)
1122
1181
 
1123
1182
    @classmethod
1124
 
    def from_string(cls, format_string):
1125
 
        if format_string != cls.get_format_string():
1126
 
            raise ValueError("Invalid format header %r" % format_string)
1127
 
        return cls()
 
1183
    def from_string(cls, text):
 
1184
        format_string = cls.get_format_string()
 
1185
        if not text.startswith(format_string):
 
1186
            raise AssertionError("Invalid format header %r for %r" % (text, cls))
 
1187
        lines = text[len(format_string):].splitlines()
 
1188
        ret = cls()
 
1189
        for lineno, line in enumerate(lines):
 
1190
            try:
 
1191
                (necessity, feature) = line.split(" ", 1)
 
1192
            except ValueError:
 
1193
                raise errors.ParseFormatError(format=cls, lineno=lineno+2,
 
1194
                    line=line, text=text)
 
1195
            ret.features[feature] = necessity
 
1196
        return ret
 
1197
 
 
1198
    def as_string(self):
 
1199
        """Return the string representation of this format.
 
1200
        """
 
1201
        lines = [self.get_format_string()]
 
1202
        lines.extend([("%s %s\n" % (item[1], item[0])) for item in
 
1203
            self.features.iteritems()])
 
1204
        return "".join(lines)
1128
1205
 
1129
1206
    @classmethod
1130
1207
    def _find_format(klass, registry, kind, format_string):
1131
1208
        try:
1132
 
            cls = registry.get(format_string)
 
1209
            first_line = format_string[:format_string.index("\n")+1]
 
1210
        except ValueError:
 
1211
            first_line = format_string
 
1212
        try:
 
1213
            cls = registry.get(first_line)
1133
1214
        except KeyError:
1134
 
            raise errors.UnknownFormatError(format=format_string, kind=kind)
1135
 
        return cls
 
1215
            raise errors.UnknownFormatError(format=first_line, kind=kind)
 
1216
        return cls.from_string(format_string)
1136
1217
 
1137
1218
    def network_name(self):
1138
1219
        """A simple byte string uniquely identifying this format for RPC calls.
1139
1220
 
1140
1221
        Metadir branch formats use their format string.
1141
1222
        """
1142
 
        return self.get_format_string()
 
1223
        return self.as_string()
1143
1224
 
1144
1225
    def __eq__(self, other):
1145
 
        return (self.__class__ is other.__class__)
 
1226
        return (self.__class__ is other.__class__ and
 
1227
                self.features == other.features)
 
1228
 
 
1229
    def _update_feature_flags(self, updated_flags):
 
1230
        """Update the feature flags in this format.
 
1231
 
 
1232
        :param updated_flags: Updated feature flags
 
1233
        """
 
1234
        for name, necessity in updated_flags.iteritems():
 
1235
            if necessity is None:
 
1236
                try:
 
1237
                    del self.features[name]
 
1238
                except KeyError:
 
1239
                    pass
 
1240
            else:
 
1241
                self.features[name] = necessity
1146
1242
 
1147
1243
 
1148
1244
class BzrProber(controldir.Prober):
1169
1265
        except errors.NoSuchFile:
1170
1266
            raise errors.NotBranchError(path=transport.base)
1171
1267
        try:
1172
 
            cls = klass.formats.get(format_string)
 
1268
            first_line = format_string[:format_string.index("\n")+1]
 
1269
        except ValueError:
 
1270
            first_line = format_string
 
1271
        try:
 
1272
            cls = klass.formats.get(first_line)
1173
1273
        except KeyError:
1174
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1274
            raise errors.UnknownFormatError(format=first_line, kind='bzrdir')
1175
1275
        return cls.from_string(format_string)
1176
1276
 
1177
1277
    @classmethod
1221
1321
        return set([RemoteBzrDirFormat()])
1222
1322
 
1223
1323
 
1224
 
class BzrDirFormat(controldir.ControlDirFormat):
 
1324
class BzrDirFormat(BzrFormat, controldir.ControlDirFormat):
1225
1325
    """ControlDirFormat base class for .bzr/ directories.
1226
1326
 
1227
1327
    Formats are placed in a dict by their format string for reference
1238
1338
    # _lock_class must be set in subclasses to the lock type, typ.
1239
1339
    # TransportLock or LockDir
1240
1340
 
1241
 
    @classmethod
1242
 
    def get_format_string(cls):
1243
 
        """Return the ASCII format string that identifies this format."""
1244
 
        raise NotImplementedError(cls.get_format_string)
1245
 
 
1246
1341
    def initialize_on_transport(self, transport):
1247
1342
        """Initialize a new bzrdir in the base directory of a Transport."""
1248
1343
        try:
1383
1478
                       "This is a Bazaar control directory.\n"
1384
1479
                       "Do not change any files in this directory.\n"
1385
1480
                       "See http://bazaar.canonical.com/ for more information about Bazaar.\n"),
1386
 
                      ('branch-format', self.get_format_string()),
 
1481
                      ('branch-format', self.as_string()),
1387
1482
                      ]
1388
1483
        # NB: no need to escape relative paths that are url safe.
1389
1484
        control_files = lockable_files.LockableFiles(bzrdir_transport,
1433
1528
            compatible with whatever sub formats are supported by self.
1434
1529
        :return: None.
1435
1530
        """
 
1531
        other_format.features = dict(self.features)
1436
1532
 
1437
1533
    def supports_transport(self, transport):
1438
1534
        # bzr formats can be opened over all known transports
1439
1535
        return True
1440
1536
 
 
1537
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1538
            basedir=None):
 
1539
        controldir.ControlDirFormat.check_support_status(self,
 
1540
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
 
1541
            basedir=basedir)
 
1542
        BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
 
1543
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
1544
 
1441
1545
 
1442
1546
class BzrDirMetaFormat1(BzrDirFormat):
1443
1547
    """Bzr meta control format 1
1459
1563
    colocated_branches = False
1460
1564
 
1461
1565
    def __init__(self):
 
1566
        BzrDirFormat.__init__(self)
1462
1567
        self._workingtree_format = None
1463
1568
        self._branch_format = None
1464
1569
        self._repository_format = None
1470
1575
            return False
1471
1576
        if other.workingtree_format != self.workingtree_format:
1472
1577
            return False
 
1578
        if other.features != self.features:
 
1579
            return False
1473
1580
        return True
1474
1581
 
1475
1582
    def __ne__(self, other):
1601
1708
        """See BzrDirFormat.get_format_description()."""
1602
1709
        return "Meta directory format 1"
1603
1710
 
1604
 
    @classmethod
1605
 
    def from_string(cls, format_string):
1606
 
        if format_string != cls.get_format_string():
1607
 
            raise ValueError("Invalid format string %r" % format_string)
1608
 
        return cls()
1609
 
 
1610
 
    def network_name(self):
1611
 
        return self.get_format_string()
1612
 
 
1613
1711
    def _open(self, transport):
1614
1712
        """See BzrDirFormat._open."""
1615
1713
        # Create a new format instance because otherwise initialisation of new
1644
1742
            compatible with whatever sub formats are supported by self.
1645
1743
        :return: None.
1646
1744
        """
 
1745
        super(BzrDirMetaFormat1, self)._supply_sub_formats_to(other_format)
1647
1746
        if getattr(self, '_repository_format', None) is not None:
1648
1747
            other_format.repository_format = self.repository_format
1649
1748
        if self._branch_format is not None:
1794
1893
    def convert(self, to_convert, pb):
1795
1894
        """See Converter.convert()."""
1796
1895
        to_convert.transport.put_bytes('branch-format',
1797
 
            self.target_format.get_format_string())
 
1896
            self.target_format.as_string())
1798
1897
        return BzrDir.open_from_transport(to_convert.root_transport)
1799
1898
 
1800
1899
 
1820
1919
        finally:
1821
1920
            to_convert.control_files.unlock()
1822
1921
        to_convert.transport.put_bytes('branch-format',
1823
 
            self.target_format.get_format_string())
 
1922
            self.target_format.as_string())
1824
1923
        return BzrDir.open_from_transport(to_convert.root_transport)
1825
1924
 
1826
1925
 
1919
2018
        :return: A repository, is_new_flag (True if the repository was
1920
2019
            created).
1921
2020
        """
1922
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
2021
        raise NotImplementedError(RepositoryAcquisitionPolicy.acquire_repository)
1923
2022
 
1924
2023
 
1925
2024
class CreateRepository(RepositoryAcquisitionPolicy):