#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE # # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # import os,sys,optparse import socket,shutil import re usage=""" Connect to a SALOME session (local or remote) and execute a Python script with data files in argument (optional) Usage: %prog [ options ] script script : The Python script to execute in the SALOME session SALOME SESSION -------------- 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 If MACHINE isn't localhost or hostname, USER is needed If Salome isn't installed on the local machine, use APPLI_DIST to execute a distant session INPUTS AND OUPUTS ----------------- script is needed in all case INPUT and OUTPUT are used only when Salome isn't on local machine. It defines a list of script (full path, blank separated) Actions done with these two lists are : - adjustment of path in a temporary script file - copy of the input files and script file on the distant machine """ appli_local=os.path.realpath(os.path.dirname(__file__)) def get_hostname(): return socket.gethostname().split('.')[0] def vararg_callback(option, opt_str, value, parser): """optparse callback for variable length arguments""" assert value is None done = 0 value = [] rargs = parser.rargs while rargs: arg = rargs[0] # Stop if we hit an arg like "--foo", "-a", "-fx", "--file=f", # etc. Note that this also stops on "-3" or "-3.0", so if # your option takes numeric values, you will need to handle this. if ((arg[:2] == "--" and len(arg) > 2) or (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): break else: value.append(arg) del rargs[0] setattr(parser.values, option.dest, value) def parse_args(): """parse arguments, check validity and set defaults""" parser = optparse.OptionParser(usage=usage) parser.add_option('-p','--port', dest="port", default='', help="The port to connect to") parser.add_option('-m','--machine', dest="machine", default='', help="The computer to connect to") parser.add_option('-d','--directory', dest="directory", help="[Distant Mode] The APPLI_HOME path on the distant machine (must be used if Salome isn't on the local machine)") parser.add_option('-u','--user', dest="user", default='', help="[Distant Mode] The user on the computer to connect to") parser.add_option('-i','--infiles', dest="infiles", default=[], action="callback", callback=vararg_callback, help="[Distant Mode] The list of input files (blank separated) used in the Python script") parser.add_option('-o','--outfiles', dest="outfiles", default=[], action="callback", callback=vararg_callback, help="[Distant Mode] The list of output files (blank separated) generated by the Python script") args=sys.argv[1:] script="" if args: script=args.pop() options, args = parser.parse_args(args) #check the arguments if not os.path.exists(script): print "ERROR: the script file is mandatory" sys.exit(1) machine=options.machine port=options.port user=options.user infiles = options.infiles outfiles = options.outfiles directory=options.directory mode="local" if machine: here=get_hostname() if machine != here and machine != "localhost": #SALOME server is on a remote computer mode="remote" if not user: print "ERROR: the remote execution needs -u user argument" sys.exit(1) if not os.path.exists(os.path.join(appli_local,"runSession")): if not directory: print "ERROR: the remote execution without SALOME installation needs -d directory argument" sys.exit(1) return mode,user,machine,port,directory,infiles,outfiles,script def copy_files(user,machine,script,infiles,outfiles,directory): """modify script, copy files to remote computer and return lists of copied files""" namescript=os.path.basename(script) logname=os.getenv("LOGNAME",user) tmp_script="/tmp/%s_%s_%s" % (logname,os.getpid(),namescript) fscript=open(script) script_text=fscript.read() fscript.close() 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 (into /tmp) 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 fscript=open(tmp_script,'w') fscript.write(script_text) fscript.close() if directory: #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 def main(): mode,user,machine,port,directory,infiles,outfiles,script = parse_args() tmp_script=script print "mode:",mode if mode == "remote": list_infiles, list_outfiles, tmp_script = copy_files(user,machine,script,infiles,outfiles,directory) ################################################# # Execution # ################################################# if directory: print "[ REMOTE ]" # execute runSession from the remote SALOME application cmd="ssh %s@%s %s/runSession " % (user,machine,directory) if port: cmd=cmd+"-p %s "%port cmd = cmd +"python " + tmp_script print '[ SSH ] ' + cmd os.system(cmd) else: print "[ LOCAL ]" # execute runSession from the local SALOME application cmd="%s/runSession " % appli_local if machine: cmd=cmd+"-m %s "%machine if port: cmd=cmd+"-p %s "%port cmd = cmd +"python " + tmp_script print '[ SH ] ' + cmd os.system(cmd) ################################################# # Get remote files and clean # ################################################# if mode == "remote": temp_files=list_infiles+list_outfiles #get the outfiles for outfile in outfiles: remote_outfile=list_outfiles.pop(0) cmd="scp %s@%s:%s %s" %(user,machine,remote_outfile,outfile) print "[ SCP ] "+cmd os.system(cmd) #clean temporary files cmd="ssh %s@%s \\rm -f %s" % (user,machine," ".join(temp_files)) print '[ SSH ] ' + cmd os.system(cmd) os.remove(tmp_script) if __name__ == '__main__': main()