1 # -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2015 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
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=[], exe=None):
61 usage = "Usage: %s [options] [command] [-- <extra>]"%exe
63 usage = "Usage: %prog [options] [command] [-- <extra>]"
65 If command is not given a shell is opened; else execute the given command.\n
66 * Command may be an executable script or program, either identified by its
67 full path or located in a directory pointed by a system variable (e.g.
69 * Command may also be a series of Python scripts with arguments:
70 [PYTHON_FILE [args] [PYTHON_FILE [args]...]]
71 Python file arguments, if any, must be comma-separated (without blank
72 characters) and prefixed by "args:" keyword (without quotes).
74 salome shell hello.py add.py args:1,2 hello.py args:you
75 will successively say hello, add 1+2, and say hello to you.\n
76 The double dash (--) syntax indicates an extra command to be run "as is". It
77 allows calling a extern program or system command with options and
78 arguments, using the syntax: -- <program> [options] [arguments].
80 salome shell -- ls -l *.py
81 salome shell -- python -tt hello.py
83 If PORT and MACHINE are not given, try to connect to the last active session
85 If PORT and MACHINE are given, try to connect to the remote session associated
87 If MACHINE is not given, try to connect to the session associated to PORT on
89 If PORT is not given, try to connect to the remote session associated to port
91 If MACHINE is remote, the following options MUST be provided:
92 * DIRECTORY: The full path to the salome command on remote machine.
93 * USER: The user on the computer to connect to.\n
94 In case of remote call, syntax "out:res1,res2,..." can be used to get results
97 salome shell -m remotemachine -p 2810 -u myself -d /full/path/to/salome
98 concatenate.py args:file1.txt,file2.txt out:result.txt
99 User "myself" connects to remotemachine to run the script concatenate.py in
100 a SALOME session on port 2810; the script takes two input parameters and
101 produces one result file.\n
103 parser = MyParser(usage=usage, epilog=epilog)
104 parser.add_option("-p", "--port", metavar="<port>", default=0,
105 action="store", type="string", dest="port",
106 help="The port to connect to."
108 parser.add_option("-m", "--machine", metavar="<machine>", default=0,
109 action="store", type="string", dest="host",
110 help="The machine to connect to."
112 parser.add_option('-d', '--directory', dest="directory", default=None,
113 help="[Remote mode] The full path to the salome command on remote machine."
115 parser.add_option('-u', '--user', dest="user", default=None,
116 help="[Remote mode] The user on the computer to connect to."
119 short_args, extra_args = getShortAndExtraArgs(args)
121 (options, args) = parser.parse_args(short_args)
129 # :GLITCH: this code defines specific environment variables (OMNIORB_CONFIG, NSPORT,
130 # NSHOST) which are later used by other modules. Working, but not really "safe"...
133 # neither MACHINE nor PORT are given
134 # --- set omniORB configuration to current session if any
135 omniorbUserPath = os.environ['OMNIORB_USER_PATH']
136 fileOmniConfig = omniorbUserPath + '/.omniORB_' + getUserName() + '_last.cfg'
137 if os.path.isfile(fileOmniConfig):
138 os.environ['OMNIORB_CONFIG'] = fileOmniConfig
139 # --- set environment variables for port and hostname of NamingService
140 host, port = getNSparams()
146 # only MACHINE is given
148 _writeConfigFile(port, host)
153 host = socket.gethostname()
154 # both MACHINE and PORT are given
155 _writeConfigFile(port, host)
157 os.environ['NSPORT'] = port
158 os.environ['NSHOST'] = host
160 # determine running mode, taht is either 'local' or 'remote'
161 here = socket.gethostname()
163 if host != here and host != "localhost" and host != "no_host":
166 params = SessionParameters(mode, port, host, options.user, options.directory)
167 return params, args+extra_args
170 # --- set the OMNIORB_CONFIG file and environment relative to this run of SALOME
171 def _writeConfigFile(port, host):
172 path = os.environ['OMNIORB_USER_PATH']
173 kwargs = {'with_username' : getUserName()}
175 from ORBConfigFile import writeORBConfigFile
176 [ filename, msgSize ] = writeORBConfigFile(path, host, port, kwargs)
178 os.environ['OMNIORB_CONFIG'] = filename
181 # command looks like a Bash command-line:
182 # script1.py [args] ; script2.py [args] ; ...
183 def __runLocalSession(command):
186 if sys.platform == "win32":
188 command = command.split(sep)
192 single_cmd = cmd.strip().split(' ')
195 proc = subprocess.Popen(single_cmd)
196 (stdoutdata, stderrdata) = proc.communicate() # Wait for process to terminate
198 outmsg.append(stdoutdata)
200 errmsg.append(stderrdata)
202 if proc.returncode != 0:
209 errmsg.append("Error raised when executing command: %s\n"%cmd)
211 sys.stdout.write("".join(outmsg))
213 sys.stderr.write("".join(errmsg))
216 return ("".join(outmsg), "".join(errmsg))
218 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
219 cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ]
220 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
221 return proc.communicate()
224 def __copyFiles(user, machine, script, infiles, outfiles):
225 """Modify script, copy files to remote computer and return lists of copied files."""
227 namescript = os.path.basename(script)
229 logname = getpass.getuser()
230 tmp_script = "/tmp/%s_%s_%s" % (logname, os.getpid(), namescript)
231 with open(script, 'r') as fscript:
232 script_text = fscript.read()
237 for infile in infiles:
238 # generate a temporary file name
239 namefile = os.path.basename(infile)
240 tmp_file = "/tmp/%s_%s_i%s_%s" % (logname, os.getpid(), n, namefile)
242 # modify the salome script
243 script_text = re.sub(infile, tmp_file, script_text)
245 # copy the infile to the remote server
246 cmd = "scp %s %s@%s:%s" % (infile, user, machine, tmp_file)
250 list_infiles.append(tmp_file)
254 for outfile in outfiles:
255 # generate a temporary file name
256 namefile = os.path.basename(outfile)
257 tmp_file = "/tmp/%s_%s_o%s_%s" % (logname, os.getpid(), n, namefile)
259 # modify the salome script
260 script_text = re.sub(outfile, tmp_file, script_text)
262 list_outfiles.append(tmp_file)
266 with open(tmp_script,'w') as fscript:
267 fscript.write(script_text)
269 # copy the salome script on the remote server
270 cmd = "scp %s %s@%s:%s" % (tmp_script, user, machine, tmp_script)
274 return list_infiles, list_outfiles, tmp_script
277 # sa_obj is a ScriptAndArgs object (from salomeContextUtils)
278 def __runRemoteSession(sa_obj, params):
280 print "ERROR: The user login on remote machine MUST be given."
282 if not params.directory:
283 print "ERROR: The remote directory MUST be given."
286 # sa_obj.script may be 'python script.py' --> only process .py file
287 header = " ".join(sa_obj.script.split()[:-1])
288 script = sa_obj.script.split()[-1]
290 tmp_in, tmp_out, tmp_script = __copyFiles(params.user, params.machine, script, sa_obj.args or [], sa_obj.out or [])
292 # execute command on the remote SALOME application
293 command = "ssh %s@%s %s/salome shell " % (params.user, params.machine, params.directory)
295 command = command + "-p %s "%params.port
296 command = command + " %s %s args:%s"%(header, tmp_script, ",".join(tmp_in))
297 print '[ SSH ] ' + command
300 # Get remote files and clean
301 temp_files = tmp_in + tmp_out + [tmp_script]
304 for outfile in (sa_obj.out or []):
305 remote_outfile = tmp_out.pop(0)
306 command = "scp %s@%s:%s %s" %(params.user, params.machine, remote_outfile, outfile)
307 print "[ SCP ] " + command
310 # clean temporary files
311 command = "ssh %s@%s \\rm -f %s" % (params.user, params.machine, " ".join(temp_files))
312 print '[ SSH ] ' + command
314 os.remove(tmp_script)
318 def runSession(params, args):
319 scriptArgs = getScriptsAndArgs(args)
321 if params.mode == "local":
322 command = formatScriptsAndArgs(scriptArgs)
323 return __runLocalSession(command)
325 elif params.mode == "remote":
326 for sa_obj in scriptArgs:
327 __runRemoteSession(sa_obj, params)