-# 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
import os
import sys
import logging
-import ConfigParser
+import configparser
from parseConfigFile import parseConfigFile
-from parseConfigFile import convertEnvFileToConfigFile
import tempfile
import pickle
from salomeContextUtils import SalomeContextException
def usage():
- #exeName = os.path.splitext(os.path.basename(__file__))[0]
-
msg = '''\
Usage: salome [command] [options] [--config=<file,folder,...>]
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 <port(s)> 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 <module(s)> 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 <command> --help to show help on command ; available for start
- and shell commands.
+ Use salome <command> --help to show help on command. Available for the
+ following commands: start, shell, connect, test, info.
--config=<file,folder,...>
==========================
- Initialize SALOME environment from a list of context files and/or a list
- of folders containing context files. The list is comma-separated, whithout
+ Initialize SALOME context from a list of context files and/or a list
+ of folders containing context files. The list is comma-separated, without
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"""
"""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"""
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)
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
"""
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
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:
# 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):
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
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 <port(s)>")
+ 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
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 <module(s)>")
+ 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
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()
#