Salome HOME
sh->cfg convert procedure, no delete temporary generated .cfg
[modules/kernel.git] / bin / salomeRunner.py
1 import os
2 import sys
3 import logging
4 import ConfigParser
5
6 from parseConfigFile import parseConfigFile
7 from parseConfigFile import convertEnvFileToConfigFile
8
9 import tempfile
10 import pickle
11 import subprocess
12 import platform
13
14
15 """
16 Define a specific exception class to manage exceptions related to SalomeRunner
17 """
18 class SalomeRunnerException(Exception):
19   """Report error messages to the user interface of SalomeRunner."""
20 #
21
22
23 """
24 The SalomeRunner class in an API to configure SALOME environment then
25 start SALOME using a single python command.
26
27 """
28 class SalomeRunner:
29   """
30   Initialize environment from a list of configuration files
31   identified by their names.
32   These files should be in appropriate (new .cfg) format.
33   However you can give old .sh environment files; in this case,
34   the SalomeRunner class will try to automatically convert them
35   to .cfg format before setting the environment.
36   """
37   def __init__(self, configFileNames=[]):
38     if len(configFileNames) == 0:
39       raise SalomeRunnerException("No configuration files given")
40
41     for filename in configFileNames:
42       basename, extension = os.path.splitext(filename)
43       if extension == ".cfg":
44         self.__setEnvironmentFromConfigFile(filename)
45       elif extension == ".sh":
46         #new convert procedures, temporary could be use not to be automatically deleted
47         temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False)
48         #temp = tempfile.NamedTemporaryFile(suffix='.cfg')
49         try:
50           convertEnvFileToConfigFile(filename, temp.name)
51           self.__setEnvironmentFromConfigFile(temp.name)
52         except ConfigParser.ParsingError, e:
53           self.getLogger().warning("Invalid token found when parsing file: %s\n"%(filename))
54           print e
55           print '\n'
56         finally:
57           # Automatically cleans up the file
58           temp.close()
59       else:
60         self.getLogger().warning("Unrecognized extension for configuration file: %s", filename)
61   #
62
63   def go(self, args):
64     # Run this module as a script, in order to use appropriate Python interpreter
65     # according to current path (initialized from environment files).
66     absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
67     proc = subprocess.Popen(['python', absoluteAppliPath+'/bin/salome/salomeRunner.py', pickle.dumps(self),  pickle.dumps(args)], shell=False, close_fds=True)
68     proc.wait()
69   #
70
71   """Append value to PATH environment variable"""
72   def addToPath(self, value):
73     self.__addToReserved('PATH', value)
74   #
75
76   """Append value to LD_LIBRARY_PATH environment variable"""
77   def addToLdLibraryPath(self, value):
78     self.__addToReserved('LD_LIBRARY_PATH', value)
79   #
80
81   """Append value to PYTHONPATH environment variable"""
82   def addToPythonPath(self, value):
83     self.__addToReserved('PYTHONPATH', value)
84   #
85
86   """Set environment variable to value"""
87   def setEnviron(self, name, value, overwrite=False):
88     env = os.getenv(name, '')
89     if env and not overwrite:
90       self.getLogger().warning("Environment variable already existing and not overwritten: %s", name)
91       return
92
93     if env:
94       self.getLogger().info("Overwriting environment variable: %s", name)
95
96     value = os.path.expandvars(value) # expand environment variables
97     self.getLogger().debug("Set environment variable: %s=%s", name, value)
98     os.environ[name] = value
99   #
100
101   """Unset environment variable"""
102   def unsetEnviron(self, name):
103     if os.environ.has_key(name):
104       del os.environ[name]
105   #
106
107   ###################################
108   # This begins the private section #
109   ###################################
110
111   def _usage(self, unused=[]):
112     exeName = os.path.splitext(os.path.basename(__file__))[0]
113
114     msg = '''\
115 Usage: %s [command] [options] [--config=file1,...,filen]
116
117 Commands:
118     start         Launches SALOME virtual application [DEFAULT]
119     shell         Executes a script under SALOME application environment
120     connect       Connects a Python console to the active SALOME session
121     killall       Kill all SALOME running sessions
122     info          Display some information about SALOME
123     help          Show this message
124     coffee        Yes! SALOME can also make coffee!!"\
125
126 '''%exeName
127
128     print msg
129   #
130
131   def __parseArguments(self, args):
132     if len(args) == 0 or args[0].startswith("-"):
133       return None, args
134
135     command = args[0]
136     options = args[1:]
137
138     availableCommands = {
139       'start' :   '_runAppli',
140       'shell' :   '_runSession',
141       'connect' : '_runConsole',
142       'killall':  '_killAll',
143       'info':     '_showInfo',
144       'help':     '_usage',
145       'coffee' :  '_makeCoffee'
146       }
147
148     if not command in availableCommands.keys():
149       self.getLogger().error("Unrecognized command: %s.", command)
150       self._usage()
151       sys.exit(1)
152
153     return availableCommands[command], options
154   #
155
156   """
157   Run SALOME!
158   Args consist in a mandatory command followed by optionnal parameters.
159   See usage for details on commands.
160   """
161   def _getStarted(self, args):
162     command, options = self.__parseArguments(args)
163     sys.argv = options
164
165     if command is None:
166       if args and args[0] in ["-h","--help","help"]:
167         self._usage()
168         sys.exit(0)
169       # try to default to "start" command
170       command = "_runAppli"
171
172     try:
173       getattr(self, command)(options) # run appropriate method
174     except AttributeError:
175       self.getLogger().error("Method %s is not implemented.", command)
176       sys.exit(1)
177     except:
178       self.getLogger().error("Unexpected error:")
179       import traceback
180       traceback.print_exc()
181       sys.exit(1)
182   #
183
184   def __setEnvironmentFromConfigFile(self, filename):
185     unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH'])
186
187     # unset variables
188     for var in unsetVars:
189       self.unsetEnviron(var)
190
191     # set environment
192     for reserved in reservedDict:
193       a = filter(None, reservedDict[reserved]) # remove empty elements
194       reformattedVals = ':'.join(a)
195       self.__addToReserved(reserved, reformattedVals)
196       pass
197
198     for key,val in configVars:
199       self.setEnviron(key, val, overwrite=True)
200       pass
201
202     sys.path[:0] = os.getenv('PYTHONPATH','').split(':')
203   #
204
205   def __addToReserved(self, name, value):
206     if value == '':
207       return
208
209     value = os.path.expandvars(value) # expand environment variables
210     self.getLogger().debug("Add to %s: %s", name, value)
211     env = os.getenv(name, None)
212     if env is None:
213       os.environ[name] = value
214     else:
215       os.environ[name] = value + os.pathsep + env
216   #
217
218   def _runAppli(self, args=[]):
219     # Initialize SALOME environment
220     sys.argv = ['runSalome'] + args
221     import setenv
222     setenv.main(True)
223
224     import runSalome
225     runSalome.runSalome()
226   #
227
228   def _runSession(self, args=[]):
229     sys.argv = ['runSession'] + args
230     import runSession
231     runSession.configureSession(args)
232
233     import setenv
234     setenv.main(True)
235
236     if args:
237       exe = args[0]
238       # if exe does not contain any slashes (/), search in PATH
239       # if exe contains slashes:
240       #    if exe begins with a slash, use this absolute path
241       #    else build absolute path relative to current working directory
242       if (os.sep in exe) and (exe[0] is not os.sep):
243         args[0] = os.getcwd() + os.sep + exe
244
245       proc = subprocess.Popen(args, shell=False, close_fds=True)
246       proc.wait()
247     else:
248       absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
249       cmd = ["/bin/bash",  "--rcfile", absoluteAppliPath + "/.bashrc" ]
250       proc = subprocess.Popen(cmd, shell=False, close_fds=True)
251       proc.wait()
252   #
253
254   def _runConsole(self, args=[]):
255     # Initialize SALOME environment
256     sys.argv = ['runConsole'] + args
257     import setenv
258     setenv.main(True)
259
260     import runConsole
261     runConsole.connect()
262   #
263
264   def _killAll(self, args=[]):
265     #self._runAppli(['-k'] + args)
266     from killSalome import killAllPorts
267     killAllPorts()
268   #
269
270   def _showInfo(self, args=[]):
271     print "Running with python", platform.python_version()
272     self._runAppli(["--version"])
273   #
274
275   def _makeCoffee(self, args=[]):
276     print "                        ("
277     print "                          )     ("
278     print "                   ___...(-------)-....___"
279     print "               .-\"\"       )    (          \"\"-."
280     print "         .-\'``\'|-._             )         _.-|"
281     print "        /  .--.|   `\"\"---...........---\"\"`   |"
282     print "       /  /    |                             |"
283     print "       |  |    |                             |"
284     print "        \\  \\   |                             |"
285     print "         `\\ `\\ |                             |"
286     print "           `\\ `|                             |"
287     print "           _/ /\\                             /"
288     print "          (__/  \\                           /"
289     print "       _..---\"\"` \\                         /`\"\"---.._"
290     print "    .-\'           \\                       /          \'-."
291     print "   :               `-.__             __.-\'              :"
292     print "   :                  ) \"\"---...---\"\" (                 :"
293     print "    \'._               `\"--...___...--\"`              _.\'"
294     print "      \\\"\"--..__                              __..--\"\"/"
295     print "       \'._     \"\"\"----.....______.....----\"\"\"     _.\'"
296     print "          `\"\"--..,,_____            _____,,..--\"\"`"
297     print "                        `\"\"\"----\"\"\"`"
298     sys.exit(0)
299   #
300
301   # Add the following two methods since logger is not pickable
302   # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
303   def __getstate__(self):
304     d = dict(self.__dict__)
305     if hasattr(self, '_logger'):
306       del d['_logger']
307     return d
308   #
309   def __setstate__(self, d):
310     self.__dict__.update(d) # I *think* this is a safe way to do it
311   #
312   # Excluding self._logger from pickle operation imply using the following method to access logger
313   def getLogger(self):
314     if not hasattr(self, '_logger'):
315       self._logger = logging.getLogger(__name__)
316       #self._logger.setLevel(logging.DEBUG)
317     return self._logger;
318   #
319
320 ###
321 import pickle
322 if __name__ == "__main__":
323   if len(sys.argv) == 3:
324     runner = pickle.loads(sys.argv[1])
325     args = pickle.loads(sys.argv[2])
326     runner._getStarted(args)
327   else:
328     SalomeRunner()._usage()
329 #