global_config.py revision 6d08b3c3fc2858ccd60a323008703179f93ae38b
1"""A singleton class for accessing global config values 2 3provides access to global configuration file 4""" 5 6__author__ = 'raphtee@google.com (Travis Miller)' 7 8import os, sys, ConfigParser 9from autotest_lib.client.common_lib import error 10 11 12class ConfigError(error.AutotestError): 13 pass 14 15 16class ConfigValueError(ConfigError): 17 pass 18 19 20 21common_lib_dir = os.path.dirname(sys.modules[__name__].__file__) 22client_dir = os.path.dirname(common_lib_dir) 23root_dir = os.path.dirname(client_dir) 24 25# Check if the config files are at autotest's root dir 26# This will happen if client is executing inside a full autotest tree, or if 27# other entry points are being executed 28global_config_path_root = os.path.join(root_dir, 'global_config.ini') 29shadow_config_path_root = os.path.join(root_dir, 'shadow_config.ini') 30config_in_root = (os.path.exists(global_config_path_root) and 31 os.path.exists(shadow_config_path_root)) 32 33# Check if the config files are at autotest's client dir 34# This will happen if a client stand alone execution is happening 35global_config_path_client = os.path.join(client_dir, 'global_config.ini') 36config_in_client = os.path.exists(global_config_path_client) 37 38if config_in_root: 39 DEFAULT_CONFIG_FILE = global_config_path_root 40 DEFAULT_SHADOW_FILE = shadow_config_path_root 41 RUNNING_STAND_ALONE_CLIENT = False 42elif config_in_client: 43 DEFAULT_CONFIG_FILE = global_config_path_client 44 DEFAULT_SHADOW_FILE = None 45 RUNNING_STAND_ALONE_CLIENT = True 46else: 47 raise ConfigError("Could not find configuration files " 48 "needed for this program to function. Please refer to " 49 "http://autotest.kernel.org/wiki/GlobalConfig " 50 "for more info.") 51 52 53class global_config(object): 54 _NO_DEFAULT_SPECIFIED = object() 55 56 config = None 57 config_file = DEFAULT_CONFIG_FILE 58 shadow_file = DEFAULT_SHADOW_FILE 59 running_stand_alone_client = RUNNING_STAND_ALONE_CLIENT 60 61 62 def check_stand_alone_client_run(self): 63 return self.running_stand_alone_client 64 65 66 def set_config_files(self, config_file=DEFAULT_CONFIG_FILE, 67 shadow_file=DEFAULT_SHADOW_FILE): 68 self.config_file = config_file 69 self.shadow_file = shadow_file 70 self.config = None 71 72 73 def _handle_no_value(self, section, key, default): 74 if default is self._NO_DEFAULT_SPECIFIED: 75 msg = ("Value '%s' not found in section '%s'" % 76 (key, section)) 77 raise ConfigError(msg) 78 else: 79 return default 80 81 82 def get_section_values(self, section): 83 """ 84 Return a config parser object containing a single section of the 85 global configuration, that can be later written to a file object. 86 87 @param section: Section we want to turn into a config parser object. 88 @return: ConfigParser() object containing all the contents of section. 89 """ 90 cfgparser = ConfigParser.ConfigParser() 91 cfgparser.add_section(section) 92 for option, value in self.config.items(section): 93 cfgparser.set(section, option, value) 94 return cfgparser 95 96 97 def get_config_value(self, section, key, type=str, 98 default=_NO_DEFAULT_SPECIFIED, allow_blank=False): 99 self._ensure_config_parsed() 100 101 try: 102 val = self.config.get(section, key) 103 except ConfigParser.Error: 104 return self._handle_no_value(section, key, default) 105 106 if not val.strip() and not allow_blank: 107 return self._handle_no_value(section, key, default) 108 109 return self._convert_value(key, section, val, type) 110 111 112 def override_config_value(self, section, key, new_value): 113 """ 114 Override a value from the config file with a new value. 115 """ 116 self._ensure_config_parsed() 117 self.config.set(section, key, new_value) 118 119 120 def reset_config_values(self): 121 """ 122 Reset all values to those found in the config files (undoes all 123 overrides). 124 """ 125 self.parse_config_file() 126 127 128 def _ensure_config_parsed(self): 129 if self.config is None: 130 self.parse_config_file() 131 132 133 def merge_configs(self, shadow_config): 134 # overwrite whats in config with whats in shadow_config 135 sections = shadow_config.sections() 136 for section in sections: 137 # add the section if need be 138 if not self.config.has_section(section): 139 self.config.add_section(section) 140 # now run through all options and set them 141 options = shadow_config.options(section) 142 for option in options: 143 val = shadow_config.get(section, option) 144 self.config.set(section, option, val) 145 146 147 def parse_config_file(self): 148 if not os.path.exists(self.config_file): 149 raise ConfigError('%s not found' % (self.config_file)) 150 self.config = ConfigParser.ConfigParser() 151 self.config.read(self.config_file) 152 153 # now also read the shadow file if there is one 154 # this will overwrite anything that is found in the 155 # other config 156 if self.shadow_file and os.path.exists(self.shadow_file): 157 shadow_config = ConfigParser.ConfigParser() 158 shadow_config.read(self.shadow_file) 159 # now we merge shadow into global 160 self.merge_configs(shadow_config) 161 162 163 # the values that are pulled from ini 164 # are strings. But we should attempt to 165 # convert them to other types if needed. 166 def _convert_value(self, key, section, value, value_type): 167 # strip off leading and trailing white space 168 sval = value.strip() 169 170 # if length of string is zero then return None 171 if len(sval) == 0: 172 if value_type == str: 173 return "" 174 elif value_type == bool: 175 return False 176 elif value_type == int: 177 return 0 178 elif value_type == float: 179 return 0.0 180 elif value_type == list: 181 return [] 182 else: 183 return None 184 185 if value_type == bool: 186 if sval.lower() == "false": 187 return False 188 else: 189 return True 190 191 if value_type == list: 192 # Split the string using ',' and return a list 193 return [val.strip() for val in sval.split(',')] 194 195 try: 196 conv_val = value_type(sval) 197 return conv_val 198 except: 199 msg = ("Could not convert %s value %r in section %s to type %s" % 200 (key, sval, section, value_type)) 201 raise ConfigValueError(msg) 202 203 204# insure the class is a singleton. Now the symbol global_config 205# will point to the one and only one instace of the class 206global_config = global_config() 207