diff options
Diffstat (limited to 'debian/lib/python/debian_linux/config.py')
-rw-r--r-- | debian/lib/python/debian_linux/config.py | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/debian/lib/python/debian_linux/config.py b/debian/lib/python/debian_linux/config.py new file mode 100644 index 000000000..7424c6278 --- /dev/null +++ b/debian/lib/python/debian_linux/config.py @@ -0,0 +1,257 @@ +import collections +import os +import os.path +import pickle +import re +import sys + +from configparser import RawConfigParser + +__all__ = [ + 'ConfigCoreDump', + 'ConfigCoreHierarchy', + 'ConfigParser', +] + + +class SchemaItemBoolean(object): + def __call__(self, i): + i = i.strip().lower() + if i in ("true", "1"): + return True + if i in ("false", "0"): + return False + raise ValueError + + +class SchemaItemInteger(object): + def __call__(self, i): + return int(i.strip(), 0) + + +class SchemaItemList(object): + def __init__(self, type=r"\s+"): + self.type = type + + def __call__(self, i): + i = i.strip() + if not i: + return [] + return [j.strip() for j in re.split(self.type, i)] + + +# Using OrderedDict instead of dict makes the pickled config reproducible +class ConfigCore(collections.OrderedDict): + def get_merge(self, section, arch, featureset, flavour, key, default=None): + temp = [] + + if arch and featureset and flavour: + temp.append(self.get((section, arch, featureset, flavour), {}) + .get(key)) + temp.append(self.get((section, arch, None, flavour), {}).get(key)) + if arch and featureset: + temp.append(self.get((section, arch, featureset), {}).get(key)) + if arch: + temp.append(self.get((section, arch), {}).get(key)) + if featureset: + temp.append(self.get((section, None, featureset), {}).get(key)) + temp.append(self.get((section,), {}).get(key)) + + ret = [] + + for i in temp: + if i is None: + continue + elif isinstance(i, (list, tuple)): + ret.extend(i) + elif ret: + # TODO + return ret + else: + return i + + return ret or default + + def merge(self, section, arch=None, featureset=None, flavour=None): + ret = {} + ret.update(self.get((section,), {})) + if featureset: + ret.update(self.get((section, None, featureset), {})) + if arch: + ret.update(self.get((section, arch), {})) + if arch and featureset: + ret.update(self.get((section, arch, featureset), {})) + if arch and featureset and flavour: + ret.update(self.get((section, arch, None, flavour), {})) + ret.update(self.get((section, arch, featureset, flavour), {})) + return ret + + def dump(self, fp): + pickle.dump(self, fp, 0) + + +class ConfigCoreDump(object): + def __new__(self, fp): + return pickle.load(fp) + + +class ConfigCoreHierarchy(object): + schema_base = { + 'base': { + 'arches': SchemaItemList(), + 'enabled': SchemaItemBoolean(), + 'featuresets': SchemaItemList(), + 'flavours': SchemaItemList(), + }, + } + + def __new__(cls, schema, dirs=[]): + schema_complete = cls.schema_base.copy() + for key, value in schema.items(): + schema_complete.setdefault(key, {}).update(value) + return cls.Reader(dirs, schema_complete)() + + class Reader(object): + config_name = "defines" + + def __init__(self, dirs, schema): + self.dirs, self.schema = dirs, schema + + def __call__(self): + ret = ConfigCore() + self.read(ret) + return ret + + def get_files(self, *dirs): + dirs = list(dirs) + dirs.append(self.config_name) + return (os.path.join(i, *dirs) for i in self.dirs if i) + + def read_arch(self, ret, arch): + config = ConfigParser(self.schema) + config.read(self.get_files(arch)) + + featuresets = config['base', ].get('featuresets', []) + flavours = config['base', ].get('flavours', []) + + for section in iter(config): + if section[0] in featuresets: + real = (section[-1], arch, section[0]) + elif len(section) > 1: + real = (section[-1], arch, None) + section[:-1] + else: + real = (section[-1], arch) + section[:-1] + s = ret.get(real, {}) + s.update(config[section]) + ret[tuple(real)] = s + + for featureset in featuresets: + self.read_arch_featureset(ret, arch, featureset) + + if flavours: + base = ret['base', arch] + featuresets.insert(0, 'none') + base['featuresets'] = featuresets + del base['flavours'] + ret['base', arch] = base + ret['base', arch, 'none'] = {'flavours': flavours, + 'implicit-flavour': True} + + def read_arch_featureset(self, ret, arch, featureset): + config = ConfigParser(self.schema) + config.read(self.get_files(arch, featureset)) + + for section in iter(config): + real = (section[-1], arch, featureset) + section[:-1] + s = ret.get(real, {}) + s.update(config[section]) + ret[tuple(real)] = s + + def read(self, ret): + config = ConfigParser(self.schema) + config.read(self.get_files()) + + arches = config['base', ]['arches'] + featuresets = config['base', ].get('featuresets', []) + + for section in iter(config): + if section[0].startswith('featureset-'): + real = (section[-1], None, section[0][11:]) + else: + real = (section[-1],) + section[1:] + ret[real] = config[section] + + for arch in arches: + self.read_arch(ret, arch) + for featureset in featuresets: + self.read_featureset(ret, featureset) + + def read_featureset(self, ret, featureset): + config = ConfigParser(self.schema) + config.read(self.get_files('featureset-%s' % featureset)) + + for section in iter(config): + real = (section[-1], None, featureset) + s = ret.get(real, {}) + s.update(config[section]) + ret[real] = s + + +class ConfigParser(object): + __slots__ = '_config', 'schemas' + + def __init__(self, schemas): + self.schemas = schemas + + self._config = RawConfigParser() + + def __getitem__(self, key): + return self._convert()[key] + + def __iter__(self): + return iter(self._convert()) + + def __str__(self): + return '<%s(%s)>' % (self.__class__.__name__, self._convert()) + + def _convert(self): + ret = {} + for section in self._config.sections(): + data = {} + for key, value in self._config.items(section): + data[key] = value + section_list = section.split('_') + section_base = section_list[-1] + if section_base in self.schemas: + section_ret = tuple(section_list) + data = self._convert_one(self.schemas[section_base], data) + else: + section_ret = (section, ) + ret[section_ret] = data + return ret + + def _convert_one(self, schema, data): + ret = {} + for key, value in data.items(): + value = value.replace('\n', ' ') + if key in schema: + value = schema[key](value) + ret[key] = value + return ret + + def keys(self): + return self._convert().keys() + + def read(self, data): + return self._config.read(data) + + +if __name__ == '__main__': + sys.path.append('debian/lib/python') + config = ConfigCoreDump(open('debian/config.defines.dump', 'rb')) + for section, items in sorted(config.items(), + key=(lambda a: tuple(i or '' for i in a[0]))): + print(u"[%s]" % (section,)) + for item, value in sorted(items.items()): + print(u"%s: %s" % (item, value)) + print() |