Gaudi Framework, version v23r5

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

Generated at Wed Nov 28 2012 12:17:09 for Gaudi Framework, version v23r5 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004