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 setVariable...for standalone)
74 if configFileNames==None:
77 if len(configFileNames) == 0:
78 raise SalomeContextException("No configuration files given")
80 reserved=['PATH', 'DYLD_LIBRARY_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)
103 def runSalome(self, args):
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)
114 msg = proc.communicate()
120 """Append value to PATH environment variable"""
121 def addToPath(self, value):
122 self.addToVariable('PATH', value)
125 """Append value to LD_LIBRARY_PATH environment variable"""
126 def addToLdLibraryPath(self, value):
127 self.addToVariable('LD_LIBRARY_PATH', value)
130 """Append value to DYLD_LIBRARY_PATH environment variable"""
131 def addToDyldLibraryPath(self, value):
132 self.addToVariable('DYLD_LIBRARY_PATH', value)
135 """Append value to PYTHONPATH environment variable"""
136 def addToPythonPath(self, value):
137 self.addToVariable('PYTHONPATH', value)
140 """Set environment variable to value"""
141 def setVariable(self, name, value, overwrite=False):
142 env = os.getenv(name, '')
143 if env and not overwrite:
144 self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value)
148 self.getLogger().warning("Overwriting environment variable: %s=%s", name, value)
150 value = os.path.expandvars(value) # expand environment variables
151 self.getLogger().debug("Set environment variable: %s=%s", name, value)
152 os.environ[name] = value
155 """Unset environment variable"""
156 def unsetVariable(self, name):
157 if os.environ.has_key(name):
161 """Append value to environment variable"""
162 def addToVariable(self, name, value, separator=os.pathsep):
166 value = os.path.expandvars(value) # expand environment variables
167 self.getLogger().debug("Add to %s: %s", name, value)
168 env = os.getenv(name, None)
170 os.environ[name] = value
172 os.environ[name] = value + separator + env
175 ###################################
176 # This begins the private section #
177 ###################################
179 def __parseArguments(self, args):
180 if len(args) == 0 or args[0].startswith("-"):
186 availableCommands = {
187 'start' : '_runAppli',
188 'shell' : '_runSession',
189 'connect' : '_runConsole',
190 'killall': '_killAll',
193 'coffee' : '_makeCoffee'
196 if not command in availableCommands.keys():
200 return availableCommands[command], options
205 Args consist in a mandatory command followed by optionnal parameters.
206 See usage for details on commands.
208 def _startSalome(self, args):
209 command, options = self.__parseArguments(args)
213 if args and args[0] in ["-h","--help","help"]:
216 # try to default to "start" command
217 command = "_runAppli"
220 res = getattr(self, command)(options) # run appropriate method
221 return res or (None, None)
222 except SystemExit, exc:
224 sys.exit(0) #catch sys.exit(0) happy end no warning
226 self.getLogger().warning("SystemExit 1 in method %s.", command)
228 except StandardError:
229 self.getLogger().error("Unexpected error:")
231 traceback.print_exc()
233 except SalomeContextException, e:
234 self.getLogger().error(e)
238 def __setEnvironmentFromConfigFile(self, filename, reserved=[]):
239 unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved)
242 for var in unsetVars:
243 self.unsetVariable(var)
246 for reserved in reservedDict:
247 a = filter(None, reservedDict[reserved]) # remove empty elements
248 reformattedVals = ':'.join(a)
249 self.addToVariable(reserved, reformattedVals)
252 for key,val in configVars:
253 self.setVariable(key, val, overwrite=True)
256 sys.path[:0] = os.getenv('PYTHONPATH','').split(':')
259 def _runAppli(self, args=[]):
260 # Initialize SALOME environment
261 sys.argv = ['runSalome'] + args
266 runSalome.runSalome()
269 def _runSession(self, args=[]):
270 sys.argv = ['runSession'] + args
272 runSession.configureSession(args)
277 scriptArgs = getScriptsAndArgs(args)
278 command = formatScriptsAndArgs(scriptArgs)
281 if sys.platform == "win32":
283 command = command.split(sep)
287 cmd = cmd.strip().split(' ')
288 #proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
289 proc = subprocess.Popen(cmd)
290 (stdoutdata, stderrdata) = proc.communicate()
291 if stdoutdata or stderrdata:
292 outmsg.append(stdoutdata)
293 errmsg.append(stderrdata)
295 return ("".join(outmsg), "".join(errmsg))
297 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
298 cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ]
299 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
300 return proc.communicate()
303 def _runConsole(self, args=[]):
304 # Initialize SALOME environment
305 sys.argv = ['runConsole'] + args
309 cmd = ["python", "-c", "import runConsole\nrunConsole.connect()" ]
310 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
311 return proc.communicate()
314 def _killAll(self, args=[]):
315 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
317 import PortManager # mandatory
318 from multiprocessing import Process
319 from killSalomeWithPort import killMyPort
320 ports = PortManager.getBusyPorts()
325 with tempfile.NamedTemporaryFile():
326 p = Process(target = killMyPort, args=(port,))
330 p = Process(target = killMyPort, args=(2809,))
334 from killSalome import killAllPorts
340 def _showInfo(self, args=[]):
341 print "Running with python", platform.python_version()
342 self._runAppli(["--version"])
345 def _usage(self, unused=[]):
349 def _makeCoffee(self, args=[]):
352 print " ___...(-------)-....___"
353 print " .-\"\" ) ( \"\"-."
354 print " .-\'``\'|-._ ) _.-|"
355 print " / .--.| `\"\"---...........---\"\"` |"
363 print " _..---\"\"` \\ /`\"\"---.._"
364 print " .-\' \\ / \'-."
365 print " : `-.__ __.-\' :"
366 print " : ) \"\"---...---\"\" ( :"
367 print " \'._ `\"--...___...--\"` _.\'"
368 print " \\\"\"--..__ __..--\"\"/"
369 print " \'._ \"\"\"----.....______.....----\"\"\" _.\'"
370 print " `\"\"--..,,_____ _____,,..--\"\"`"
371 print " `\"\"\"----\"\"\"`"
375 # Add the following two methods since logger is not pickable
376 # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
377 def __getstate__(self):
378 d = dict(self.__dict__)
379 if hasattr(self, '_logger'):
383 def __setstate__(self, d):
384 self.__dict__.update(d) # I *think* this is a safe way to do it
386 # Excluding self._logger from pickle operation imply using the following method to access logger
388 if not hasattr(self, '_logger'):
389 self._logger = logging.getLogger(__name__)
390 #self._logger.setLevel(logging.DEBUG)
391 self._logger.setLevel(logging.ERROR)
397 if __name__ == "__main__":
398 if len(sys.argv) == 3:
399 context = pickle.loads(sys.argv[1])
400 args = pickle.loads(sys.argv[2])
401 (out, err) = context._startSalome(args)
403 sys.stdout.write(out)
405 sys.stderr.write(err)