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
33 # Use to display newlines (\n) in epilog
34 class MyParser(OptionParser):
35 def format_epilog(self, formatter):
39 class SessionParameters:
40 def __init__(self, mode, port, machine, user, directory):
43 self.machine = machine
45 self.directory = directory
48 def configureSession(args=None, exe=None):
52 usage = "Usage: %s [options] [command]"%exe
54 usage = "Usage: %prog [options] [command]"
56 If command is not given a shell is opened; else execute the given command.\n
57 * Command may be an executable script or program, either identified by its full path or located in a directory pointed by a system variable (e.g. PATH).\n
58 * Command may also be a series of Python scripts with arguments: [PYTHON_FILE [args] [PYTHON_FILE [args]...]]
59 Python file arguments, if any, must be comma-separated (without blank characters) and prefixed by "args:" (without quotes).
61 salome shell hello.py add.py args:1,2 hello.py args:you
62 will successively say hello, add 1+2, and say hello to you.
64 If PORT and MACHINE are not given, try to connect to the last active session on the local machine.
65 If PORT and MACHINE are given, try to connect to the remote session associated with PORT on MACHINE.
66 If MACHINE is not given, try to connect to the session associated to PORT on the local machine.
67 If PORT is not given, try to connect to the remote session associated to port 2810 on MACHINE.\n
68 If MACHINE is remote, the following options MUST be provided:
69 * DIRECTORY: The full path to the salome command on remote machine.
70 * USER: The user on the computer to connect to.\n
71 In case of remote call, syntax "out:res1,res2,..." can be used to get results from remote machine.
73 salome shell -m remotemachine -p 2810 -u myself -d /full/path/to/salome concatenate.py args:file1.txt,file2.txt out:result.txt
74 User "myself" connects to remotemachine to run the script concatenate.py in a SALOME session on port 2810; the script takes two input parameters and produces one result file.\n
76 parser = MyParser(usage=usage, epilog=epilog)
77 parser.add_option("-p", "--port", metavar="<port>", default=0,
78 action="store", type="string", dest="port",
79 help="The port to connect to."
81 parser.add_option("-m", "--machine", metavar="<machine>", default=0,
82 action="store", type="string", dest="host",
83 help="The machine to connect to."
85 parser.add_option('-d', '--directory', dest="directory", default=None,
86 help="[Remote mode] The full path to the salome command on remote machine."
88 parser.add_option('-u', '--user', dest="user", default=None,
89 help="[Remote mode] The user on the computer to connect to."
92 (options, args) = parser.parse_args(args)
100 # :GLITCH: this code defines specific environment variables (OMNIORB_CONFIG, NSPORT,
101 # NSHOST) which are later used by other modules. Working, but not really "safe"...
104 # neither MACHINE nor PORT are given
105 # --- set omniORB configuration to current session if any
106 omniorbUserPath = os.environ['OMNIORB_USER_PATH']
107 fileOmniConfig = omniorbUserPath + '/.omniORB_' + os.environ['USER'] + '_last.cfg'
108 if os.path.isfile(fileOmniConfig):
109 os.environ['OMNIORB_CONFIG'] = fileOmniConfig
110 # --- set environment variables for port and hostname of NamingService
111 host, port = getNSparams()
117 # only MACHINE is given
119 _writeConfigFile(port, host)
124 host = socket.gethostname()
125 # both MACHINE and PORT are given
126 _writeConfigFile(port, host)
128 os.environ['NSPORT'] = port
129 os.environ['NSHOST'] = host
131 # determine running mode, taht is either 'local' or 'remote'
132 here = socket.gethostname()
134 if host != here and host != "localhost" and host != "no_host":
137 params = SessionParameters(mode, port, host, options.user, options.directory)
141 # --- set the OMNIORB_CONFIG file and environment relative to this run of SALOME
142 def _writeConfigFile(port, host):
143 path = os.environ['OMNIORB_USER_PATH']
144 kwargs = {'with_username' : os.environ['USER']}
146 from ORBConfigFile import writeORBConfigFile
147 [ filename, msgSize ] = writeORBConfigFile(path, host, port, kwargs)
149 os.environ['OMNIORB_CONFIG'] = filename
152 # command looks like a Bash command-line:
153 # script1.py [args] ; script2.py [args] ; ...
154 def __runLocalSession(command):
157 if sys.platform == "win32":
159 command = command.split(sep)
163 single_cmd = cmd.strip().split(' ')
166 proc = subprocess.Popen(single_cmd)
167 (stdoutdata, stderrdata) = proc.communicate() # Wait for process to terminate
169 outmsg.append(stdoutdata)
171 errmsg.append(stderrdata)
173 if proc.returncode != 0:
180 errmsg.append("Error raised when executing command: %s\n"%cmd)
182 sys.stdout.write("".join(outmsg))
184 sys.stderr.write("".join(errmsg))
187 return ("".join(outmsg), "".join(errmsg))
189 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
190 cmd = ["/bin/bash", "--rcfile", absoluteAppliPath + "/.bashrc" ]
191 proc = subprocess.Popen(cmd, shell=False, close_fds=True)
192 return proc.communicate()
195 def __copyFiles(user, machine, script, infiles, outfiles):
196 """Modify script, copy files to remote computer and return lists of copied files."""
198 namescript = os.path.basename(script)
200 logname = getpass.getuser()
201 tmp_script = "/tmp/%s_%s_%s" % (logname, os.getpid(), namescript)
202 with open(script, 'r') as fscript:
203 script_text = fscript.read()
208 for infile in infiles:
209 # generate a temporary file name
210 namefile = os.path.basename(infile)
211 tmp_file = "/tmp/%s_%s_i%s_%s" % (logname, os.getpid(), n, namefile)
213 # modify the salome script
214 script_text = re.sub(infile, tmp_file, script_text)
216 # copy the infile to the remote server
217 cmd = "scp %s %s@%s:%s" % (infile, user, machine, tmp_file)
221 list_infiles.append(tmp_file)
225 for outfile in outfiles:
226 # generate a temporary file name
227 namefile = os.path.basename(outfile)
228 tmp_file = "/tmp/%s_%s_o%s_%s" % (logname, os.getpid(), n, namefile)
230 # modify the salome script
231 script_text = re.sub(outfile, tmp_file, script_text)
233 list_outfiles.append(tmp_file)
237 with open(tmp_script,'w') as fscript:
238 fscript.write(script_text)
240 # copy the salome script on the remote server
241 cmd = "scp %s %s@%s:%s" % (tmp_script, user, machine, tmp_script)
245 return list_infiles, list_outfiles, tmp_script
248 # sa_obj is a ScriptAndArgs object (from salomeContextUtils)
249 def __runRemoteSession(sa_obj, params):
251 print "ERROR: The user login on remote machine MUST be given."
253 if not params.directory:
254 print "ERROR: The remote directory MUST be given."
257 # sa_obj.script may be 'python script.py' --> only process .py file
258 header = " ".join(sa_obj.script.split()[:-1])
259 script = sa_obj.script.split()[-1]
261 tmp_in, tmp_out, tmp_script = __copyFiles(params.user, params.machine, script, sa_obj.args or [], sa_obj.out or [])
263 # execute command on the remote SALOME application
264 command = "ssh %s@%s %s/salome shell " % (params.user, params.machine, params.directory)
266 command = command + "-p %s "%params.port
267 command = command + " %s %s args:%s"%(header, tmp_script, ",".join(tmp_in))
268 print '[ SSH ] ' + command
271 # Get remote files and clean
272 temp_files = tmp_in + tmp_out + [tmp_script]
275 for outfile in (sa_obj.out or []):
276 remote_outfile = tmp_out.pop(0)
277 command = "scp %s@%s:%s %s" %(params.user, params.machine, remote_outfile, outfile)
278 print "[ SCP ] " + command
281 # clean temporary files
282 command = "ssh %s@%s \\rm -f %s" % (params.user, params.machine, " ".join(temp_files))
283 print '[ SSH ] ' + command
285 os.remove(tmp_script)
289 def runSession(params, args):
290 scriptArgs = getScriptsAndArgs(args)
292 if params.mode == "local":
293 command = formatScriptsAndArgs(scriptArgs)
294 return __runLocalSession(command)
296 elif params.mode == "remote":
297 for sa_obj in scriptArgs:
298 __runRemoteSession(sa_obj, params)