Gaudi Framework, version v24r2

Home   Generated: Wed Dec 4 2013
 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)) 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 

Generated at Wed Dec 4 2013 14:33:06 for Gaudi Framework, version v24r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004