Gaudi Framework, version v25r2

Home   Generated: Wed Jun 4 2014
 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:
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))
108  for n, v in self.variables.items()
109  if n != '.'])
110  else:
111  # clone the dictionary to remove the internal special var '.'
112  vars_ = dict(self.variables)
113  if '.' in vars_:
114  del vars_['.']
115  return vars_
116 
117  def var(self, name):
118  '''Gets a single variable. If not available then tries to load from system.'''
119  if name in self.variables:
120  return self.variables[name]
121  else:
122  return os.environ[name]
123 
124  def search(self, varName, expr, regExp=False):
125  '''Searches in a variable for a value.'''
126  return self.variables[varName].search(expr, regExp)
127 
128  def _guessType(self, varname):
129  '''
130  Guess the type of the variable from its name: if the name contains
131  'PATH' or 'DIRS', then the variable is a list, otherwise it is a scalar.
132  '''
133  varname = varname.upper() # make the comparison case insensitive
134  if 'PATH' in varname or 'DIRS' in varname:
135  return 'list'
136  else:
137  return 'scalar'
138 
139  def declare(self, name, vartype, local):
140  '''Creates an instance of new variable. It loads values from the OS if the variable is not local.'''
141  if self.asWriter:
142  self._writeVarToXML(name, 'declare', '', vartype, local)
143 
144  if not isinstance(local, bool):
145  if str(local).lower() == 'true':
146  local = True
147  else:
148  local = False
149 
150  if name in self.variables.keys():
151  if self.variables[name].local != local:
152  raise Variable.EnvError(name, 'redeclaration')
153  else:
154  if vartype.lower() == "list":
155  if not isinstance(self.variables[name],Variable.List):
156  raise Variable.EnvError(name, 'redeclaration')
157  else:
158  if not isinstance(self.variables[name],Variable.Scalar):
159  raise Variable.EnvError(name, 'redeclaration')
160 
161  if vartype.lower() == "list":
162  a = Variable.List(name, local)
163  else:
164  a = Variable.Scalar(name, local)
165 
166  if self.loadFromSystem and not local and name in os.environ:
167  a.expandVars = False # disable var expansion when importing from the environment
168  a.set(os.environ[name], os.pathsep, environment=self.variables)
169  a.expandVars = True
170 
171  self.variables[name] = a
172 
173  def append(self, name, value):
174  '''Appends to an existing variable.'''
175  if self.asWriter:
176  self._writeVarToXML(name, 'append', value)
177  else:
178  if name not in self.variables:
179  self.declare(name, self._guessType(name), False)
180  self.variables[name].append(value, self.separator, self.variables)
181 
182  def prepend(self, name, value):
183  '''Prepends to an existing variable, or create a new one.'''
184  if self.asWriter:
185  self._writeVarToXML(name, 'prepend', value)
186  else:
187  if name not in self.variables:
188  self.declare(name, self._guessType(name), False)
189  self.variables[name].prepend(value, self.separator, self.variables)
190 
191  def set(self, name, value):
192  '''Sets a single variable - overrides any previous value!'''
193  name = str(name)
194  if self.asWriter:
195  self._writeVarToXML(name, 'set', value)
196  else:
197  if name not in self.variables:
198  self.declare(name, self._guessType(name), False)
199  self.variables[name].set(value, self.separator, self.variables)
200 
201  def default(self, name, value):
202  '''Sets a single variable only if it is not already set!'''
203  name = str(name)
204  if self.asWriter:
205  self._writeVarToXML(name, 'default', value)
206  else:
207  # Here it is different from the other actions because after a 'declare'
208  # we cannot tell if the variable was already set or not.
209  # FIXME: improve declare() to allow for a default.
210  if name not in self.variables:
211  if self._guessType(name) == 'list':
212  v = Variable.List(name, False)
213  else:
214  v = Variable.Scalar(name, False)
215  if self.loadFromSystem and name in os.environ:
216  v.set(os.environ[name], os.pathsep, environment=self.variables)
217  else:
218  v.set(value, self.separator, environment=self.variables)
219  self.variables[name] = v
220  else:
221  v = self.variables[name]
222  if not v.val:
223  v.set(value, self.separator, environment=self.variables)
224 
225  def unset(self, name, value=None):# pylint: disable=W0613
226  '''Unsets a single variable to an empty value - overrides any previous value!'''
227  if self.asWriter:
228  self._writeVarToXML(name, 'unset', '')
229  else:
230  if name in self.variables:
231  del self.variables[name]
232 
233  def remove(self, name, value, regexp=False):
234  '''Remove value from variable.'''
235  if self.asWriter:
236  self._writeVarToXML(name, 'remove', value)
237  else:
238  if name not in self.variables:
239  self.declare(name, self._guessType(name), False)
240  self.variables[name].remove(value, self.separator, regexp)
241 
242  def remove_regexp(self, name, value):
243  self.remove(name, value, True)
244 
245 
246  def searchFile(self, filename, varName):
247  '''Searches for appearance of variable in a file.'''
248  XMLFile = xmlModule.XMLFile()
249  variable = XMLFile.variable(filename, name=varName)
250  return variable
251 
252  def loadXML(self, fileName=None, namespace='EnvSchema'):
253  '''Loads XML file for input variables.'''
254  XMLfile = xmlModule.XMLFile()
255  fileName = self._locate(fileName)
256  if fileName in self.loadedFiles:
257  return # ignore recursion
258  self.loadedFiles.add(fileName)
259  dot = self.variables['.']
260  # push the previous value of ${.} onto the stack...
261  self._fileDirStack.append(dot.value())
262  # ... and update the variable
263  dot.set(os.path.dirname(fileName))
264  variables = XMLfile.variable(fileName, namespace=namespace)
265  for i, (action, args) in enumerate(variables):
266  if action not in self.actions:
267  self.log.error('Node {0}: No action taken with var "{1}". Probably wrong action argument: "{2}".'.format(i, args[0], action))
268  else:
269  self.actions[action](*args) # pylint: disable=W0142
270  # restore the old value of ${.}
271  dot.set(self._fileDirStack.pop())
272  # ensure that a change of ${.} in the file is reverted when exiting it
273  self.variables['.'] = dot
274 
275  def startXMLinput(self):
276  '''Renew writer for new input.'''
277  self.writer.resetWriter()
278 
279 
280  def finishXMLinput(self, outputFile = ''):
281  '''Finishes input of XML file and closes the file.'''
282  self.writer.writeToFile(outputFile)
283 
284 
285  def writeToFile(self, fileName, shell='sh'):
286  '''Creates an output file with a specified name to be used for setting variables by sourcing this file'''
287  f = open(fileName, 'w')
288  if shell == 'sh':
289  f.write('#!/bin/bash\n')
290  for variable in self.variables:
291  if not self[variable].local:
292  f.write('export ' +variable+'='+self[variable].value(True, os.pathsep)+'\n')
293  elif shell == 'csh':
294  f.write('#!/bin/csh\n')
295  for variable in self.variables:
296  if not self[variable].local:
297  f.write('setenv ' +variable+' '+self[variable].value(True, os.pathsep)+'\n')
298  else:
299  f.write('')
300  f.write('REM This is an enviroment settings file generated on '+strftime("%a, %d %b %Y %H:%M:%S\n", gmtime()))
301  for variable in self.variables:
302  if not self[variable].local:
303  f.write('set '+variable+'='+self[variable].value(True, os.pathsep)+'\n')
304 
305  f.close()
306 
307 
308  def writeToXMLFile(self, fileName):
309  '''Writes the current state of environment to a XML file.
310 
311  NOTE: There is no trace of actions taken, variables are written with a set action only.
312  '''
313  writer = xmlModule.XMLFile()
314  for varName in self.variables:
315  if varName == '.':
316  continue # this is an internal transient variable
317  writer.writeVar(varName, 'set', self.variables[varName].value(True, self.separator))
318  writer.writeToFile(fileName)
319 
320 
321  def presetFromSystem(self):
322  '''Loads all variables from the current system settings.'''
323  for k, v in os.environ.items():
324  if k not in self.variables:
325  self.set(k, v)
326 
327  def process(self):
328  '''
329  Call the variable processors on all the variables.
330  '''
331  for v in self.variables.values():
332  v.val = v.process(v.val, self.variables)
333 
334  def _concatenate(self, value):
335  '''Returns a variable string with separator separator from the values list'''
336  stri = ""
337  for it in value:
338  stri += it + self.separator
339  stri = stri[0:len(stri)-1]
340  return stri
341 
342 
343  def _writeVarToXML(self, name, action, value, vartype='list', local='false'):
344  '''Writes single variable to XML file.'''
345  if isinstance(value, list):
346  value = self._concatenate(value)
347  self.writer.writeVar(name, action, value, vartype, local)
348 
349 
350  def __getitem__(self, key):
351  return self.variables[key]
352 
353  def __setitem__(self, key, value):
354  if key in self.variables.keys():
355  self.log.warning('Addition canceled because of duplicate entry. Var: "%s" value: "%s".', key, value)
356  else:
357  self.append(key, value)
358 
359  def __delitem__(self, key):
360  del self.variables[key]
361 
362  def __iter__(self):
363  for i in self.variables:
364  yield i
365 
366  def __contains__(self, item):
367  return item in self.variables.keys()
368 
369  def __len__(self):
370  return len(self.variables.keys())
371 

Generated at Wed Jun 4 2014 14:48:55 for Gaudi Framework, version v25r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004