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