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