import os, os.path, re, sys, textwrap, ConfigParser __all__ = [ 'config_parser', 'config_reader', 'config_reader_arch', ] _marker = object() class schema_item_boolean(object): def __call__(self, i): i = i.strip().lower() if i in ("true", "1"): return True if i in ("false", "0"): return False raise Error class schema_item_list(object): def __init__(self, type = "\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)] class config_reader(dict): config_name = "defines" def __init__(self, dirs = []): self._dirs = dirs def __getitem__(self, key): return self.get(key) def _get_files(self, name): return [os.path.join(i, name) for i in self._dirs if i] def _update(self, ret, inputkey): for key, value in super(config_reader, self).get(tuple(inputkey), {}).iteritems(): ret[key] = value def get(self, key, default = _marker): if isinstance(key, basestring): key = key, ret = super(config_reader, self).get(tuple(key), default) if ret == _marker: raise KeyError, key return ret def merge(self, section, *args): ret = {} for i in xrange(0, len(args) + 1): ret.update(self.get(tuple([section] + list(args[:i])), {})) return ret def sections(self): return super(config_reader, self).keys() class config_reader_arch(config_reader): schema = { 'arches': schema_item_list(), 'available': schema_item_boolean(), 'configs': schema_item_list(), 'flavours': schema_item_list(), 'initramfs': schema_item_boolean(), 'initramfs-generators': schema_item_list(), 'modules': schema_item_boolean(), 'subarches': schema_item_list(), 'versions': schema_item_list(), } def __init__(self, dirs = []): super(config_reader_arch, self).__init__(dirs) self._read_base() def _read_arch(self, arch): files = self._get_files("%s/%s" % (arch, self.config_name)) config = config_parser(self.schema, files) subarches = config['base',].get('subarches', []) flavours = config['base',].get('flavours', []) for section in iter(config): real = list(section) # TODO if real[-1] in subarches: real[0:0] = ['base', arch] elif real[-1] in flavours: real[0:0] = ['base', arch, 'none'] else: real[0:0] = [real.pop()] if real[-1] in flavours: real[1:1] = [arch, 'none'] else: real[1:1] = [arch] real = tuple(real) s = self.get(real, {}) s.update(config[section]) self[tuple(real)] = s for subarch in subarches: if self.has_key(('base', arch, subarch)): avail = self['base', arch, subarch].get('available', True) else: avail = True if avail: self._read_subarch(arch, subarch) if flavours: base = self['base', arch] subarches.insert(0, 'none') base['subarches'] = subarches del base['flavours'] self['base', arch] = base self['base', arch, 'none'] = {'flavours': flavours} for flavour in flavours: self._read_flavour(arch, 'none', flavour) def _read_base(self): files = self._get_files(self.config_name) config = config_parser(self.schema, files) arches = config['base',]['arches'] for section in iter(config): real = list(section) if real[-1] in arches: real.insert(0, 'base') else: real.insert(0, real.pop()) self[tuple(real)] = config[section] for arch in arches: try: avail = self['base', arch].get('available', True) except KeyError: avail = True if avail: self._read_arch(arch) def _read_flavour(self, arch, subarch, flavour): if not self.has_key(('base', arch, subarch, flavour)): if subarch == 'none': import warnings warnings.warn('No config entry for flavour %s, subarch none, arch %s' % (flavour, arch), DeprecationWarning) self['base', arch, subarch, flavour] = {} def _read_subarch(self, arch, subarch): files = self._get_files("%s/%s/%s" % (arch, subarch, self.config_name)) config = config_parser(self.schema, files) flavours = config['base',].get('flavours', []) for section in iter(config): real = list(section) if real[-1] in flavours: real[0:0] = ['base', arch, subarch] else: real[0:0] = [real.pop(), arch, subarch] real = tuple(real) s = self.get(real, {}) s.update(config[section]) self[tuple(real)] = s for flavour in flavours: self._read_flavour(arch, subarch, flavour) def merge(self, section, arch = None, subarch = None, flavour = None): ret = {} ret.update(self.get((section,), {})) if arch: ret.update(self.get((section, arch), {})) if flavour and subarch and subarch != 'none': ret.update(self.get((section, arch, 'none', flavour), {})) if subarch: ret.update(self.get((section, arch, subarch), {})) if flavour: ret.update(self.get((section, arch, subarch, flavour), {})) return ret class config_parser(object): __slots__ = 'configs', 'schema' def __init__(self, schema, files): self.configs = [] self.schema = schema for file in files: config = ConfigParser.ConfigParser() config.read(file) self.configs.append(config) def __getitem__(self, key): return self.items(key) def __iter__(self): return iter(self.sections()) def items(self, section, var = {}): ret = {} section = '_'.join(section) exceptions = [] for config in self.configs: try: items = config.items(section) except ConfigParser.NoSectionError, e: exceptions.append(e) else: for key, value in items: try: value = self.schema[key](value) except KeyError: pass ret[key] = value if len(exceptions) == len(self.configs): raise exceptions[0] return ret def sections(self): sections = [] for config in self.configs: for section in config.sections(): section = tuple(section.split('_')) if section not in sections: sections.append(section) return sections if __name__ == '__main__': import sys config = config_reader() sections = config.sections() sections.sort() for section in sections: print "[%s]" % (section,) items = config[section] items_keys = items.keys() items_keys.sort() for item in items: print "%s: %s" % (item, items[item]) print