X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=bin%2FsalomeContext.py;h=aa8ce10a654fc742b830fca5b18045e52178084f;hb=4b14a3f48efda72f90b88c78c6ae02153631dfd6;hp=954f86fd89344adc396033cb9c4cfccebc004939;hpb=7e6982e9ccf83f3ede551d990d5a80807dcf1a87;p=modules%2Fkernel.git diff --git a/bin/salomeContext.py b/bin/salomeContext.py index 954f86fd8..aa8ce10a6 100644 --- a/bin/salomeContext.py +++ b/bin/salomeContext.py @@ -1,4 +1,4 @@ -# Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE +# Copyright (C) 2013-2017 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 @@ -20,10 +20,9 @@ import os import sys import logging -import ConfigParser +import configparser from parseConfigFile import parseConfigFile -from parseConfigFile import convertEnvFileToConfigFile import tempfile import pickle @@ -33,99 +32,107 @@ import platform from salomeContextUtils import SalomeContextException def usage(): - #exeName = os.path.splitext(os.path.basename(__file__))[0] - msg = '''\ Usage: salome [command] [options] [--config=] Commands: ========= - start Starts a SALOME session (through virtual application) - shell Initializes SALOME environment, and executes scripts passed - as command arguments - connect Connects a Python console to the active SALOME session - killall Kill all SALOME running sessions for current user - info Display some information about SALOME - help Show this message - coffee Yes! SALOME can also make coffee!! - -If no command is given, default to start. + start Start a new SALOME instance. + context Initialize SALOME context. Current environment is extended. + shell Initialize SALOME context, attached to the last created SALOME + instance if any, and executes scripts passed as command arguments. + User works in a Shell terminal. SALOME environment is set but + application is not started. + connect Connect a Python console to the active SALOME instance. + kill Terminate SALOME instances running on given ports for current user. + Port numbers must be separated by blank characters. + killall Terminate *all* SALOME running instances for current user. + Do not start a new one. + test Run SALOME tests. + info Display some information about SALOME. + doc Show online module documentation (if available). + Module names must be separated by blank characters. + help Show this message. + +If no command is given, default is start. Command options: ================ - Use salome --help to show help on command ; available for start - and shell commands. + Use salome --help to show help on command. Available for the + following commands: start, shell, connect, test, info. --config= ========================== - Initialize SALOME environment from a list of context files and/or a list + Initialize SALOME context from a list of context files and/or a list of folders containing context files. The list is comma-separated, whithout any blank characters. ''' - print msg + print(msg) # """ -The SalomeContext class in an API to configure SALOME environment then +The SalomeContext class in an API to configure SALOME context then start SALOME using a single python command. """ class SalomeContext: """ - Initialize environment from a list of configuration files + Initialize context 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. + These files should be in appropriate .cfg format. """ def __init__(self, configFileNames=0): - #it could be None explicitely (if user use multiples setVariable...for standalone) + self.getLogger().setLevel(logging.INFO) + #it could be None explicitly (if user use multiples setVariable...for standalone) if configFileNames is None: return configFileNames = configFileNames or [] if len(configFileNames) == 0: raise SalomeContextException("No configuration files given") - reserved=['PATH', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH'] + reserved=['PATH', 'DYLD_FALLBACK_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH', 'INCLUDE', 'LIBPATH', 'SALOME_PLUGINS_PATH', 'LIBRARY_PATH', 'QT_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) - temp.close() - except (ConfigParser.ParsingError, ValueError) as e: - self.getLogger().error("Invalid token found when parsing file: %s\n"%(filename)) - temp.close() - sys.exit(1) + self.__setContextFromConfigFile(filename, reserved) else: - self.getLogger().warning("Unrecognized extension for configuration file: %s", filename) + self.getLogger().error("Unrecognized extension for configuration file: %s", filename) + # + + def __loadEnvModules(self, env_modules): + print("Trying to load env modules: %s..." % ' '.join(env_modules)) + try: + out, err = subprocess.Popen(["modulecmd", "python", "load"] + env_modules, stdout=subprocess.PIPE).communicate() + exec(out) # define specific environment variables + print("OK") + except: + print("** Failed **") + pass # def runSalome(self, args): + import os # 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) + # according to current path (initialized from context files). + env_modules_option = "--with-env-modules=" + env_modules_l = [x for x in args if x.startswith(env_modules_option)] + if env_modules_l: + env_modules = env_modules_l[-1][len(env_modules_option):].split(',') + self.__loadEnvModules(env_modules) + args = [x for x in args if not x.startswith(env_modules_option)] + else: + env_modules = os.getenv("SALOME_ENV_MODULES", None) + if env_modules: + self.__loadEnvModules(env_modules.split(',')) - import os absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','') env_copy = os.environ.copy() - proc = subprocess.Popen(['python', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), pickle.dumps(self), pickle.dumps(args)], shell=False, close_fds=True, env=env_copy) - msg = proc.communicate() - # if kill: - # self._killAll(args) - return msg, proc.returncode + selfBytes= pickle.dumps(self, protocol=0) + argsBytes= pickle.dumps(args, protocol=0) + proc = subprocess.Popen(['python3', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), selfBytes.decode(), argsBytes.decode()], shell=False, close_fds=True, env=env_copy) + out, err = proc.communicate() + return out, err, proc.returncode # """Append value to PATH environment variable""" @@ -135,7 +142,15 @@ class SalomeContext: """Append value to LD_LIBRARY_PATH environment variable""" def addToLdLibraryPath(self, value): - self.addToVariable('LD_LIBRARY_PATH', value) + if platform.system() == 'Windows': + self.addToVariable('PATH', value) + elif platform.system() == 'Darwin': + if "LAPACK" in value: + self.addToVariable('DYLD_FALLBACK_LIBRARY_PATH', value) + else: + self.addToVariable('DYLD_LIBRARY_PATH', value) + else: + self.addToVariable('LD_LIBRARY_PATH', value) # """Append value to DYLD_LIBRARY_PATH environment variable""" @@ -152,11 +167,11 @@ class SalomeContext: def setVariable(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) + self.getLogger().error("Environment variable already existing (and not overwritten): %s=%s", name, value) return if env: - self.getLogger().warning("Overwriting environment variable: %s=%s", name, value) + self.getLogger().debug("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) @@ -195,16 +210,21 @@ class SalomeContext: options = args[1:] availableCommands = { - 'start' : '_runAppli', - 'shell' : '_runSession', + 'start' : '_runAppli', + 'context' : '_setContext', + 'shell' : '_runSession', 'connect' : '_runConsole', - 'killall': '_killAll', - 'info': '_showInfo', - 'help': '_usage', - 'coffee' : '_makeCoffee' + 'kill' : '_kill', + 'killall' : '_killAll', + 'test' : '_runTests', + 'info' : '_showInfo', + 'doc' : '_showDoc', + 'help' : '_usage', + 'coffee' : '_makeCoffee', + 'car' : '_getCar', } - if not command in availableCommands.keys(): + if command not in availableCommands: command = "start" options = args @@ -213,17 +233,20 @@ class SalomeContext: """ Run SALOME! - Args consist in a mandatory command followed by optionnal parameters. + Args consist in a mandatory command followed by optional parameters. See usage for details on commands. """ def _startSalome(self, args): + import os + import sys try: - import os + from setenv import add_path absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH') - import sys path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome")) - if not path in sys.path: - sys.path[:0] = [path] + add_path(path, "PYTHONPATH") + path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome", "appliskel")) + add_path(path, "PYTHONPATH") + except: pass @@ -233,67 +256,50 @@ class SalomeContext: if command is None: if args and args[0] in ["-h","--help","help"]: usage() - sys.exit(0) + return 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, returncode: - if returncode != 0: - self.getLogger().warning("SystemExit %s in method %s.", returncode, command) - sys.exit(returncode) - except StandardError: + return res or 0 + except SystemExit as ex: + if ex.code != 0: + self.getLogger().error("SystemExit %s in method %s.", ex.code, command) + return ex.code + except SalomeContextException as e: + self.getLogger().error(e) + return 1 + except Exception: self.getLogger().error("Unexpected error:") import traceback traceback.print_exc() - sys.exit(1) - except SalomeContextException, e: - self.getLogger().error(e) - sys.exit(1) + return 1 # - def __setEnvironmentFromConfigFile(self, filename, reserved=None): + def __setContextFromConfigFile(self, filename, reserved=None): if reserved is None: reserved = [] try: unsetVars, configVars, reservedDict = parseConfigFile(filename, reserved) - except SalomeContextException, e: + except SalomeContextException as e: msg = "%s"%e - file_dir = os.path.dirname(filename) - file_base = os.path.basename(filename) - base_no_ext, ext = os.path.splitext(file_base) - sh_file = os.path.join(file_dir, base_no_ext+'.sh') - if ext == ".cfg" and os.path.isfile(sh_file): - msg += "Found similar %s file; trying to parse this one instead..."%(base_no_ext+'.sh') - temp = tempfile.NamedTemporaryFile(suffix='.cfg') - try: - convertEnvFileToConfigFile(sh_file, temp.name, reserved) - self.__setEnvironmentFromConfigFile(temp.name, reserved) - msg += "OK\n" - self.getLogger().warning(msg) - temp.close() - return - except (ConfigParser.ParsingError, ValueError) as e: - msg += "Invalid token found when parsing file: %s\n"%(sh_file) - self.getLogger().error(msg) - temp.close() - sys.exit(1) - else: - self.getLogger().error(msg) - sys.exit(1) + self.getLogger().error(msg) + return 1 # unset variables for var in unsetVars: self.unsetVariable(var) - # set environment + # set context for reserved in reservedDict: - a = filter(None, reservedDict[reserved]) # remove empty elements + a = [_f for _f in reservedDict[reserved] if _f] # remove empty elements a = [ os.path.realpath(x) for x in a ] reformattedVals = os.pathsep.join(a) - self.addToVariable(reserved, reformattedVals) + if reserved in ["INCLUDE", "LIBPATH"]: + self.addToVariable(reserved, reformattedVals, separator=' ') + else: + self.addToVariable(reserved, reformattedVals) pass for key,val in configVars: @@ -311,10 +317,32 @@ class SalomeContext: # Initialize SALOME environment sys.argv = ['runSalome'] + args import setenv - setenv.main(True) + setenv.main(True, exeName="salome start") import runSalome runSalome.runSalome() + return 0 + # + + def _setContext(self, args=None): + salome_context_set = os.getenv("SALOME_CONTEXT_SET") + if salome_context_set: + print("***") + print("*** SALOME context has already been set.") + print("*** Enter 'exit' (only once!) to leave SALOME context.") + print("***") + return 0 + + os.environ["SALOME_CONTEXT_SET"] = "yes" + print("***") + print("*** SALOME context is now set.") + print("*** Enter 'exit' (only once!) to leave SALOME context.") + print("***") + + cmd = ["/bin/bash"] + proc = subprocess.Popen(cmd, shell=False, close_fds=True) + proc.communicate() + return proc.returncode # def _runSession(self, args=None): @@ -322,7 +350,7 @@ class SalomeContext: args = [] sys.argv = ['runSession'] + args import runSession - params, args = runSession.configureSession(args) + params, args = runSession.configureSession(args, exe="salome shell") sys.argv = ['runSession'] + args import setenv @@ -335,23 +363,39 @@ class SalomeContext: if args is None: args = [] # Initialize SALOME environment - sys.argv = ['runConsole'] + args + sys.argv = ['runConsole'] import setenv setenv.main(True) - cmd = ["python", "-c", "import runConsole\nrunConsole.connect()" ] - proc = subprocess.Popen(cmd, shell=False, close_fds=True) - return proc.communicate() + import runConsole + return runConsole.connect(args) # - def _killAll(self, args=None): + def _kill(self, args=None): if args is None: args = [] + ports = args + if not ports: + print("Port number(s) not provided to command: salome kill ") + return 1 + + from multiprocessing import Process + from killSalomeWithPort import killMyPort + import tempfile + for port in ports: + with tempfile.NamedTemporaryFile(): + p = Process(target = killMyPort, args=(port,)) + p.start() + p.join() + return 0 + # + + def _killAll(self, unused=None): try: import PortManager # mandatory from multiprocessing import Process from killSalomeWithPort import killMyPort - ports = PortManager.getBusyPorts() + ports = PortManager.getBusyPorts()['this'] if ports: import tempfile @@ -361,45 +405,196 @@ class SalomeContext: p.start() p.join() except ImportError: + # :TODO: should be declared obsolete from killSalome import killAllPorts killAllPorts() pass + return 0 + # + def _runTests(self, args=None): + if args is None: + args = [] + sys.argv = ['runTests'] + import setenv + setenv.main(True) + + import runTests + return runTests.runTests(args, exe="salome test") # + def _showSoftwareVersions(self, softwares=None): + config = configparser.SafeConfigParser() + absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH') + filename = os.path.join(absoluteAppliPath, "sha1_collections.txt") + versions = {} + max_len = 0 + with open(filename) as f: + for line in f: + try: + software, version, sha1 = line.split() + versions[software.upper()] = version + if len(software) > max_len: + max_len = len(software) + except: + pass + pass + pass + if softwares: + for soft in softwares: + if versions.has_key(soft.upper()): + print(soft.upper().rjust(max_len), versions[soft.upper()]) + else: + import collections + od = collections.OrderedDict(sorted(versions.items())) + for name, version in od.iteritems(): + print(name.rjust(max_len), versions[name]) + pass + def _showInfo(self, args=None): - print "Running with python", platform.python_version() - self._runAppli(["--version"]) + if args is None: + args = [] + + usage = "Usage: salome info [options]" + epilog = """\n +Display some information about SALOME.\n +Available options are: + -p,--ports Show the list of busy ports (running SALOME instances). + -s,--softwares [software(s)] Show the list and versions of SALOME softwares. + Software names must be separated by blank characters. + If no software is given, show version of all softwares. + -v,--version Show running SALOME version. + -h,--help Show this message. +""" + if not args: + args = ["--version"] + + if "-h" in args or "--help" in args: + print(usage + epilog) + return 0 + + if "-p" in args or "--ports" in args: + import PortManager + ports = PortManager.getBusyPorts() + this_ports = ports['this'] + other_ports = ports['other'] + if this_ports or other_ports: + print("SALOME instances are running on the following ports:") + if this_ports: + print(" This application:", this_ports) + else: + print(" No SALOME instances of this application") + if other_ports: + print(" Other applications:", other_ports) + else: + print(" No SALOME instances of other applications") + else: + print("No SALOME instances are running") + + if "-s" in args or "--softwares" in args: + if "-s" in args: + index = args.index("-s") + else: + index = args.index("--softwares") + indexEnd=index+1 + while indexEnd < len(args) and args[indexEnd][0] != "-": + indexEnd = indexEnd + 1 + self._showSoftwareVersions(softwares=args[index+1:indexEnd]) + + if "-v" in args or "--version" in args: + print("Running with python", platform.python_version()) + return self._runAppli(["--version"]) + + return 0 # + def _showDoc(self, args=None): + if args is None: + args = [] + + modules = args + if not modules: + print("Module(s) not provided to command: salome doc ") + return 1 + + appliPath = os.getenv("ABSOLUTE_APPLI_PATH") + if not appliPath: + raise SalomeContextException("Unable to find application path. Please check that the variable ABSOLUTE_APPLI_PATH is set.") + baseDir = os.path.join(appliPath, "share", "doc", "salome") + for module in modules: + docfile = os.path.join(baseDir, "gui", module.upper(), "index.html") + if not os.path.isfile(docfile): + docfile = os.path.join(baseDir, "tui", module.upper(), "index.html") + if not os.path.isfile(docfile): + docfile = os.path.join(baseDir, "dev", module.upper(), "index.html") + if os.path.isfile(docfile): + out, err = subprocess.Popen(["xdg-open", docfile]).communicate() + else: + print("Online documentation is not accessible for module:", module) + def _usage(self, unused=None): usage() # - def _makeCoffee(self, args=None): - 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) + def _makeCoffee(self, unused=None): + print(" (") + print(" ) (") + print(" ___...(-------)-....___") + print(" .-\"\" ) ( \"\"-.") + print(" .-\'``\'|-._ ) _.-|") + print(" / .--.| `\"\"---...........---\"\"` |") + print(" / / | |") + print(" | | | |") + print(" \\ \\ | |") + print(" `\\ `\\ | |") + print(" `\\ `| SALOME |") + print(" _/ /\\ 4 EVER /") + print(" (__/ \\ <3 /") + print(" _..---\"\"` \\ /`\"\"---.._") + print(" .-\' \\ / \'-.") + print(" : `-.__ __.-\' :") + print(" : ) \"\"---...---\"\" ( :") + print(" \'._ `\"--...___...--\"` _.\'") + print(" \\\"\"--..__ __..--\"\"/") + print(" \'._ \"\"\"----.....______.....----\"\"\" _.\'") + print(" `\"\"--..,,_____ _____,,..--\"\"`") + print(" `\"\"\"----\"\"\"`") + print("") + print(" SALOME is working for you; what else?") + print("") + # + + def _getCar(self, unused=None): + print(" _____________") + print(" ..---:::::::-----------. ::::;;.") + print(" .\'\"\"\"\"\"\" ;; \\ \":.") + print(" .\'\' ; \\ \"\\__.") + print(" .\' ;; ; \\\\\";") + print(" .\' ; _____; \\\\/") + print(" .\' :; ;\" \\ ___:\'.") + print(" .\'--........................... : = ____:\" \\ \\") + print(" ..-\"\" \"\"\"\' o\"\"\" ; ; :") + print(" .--\"\" .----- ..----... _.- --. ..-\" ; ; ; ;") + print(" .\"\"_- \"--\"\"-----\'\"\" _-\" .-\"\" ; ; .-.") + print(" .\' .\' SALOME .\" .\" ; ; /. |") + print(" /-./\' 4 EVER <3 .\" / _.. ; ; ;;;|") + print(" : ;-.______ / _________==. /_ \\ ; ; ;;;;") + print(" ; / | \"\"\"\"\"\"\"\"\"\"\".---.\"\"\"\"\"\"\" : /\" \". |; ; _; ;;;") + print(" /\"-/ | / / / / ;|; ;-\" | ;\';") + print(":- : \"\"\"----______ / / ____. . .\"\'. ;; .-\"..T\" .") + print("\'. \" ___ \"\": \'\"\"\"\"\"\"\"\"\"\"\"\"\"\" . ; ; ;; ;.\" .\" \'--\"") + print(" \", __ \"\"\" \"\"---... :- - - - - - - - - \' \' ; ; ; ;;\" .\"") + print(" /. ; \"\"\"---___ ; ; ; ;|.\"\"") + print(" : \": \"\"\"----. .-------. ; ; ; ;:") + print(" \\ \'--__ \\ \\ \\ / | ; ;;") + print(" \'-.. \"\"\"\"---___ : .______..\\ __/..-\"\"| ; ; ;") + print(" \"\"--.. \"\"\"--\" m l s . \". . ;") + print(" \"\"------... ..--\"\" \" :") + print(" \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\" \\ /") + print(" \"------\"") + print("") + print(" Drive your simulation properly with SALOME!") + print("") # # Add the following two methods since logger is not pickable @@ -425,14 +620,11 @@ class SalomeContext: if __name__ == "__main__": if len(sys.argv) == 3: - context = pickle.loads(sys.argv[1]) - args = pickle.loads(sys.argv[2]) - - (out, err) = context._startSalome(args) - if out: - sys.stdout.write(out) - if err: - sys.stderr.write(err) + context = pickle.loads(sys.argv[1].encode()) + args = pickle.loads(sys.argv[2].encode()) + + status = context._startSalome(args) + sys.exit(status) else: usage() #