1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
4 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
26 from optparse import OptionParser
27 from NSparam import getNSparams
31 from salomeContextUtils import getScriptsAndArgs, formatScriptsAndArgs, getShortAndExtraArgs
32 from salome_utils import getUserName, getShortHostName
34 # Use to display newlines (\n) in epilog
35 class MyParser(OptionParser):
36 def format_epilog(self, formatter):
40 class SessionParameters:
41 def __init__(self, mode, port, machine, user, directory):
44 self.machine = machine
46 self.directory = directory
49 msg = "\n# Session Parameters:\n"
50 msg += " * mode: %s\n"%self.mode
51 msg += " * port: %s\n"%self.port
52 msg += " * machine: %s\n"%self.machine
53 msg += " * user: %s\n"%self.user
54 msg += " * directory: %s\n"%self.directory
59 def configureSession(args=None, exe=None):
63 usage = "Usage: %s [options] [command] [-- <extra>]"%exe
65 usage = "Usage: %prog [options] [command] [-- <extra>]"
67 If command is not given a shell is opened; else execute the given command.\n
68 * Command may be an executable script or program, either identified by its
69 full path or located in a directory pointed by a system variable (e.g.
71 * Command may also be a series of Python scripts with arguments:
72 [PYTHON_FILE [args] [PYTHON_FILE [args]...]]
73 Python file arguments, if any, must be comma-separated (without blank
74 characters) and prefixed by "args:" keyword (without quotes).
76 salome shell hello.py add.py args:1,2 hello.py args:you
77 will successively say hello, add 1+2, and say hello to you.\n
78 The double dash (--) syntax indicates an extra command to be run "as is". It
79 allows calling a extern program or system command with options and
80 arguments, using the syntax: -- <program> [options] [arguments].
82 salome shell -- ls -l *.py
83 salome shell -- python -tt hello.py
85 If PORT and MACHINE are not given, try to connect to the last active session
87 If PORT and MACHINE are given, try to connect to the remote session associated
89 If MACHINE is not given, try to connect to the session associated to PORT on
91 If PORT is not given, try to connect to the remote session associated to port
93 If MACHINE is remote, the following options MUST be provided:
94 * DIRECTORY: The full path to the salome command on remote machine.
95 * USER: The user on the computer to connect to.\n
96 In case of remote call, syntax "out:res1,res2,..." can be used to get results
99 salome shell -m remotemachine -p 2810 -u myself -d /full/path/to/salome
100 concatenate.py args:file1.txt,file2.txt out:result.txt
101 User "myself" connects to remotemachine to run the script concatenate.py in
102 a SALOME session on port 2810; the script takes two input parameters and
103 produces one result file.\n
105 parser = MyParser(usage=usage, epilog=epilog)
106 parser.add_option("-p", "--port", metavar="<port>", default=0,
107 action="store", type="string", dest="port",
108 help="The port to connect to."
110 parser.add_option("-m", "--machine", metavar="<machine>", default=0,
111 action="store", type="string", dest="host",
112 help="The machine to connect to."
114 parser.add_option('-d', '--directory', dest="directory", default=None,
115 help="[Remote mode] The full path to the salome command on remote machine."
117 parser.add_option('-u', '--user', dest="user", default=None,
118 help="[Remote mode] The user on the computer to connect to."
121 parser.add_option('-l', '--launcher', dest="launcher", default=None,
122 help="[Remote mode] The machine and the port to connect to."
125 short_args, extra_args = getShortAndExtraArgs(args)
127 (options, args) = parser.parse_args(short_args)
128 except Exception as e:
134 launcher = options.launcher
135 if launcher is not None:
136 pos = launcher.find(":")
138 host = launcher[0:pos]
139 port = launcher[pos+1:]
141 # :GLITCH: this code defines specific environment variables (OMNIORB_CONFIG, NSPORT,
142 # NSHOST) which are later used by other modules. Working, but not really "safe"...
145 # neither MACHINE nor PORT are given
146 # --- set omniORB configuration to current session if any
147 omniorbUserPath = os.environ['OMNIORB_USER_PATH']
148 fileOmniConfig = omniorbUserPath + '/.omniORB_' + getUserName() + '_last.cfg'
149 if os.path.isfile(fileOmniConfig):
150 os.environ['OMNIORB_CONFIG'] = fileOmniConfig
151 # --- set environment variables for port and hostname of NamingService
152 host, port = getNSparams()
154 # keep short name for host, for a correct comparison with getShortHostName() later
155 host=host.split('.')[0]
163 # only MACHINE is given
165 _writeConfigFile(port, host)
170 host = getShortHostName()
171 # both MACHINE and PORT are given
172 _writeConfigFile(port, host)
174 os.environ['NSPORT'] = port
175 os.environ['NSHOST'] = host
177 # determine running mode, that is either 'local' or 'remote'
178 here = getShortHostName()
180 if host != here and host != "localhost" and host != "no_host" and launcher is None:
183 params = SessionParameters(mode, port, host, options.user, options.directory)
184 return params, args+extra_args
187 # --- set the OMNIORB_CONFIG file and environment relative to this run of SALOME
188 def _writeConfigFile(port, host):
189 path = os.environ['OMNIORB_USER_PATH']
190 kwargs = {'with_username' : getUserName()}
192 from ORBConfigFile import writeORBConfigFile
193 [ filename, msgSize ] = writeORBConfigFile(path, host, port, kwargs)
195 os.environ['OMNIORB_CONFIG'] = filename
198 # command looks like a Bash command-line:
199 # script1.py [args] ; script2.py [args] ; ...
200 def __runLocalSession(command):
203 if sys.platform == "win32":
205 command = command.split(sep)
209 single_cmd = cmd.strip().split(' ')
213 proc = subprocess.Popen(single_cmd)
214 (stdoutdata, stderrdata) = proc.communicate() # Wait for process to terminate
216 outmsg.append(stdoutdata)
218 errmsg.append(stderrdata)
220 if proc.returncode != 0:
222 error_code = proc.returncode
228 errmsg.append("Error raised when executing command: %s\n"%cmd)
230 sys.stdout.write("".join(outmsg))
232 sys.stderr.write("".join(errmsg))
237 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
238 if sys.platform == "win32":
239 cmd = ["cmd", "/K", "set PROMPT=[SALOME] $P$G"]
241 cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ]
242 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
244 return proc.returncode
247 def __copyFiles(user, machine, script, infiles, outfiles):
248 """Modify script, copy files to remote computer and return lists of copied files."""
250 namescript = os.path.basename(script)
252 logname = getpass.getuser()
253 tmp_script = "/tmp/%s_%s_%s" % (logname, os.getpid(), namescript)
254 with open(script, 'r') as fscript:
255 script_text = fscript.read()
260 for infile in infiles:
261 # generate a temporary file name
262 namefile = os.path.basename(infile)
263 tmp_file = "/tmp/%s_%s_i%s_%s" % (logname, os.getpid(), n, namefile)
265 # modify the salome script
266 script_text = re.sub(infile, tmp_file, script_text)
268 # copy the infile to the remote server
269 cmd = "scp %s %s@%s:%s" % (infile, user, machine, tmp_file)
270 print("[ SCP ]", cmd)
273 list_infiles.append(tmp_file)
277 for outfile in outfiles:
278 # generate a temporary file name
279 namefile = os.path.basename(outfile)
280 tmp_file = "/tmp/%s_%s_o%s_%s" % (logname, os.getpid(), n, namefile)
282 # modify the salome script
283 script_text = re.sub(outfile, tmp_file, script_text)
285 list_outfiles.append(tmp_file)
289 with open(tmp_script,'w') as fscript:
290 fscript.write(script_text)
292 # copy the salome script on the remote server
293 cmd = "scp %s %s@%s:%s" % (tmp_script, user, machine, tmp_script)
294 print("[ SCP ]", cmd)
297 return list_infiles, list_outfiles, tmp_script
300 # sa_obj is a ScriptAndArgs object (from salomeContextUtils)
301 def __runRemoteSession(sa_obj, params):
303 print("ERROR: The user login on remote machine MUST be given.")
305 if not params.directory:
306 print("ERROR: The remote directory MUST be given.")
309 # sa_obj.script may be 'python script.py' --> only process .py file
310 header = " ".join(sa_obj.script.split()[:-1])
311 script = sa_obj.script.split()[-1]
313 tmp_in, tmp_out, tmp_script = __copyFiles(params.user, params.machine, script, sa_obj.args or [], sa_obj.out or [])
315 # execute command on the remote SALOME application
316 command = "%s/salome shell" % (params.directory)
318 command += " -p %s "%params.port
319 command += " %s %s args:%s"%(header, tmp_script, ",".join(tmp_in))
320 # salome shell command must run in a login shell because of module function
321 command = "ssh %s@%s -t 'bash -l -c \"%s\"'" % (params.user, params.machine, command)
322 print('[ SSH ] ' + command)
325 # Get remote files and clean
326 temp_files = tmp_in + tmp_out + [tmp_script]
329 for outfile in (sa_obj.out or []):
330 remote_outfile = tmp_out.pop(0)
331 command = "scp %s@%s:%s %s" %(params.user, params.machine, remote_outfile, outfile)
332 print("[ SCP ] " + command)
335 # clean temporary files
336 command = "ssh %s@%s \\rm -f %s" % (params.user, params.machine, " ".join(temp_files))
337 print('[ SSH ] ' + command)
339 os.remove(tmp_script)
344 def runSession(params, args):
345 scriptArgs = getScriptsAndArgs(args)
347 if params.mode == "local":
348 command = formatScriptsAndArgs(scriptArgs)
349 return __runLocalSession(command)
351 elif params.mode == "remote":
353 for sa_obj in scriptArgs:
354 ok = __runRemoteSession(sa_obj, params)