from NSparam import getNSparams
import socket
import subprocess
+import re
+from salomeContextUtils import getScriptsAndArgs, formatScriptsAndArgs
# Use to display newlines (\n) in epilog
class MyParser(OptionParser):
return self.epilog
#
+class SessionParameters:
+ def __init__(self, mode, port, machine, user, directory):
+ self.mode = mode
+ self.port = port
+ self.machine = machine
+ self.user = user
+ self.directory = directory
+#
+
def configureSession(args=None):
if args is None:
args = []
If PORT and MACHINE are not given, try to connect to the last active session on the local machine.
If PORT and MACHINE are given, try to connect to the remote session associated with PORT on MACHINE.
If MACHINE is not given, try to connect to the session associated to PORT on the local machine.
-If PORT is not given, try to connect to the remote session associated to port 2810 on MACHINE.\n\n"""
+If PORT is not given, try to connect to the remote session associated to port 2810 on MACHINE.
+\n
+If MACHINE is remote, the following options MUST be provided:
+ * DIRECTORY: The full path to the salome command on remote machine.
+ * USER: The user on the computer to connect to.
+"""
parser = MyParser(usage=usage, epilog=epilog)
parser.add_option("-p", "--port", metavar="<port>", default=0,
action="store", type="string", dest="port",
action="store", type="string", dest="host",
help="The machine to connect to."
)
+ parser.add_option('-d', '--directory', dest="directory", default=None,
+ help="[Remote mode] The full path to the salome command on remote machine."
+ )
+ parser.add_option('-u', '--user', dest="user", default=None,
+ help="[Remote mode] The user on the computer to connect to."
+ )
try:
(options, args) = parser.parse_args(args)
except Exception, e:
#
os.environ['NSPORT'] = port
os.environ['NSHOST'] = host
+
+ # determine running mode, taht is either 'local' or 'remote'
+ from salomeContextUtils import getHostname
+ here = getHostname()
+ mode = "local"
+ if host != here and host != "localhost" and host != "no_host":
+ mode="remote"
+ pass
+ params = SessionParameters(mode, port, host, options.user, options.directory)
+ return params, args
#
# --- set the OMNIORB_CONFIG file and environment relative to this run of SALOME
# command looks like a Bash command-line:
# script1.py [args] ; script2.py [args] ; ...
-def runSession(command):
+def __runLocalSession(command):
if command:
sep = ";"
if sys.platform == "win32":
outmsg = []
errmsg = []
for cmd in command:
- save_cmd = cmd
- cmd = cmd.strip().split(' ')
- #proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- proc = subprocess.Popen(cmd)
- (stdoutdata, stderrdata) = proc.communicate()
+ single_cmd = cmd.strip().split(' ')
+ proc = subprocess.Popen(single_cmd)
+ (stdoutdata, stderrdata) = proc.communicate() # Wait for process to terminate
if stdoutdata:
outmsg.append(stdoutdata)
if stderrdata:
errmsg.append(stderrdata)
if proc.returncode != 0:
- errmsg.append("Error raised when executing command: %s\n"%save_cmd)
+ errmsg.append("Error raised when executing command: %s\n"%cmd)
if outmsg:
sys.stdout.write("".join(outmsg))
if errmsg:
proc = subprocess.Popen(cmd, shell=False, close_fds=True)
return proc.communicate()
#
+
+def __copyFiles(user, machine, script, infiles, outfiles):
+ """Modify script, copy files to remote computer and return lists of copied files."""
+
+ namescript = os.path.basename(script)
+ import getpass
+ logname = getpass.getuser()
+ tmp_script = "/tmp/%s_%s_%s" % (logname, os.getpid(), namescript)
+ with open(script, 'r') as fscript:
+ script_text = fscript.read()
+
+ list_infiles = []
+ list_outfiles = []
+ n = 0
+ for infile in infiles:
+ # generate a temporary file name
+ namefile = os.path.basename(infile)
+ tmp_file = "/tmp/%s_%s_i%s_%s" % (logname, os.getpid(), n, namefile)
+
+ # modify the salome script
+ script_text = re.sub(infile, tmp_file, script_text)
+
+ # copy the infile to the remote server
+ cmd = "scp %s %s@%s:%s" % (infile, user, machine, tmp_file)
+ print "[ SCP ]", cmd
+ os.system(cmd)
+
+ list_infiles.append(tmp_file)
+ n = n + 1
+ #
+ n = 0
+ for outfile in outfiles:
+ # generate a temporary file name
+ namefile = os.path.basename(outfile)
+ tmp_file = "/tmp/%s_%s_o%s_%s" % (logname, os.getpid(), n, namefile)
+
+ # modify the salome script
+ script_text = re.sub(outfile, tmp_file, script_text)
+
+ list_outfiles.append(tmp_file)
+ n = n + 1
+ #
+
+ with open(tmp_script,'w') as fscript:
+ fscript.write(script_text)
+
+ # copy the salome script on the remote server
+ cmd = "scp %s %s@%s:%s" % (tmp_script, user, machine, tmp_script)
+ print "[ SCP ]", cmd
+ os.system(cmd)
+
+ return list_infiles, list_outfiles, tmp_script
+#
+
+# sa_obj is a ScriptAndArgs object (from salomeContextUtils)
+def __runRemoteSession(sa_obj, params):
+ if not params.user:
+ print "ERROR: The user login on remote machine MUST be given."
+ return
+ if not params.directory:
+ print "ERROR: The remote directory MUST be given."
+ return
+
+ # sa_obj.script may be 'python script.py' --> only process .py file
+ header = " ".join(sa_obj.script.split()[:-1])
+ script = sa_obj.script.split()[-1]
+
+ tmp_in, tmp_out, tmp_script = __copyFiles(params.user, params.machine, script, sa_obj.args or [], sa_obj.out or [])
+
+ # execute command on the remote SALOME application
+ command = "ssh %s@%s %s/runSession " % (params.user, params.machine, params.directory)
+ if params.port:
+ command = command + "-p %s "%params.port
+ command = command + " ".join([header,tmp_script] + tmp_in)
+ print '[ SSH ] ' + command
+ os.system(command)
+
+ # Get remote files and clean
+ temp_files = tmp_in + tmp_out + [tmp_script]
+
+ # get the outfiles
+ for outfile in (sa_obj.out or []):
+ remote_outfile = tmp_out.pop(0)
+ command = "scp %s@%s:%s %s" %(params.user, params.machine, remote_outfile, outfile)
+ print "[ SCP ] " + command
+ os.system(command)
+
+ # clean temporary files
+ command = "ssh %s@%s \\rm -f %s" % (params.user, params.machine, " ".join(temp_files))
+ print '[ SSH ] ' + command
+ os.system(command)
+ os.remove(tmp_script)
+
+#
+
+def runSession(params, args):
+ scriptArgs = getScriptsAndArgs(args)
+ command = formatScriptsAndArgs(scriptArgs)
+
+ if params.mode == "local":
+ command = formatScriptsAndArgs(scriptArgs)
+ return __runLocalSession(command)
+
+ elif params.mode == "remote":
+ for sa_obj in scriptArgs:
+ __runRemoteSession(sa_obj, params)
+#
import glob
import subprocess
import re
+import socket
"""
Define a specific exception class to manage exceptions related to SalomeContext
return None
#
-# Return an array of dictionaries {script_name: [list_of_its_args]}
+class ScriptAndArgs:
+ # script: the command to be run, e.g. python <script.py>
+ # args: its input parameters
+ # out: its output parameters
+ def __init__(self, script = None, args = None, out = None):
+ self.script = script
+ self.args = args
+ self.out = out
+#
+
+# Return an array of ScriptAndArgs objects
def getScriptsAndArgs(args=None, searchPathList=None):
if args is None:
args = []
scriptArgs = []
currentKey = None
argsPrefix = "args:"
+ outPrefix = "out:"
callPython = False
+ afterArgs = False
currentScript = None
for i in range(len(args)):
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(",")
+ scriptArgs[len(scriptArgs)-1].args = elt.split(",")
+ currentKey = None
+ callPython = False
+ afterArgs = True
+ elif elt.startswith(outPrefix):
+ if (not currentKey and not afterArgs) or callPython:
+ raise SalomeContextException("out list must follow both corresponding script file and its args in command line.")
+ elt = elt.replace(outPrefix, '')
+ scriptArgs[len(scriptArgs)-1].out = elt.split(",")
currentKey = None
callPython = False
+ afterArgs = False
elif elt.startswith("python"):
callPython = True
+ afterArgs = False
else:
if not os.path.isfile(elt) and not os.path.isfile(elt+".py"):
eltInSearchPath = __getScriptPath(elt, searchPathList)
pass
if currentScript and callPython:
currentKey = "@PYTHONBIN@ "+currentScript
- scriptArgs.append({currentKey:[]})
+ scriptArgs.append(ScriptAndArgs(script=currentKey))
callPython = False
elif currentScript:
if not os.access(currentScript, os.X_OK):
currentKey = "@PYTHONBIN@ "+currentScript
- scriptArgs.append({currentKey:[]})
+ scriptArgs.append(ScriptAndArgs(script=currentKey))
else:
ispython = False
try:
else:
currentKey = currentScript
pass
- scriptArgs.append({currentKey:[]})
+ scriptArgs.append(ScriptAndArgs(script=currentKey))
+ # CLOSE elif currentScript
+ afterArgs = False
# end for loop
return scriptArgs
#
# Formatting scripts and args as a Bash-like command-line:
# script1.py [args] ; script2.py [args] ; ...
+# scriptArgs is a list of ScriptAndArgs objects; their output parameters are omitted
def formatScriptsAndArgs(scriptArgs=None):
if scriptArgs is None:
- scriptArgs = []
+ return ""
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)
+ for sa_obj in scriptArgs:
+ cmd = sa_obj.script
+ if sa_obj.args:
+ cmd = " ".join([cmd]+sa_obj.args)
+ commands.append(cmd)
+
sep = " ; "
if sys.platform == "win32":
- sep= " & "
+ sep = " & "
command = sep.join(["%s"%x for x in commands])
return command
#
pass
os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath
#
+
+def getHostname():
+ return socket.gethostname().split('.')[0]
+#