1 # Copyright (C) 2013-2014 CEA/DEN, EDF R&D, OPEN CASCADE
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # Lesser General Public License for more details.
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
25 from parseConfigFile import parseConfigFile
26 from parseConfigFile import convertEnvFileToConfigFile
33 from salomeContextUtils import SalomeContextException
34 from salomeContextUtils import getScriptsAndArgs, formatScriptsAndArgs
37 #exeName = os.path.splitext(os.path.basename(__file__))[0]
40 Usage: salome [command] [options] [--config=file1,...,filen]
43 start Launches SALOME virtual application [DEFAULT]
44 shell Executes a script under SALOME application environment
45 connect Connects a Python console to the active SALOME session
46 killall Kill all SALOME running sessions
47 info Display some information about SALOME
48 help Show this message
49 coffee Yes! SALOME can also make coffee!!"
51 Use salome start --help or salome shell --help
52 to show help on start and shell commands.
59 The SalomeContext class in an API to configure SALOME environment then
60 start SALOME using a single python command.
65 Initialize environment from a list of configuration files
66 identified by their names.
67 These files should be in appropriate (new .cfg) format.
68 However you can give old .sh environment files; in this case,
69 the SalomeContext class will try to automatically convert them
70 to .cfg format before setting the environment.
72 def __init__(self, configFileNames=[]):
73 #it could be None explicitely (if user use multiples setEnviron...for standalone)
74 if configFileNames==None:
77 if len(configFileNames) == 0:
78 raise SalomeContextException("No configuration files given")
80 reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH']
81 for filename in configFileNames:
82 basename, extension = os.path.splitext(filename)
83 if extension == ".cfg":
84 self.__setEnvironmentFromConfigFile(filename, reserved)
85 elif extension == ".sh":
86 #new convert procedures, temporary could be use not to be automatically deleted
87 #temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False)
88 temp = tempfile.NamedTemporaryFile(suffix='.cfg')
90 convertEnvFileToConfigFile(filename, temp.name, reserved)
91 self.__setEnvironmentFromConfigFile(temp.name, reserved)
92 except ConfigParser.ParsingError, e:
93 self.getLogger().warning("Invalid token found when parsing file: %s\n"%(filename))
97 # Automatically cleans up the file
100 self.getLogger().warning("Unrecognized extension for configuration file: %s", filename)
104 # Run this module as a script, in order to use appropriate Python interpreter
105 # according to current path (initialized from environment files).
108 if "--shutdown-server" in e:
112 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
113 proc = subprocess.Popen(['python', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), pickle.dumps(self), pickle.dumps(args)], shell=False, close_fds=True)
119 """Append value to PATH environment variable"""
120 def addToPath(self, value):
121 self.addToEnviron('PATH', value)
124 """Append value to LD_LIBRARY_PATH environment variable"""
125 def addToLdLibraryPath(self, value):
126 self.addToEnviron('LD_LIBRARY_PATH', value)
129 """Append value to PYTHONPATH environment variable"""
130 def addToPythonPath(self, value):
131 self.addToEnviron('PYTHONPATH', value)
134 """Set environment variable to value"""
135 def setEnviron(self, name, value, overwrite=False):
136 env = os.getenv(name, '')
137 if env and not overwrite:
138 self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value)
142 self.getLogger().warning("Overwriting environment variable: %s=%s", name, value)
144 value = os.path.expandvars(value) # expand environment variables
145 self.getLogger().debug("Set environment variable: %s=%s", name, value)
146 os.environ[name] = value
149 """Unset environment variable"""
150 def unsetEnviron(self, name):
151 if os.environ.has_key(name):
155 """Append value to environment variable"""
156 def addToEnviron(self, name, value, separator=os.pathsep):
160 value = os.path.expandvars(value) # expand environment variables
161 self.getLogger().debug("Add to %s: %s", name, value)
162 env = os.getenv(name, None)
164 os.environ[name] = value
166 os.environ[name] = value + separator + env
169 ###################################
170 # This begins the private section #
171 ###################################
173 def __parseArguments(self, args):
174 if len(args) == 0 or args[0].startswith("-"):
180 availableCommands = {
181 'start' : '_runAppli',
182 'shell' : '_runSession',
183 'connect' : '_runConsole',
184 'killall': '_killAll',
187 'coffee' : '_makeCoffee'
190 if not command in availableCommands.keys():
194 return availableCommands[command], options
199 Args consist in a mandatory command followed by optionnal parameters.
200 See usage for details on commands.
202 def _getStarted(self, args):
203 command, options = self.__parseArguments(args)
207 if args and args[0] in ["-h","--help","help"]:
210 # try to default to "start" command
211 command = "_runAppli"
214 res = getattr(self, command)(options) # run appropriate method
215 return res or (None, None)
216 except SystemExit, exc:
218 sys.exit(0) #catch sys.exit(0) happy end no warning
220 self.getLogger().warning("SystemExit 1 in method %s.", command)
222 except StandardError:
223 self.getLogger().error("Unexpected error:")
225 traceback.print_exc()
227 except SalomeContextException, e:
228 self.getLogger().error(e)
232 def __setEnvironmentFromConfigFile(self, filename, reserved=[]):
233 unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved)
236 for var in unsetVars:
237 self.unsetEnviron(var)
240 for reserved in reservedDict:
241 a = filter(None, reservedDict[reserved]) # remove empty elements
242 reformattedVals = ':'.join(a)
243 self.addToEnviron(reserved, reformattedVals)
246 for key,val in configVars:
247 self.setEnviron(key, val, overwrite=True)
250 sys.path[:0] = os.getenv('PYTHONPATH','').split(':')
253 def _runAppli(self, args=[]):
254 # Initialize SALOME environment
255 sys.argv = ['runSalome'] + args
260 runSalome.runSalome()
263 def _runSession(self, args=[]):
264 sys.argv = ['runSession'] + args
266 runSession.configureSession(args)
271 scriptArgs = getScriptsAndArgs(args)
272 command = formatScriptsAndArgs(scriptArgs)
275 if sys.platform == "win32":
277 command = command.split(sep)
281 cmd = cmd.strip().split(' ')
282 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
283 (stdoutdata, stderrdata) = proc.communicate()
284 if stdoutdata or stderrdata:
285 outmsg.append(stdoutdata)
286 errmsg.append(stderrdata)
288 return ("".join(outmsg), "".join(errmsg))
290 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
291 cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ]
292 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
296 def _runConsole(self, args=[]):
297 # Initialize SALOME environment
298 sys.argv = ['runConsole'] + args
306 def _killAll(self, args=[]):
307 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
309 import PortManager # mandatory
310 from multiprocessing import Process
311 from killSalomeWithPort import killMyPort
312 ports = PortManager.getBusyPorts()
317 with tempfile.NamedTemporaryFile():
318 p = Process(target = killMyPort, args=(port,))
322 p = Process(target = killMyPort, args=(2809,))
326 from killSalome import killAllPorts
332 def _showInfo(self, args=[]):
333 print "Running with python", platform.python_version()
334 self._runAppli(["--version"])
337 def _usage(self, unused=[]):
341 def _makeCoffee(self, args=[]):
344 print " ___...(-------)-....___"
345 print " .-\"\" ) ( \"\"-."
346 print " .-\'``\'|-._ ) _.-|"
347 print " / .--.| `\"\"---...........---\"\"` |"
355 print " _..---\"\"` \\ /`\"\"---.._"
356 print " .-\' \\ / \'-."
357 print " : `-.__ __.-\' :"
358 print " : ) \"\"---...---\"\" ( :"
359 print " \'._ `\"--...___...--\"` _.\'"
360 print " \\\"\"--..__ __..--\"\"/"
361 print " \'._ \"\"\"----.....______.....----\"\"\" _.\'"
362 print " `\"\"--..,,_____ _____,,..--\"\"`"
363 print " `\"\"\"----\"\"\"`"
367 # Add the following two methods since logger is not pickable
368 # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
369 def __getstate__(self):
370 d = dict(self.__dict__)
371 if hasattr(self, '_logger'):
375 def __setstate__(self, d):
376 self.__dict__.update(d) # I *think* this is a safe way to do it
378 # Excluding self._logger from pickle operation imply using the following method to access logger
380 if not hasattr(self, '_logger'):
381 self._logger = logging.getLogger(__name__)
382 #self._logger.setLevel(logging.DEBUG)
383 self._logger.setLevel(logging.ERROR)
389 if __name__ == "__main__":
390 if len(sys.argv) == 3:
391 context = pickle.loads(sys.argv[1])
392 args = pickle.loads(sys.argv[2])
393 (out, err) = context._getStarted(args)
395 sys.stdout.write(out)
397 sys.stderr.write(err)