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