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