1 """A singleton class for accessing global config values
3 provides access to global configuration file
6 __author__
= 'raphtee@google.com (Travis Miller)'
8 import os
, sys
, ConfigParser
, logging
9 from autotest_lib
.client
.common_lib
import error
12 class ConfigError(error
.AutotestError
):
16 class ConfigValueError(ConfigError
):
21 common_lib_dir
= os
.path
.dirname(sys
.modules
[__name__
].__file
__)
22 client_dir
= os
.path
.dirname(common_lib_dir
)
23 root_dir
= os
.path
.dirname(client_dir
)
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
28 global_config_path_root
= os
.path
.join(root_dir
, 'global_config.ini')
29 shadow_config_path_root
= os
.path
.join(root_dir
, 'shadow_config.ini')
30 config_in_root
= (os
.path
.exists(global_config_path_root
) and
31 os
.path
.exists(shadow_config_path_root
))
33 # Check if the config files are at autotest's client dir
34 # This will happen if a client stand alone execution is happening
35 global_config_path_client
= os
.path
.join(client_dir
, 'global_config.ini')
36 config_in_client
= os
.path
.exists(global_config_path_client
)
39 DEFAULT_CONFIG_FILE
= global_config_path_root
40 DEFAULT_SHADOW_FILE
= shadow_config_path_root
41 RUNNING_STAND_ALONE_CLIENT
= False
42 elif config_in_client
:
43 DEFAULT_CONFIG_FILE
= global_config_path_client
44 DEFAULT_SHADOW_FILE
= None
45 RUNNING_STAND_ALONE_CLIENT
= True
47 DEFAULT_CONFIG_FILE
= None
48 DEFAULT_SHADOW_FILE
= None
49 RUNNING_STAND_ALONE_CLIENT
= True
51 class global_config(object):
52 _NO_DEFAULT_SPECIFIED
= object()
55 config_file
= DEFAULT_CONFIG_FILE
56 shadow_file
= DEFAULT_SHADOW_FILE
57 running_stand_alone_client
= RUNNING_STAND_ALONE_CLIENT
60 def check_stand_alone_client_run(self
):
61 return self
.running_stand_alone_client
64 def set_config_files(self
, config_file
=DEFAULT_CONFIG_FILE
,
65 shadow_file
=DEFAULT_SHADOW_FILE
):
66 self
.config_file
= config_file
67 self
.shadow_file
= shadow_file
71 def _handle_no_value(self
, section
, key
, default
):
72 if default
is self
._NO
_DEFAULT
_SPECIFIED
:
73 msg
= ("Value '%s' not found in section '%s'" %
75 raise ConfigError(msg
)
80 def get_section_values(self
, section
):
82 Return a config parser object containing a single section of the
83 global configuration, that can be later written to a file object.
85 @param section: Section we want to turn into a config parser object.
86 @return: ConfigParser() object containing all the contents of section.
88 cfgparser
= ConfigParser
.ConfigParser()
89 cfgparser
.add_section(section
)
90 for option
, value
in self
.config
.items(section
):
91 cfgparser
.set(section
, option
, value
)
95 def get_config_value(self
, section
, key
, type=str,
96 default
=_NO_DEFAULT_SPECIFIED
, allow_blank
=False):
97 self
._ensure
_config
_parsed
()
100 val
= self
.config
.get(section
, key
)
101 except ConfigParser
.Error
:
102 return self
._handle
_no
_value
(section
, key
, default
)
104 if not val
.strip() and not allow_blank
:
105 return self
._handle
_no
_value
(section
, key
, default
)
107 return self
._convert
_value
(key
, section
, val
, type)
110 def override_config_value(self
, section
, key
, new_value
):
112 Override a value from the config file with a new value.
114 self
._ensure
_config
_parsed
()
115 self
.config
.set(section
, key
, new_value
)
118 def reset_config_values(self
):
120 Reset all values to those found in the config files (undoes all
123 self
.parse_config_file()
126 def _ensure_config_parsed(self
):
127 if self
.config
is None:
128 self
.parse_config_file()
131 def merge_configs(self
, shadow_config
):
132 # overwrite whats in config with whats in shadow_config
133 sections
= shadow_config
.sections()
134 for section
in sections
:
135 # add the section if need be
136 if not self
.config
.has_section(section
):
137 self
.config
.add_section(section
)
138 # now run through all options and set them
139 options
= shadow_config
.options(section
)
140 for option
in options
:
141 val
= shadow_config
.get(section
, option
)
142 self
.config
.set(section
, option
, val
)
145 def parse_config_file(self
):
146 self
.config
= ConfigParser
.ConfigParser()
147 if self
.config_file
and os
.path
.exists(self
.config_file
):
148 self
.config
.read(self
.config_file
)
150 raise ConfigError('%s not found' % (self
.config_file
))
152 # now also read the shadow file if there is one
153 # this will overwrite anything that is found in the
155 if self
.shadow_file
and os
.path
.exists(self
.shadow_file
):
156 shadow_config
= ConfigParser
.ConfigParser()
157 shadow_config
.read(self
.shadow_file
)
158 # now we merge shadow into global
159 self
.merge_configs(shadow_config
)
162 # the values that are pulled from ini
163 # are strings. But we should attempt to
164 # convert them to other types if needed.
165 def _convert_value(self
, key
, section
, value
, value_type
):
166 # strip off leading and trailing white space
169 # if length of string is zero then return None
171 if value_type
== str:
173 elif value_type
== bool:
175 elif value_type
== int:
177 elif value_type
== float:
179 elif value_type
== list:
184 if value_type
== bool:
185 if sval
.lower() == "false":
190 if value_type
== list:
191 # Split the string using ',' and return a list
192 return [val
.strip() for val
in sval
.split(',')]
195 conv_val
= value_type(sval
)
198 msg
= ("Could not convert %s value %r in section %s to type %s" %
199 (key
, sval
, section
, value_type
))
200 raise ConfigValueError(msg
)
203 # insure the class is a singleton. Now the symbol global_config
204 # will point to the one and only one instace of the class
205 global_config
= global_config()