| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Control.py
Go to the documentation of this file.
1 '''
2 Created on Jun 27, 2011
3
4 @author: mplajner
5 '''
6 import xmlModule
7 import os
8 from time import gmtime, strftime
9 import Variable
10 import EnvConfig
11 import logging
12
13 class Environment(object):
14 '''object to hold settings of environment'''
15
16 def __init__(self, loadFromSystem=True, useAsWriter=False, searchPath=None):
17 '''Initial variables to be pushed and setup
18
19 append switch between append and prepend for initial variables.
20 loadFromSystem causes variable`s system value to be loaded on first encounter.
21 If useAsWriter == True than every change to variables is recorded to XML file.
22 reportLevel sets the level of messaging.
23 '''
24 self.log = logging.getLogger('Environment')
25
26 self.separator = ':'
27
28 # Prepeare the internal search path for xml files (used by 'include' elements)
29 if searchPath is None:
30 self.searchPath = []
31 else:
32 self.searchPath = list(searchPath)
33
34 self.actions = {}
35 self.actions['include'] = lambda n, c, h: self.loadXML(self._locate(n, c, h))
36 self.actions['append'] = lambda n, v, _: self.append(n, v)
37 self.actions['prepend'] = lambda n, v, _: self.prepend(n, v)
38 self.actions['set'] = lambda n, v, _: self.set(n, v)
39 self.actions['unset'] = lambda n, v, _: self.unset(n, v)
40 self.actions['default'] = lambda n, v, _: self.default(n, v)
41 self.actions['remove'] = lambda n, v, _: self.remove(n, v)
42 self.actions['remove-regexp'] = lambda n, v, _: self.remove_regexp(n, v)
43 self.actions['declare'] = self.declare
44 self.actions['search_path'] = lambda n, _1, _2: self.searchPath.extend(n.split(self.separator))
45
46 self.variables = {}
47
48 self.loadFromSystem = loadFromSystem
49 self.asWriter = useAsWriter
50 if useAsWriter:
51 self.writer = xmlModule.XMLFile()
52 self.startXMLinput()
53
54 self.loadedFiles = set()
55
56 # Prepare the stack for the directory of the loaded file(s)
57 self._fileDirStack = []
58 # Note: cannot use self.declare() because we do not want to write out
59 # the changes to ${.}
60 dot = Variable.Scalar('.', local=True)
61 dot.expandVars = False
62 dot.set('')
63 self.variables['.'] = dot
64
65
66 def _locate(self, filename, caller=None, hints=None):
67 '''
68 Find 'filename' in the internal search path.
69 '''
70 from os.path import isabs, isfile, join, dirname, normpath, abspath
71 if isabs(filename):
72 return filename
73
74 self.log.debug('looking for %s', filename)
75 if hints is None:
76 hints = []
77 elif type(hints) is str:
78 hints = hints.split(self.separator)
79
80 if caller:
81 calldir = dirname(caller)
82 localfile = join(calldir, filename)
83 self.log.debug('trying %s', localfile)
84 if isfile(localfile):
85 self.log.debug('OK (local file)')
86 return localfile
87 # allow for relative hints
88 hints = [join(calldir, hint) for hint in hints]
89
90 sp = EnvConfig.path + self.searchPath + hints
91 def candidates():
92 for d in sp:
93 f = normpath(join(d, filename))
94 self.log.debug('trying %s', f)
95 yield f
96 try:
97 f = (abspath(f) for f in candidates() if isfile(f)).next()
98 self.log.debug('OK')
99 return f
100 except StopIteration:
101 from errno import ENOENT
102 raise OSError(ENOENT, 'cannot find file in %r' % sp, filename)
103
104 def vars(self, strings=True):
105 '''returns dictionary of all variables optionally converted to string'''
106 if strings:
107 return dict([(n, v.value(True)) for n, v in self.variables.items()])
108 else:
109 return self.variables
110
111 def var(self, name):
112 '''Gets a single variable. If not available then tries to load from system.'''
113 if name in self.variables:
114 return self.variables[name]
115 else:
116 return os.environ[name]
117
118 def search(self, varName, expr, regExp=False):
119 '''Searches in a variable for a value.'''
120 return self.variables[varName].search(expr, regExp)
121
122 def _guessType(self, varname):
123 '''
124 Guess the type of the variable from its name: if the name contains
125 'PATH' or 'DIRS', then the variable is a list, otherwise it is a scalar.
126 '''
127 varname = varname.upper() # make the comparison case insensitive
128 if 'PATH' in varname or 'DIRS' in varname:
129 return 'list'
130 else:
131 return 'scalar'
132
133 def declare(self, name, vartype, local):
134 '''Creates an instance of new variable. It loads values from the OS if the variable is not local.'''
135 if self.asWriter:
136 self._writeVarToXML(name, 'declare', '', vartype, local)
137
138 if not isinstance(local, bool):
139 if str(local).lower() == 'true':
140 local = True
141 else:
142 local = False
143
144 if name in self.variables.keys():
145 if self.variables[name].local != local:
146 raise Variable.EnvError(name, 'redeclaration')
147 else:
148 if vartype.lower() == "list":
149 if not isinstance(self.variables[name],Variable.List):
150 raise Variable.EnvError(name, 'redeclaration')
151 else:
152 if not isinstance(self.variables[name],Variable.Scalar):
153 raise Variable.EnvError(name, 'redeclaration')
154
155 if vartype.lower() == "list":
156 a = Variable.List(name, local)
157 else:
158 a = Variable.Scalar(name, local)
159
160 if self.loadFromSystem and not local and name in os.environ:
161 a.expandVars = False # disable var expansion when importing from the environment
162 a.set(os.environ[name], os.pathsep, environment=self.variables)
163 a.expandVars = True
164
165 self.variables[name] = a
166
167 def append(self, name, value):
168 '''Appends to an existing variable.'''
169 if self.asWriter:
170 self._writeVarToXML(name, 'append', value)
171 else:
172 if name not in self.variables:
173 self.declare(name, self._guessType(name), False)
174 self.variables[name].append(value, self.separator, self.variables)
175
176 def prepend(self, name, value):
177 '''Prepends to an existing variable, or create a new one.'''
178 if self.asWriter:
179 self._writeVarToXML(name, 'prepend', value)
180 else:
181 if name not in self.variables:
182 self.declare(name, self._guessType(name), False)
183 self.variables[name].prepend(value, self.separator, self.variables)
184
185 def set(self, name, value):
186 '''Sets a single variable - overrides any previous value!'''
187 name = str(name)
188 if self.asWriter:
189 self._writeVarToXML(name, 'set', value)
190 else:
191 if name not in self.variables:
192 self.declare(name, self._guessType(name), False)
193 self.variables[name].set(value, self.separator, self.variables)
194
195 def default(self, name, value):
196 '''Sets a single variable only if it is not already set!'''
197 name = str(name)
198 if self.asWriter:
199 self._writeVarToXML(name, 'default', value)
200 else:
201 # Here it is different from the other actions because after a 'declare'
202 # we cannot tell if the variable was already set or not.
203 # FIXME: improve declare() to allow for a default.
204 if name not in self.variables:
205 if self._guessType(name) == 'list':
206 v = Variable.List(name, False)
207 else:
208 v = Variable.Scalar(name, False)
209 if self.loadFromSystem and name in os.environ:
210 v.set(os.environ[name], os.pathsep, environment=self.variables)
211 else:
212 v.set(value, self.separator, environment=self.variables)
213 self.variables[name] = v
214 else:
215 v = self.variables[name]
216 if not v.val:
217 v.set(value, self.separator, environment=self.variables)
218
219 def unset(self, name, value=None):# pylint: disable=W0613
220 '''Unsets a single variable to an empty value - overrides any previous value!'''
221 if self.asWriter:
222 self._writeVarToXML(name, 'unset', '')
223 else:
224 if name in self.variables:
225 del self.variables[name]
226
227 def remove(self, name, value, regexp=False):
228 '''Remove value from variable.'''
229 if self.asWriter:
230 self._writeVarToXML(name, 'remove', value)
231 else:
232 if name not in self.variables:
233 self.declare(name, self._guessType(name), False)
234 self.variables[name].remove(value, self.separator, regexp)
235
236 def remove_regexp(self, name, value):
237 self.remove(name, value, True)
238
239
240 def searchFile(self, filename, varName):
241 '''Searches for appearance of variable in a file.'''
242 XMLFile = xmlModule.XMLFile()
243 variable = XMLFile.variable(filename, name=varName)
244 return variable
245
246 def loadXML(self, fileName=None, namespace='EnvSchema'):
247 '''Loads XML file for input variables.'''
248 XMLfile = xmlModule.XMLFile()
249 fileName = self._locate(fileName)
250 if fileName in self.loadedFiles:
251 return # ignore recursion
252 self.loadedFiles.add(fileName)
253 dot = self.variables['.']
254 # push the previous value of ${.} onto the stack...
255 self._fileDirStack.append(dot.value())
256 # ... and update the variable
257 dot.set(os.path.dirname(fileName))
258 variables = XMLfile.variable(fileName, namespace=namespace)
259 for i, (action, args) in enumerate(variables):
260 if action not in self.actions:
261 self.log.error('Node {0}: No action taken with var "{1}". Probably wrong action argument: "{2}".'.format(i, args[0], action))
262 else:
263 self.actions[action](*args) # pylint: disable=W0142
264 # restore the old value of ${.}
265 dot.set(self._fileDirStack.pop())
266 # ensure that a change of ${.} in the file is reverted when exiting it
267 self.variables['.'] = dot
268
269 def startXMLinput(self):
270 '''Renew writer for new input.'''
271 self.writer.resetWriter()
272
273
274 def finishXMLinput(self, outputFile = ''):
275 '''Finishes input of XML file and closes the file.'''
276 self.writer.writeToFile(outputFile)
277
278
279 def writeToFile(self, fileName, shell='sh'):
280 '''Creates an output file with a specified name to be used for setting variables by sourcing this file'''
281 f = open(fileName, 'w')
282 if shell == 'sh':
283 f.write('#!/bin/bash\n')
284 for variable in self.variables:
285 if not self[variable].local:
286 f.write('export ' +variable+'='+self[variable].value(True, os.pathsep)+'\n')
287 elif shell == 'csh':
288 f.write('#!/bin/csh\n')
289 for variable in self.variables:
290 if not self[variable].local:
291 f.write('setenv ' +variable+' '+self[variable].value(True, os.pathsep)+'\n')
292 else:
293 f.write('')
294 f.write('REM This is an enviroment settings file generated on '+strftime("%a, %d %b %Y %H:%M:%S\n", gmtime()))
295 for variable in self.variables:
296 if not self[variable].local:
297 f.write('set '+variable+'='+self[variable].value(True, os.pathsep)+'\n')
298
299 f.close()
300
301
302 def writeToXMLFile(self, fileName):
303 '''Writes the current state of environment to a XML file.
304
305 NOTE: There is no trace of actions taken, variables are written with a set action only.
306 '''
307 writer = xmlModule.XMLFile()
308 for varName in self.variables:
309 if varName == '.':
310 continue # this is an internal transient variable
311 writer.writeVar(varName, 'set', self.variables[varName].value(True, self.separator))
312 writer.writeToFile(fileName)
313
314
315 def presetFromSystem(self):
316 '''Loads all variables from the current system settings.'''
317 for k, v in os.environ.items():
318 if k not in self.variables:
319 self.set(k, v)
320
321 def process(self):
322 '''
323 Call the variable processors on all the variables.
324 '''
325 for v in self.variables.values():
326 v.val = v.process(v.val, self.variables)
327
328 def _concatenate(self, value):
329 '''Returns a variable string with separator separator from the values list'''
330 stri = ""
331 for it in value:
332 stri += it + self.separator
333 stri = stri[0:len(stri)-1]
334 return stri
335
336
337 def _writeVarToXML(self, name, action, value, vartype='list', local='false'):
338 '''Writes single variable to XML file.'''
339 if isinstance(value, list):
340 value = self._concatenate(value)
341 self.writer.writeVar(name, action, value, vartype, local)
342
343
344 def __getitem__(self, key):
345 return self.variables[key]
346
347 def __setitem__(self, key, value):
348 if key in self.variables.keys():
349 self.log.warning('Addition canceled because of duplicate entry. Var: "%s" value: "%s".', key, value)
350 else:
351 self.append(key, value)
352
353 def __delitem__(self, key):
354 del self.variables[key]
355
356 def __iter__(self):
357 for i in self.variables:
358 yield i
359
360 def __contains__(self, item):
361 return item in self.variables.keys()
362
363 def __len__(self):
364 return len(self.variables.keys())
365