Mercurial > bitten > bitten-test
view bitten/build/config.py @ 832:7c80375d4817
Updated copyright to 2010.
author | osimons |
---|---|
date | Wed, 06 Oct 2010 09:49:05 +0000 |
parents | 251be647314c |
children |
line wrap: on
line source
# -*- coding: utf-8 -*- # # Copyright (C) 2005-2007 Christopher Lenz <cmlenz@gmx.de> # Copyright (C) 2007-2010 Edgewall Software # All rights reserved. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms # are also available at http://bitten.edgewall.org/wiki/License. """Support for build slave configuration.""" from ConfigParser import SafeConfigParser import logging import os import platform import re from string import Template log = logging.getLogger('bitten.config') __docformat__ = 'restructuredtext en' class ConfigFileNotFound(Exception): pass class Configuration(object): """Encapsulates the configuration of a build machine. Configuration values can be provided through a configuration file (in INI format) or through command-line parameters (properties). In addition to explicitly defined properties, this class automatically collects platform information and stores them as properties. These defaults can be overridden (useful for cross-compilation). """ def __init__(self, filename=None, properties=None): """Create the configuration object. :param filename: the path to the configuration file, if any :param properties: a dictionary of the configuration properties provided on the command-line """ self.properties = {} self.packages = {} parser = SafeConfigParser() if filename: if not (os.path.isfile(filename) or os.path.islink(filename)): raise ConfigFileNotFound( "Configuration file %r not found." % filename) parser.read(filename) self._merge_sysinfo(parser, properties) self._merge_packages(parser, properties) def _merge_sysinfo(self, parser, properties): """Merge the platform information properties into the configuration.""" system, _, release, version, machine, processor = platform.uname() system, release, version = platform.system_alias(system, release, version) self.properties['machine'] = machine self.properties['processor'] = processor self.properties['os'] = system self.properties['family'] = os.name self.properties['version'] = release mapping = {'machine': ('machine', 'name'), 'processor': ('machine', 'processor'), 'os': ('os', 'name'), 'family': ('os', 'family'), 'version': ('os', 'version')} for key, (section, option) in mapping.items(): if parser.has_option(section, option): value = parser.get(section, option) if value is not None: self.properties[key] = value if properties: for key, value in properties.items(): if key in mapping: self.properties[key] = value def _merge_packages(self, parser, properties): """Merge package information into the configuration.""" for section in parser.sections(): if section in ('os', 'machine', 'maintainer'): continue package = {} for option in parser.options(section): if option == 'name': log.warning("Reserved configuration option 'name' used " "for package/section '%s'. Skipping." % section) continue package[option] = parser.get(section, option) self.packages[section] = package if properties: for key, value in properties.items(): if '.' in key: package, propname = key.split('.', 1) if propname == 'name': log.warning("Reserved configuration option 'name' " "used for property '%s'. Skipping." % key) continue if package not in self.packages: self.packages[package] = {} self.packages[package][propname] = value def __contains__(self, key): """Return whether the configuration contains a value for the specified key. :param key: name of the configuration option using dotted notation (for example, "python.path") """ if '.' in key: package, propname = key.split('.', 1) return propname in self.packages.get(package, {}) return key in self.properties def __getitem__(self, key): """Return the value for the specified configuration key. :param key: name of the configuration option using dotted notation (for example, "python.path") """ if '.' in key: package, propname = key.split('.', 1) return self.packages.get(package, {}).get(propname) return self.properties.get(key) def __str__(self): return str({'properties': self.properties, 'packages': self.packages}) def get_dirpath(self, key): """Return the value of the specified configuration key, but verify that the value refers to the path of an existing directory. If the value does not exist, or is not a directory path, return `None`. :param key: name of the configuration option using dotted notation (for example, "ant.home") """ dirpath = self[key] if dirpath: if os.path.isdir(dirpath): return dirpath log.warning('Invalid %s: %s is not a directory', key, dirpath) return None def get_filepath(self, key): """Return the value of the specified configuration key, but verify that the value refers to the path of an existing file. If the value does not exist, or is not a file path, return `None`. :param key: name of the configuration option using dotted notation (for example, "python.path") """ filepath = self[key] if filepath: if os.path.isfile(filepath): return filepath log.warning('Invalid %s: %s is not a file', key, filepath) return None _VAR_RE = re.compile(r'\$\{(?P<ref>\w[\w.]*?\w)(?:\:(?P<def>.+))?\}') def interpolate(self, text, **vars): """Interpolate configuration and environment properties into a string. Configuration properties can be referenced in the text using the notation ``${property.name}``. A default value can be provided by appending it to the property name separated by a colon, for example ``${property.name:defaultvalue}``. This value will be used when there's no such property in the configuration. Otherwise, if no default is provided, the reference is not replaced at all. Environment properties substitute from environment variables, supporting the common notations of ``$VAR`` and ``${VAR}``. :param text: the string containing variable references :param vars: extra variables to use for the interpolation """ def _replace(m): refname = m.group('ref') if refname in self: return self[refname] elif refname in vars: return vars[refname] elif m.group('def'): return m.group('def') else: return m.group(0) return Template(self._VAR_RE.sub(_replace, text) ).safe_substitute(os.environ)