blob: 04ab7ffcac66026073039bfdb132d38f1ba40a93 [file] [log] [blame]
mblighed4d6dd2008-02-27 16:49:43 +00001"""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
mbligh11788292009-05-12 20:50:49 +00008import os, sys, ConfigParser
9from autotest_lib.client.common_lib import error
mblighed4d6dd2008-02-27 16:49:43 +000010
mbligh104e9ce2008-03-11 22:01:44 +000011
mblighed4d6dd2008-02-27 16:49:43 +000012class ConfigError(error.AutotestError):
jadmanski0afbb632008-06-06 21:10:57 +000013 pass
mblighed4d6dd2008-02-27 16:49:43 +000014
15
mbligh104e9ce2008-03-11 22:01:44 +000016class ConfigValueError(ConfigError):
jadmanski0afbb632008-06-06 21:10:57 +000017 pass
mbligh104e9ce2008-03-11 22:01:44 +000018
19
lmr6d08b3c2009-11-18 19:26:38 +000020
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
mblighed4d6dd2008-02-27 16:49:43 +000053class global_config(object):
showard893db3d2009-09-14 23:56:00 +000054 _NO_DEFAULT_SPECIFIED = object()
55
jadmanski0afbb632008-06-06 21:10:57 +000056 config = None
57 config_file = DEFAULT_CONFIG_FILE
58 shadow_file = DEFAULT_SHADOW_FILE
lmr6d08b3c2009-11-18 19:26:38 +000059 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
mblighf9751332008-04-08 18:25:33 +000064
mblighed4d6dd2008-02-27 16:49:43 +000065
jadmanski0afbb632008-06-06 21:10:57 +000066 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
mbligh104e9ce2008-03-11 22:01:44 +000071
72
showardd1ee1dd2009-01-07 21:33:08 +000073 def _handle_no_value(self, section, key, default):
showard893db3d2009-09-14 23:56:00 +000074 if default is self._NO_DEFAULT_SPECIFIED:
showardd1ee1dd2009-01-07 21:33:08 +000075 msg = ("Value '%s' not found in section '%s'" %
76 (key, section))
77 raise ConfigError(msg)
78 else:
79 return default
80
81
lmr6d08b3c2009-11-18 19:26:38 +000082 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
showard893db3d2009-09-14 23:56:00 +000097 def get_config_value(self, section, key, type=str,
98 default=_NO_DEFAULT_SPECIFIED, allow_blank=False):
showard50c0e712008-09-22 16:20:37 +000099 self._ensure_config_parsed()
jadmanski0afbb632008-06-06 21:10:57 +0000100
101 try:
102 val = self.config.get(section, key)
showardd1ee1dd2009-01-07 21:33:08 +0000103 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)
jadmanski0afbb632008-06-06 21:10:57 +0000108
showard893db3d2009-09-14 23:56:00 +0000109 return self._convert_value(key, section, val, type)
mbligh104e9ce2008-03-11 22:01:44 +0000110
111
showard50c0e712008-09-22 16:20:37 +0000112 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):
mblighd876f452008-12-03 15:09:17 +0000129 if self.config is None:
showard50c0e712008-09-22 16:20:37 +0000130 self.parse_config_file()
131
132
jadmanski0afbb632008-06-06 21:10:57 +0000133 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)
mblighed4d6dd2008-02-27 16:49:43 +0000145
mblighf9751332008-04-08 18:25:33 +0000146
jadmanski0afbb632008-06-06 21:10:57 +0000147 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
lmr6d08b3c2009-11-18 19:26:38 +0000156 if self.shadow_file and os.path.exists(self.shadow_file):
jadmanski0afbb632008-06-06 21:10:57 +0000157 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.
showard893db3d2009-09-14 23:56:00 +0000166 def _convert_value(self, key, section, value, value_type):
jadmanski0afbb632008-06-06 21:10:57 +0000167 # 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:
showarda5f30c22008-10-06 10:08:48 +0000172 if value_type == str:
jadmanski0afbb632008-06-06 21:10:57 +0000173 return ""
showarda5f30c22008-10-06 10:08:48 +0000174 elif value_type == bool:
jadmanski0afbb632008-06-06 21:10:57 +0000175 return False
showarda5f30c22008-10-06 10:08:48 +0000176 elif value_type == int:
jadmanski0afbb632008-06-06 21:10:57 +0000177 return 0
showarda5f30c22008-10-06 10:08:48 +0000178 elif value_type == float:
jadmanski0afbb632008-06-06 21:10:57 +0000179 return 0.0
showarda5f30c22008-10-06 10:08:48 +0000180 elif value_type == list:
mblighc5ddfd12008-08-04 17:15:00 +0000181 return []
jadmanski0afbb632008-06-06 21:10:57 +0000182 else:
183 return None
184
showarda5f30c22008-10-06 10:08:48 +0000185 if value_type == bool:
jadmanski0afbb632008-06-06 21:10:57 +0000186 if sval.lower() == "false":
187 return False
188 else:
189 return True
190
showarda5f30c22008-10-06 10:08:48 +0000191 if value_type == list:
mblighc5ddfd12008-08-04 17:15:00 +0000192 # Split the string using ',' and return a list
193 return [val.strip() for val in sval.split(',')]
194
jadmanski0afbb632008-06-06 21:10:57 +0000195 try:
showarda5f30c22008-10-06 10:08:48 +0000196 conv_val = value_type(sval)
jadmanski0afbb632008-06-06 21:10:57 +0000197 return conv_val
198 except:
showarda5f30c22008-10-06 10:08:48 +0000199 msg = ("Could not convert %s value %r in section %s to type %s" %
200 (key, sval, section, value_type))
jadmanski0afbb632008-06-06 21:10:57 +0000201 raise ConfigValueError(msg)
202
203
204# insure the class is a singleton. Now the symbol global_config
mblighed4d6dd2008-02-27 16:49:43 +0000205# will point to the one and only one instace of the class
206global_config = global_config()