From: Cédric Aguerre Date: Tue, 11 Mar 2014 14:22:11 +0000 (+0100) Subject: rename salome runner/launcher as salome context X-Git-Tag: V7_4_0b1~4^2~17 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=3326f1f9ca282cca567edc2946b02140e39446b2;p=modules%2Fkernel.git rename salome runner/launcher as salome context --- diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 431f7f961..455fc61e1 100755 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -20,7 +20,7 @@ ADD_SUBDIRECTORY(appliskel) SALOME_CONFIGURE_FILE(VERSION.in VERSION INSTALL ${SALOME_INSTALL_BINS}) -SALOME_CONFIGURE_FILE(salomeLauncherUtils.py.in salomeLauncherUtils.py) +SALOME_CONFIGURE_FILE(salomeContextUtils.py.in salomeContextUtils.py) # =============================================================== # Files to be installed @@ -49,8 +49,8 @@ SET(SCRIPTS runSession.py runConsole.py salomeConsole.py - ${CMAKE_CURRENT_BINARY_DIR}/salomeLauncherUtils.py - salomeRunner.py + ${CMAKE_CURRENT_BINARY_DIR}/salomeContextUtils.py + salomeContext.py salome_session.py salome_utils.py searchFreePort.py diff --git a/bin/appliskel/salome b/bin/appliskel/salome index baeead6c4..e61b6cbab 100755 --- a/bin/appliskel/salome +++ b/bin/appliskel/salome @@ -40,7 +40,7 @@ def __initialize(): # define folder to store omniorb config (initially in virtual application folder) try: - from salomeLauncherUtils import setOmniOrbUserPath + from salomeContextUtils import setOmniOrbUserPath setOmniOrbUserPath() except Exception, e: print e @@ -52,32 +52,32 @@ def main(args): __initialize() if args == ['--help']: - from salomeRunner import usage + from salomeContext import usage usage() sys.exit(0) - from salomeLauncherUtils import getConfigFileNames + from salomeContextUtils import getConfigFileNames configFileNames, args, unexisting = getConfigFileNames(args, checkExistence=True) if len(unexisting) > 0: print "ERROR: unexisting configuration file(s): " + ', '.join(unexisting) sys.exit(1) - # Create a SalomeRunner which parses configFileNames to initialize environment + # Create a SalomeContext which parses configFileNames to initialize environment try: - from salomeRunner import SalomeRunner, SalomeRunnerException - runner = SalomeRunner(configFileNames) + from salomeContext import SalomeContext, SalomeContextException + context = SalomeContext(configFileNames) # Here set specific variables, if needed - # runner.addToPath('mypath') - # runner.addToLdLibraryPath('myldlibrarypath') - # runner.addToPythonPath('mypythonpath') - # runner.setEnviron('myvarname', 'value') + # context.addToPath('mypath') + # context.addToLdLibraryPath('myldlibrarypath') + # context.addToPythonPath('mypythonpath') + # context.setEnviron('myvarname', 'value') # Start SALOME, parsing command line arguments - runner.go(args) - print 'Thank you for using SALOME!' + context.go(args) + #print 'Thank you for using SALOME!' - except SalomeRunnerException, e: + except SalomeContextException, e: import logging logging.getLogger("salome").error(e) sys.exit(1) diff --git a/bin/launchConfigureParser.py b/bin/launchConfigureParser.py index 2176d4e7f..cfb247f61 100755 --- a/bin/launchConfigureParser.py +++ b/bin/launchConfigureParser.py @@ -28,7 +28,7 @@ import types from salome_utils import verbose, setVerbose, getPortNumber, getHomeDir -from salomeLauncherUtils import getScriptsAndArgs +from salomeContextUtils import getScriptsAndArgs # names of tags in XML configuration file doc_tag = "document" diff --git a/bin/runSalome.py b/bin/runSalome.py index df7b7b0c6..514bd07fc 100755 --- a/bin/runSalome.py +++ b/bin/runSalome.py @@ -764,7 +764,7 @@ def useSalome(args, modules_list, modules_root_dir): if not args['gui'] or not args['session_gui']: toimport = args['pyscript'] - from salomeLauncherUtils import formatScriptsAndArgs + from salomeContextUtils import formatScriptsAndArgs command = formatScriptsAndArgs(toimport) if command: proc = subprocess.Popen(command, shell=True) @@ -812,9 +812,9 @@ def no_main(): searchFreePort(args, 0) clt = useSalome(args, modules_list, modules_root_dir) - if args.has_key('shutdown_servers') : + if args.has_key('shutdown_servers') : var = args['shutdown_servers'] - if hasattr(var, 'delete') and callable(getattr(var, 'delete')) : + if hasattr(var, 'delete') and callable(getattr(var, 'delete')) : var.delete() return clt @@ -825,7 +825,7 @@ def main(): # define folder to store omniorb config (initially in virtual application folder) try: - from salomeLauncherUtils import setOmniOrbUserPath + from salomeContextUtils import setOmniOrbUserPath setOmniOrbUserPath() except Exception, e: print e @@ -944,9 +944,9 @@ def runSalome(): foreGround(clt, args) pass # -- - if args.has_key('shutdown_servers') : + if args.has_key('shutdown_servers') : var = args['shutdown_servers'] - if hasattr(var, 'delete') and callable(getattr(var, 'delete')) : + if hasattr(var, 'delete') and callable(getattr(var, 'delete')) : var.delete() pass # diff --git a/bin/salomeContext.py b/bin/salomeContext.py new file mode 100644 index 000000000..d7d282c9d --- /dev/null +++ b/bin/salomeContext.py @@ -0,0 +1,400 @@ +# Copyright (C) 2013-2014 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +import os +import sys +import logging +import ConfigParser + +from parseConfigFile import parseConfigFile +from parseConfigFile import convertEnvFileToConfigFile + +import tempfile +import pickle +import subprocess +import platform + +from salomeContextUtils import SalomeContextException +from salomeContextUtils import getScriptsAndArgs, formatScriptsAndArgs + +def usage(): + #exeName = os.path.splitext(os.path.basename(__file__))[0] + + msg = '''\ +Usage: salome [command] [options] [--config=file1,...,filen] + +Commands: + start Launches SALOME virtual application [DEFAULT] + shell Executes a script under SALOME application environment + connect Connects a Python console to the active SALOME session + killall Kill all SALOME running sessions + info Display some information about SALOME + help Show this message + coffee Yes! SALOME can also make coffee!!" + +Use salome start --help or salome shell --help +to show help on start and shell commands. +''' + + print msg +# + +""" +The SalomeContext class in an API to configure SALOME environment then +start SALOME using a single python command. + +""" +class SalomeContext: + """ + Initialize environment from a list of configuration files + identified by their names. + These files should be in appropriate (new .cfg) format. + However you can give old .sh environment files; in this case, + the SalomeContext class will try to automatically convert them + to .cfg format before setting the environment. + """ + def __init__(self, configFileNames=[]): + #it could be None explicitely (if user use multiples setEnviron...for standalone) + if configFileNames==None: + return + + if len(configFileNames) == 0: + raise SalomeContextException("No configuration files given") + + reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH'] + for filename in configFileNames: + basename, extension = os.path.splitext(filename) + if extension == ".cfg": + self.__setEnvironmentFromConfigFile(filename, reserved) + elif extension == ".sh": + #new convert procedures, temporary could be use not to be automatically deleted + #temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False) + temp = tempfile.NamedTemporaryFile(suffix='.cfg') + try: + convertEnvFileToConfigFile(filename, temp.name, reserved) + self.__setEnvironmentFromConfigFile(temp.name, reserved) + except ConfigParser.ParsingError, e: + self.getLogger().warning("Invalid token found when parsing file: %s\n"%(filename)) + print e + print '\n' + finally: + # Automatically cleans up the file + temp.close() + else: + self.getLogger().warning("Unrecognized extension for configuration file: %s", filename) + # + + def go(self, args): + # Run this module as a script, in order to use appropriate Python interpreter + # according to current path (initialized from environment files). + kill = False + for e in args: + if "--shutdown-server" in e: + kill = True + args.remove(e) + + absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') + proc = subprocess.Popen(['python', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), pickle.dumps(self), pickle.dumps(args)], shell=False, close_fds=True) + proc.communicate() + if kill: + self._killAll(args) + # + + """Append value to PATH environment variable""" + def addToPath(self, value): + self.addToEnviron('PATH', value) + # + + """Append value to LD_LIBRARY_PATH environment variable""" + def addToLdLibraryPath(self, value): + self.addToEnviron('LD_LIBRARY_PATH', value) + # + + """Append value to PYTHONPATH environment variable""" + def addToPythonPath(self, value): + self.addToEnviron('PYTHONPATH', value) + # + + """Set environment variable to value""" + def setEnviron(self, name, value, overwrite=False): + env = os.getenv(name, '') + if env and not overwrite: + self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value) + return + + if env: + self.getLogger().warning("Overwriting environment variable: %s=%s", name, value) + + value = os.path.expandvars(value) # expand environment variables + self.getLogger().debug("Set environment variable: %s=%s", name, value) + os.environ[name] = value + # + + """Unset environment variable""" + def unsetEnviron(self, name): + if os.environ.has_key(name): + del os.environ[name] + # + + """Append value to environment variable""" + def addToEnviron(self, name, value, separator=os.pathsep): + if value == '': + return + + value = os.path.expandvars(value) # expand environment variables + self.getLogger().debug("Add to %s: %s", name, value) + env = os.getenv(name, None) + if env is None: + os.environ[name] = value + else: + os.environ[name] = value + separator + env + # + + ################################### + # This begins the private section # + ################################### + + def __parseArguments(self, args): + if len(args) == 0 or args[0].startswith("-"): + return None, args + + command = args[0] + options = args[1:] + + availableCommands = { + 'start' : '_runAppli', + 'shell' : '_runSession', + 'connect' : '_runConsole', + 'killall': '_killAll', + 'info': '_showInfo', + 'help': '_usage', + 'coffee' : '_makeCoffee' + } + + if not command in availableCommands.keys(): + command = "start" + options = args + + return availableCommands[command], options + # + + """ + Run SALOME! + Args consist in a mandatory command followed by optionnal parameters. + See usage for details on commands. + """ + def _getStarted(self, args): + command, options = self.__parseArguments(args) + sys.argv = options + + if command is None: + if args and args[0] in ["-h","--help","help"]: + usage() + sys.exit(0) + # try to default to "start" command + command = "_runAppli" + + try: + res = getattr(self, command)(options) # run appropriate method + return res or (None, None) + except SystemExit, exc: + if exc==0: + sys.exit(0) #catch sys.exit(0) happy end no warning + if exc==1: + self.getLogger().warning("SystemExit 1 in method %s.", command) + sys.exit(1) + except StandardError: + self.getLogger().error("Unexpected error:") + import traceback + traceback.print_exc() + sys.exit(1) + except SalomeContextException, e: + self.getLogger().error(e) + sys.exit(1) + # + + def __setEnvironmentFromConfigFile(self, filename, reserved=[]): + unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved) + + # unset variables + for var in unsetVars: + self.unsetEnviron(var) + + # set environment + for reserved in reservedDict: + a = filter(None, reservedDict[reserved]) # remove empty elements + reformattedVals = ':'.join(a) + self.addToEnviron(reserved, reformattedVals) + pass + + for key,val in configVars: + self.setEnviron(key, val, overwrite=True) + pass + + sys.path[:0] = os.getenv('PYTHONPATH','').split(':') + # + + def _runAppli(self, args=[]): + # Initialize SALOME environment + sys.argv = ['runSalome'] + args + import setenv + setenv.main(True) + + import runSalome + runSalome.runSalome() + # + + def _runSession(self, args=[]): + sys.argv = ['runSession'] + args + import runSession + runSession.configureSession(args) + + import setenv + setenv.main(True) + + scriptArgs = getScriptsAndArgs(args) + command = formatScriptsAndArgs(scriptArgs) + if command: + sep = ";" + if sys.platform == "win32": + sep= "&" + command = command.split(sep) + outmsg = [] + errmsg = [] + for cmd in command: + cmd = cmd.strip().split(' ') + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdoutdata, stderrdata) = proc.communicate() + if stdoutdata or stderrdata: + outmsg.append(stdoutdata) + errmsg.append(stderrdata) + + return ("".join(outmsg), "".join(errmsg)) + else: + absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') + cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ] + proc = subprocess.Popen(cmd, shell=False, close_fds=True) + proc.wait() + # + + def _runConsole(self, args=[]): + # Initialize SALOME environment + sys.argv = ['runConsole'] + args + import setenv + setenv.main(True) + + import runConsole + runConsole.connect() + # + + def _killAll(self, args=[]): + absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') + try: + import PortManager # mandatory + from multiprocessing import Process + from killSalomeWithPort import killMyPort + ports = PortManager.getBusyPorts() + + if ports: + import tempfile + for port in ports: + with tempfile.NamedTemporaryFile(): + p = Process(target = killMyPort, args=(port,)) + p.start() + p.join() + + p = Process(target = killMyPort, args=(2809,)) + p.start() + p.join() + except ImportError: + from killSalome import killAllPorts + killAllPorts() + pass + + # + + def _showInfo(self, args=[]): + print "Running with python", platform.python_version() + self._runAppli(["--version"]) + # + + def _usage(self, unused=[]): + usage() + # + + def _makeCoffee(self, args=[]): + print " (" + print " ) (" + print " ___...(-------)-....___" + print " .-\"\" ) ( \"\"-." + print " .-\'``\'|-._ ) _.-|" + print " / .--.| `\"\"---...........---\"\"` |" + print " / / | |" + print " | | | |" + print " \\ \\ | |" + print " `\\ `\\ | |" + print " `\\ `| |" + print " _/ /\\ /" + print " (__/ \\ /" + print " _..---\"\"` \\ /`\"\"---.._" + print " .-\' \\ / \'-." + print " : `-.__ __.-\' :" + print " : ) \"\"---...---\"\" ( :" + print " \'._ `\"--...___...--\"` _.\'" + print " \\\"\"--..__ __..--\"\"/" + print " \'._ \"\"\"----.....______.....----\"\"\" _.\'" + print " `\"\"--..,,_____ _____,,..--\"\"`" + print " `\"\"\"----\"\"\"`" + sys.exit(0) + # + + # Add the following two methods since logger is not pickable + # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python + def __getstate__(self): + d = dict(self.__dict__) + if hasattr(self, '_logger'): + del d['_logger'] + return d + # + def __setstate__(self, d): + self.__dict__.update(d) # I *think* this is a safe way to do it + # + # Excluding self._logger from pickle operation imply using the following method to access logger + def getLogger(self): + if not hasattr(self, '_logger'): + self._logger = logging.getLogger(__name__) + #self._logger.setLevel(logging.DEBUG) + self._logger.setLevel(logging.ERROR) + return self._logger + # + +### +import pickle +if __name__ == "__main__": + if len(sys.argv) == 3: + context = pickle.loads(sys.argv[1]) + args = pickle.loads(sys.argv[2]) + (out, err) = context._getStarted(args) + if out: + sys.stdout.write(out) + if err: + sys.stderr.write(err) + else: + usage() +# diff --git a/bin/salomeContextUtils.py.in b/bin/salomeContextUtils.py.in new file mode 100644 index 000000000..a48e66848 --- /dev/null +++ b/bin/salomeContextUtils.py.in @@ -0,0 +1,187 @@ +#! /usr/bin/env python + +# Copyright (C) 2013-2014 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +import os +import sys +import glob +import subprocess +import re + +""" +Define a specific exception class to manage exceptions related to SalomeContext +""" +class SalomeContextException(Exception): + """Report error messages to the user interface of SalomeContext.""" +# + +def __listDirectory(path): + allFiles = [] + for root, dirs, files in os.walk(path): + configFileNames = glob.glob(os.path.join(root,'*.cfg')) + glob.glob(os.path.join(root,'*.sh')) + allFiles += configFileNames + return allFiles +# + +def __getConfigFileNamesDefault(): + absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') + if not absoluteAppliPath: + return [] + + envdDir = absoluteAppliPath + '/env.d' + if not os.path.isdir(envdDir): + return [] + + return __listDirectory(envdDir) +# + +def getConfigFileNames(args, checkExistence=False): + # special case: configuration files are provided by user + # Search for command-line argument(s) --config=file1,file2,..., filen + # Search for command-line argument(s) --config=dir1,dir2,..., dirn + configOptionPrefix = "--config=" + configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ] + + if len(configArgs) == 0: + return __getConfigFileNamesDefault(), args, [] + + args = [ x for x in args if not x.startswith(configOptionPrefix) ] + allLists = [ x.replace(configOptionPrefix, '') for x in configArgs ] + + configFileNames = [] + unexisting = [] + for currentList in allLists: + elements = currentList.split(',') + for elt in elements: + elt = os.path.realpath(os.path.expanduser(elt)) + if os.path.isdir(elt): + configFileNames += __listDirectory(elt) + else: + if checkExistence and not os.path.isfile(elt): + unexisting += [elt] + else: + configFileNames += [elt] + + return configFileNames, args, unexisting +# + +# Return an array of dictionaries {script_name: [list_of_its_args]} +def getScriptsAndArgs(args=[]): + # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an] + scriptArgs = [] + currentKey = None + argsPrefix = "args:" + callPython = False + currentScript = None + + for i in range(len(args)): + elt = args[i] + + if elt.startswith(argsPrefix): + if not currentKey or callPython: + raise SalomeContextException("args list must follow corresponding script file in command line.") + elt = elt.replace(argsPrefix, '') + scriptArgs[len(scriptArgs)-1][currentKey] = elt.split(",") + currentKey = None + callPython = False + elif elt.startswith("python"): + callPython = True + elif os.path.isfile(elt) or os.path.isfile(elt+".py"): + if elt[-4:] != ".hdf": + if elt[-3:] == ".py": + currentScript = os.path.abspath(elt) + elif os.path.isfile(elt+".py"): + currentScript = os.path.abspath(elt+".py") + else: + currentScript = os.path.abspath(elt) # python script not necessary has .py extension + pass + if currentScript and callPython: + currentKey = "@PYTHONBIN@ "+currentScript + scriptArgs.append({currentKey:[]}) + callPython = False + elif currentScript: + if not os.access(currentScript, os.X_OK): + currentKey = "@PYTHONBIN@ "+currentScript + scriptArgs.append({currentKey:[]}) + else: + ispython = False + try: + fn = open(currentScript) + for i in xrange(10): # read only 10 first lines + ln = fn.readline() + if re.search("#!.*python"): + ispython = True + break + pass + fn.close() + except: + pass + if not ispython and currentScript[-3:] == ".py": + currentKey = "@PYTHONBIN@ "+currentScript + else: + currentKey = currentScript + pass + scriptArgs.append({currentKey:[]}) + # end for loop + return scriptArgs +# + +# Formatting scripts and args as a Bash-like command-line: +# script1.py [args] ; script2.py [args] ; ... +def formatScriptsAndArgs(scriptArgs=[]): + commands = [] + for sc_dict in scriptArgs: + for script, sc_args in sc_dict.items(): # single entry + cmd = script + if sc_args: + cmd = cmd + " " + " ".join(sc_args) + commands.append(cmd) + sep = " ; " + if sys.platform == "win32": + sep= " & " + command = sep.join(["%s"%x for x in commands]) + return command +# + +# Ensure OMNIORB_USER_PATH is defined. This variable refers to a the folder in which +# SALOME will write omniOrb configuration files. +# If OMNIORB_USER_PATH is already set, only checks write access to associated directory ; +# an exception is raised if check fails. It allows users for choosing a specific folder. +# Else the function sets OMNIORB_USER_PATH this way: +# - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS. +# The function does not check USERS folder existence or wrute access. This folder +# must exist ; this is the case if SALOME virtual application has been create using +# appli_gen.py script. +# - Else OMNIORB_USER_PATH is set to user home directory. +def setOmniOrbUserPath(): + omniorbUserPath = os.getenv("OMNIORB_USER_PATH") + if omniorbUserPath: + if not os.access(omniorbUserPath, os.W_OK): + raise Exception("Unable to get write access to directory: %s"%omniorbUserPath) + pass + else: + homePath = os.path.realpath(os.path.expanduser('~')) + #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS") + defaultOmniorbUserPath = homePath + if os.getenv("APPLI"): + defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS") + pass + os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath +# diff --git a/bin/salomeLauncherUtils.py.in b/bin/salomeLauncherUtils.py.in deleted file mode 100644 index 0b03c392f..000000000 --- a/bin/salomeLauncherUtils.py.in +++ /dev/null @@ -1,187 +0,0 @@ -#! /usr/bin/env python - -# Copyright (C) 2013-2014 CEA/DEN, EDF R&D, OPEN CASCADE -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -import os -import sys -import glob -import subprocess -import re - -""" -Define a specific exception class to manage exceptions related to SalomeRunner -""" -class SalomeRunnerException(Exception): - """Report error messages to the user interface of SalomeRunner.""" -# - -def __listDirectory(path): - allFiles = [] - for root, dirs, files in os.walk(path): - configFileNames = glob.glob(os.path.join(root,'*.cfg')) + glob.glob(os.path.join(root,'*.sh')) - allFiles += configFileNames - return allFiles -# - -def __getConfigFileNamesDefault(): - absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') - if not absoluteAppliPath: - return [] - - envdDir = absoluteAppliPath + '/env.d' - if not os.path.isdir(envdDir): - return [] - - return __listDirectory(envdDir) -# - -def getConfigFileNames(args, checkExistence=False): - # special case: configuration files are provided by user - # Search for command-line argument(s) --config=file1,file2,..., filen - # Search for command-line argument(s) --config=dir1,dir2,..., dirn - configOptionPrefix = "--config=" - configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ] - - if len(configArgs) == 0: - return __getConfigFileNamesDefault(), args, [] - - args = [ x for x in args if not x.startswith(configOptionPrefix) ] - allLists = [ x.replace(configOptionPrefix, '') for x in configArgs ] - - configFileNames = [] - unexisting = [] - for currentList in allLists: - elements = currentList.split(',') - for elt in elements: - elt = os.path.realpath(os.path.expanduser(elt)) - if os.path.isdir(elt): - configFileNames += __listDirectory(elt) - else: - if checkExistence and not os.path.isfile(elt): - unexisting += [elt] - else: - configFileNames += [elt] - - return configFileNames, args, unexisting -# - -# Return an array of dictionaries {script_name: [list_of_its_args]} -def getScriptsAndArgs(args=[]): - # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an] - scriptArgs = [] - currentKey = None - argsPrefix = "args:" - callPython = False - currentScript = None - - for i in range(len(args)): - elt = args[i] - - if elt.startswith(argsPrefix): - if not currentKey or callPython: - raise SalomeRunnerException("args list must follow corresponding script file in command line.") - elt = elt.replace(argsPrefix, '') - scriptArgs[len(scriptArgs)-1][currentKey] = elt.split(",") - currentKey = None - callPython = False - elif elt.startswith("python"): - callPython = True - elif os.path.isfile(elt) or os.path.isfile(elt+".py"): - if elt[-4:] != ".hdf": - if elt[-3:] == ".py": - currentScript = os.path.abspath(elt) - elif os.path.isfile(elt+".py"): - currentScript = os.path.abspath(elt+".py") - else: - currentScript = os.path.abspath(elt) # python script not necessary has .py extension - pass - if currentScript and callPython: - currentKey = "@PYTHONBIN@ "+currentScript - scriptArgs.append({currentKey:[]}) - callPython = False - elif currentScript: - if not os.access(currentScript, os.X_OK): - currentKey = "@PYTHONBIN@ "+currentScript - scriptArgs.append({currentKey:[]}) - else: - ispython = False - try: - fn = open(currentScript) - for i in xrange(10): # read only 10 first lines - ln = fn.readline() - if re.search("#!.*python"): - ispython = True - break - pass - fn.close() - except: - pass - if not ispython and currentScript[-3:] == ".py": - currentKey = "@PYTHONBIN@ "+currentScript - else: - currentKey = currentScript - pass - scriptArgs.append({currentKey:[]}) - # end for loop - return scriptArgs -# - -# Formatting scripts and args as a Bash-like command-line: -# script1.py [args] ; script2.py [args] ; ... -def formatScriptsAndArgs(scriptArgs=[]): - commands = [] - for sc_dict in scriptArgs: - for script, sc_args in sc_dict.items(): # single entry - cmd = script - if sc_args: - cmd = cmd + " " + " ".join(sc_args) - commands.append(cmd) - sep = " ; " - if sys.platform == "win32": - sep= " & " - command = sep.join(["%s"%x for x in commands]) - return command -# - -# Ensure OMNIORB_USER_PATH is defined. This variable refers to a the folder in which -# SALOME will write omniOrb configuration files. -# If OMNIORB_USER_PATH is already set, only checks write access to associated directory ; -# an exception is raised if check fails. It allows users for choosing a specific folder. -# Else the function sets OMNIORB_USER_PATH this way: -# - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS. -# The function does not check USERS folder existence or wrute access. This folder -# must exist ; this is the case if SALOME virtual application has been create using -# appli_gen.py script. -# - Else OMNIORB_USER_PATH is set to user home directory. -def setOmniOrbUserPath(): - omniorbUserPath = os.getenv("OMNIORB_USER_PATH") - if omniorbUserPath: - if not os.access(omniorbUserPath, os.W_OK): - raise Exception("Unable to get write access to directory: %s"%omniorbUserPath) - pass - else: - homePath = os.path.realpath(os.path.expanduser('~')) - #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS") - defaultOmniorbUserPath = homePath - if os.getenv("APPLI"): - defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS") - pass - os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath -# diff --git a/bin/salomeRunner.py b/bin/salomeRunner.py deleted file mode 100644 index a12311c1f..000000000 --- a/bin/salomeRunner.py +++ /dev/null @@ -1,400 +0,0 @@ -# Copyright (C) 2013-2014 CEA/DEN, EDF R&D, OPEN CASCADE -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -import os -import sys -import logging -import ConfigParser - -from parseConfigFile import parseConfigFile -from parseConfigFile import convertEnvFileToConfigFile - -import tempfile -import pickle -import subprocess -import platform - -from salomeLauncherUtils import SalomeRunnerException -from salomeLauncherUtils import getScriptsAndArgs, formatScriptsAndArgs - -def usage(): - #exeName = os.path.splitext(os.path.basename(__file__))[0] - - msg = '''\ -Usage: salome [command] [options] [--config=file1,...,filen] - -Commands: - start Launches SALOME virtual application [DEFAULT] - shell Executes a script under SALOME application environment - connect Connects a Python console to the active SALOME session - killall Kill all SALOME running sessions - info Display some information about SALOME - help Show this message - coffee Yes! SALOME can also make coffee!!" - -Use salome start --help or salome shell --help -to show help on start and shell commands. -''' - - print msg -# - -""" -The SalomeRunner class in an API to configure SALOME environment then -start SALOME using a single python command. - -""" -class SalomeRunner: - """ - Initialize environment from a list of configuration files - identified by their names. - These files should be in appropriate (new .cfg) format. - However you can give old .sh environment files; in this case, - the SalomeRunner class will try to automatically convert them - to .cfg format before setting the environment. - """ - def __init__(self, configFileNames=[]): - #it could be None explicitely (if user use multiples setEnviron...for standalone) - if configFileNames==None: - return - - if len(configFileNames) == 0: - raise SalomeRunnerException("No configuration files given") - - reserved=['PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH'] - for filename in configFileNames: - basename, extension = os.path.splitext(filename) - if extension == ".cfg": - self.__setEnvironmentFromConfigFile(filename, reserved) - elif extension == ".sh": - #new convert procedures, temporary could be use not to be automatically deleted - #temp = tempfile.NamedTemporaryFile(suffix='.cfg', delete=False) - temp = tempfile.NamedTemporaryFile(suffix='.cfg') - try: - convertEnvFileToConfigFile(filename, temp.name, reserved) - self.__setEnvironmentFromConfigFile(temp.name, reserved) - except ConfigParser.ParsingError, e: - self.getLogger().warning("Invalid token found when parsing file: %s\n"%(filename)) - print e - print '\n' - finally: - # Automatically cleans up the file - temp.close() - else: - self.getLogger().warning("Unrecognized extension for configuration file: %s", filename) - # - - def go(self, args): - # Run this module as a script, in order to use appropriate Python interpreter - # according to current path (initialized from environment files). - kill = False - for e in args: - if "--shutdown-server" in e: - kill = True - args.remove(e) - - absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') - proc = subprocess.Popen(['python', os.path.join(absoluteAppliPath,"bin","salome","salomeRunner.py"), pickle.dumps(self), pickle.dumps(args)], shell=False, close_fds=True) - proc.communicate() - if kill: - self._killAll(args) - # - - """Append value to PATH environment variable""" - def addToPath(self, value): - self.addToEnviron('PATH', value) - # - - """Append value to LD_LIBRARY_PATH environment variable""" - def addToLdLibraryPath(self, value): - self.addToEnviron('LD_LIBRARY_PATH', value) - # - - """Append value to PYTHONPATH environment variable""" - def addToPythonPath(self, value): - self.addToEnviron('PYTHONPATH', value) - # - - """Set environment variable to value""" - def setEnviron(self, name, value, overwrite=False): - env = os.getenv(name, '') - if env and not overwrite: - self.getLogger().warning("Environment variable already existing (and not overwritten): %s=%s", name, value) - return - - if env: - self.getLogger().warning("Overwriting environment variable: %s=%s", name, value) - - value = os.path.expandvars(value) # expand environment variables - self.getLogger().debug("Set environment variable: %s=%s", name, value) - os.environ[name] = value - # - - """Unset environment variable""" - def unsetEnviron(self, name): - if os.environ.has_key(name): - del os.environ[name] - # - - """Append value to environment variable""" - def addToEnviron(self, name, value, separator=os.pathsep): - if value == '': - return - - value = os.path.expandvars(value) # expand environment variables - self.getLogger().debug("Add to %s: %s", name, value) - env = os.getenv(name, None) - if env is None: - os.environ[name] = value - else: - os.environ[name] = value + separator + env - # - - ################################### - # This begins the private section # - ################################### - - def __parseArguments(self, args): - if len(args) == 0 or args[0].startswith("-"): - return None, args - - command = args[0] - options = args[1:] - - availableCommands = { - 'start' : '_runAppli', - 'shell' : '_runSession', - 'connect' : '_runConsole', - 'killall': '_killAll', - 'info': '_showInfo', - 'help': '_usage', - 'coffee' : '_makeCoffee' - } - - if not command in availableCommands.keys(): - command = "start" - options = args - - return availableCommands[command], options - # - - """ - Run SALOME! - Args consist in a mandatory command followed by optionnal parameters. - See usage for details on commands. - """ - def _getStarted(self, args): - command, options = self.__parseArguments(args) - sys.argv = options - - if command is None: - if args and args[0] in ["-h","--help","help"]: - usage() - sys.exit(0) - # try to default to "start" command - command = "_runAppli" - - try: - res = getattr(self, command)(options) # run appropriate method - return res or (None, None) - except SystemExit, exc: - if exc==0: - sys.exit(0) #catch sys.exit(0) happy end no warning - if exc==1: - self.getLogger().warning("SystemExit 1 in method %s.", command) - sys.exit(1) - except StandardError: - self.getLogger().error("Unexpected error:") - import traceback - traceback.print_exc() - sys.exit(1) - except SalomeRunnerException, e: - self.getLogger().error(e) - sys.exit(1) - # - - def __setEnvironmentFromConfigFile(self, filename, reserved=[]): - unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved) - - # unset variables - for var in unsetVars: - self.unsetEnviron(var) - - # set environment - for reserved in reservedDict: - a = filter(None, reservedDict[reserved]) # remove empty elements - reformattedVals = ':'.join(a) - self.addToEnviron(reserved, reformattedVals) - pass - - for key,val in configVars: - self.setEnviron(key, val, overwrite=True) - pass - - sys.path[:0] = os.getenv('PYTHONPATH','').split(':') - # - - def _runAppli(self, args=[]): - # Initialize SALOME environment - sys.argv = ['runSalome'] + args - import setenv - setenv.main(True) - - import runSalome - runSalome.runSalome() - # - - def _runSession(self, args=[]): - sys.argv = ['runSession'] + args - import runSession - runSession.configureSession(args) - - import setenv - setenv.main(True) - - scriptArgs = getScriptsAndArgs(args) - command = formatScriptsAndArgs(scriptArgs) - if command: - sep = ";" - if sys.platform == "win32": - sep= "&" - command = command.split(sep) - outmsg = [] - errmsg = [] - for cmd in command: - cmd = cmd.strip().split(' ') - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - (stdoutdata, stderrdata) = proc.communicate() - if stdoutdata or stderrdata: - outmsg.append(stdoutdata) - errmsg.append(stderrdata) - - return ("".join(outmsg), "".join(errmsg)) - else: - absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') - cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ] - proc = subprocess.Popen(cmd, shell=False, close_fds=True) - proc.wait() - # - - def _runConsole(self, args=[]): - # Initialize SALOME environment - sys.argv = ['runConsole'] + args - import setenv - setenv.main(True) - - import runConsole - runConsole.connect() - # - - def _killAll(self, args=[]): - absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') - try: - import PortManager # mandatory - from multiprocessing import Process - from killSalomeWithPort import killMyPort - ports = PortManager.getBusyPorts() - - if ports: - import tempfile - for port in ports: - with tempfile.NamedTemporaryFile(): - p = Process(target = killMyPort, args=(port,)) - p.start() - p.join() - - p = Process(target = killMyPort, args=(2809,)) - p.start() - p.join() - except ImportError: - from killSalome import killAllPorts - killAllPorts() - pass - - # - - def _showInfo(self, args=[]): - print "Running with python", platform.python_version() - self._runAppli(["--version"]) - # - - def _usage(self, unused=[]): - usage() - # - - def _makeCoffee(self, args=[]): - print " (" - print " ) (" - print " ___...(-------)-....___" - print " .-\"\" ) ( \"\"-." - print " .-\'``\'|-._ ) _.-|" - print " / .--.| `\"\"---...........---\"\"` |" - print " / / | |" - print " | | | |" - print " \\ \\ | |" - print " `\\ `\\ | |" - print " `\\ `| |" - print " _/ /\\ /" - print " (__/ \\ /" - print " _..---\"\"` \\ /`\"\"---.._" - print " .-\' \\ / \'-." - print " : `-.__ __.-\' :" - print " : ) \"\"---...---\"\" ( :" - print " \'._ `\"--...___...--\"` _.\'" - print " \\\"\"--..__ __..--\"\"/" - print " \'._ \"\"\"----.....______.....----\"\"\" _.\'" - print " `\"\"--..,,_____ _____,,..--\"\"`" - print " `\"\"\"----\"\"\"`" - sys.exit(0) - # - - # Add the following two methods since logger is not pickable - # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python - def __getstate__(self): - d = dict(self.__dict__) - if hasattr(self, '_logger'): - del d['_logger'] - return d - # - def __setstate__(self, d): - self.__dict__.update(d) # I *think* this is a safe way to do it - # - # Excluding self._logger from pickle operation imply using the following method to access logger - def getLogger(self): - if not hasattr(self, '_logger'): - self._logger = logging.getLogger(__name__) - #self._logger.setLevel(logging.DEBUG) - self._logger.setLevel(logging.ERROR) - return self._logger - # - -### -import pickle -if __name__ == "__main__": - if len(sys.argv) == 3: - runner = pickle.loads(sys.argv[1]) - args = pickle.loads(sys.argv[2]) - (out, err) = runner._getStarted(args) - if out: - sys.stdout.write(out) - if err: - sys.stderr.write(err) - else: - usage() -#