~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/bzrdir.py

  • Committer: Patch Queue Manager
  • Date: 2011-12-22 18:52:58 UTC
  • mfrom: (6213.1.55 feature-flags)
  • Revision ID: pqm@pqm.ubuntu.com-20111222185258-wgcba8590pbw5sf1
(jelmer) Add support for feature flags in bzr formats. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1102
1102
        return self.transport.clone(path)
1103
1103
 
1104
1104
 
1105
 
class BzrDirMetaComponentFormat(controldir.ControlComponentFormat):
 
1105
class BzrFormat(object):
1106
1106
    """Base class for all formats of things living in metadirs.
1107
1107
 
1108
1108
    This class manages the format string that is stored in the 'format'
1113
1113
    (i.e. different from .bzr/branch-format) derive from this class,
1114
1114
    as well as the relevant base class for their kind
1115
1115
    (BranchFormat, WorkingTreeFormat, RepositoryFormat).
 
1116
 
 
1117
    Each format is identified by a "format" or "branch-format" file with a
 
1118
    single line containing the base format name and then an optional list of
 
1119
    feature flags.
 
1120
 
 
1121
    Feature flags are supported as of bzr 2.5. Setting feature flags on formats
 
1122
    will render them inaccessible to older versions of bzr.
 
1123
 
 
1124
    :ivar features: Dictionary mapping feature names to their necessity
1116
1125
    """
1117
1126
 
 
1127
    _present_features = set()
 
1128
 
 
1129
    def __init__(self):
 
1130
        self.features = {}
 
1131
 
 
1132
    @classmethod
 
1133
    def register_feature(cls, name):
 
1134
        """Register a feature as being present.
 
1135
 
 
1136
        :param name: Name of the feature
 
1137
        """
 
1138
        if " " in name:
 
1139
            raise ValueError("spaces are not allowed in feature names")
 
1140
        if name in cls._present_features:
 
1141
            raise errors.FeatureAlreadyRegistered(name)
 
1142
        cls._present_features.add(name)
 
1143
 
 
1144
    @classmethod
 
1145
    def unregister_feature(cls, name):
 
1146
        """Unregister a feature."""
 
1147
        cls._present_features.remove(name)
 
1148
 
 
1149
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1150
            basedir=None):
 
1151
        for name, necessity in self.features.iteritems():
 
1152
            if name in self._present_features:
 
1153
                continue
 
1154
            if necessity == "optional":
 
1155
                mutter("ignoring optional missing feature %s", name)
 
1156
                continue
 
1157
            elif necessity == "required":
 
1158
                raise errors.MissingFeature(name)
 
1159
            else:
 
1160
                mutter("treating unknown necessity as require for %s",
 
1161
                       name)
 
1162
                raise errors.MissingFeature(name)
 
1163
 
1118
1164
    @classmethod
1119
1165
    def get_format_string(cls):
1120
1166
        """Return the ASCII format string that identifies this format."""
1121
1167
        raise NotImplementedError(cls.get_format_string)
1122
1168
 
1123
1169
    @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()
 
1170
    def from_string(cls, text):
 
1171
        format_string = cls.get_format_string()
 
1172
        if not text.startswith(format_string):
 
1173
            raise AssertionError("Invalid format header %r for %r" % (text, cls))
 
1174
        lines = text[len(format_string):].splitlines()
 
1175
        ret = cls()
 
1176
        for lineno, line in enumerate(lines):
 
1177
            try:
 
1178
                (necessity, feature) = line.split(" ", 1)
 
1179
            except ValueError:
 
1180
                raise errors.ParseFormatError(format=cls, lineno=lineno+2,
 
1181
                    line=line, text=text)
 
1182
            ret.features[feature] = necessity
 
1183
        return ret
 
1184
 
 
1185
    def as_string(self):
 
1186
        """Return the string representation of this format.
 
1187
        """
 
1188
        lines = [self.get_format_string()]
 
1189
        lines.extend([("%s %s\n" % (item[1], item[0])) for item in
 
1190
            self.features.iteritems()])
 
1191
        return "".join(lines)
1128
1192
 
1129
1193
    @classmethod
1130
1194
    def _find_format(klass, registry, kind, format_string):
1131
1195
        try:
1132
 
            cls = registry.get(format_string)
 
1196
            first_line = format_string[:format_string.index("\n")+1]
 
1197
        except ValueError:
 
1198
            first_line = format_string
 
1199
        try:
 
1200
            cls = registry.get(first_line)
1133
1201
        except KeyError:
1134
 
            raise errors.UnknownFormatError(format=format_string, kind=kind)
1135
 
        return cls
 
1202
            raise errors.UnknownFormatError(format=first_line, kind=kind)
 
1203
        return cls.from_string(format_string)
1136
1204
 
1137
1205
    def network_name(self):
1138
1206
        """A simple byte string uniquely identifying this format for RPC calls.
1139
1207
 
1140
1208
        Metadir branch formats use their format string.
1141
1209
        """
1142
 
        return self.get_format_string()
 
1210
        return self.as_string()
1143
1211
 
1144
1212
    def __eq__(self, other):
1145
 
        return (self.__class__ is other.__class__)
 
1213
        return (self.__class__ is other.__class__ and
 
1214
                self.features == other.features)
1146
1215
 
1147
1216
 
1148
1217
class BzrProber(controldir.Prober):
1169
1238
        except errors.NoSuchFile:
1170
1239
            raise errors.NotBranchError(path=transport.base)
1171
1240
        try:
1172
 
            cls = klass.formats.get(format_string)
 
1241
            first_line = format_string[:format_string.index("\n")+1]
 
1242
        except ValueError:
 
1243
            first_line = format_string
 
1244
        try:
 
1245
            cls = klass.formats.get(first_line)
1173
1246
        except KeyError:
1174
 
            raise errors.UnknownFormatError(format=format_string, kind='bzrdir')
 
1247
            raise errors.UnknownFormatError(format=first_line, kind='bzrdir')
1175
1248
        return cls.from_string(format_string)
1176
1249
 
1177
1250
    @classmethod
1221
1294
        return set([RemoteBzrDirFormat()])
1222
1295
 
1223
1296
 
1224
 
class BzrDirFormat(controldir.ControlDirFormat):
 
1297
class BzrDirFormat(BzrFormat, controldir.ControlDirFormat):
1225
1298
    """ControlDirFormat base class for .bzr/ directories.
1226
1299
 
1227
1300
    Formats are placed in a dict by their format string for reference
1238
1311
    # _lock_class must be set in subclasses to the lock type, typ.
1239
1312
    # TransportLock or LockDir
1240
1313
 
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
1314
    def initialize_on_transport(self, transport):
1247
1315
        """Initialize a new bzrdir in the base directory of a Transport."""
1248
1316
        try:
1433
1501
            compatible with whatever sub formats are supported by self.
1434
1502
        :return: None.
1435
1503
        """
 
1504
        other_format.features = dict(self.features)
1436
1505
 
1437
1506
    def supports_transport(self, transport):
1438
1507
        # bzr formats can be opened over all known transports
1439
1508
        return True
1440
1509
 
 
1510
    def check_support_status(self, allow_unsupported, recommend_upgrade=True,
 
1511
            basedir=None):
 
1512
        controldir.ControlDirFormat.check_support_status(self,
 
1513
            allow_unsupported=allow_unsupported, recommend_upgrade=recommend_upgrade,
 
1514
            basedir=basedir)
 
1515
        BzrFormat.check_support_status(self, allow_unsupported=allow_unsupported,
 
1516
            recommend_upgrade=recommend_upgrade, basedir=basedir)
 
1517
 
1441
1518
 
1442
1519
class BzrDirMetaFormat1(BzrDirFormat):
1443
1520
    """Bzr meta control format 1
1459
1536
    colocated_branches = False
1460
1537
 
1461
1538
    def __init__(self):
 
1539
        BzrDirFormat.__init__(self)
1462
1540
        self._workingtree_format = None
1463
1541
        self._branch_format = None
1464
1542
        self._repository_format = None
1470
1548
            return False
1471
1549
        if other.workingtree_format != self.workingtree_format:
1472
1550
            return False
 
1551
        if other.features != self.features:
 
1552
            return False
1473
1553
        return True
1474
1554
 
1475
1555
    def __ne__(self, other):
1601
1681
        """See BzrDirFormat.get_format_description()."""
1602
1682
        return "Meta directory format 1"
1603
1683
 
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
1684
    def _open(self, transport):
1614
1685
        """See BzrDirFormat._open."""
1615
1686
        # Create a new format instance because otherwise initialisation of new
1644
1715
            compatible with whatever sub formats are supported by self.
1645
1716
        :return: None.
1646
1717
        """
 
1718
        super(BzrDirMetaFormat1, self)._supply_sub_formats_to(other_format)
1647
1719
        if getattr(self, '_repository_format', None) is not None:
1648
1720
            other_format.repository_format = self.repository_format
1649
1721
        if self._branch_format is not None:
1919
1991
        :return: A repository, is_new_flag (True if the repository was
1920
1992
            created).
1921
1993
        """
1922
 
        raise NotImplemented(RepositoryAcquisitionPolicy.acquire_repository)
 
1994
        raise NotImplementedError(RepositoryAcquisitionPolicy.acquire_repository)
1923
1995
 
1924
1996
 
1925
1997
class CreateRepository(RepositoryAcquisitionPolicy):