blob: 9514a1f6619ab79872057f53034cc8e9b5084ea9 [file] [log] [blame]
"""A singleton class for accessing global config values
provides access to global configuration file
"""
__author__ = 'raphtee@google.com (Travis Miller)'
import os, sys, ConfigParser, logging
from autotest_lib.client.common_lib import error
class ConfigError(error.AutotestError):
pass
class ConfigValueError(ConfigError):
pass
common_lib_dir = os.path.dirname(sys.modules[__name__].__file__)
client_dir = os.path.dirname(common_lib_dir)
root_dir = os.path.dirname(client_dir)
# Check if the config files are at autotest's root dir
# This will happen if client is executing inside a full autotest tree, or if
# other entry points are being executed
global_config_path_root = os.path.join(root_dir, 'global_config.ini')
shadow_config_path_root = os.path.join(root_dir, 'shadow_config.ini')
config_in_root = os.path.exists(global_config_path_root)
# Check if the config files are at autotest's client dir
# This will happen if a client stand alone execution is happening
global_config_path_client = os.path.join(client_dir, 'global_config.ini')
config_in_client = os.path.exists(global_config_path_client)
if config_in_root:
DEFAULT_CONFIG_FILE = global_config_path_root
if os.path.exists(shadow_config_path_root):
DEFAULT_SHADOW_FILE = shadow_config_path_root
else:
DEFAULT_SHADOW_FILE = None
RUNNING_STAND_ALONE_CLIENT = False
elif config_in_client:
DEFAULT_CONFIG_FILE = global_config_path_client
DEFAULT_SHADOW_FILE = None
RUNNING_STAND_ALONE_CLIENT = True
else:
DEFAULT_CONFIG_FILE = None
DEFAULT_SHADOW_FILE = None
RUNNING_STAND_ALONE_CLIENT = True
class global_config(object):
_NO_DEFAULT_SPECIFIED = object()
config = None
config_file = DEFAULT_CONFIG_FILE
shadow_file = DEFAULT_SHADOW_FILE
running_stand_alone_client = RUNNING_STAND_ALONE_CLIENT
def check_stand_alone_client_run(self):
return self.running_stand_alone_client
def set_config_files(self, config_file=DEFAULT_CONFIG_FILE,
shadow_file=DEFAULT_SHADOW_FILE):
self.config_file = config_file
self.shadow_file = shadow_file
self.config = None
def _handle_no_value(self, section, key, default):
if default is self._NO_DEFAULT_SPECIFIED:
msg = ("Value '%s' not found in section '%s'" %
(key, section))
raise ConfigError(msg)
else:
return default
def get_section_values(self, section):
"""
Return a config parser object containing a single section of the
global configuration, that can be later written to a file object.
@param section: Section we want to turn into a config parser object.
@return: ConfigParser() object containing all the contents of section.
"""
cfgparser = ConfigParser.ConfigParser()
cfgparser.add_section(section)
for option, value in self.config.items(section):
cfgparser.set(section, option, value)
return cfgparser
def get_config_value(self, section, key, type=str,
default=_NO_DEFAULT_SPECIFIED, allow_blank=False):
self._ensure_config_parsed()
try:
val = self.config.get(section, key)
except ConfigParser.Error:
return self._handle_no_value(section, key, default)
if not val.strip() and not allow_blank:
return self._handle_no_value(section, key, default)
return self._convert_value(key, section, val, type)
def override_config_value(self, section, key, new_value):
"""
Override a value from the config file with a new value.
"""
self._ensure_config_parsed()
self.config.set(section, key, new_value)
def reset_config_values(self):
"""
Reset all values to those found in the config files (undoes all
overrides).
"""
self.parse_config_file()
def _ensure_config_parsed(self):
if self.config is None:
self.parse_config_file()
def merge_configs(self, shadow_config):
# overwrite whats in config with whats in shadow_config
sections = shadow_config.sections()
for section in sections:
# add the section if need be
if not self.config.has_section(section):
self.config.add_section(section)
# now run through all options and set them
options = shadow_config.options(section)
for option in options:
val = shadow_config.get(section, option)
self.config.set(section, option, val)
def parse_config_file(self):
self.config = ConfigParser.ConfigParser()
if self.config_file and os.path.exists(self.config_file):
self.config.read(self.config_file)
else:
raise ConfigError('%s not found' % (self.config_file))
# now also read the shadow file if there is one
# this will overwrite anything that is found in the
# other config
if self.shadow_file and os.path.exists(self.shadow_file):
shadow_config = ConfigParser.ConfigParser()
shadow_config.read(self.shadow_file)
# now we merge shadow into global
self.merge_configs(shadow_config)
# the values that are pulled from ini
# are strings. But we should attempt to
# convert them to other types if needed.
def _convert_value(self, key, section, value, value_type):
# strip off leading and trailing white space
sval = value.strip()
# if length of string is zero then return None
if len(sval) == 0:
if value_type == str:
return ""
elif value_type == bool:
return False
elif value_type == int:
return 0
elif value_type == float:
return 0.0
elif value_type == list:
return []
else:
return None
if value_type == bool:
if sval.lower() == "false":
return False
else:
return True
if value_type == list:
# Split the string using ',' and return a list
return [val.strip() for val in sval.split(',')]
try:
conv_val = value_type(sval)
return conv_val
except:
msg = ("Could not convert %s value %r in section %s to type %s" %
(key, sval, section, value_type))
raise ConfigValueError(msg)
# insure the class is a singleton. Now the symbol global_config
# will point to the one and only one instace of the class
global_config = global_config()