Salome HOME
run scripts on remote machines (substitute for runSalomeScript)
[modules/kernel.git] / bin / salomeContextUtils.py.in
1 #! /usr/bin/env python
2
3 # Copyright (C) 2013-2014  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 import os
23 import sys
24 import glob
25 import subprocess
26 import re
27 import socket
28
29 """
30 Define a specific exception class to manage exceptions related to SalomeContext
31 """
32 class SalomeContextException(Exception):
33   """Report error messages to the user interface of SalomeContext."""
34 #
35
36 def __listDirectory(path):
37   allFiles = []
38   for root, dirs, files in os.walk(path):
39     cfgFiles = glob.glob(os.path.join(root,'*.cfg'))
40     allFiles += cfgFiles
41
42     shFiles = glob.glob(os.path.join(root,'*.sh'))
43     for f in shFiles:
44       no_ext = os.path.splitext(f)[0]
45       if not os.path.isfile(no_ext+".cfg"):
46         allFiles.append(f)
47
48   return allFiles
49 #
50
51 def __getConfigFileNamesDefault():
52   absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
53   if not absoluteAppliPath:
54     return []
55
56   envdDir = absoluteAppliPath + '/env.d'
57   if not os.path.isdir(envdDir):
58     return []
59
60   return __listDirectory(envdDir)
61 #
62
63 def getConfigFileNames(args, checkExistence=False):
64   # special case: configuration files are provided by user
65   # Search for command-line argument(s) --config=file1,file2,..., filen
66   # Search for command-line argument(s) --config=dir1,dir2,..., dirn
67   configOptionPrefix = "--config="
68   configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ]
69
70   if len(configArgs) == 0:
71     return __getConfigFileNamesDefault(), args, []
72
73   args = [ x for x in args if not x.startswith(configOptionPrefix) ]
74   allLists = [ x.replace(configOptionPrefix, '') for x in configArgs ]
75
76   configFileNames = []
77   unexisting = []
78   for currentList in allLists:
79     elements = currentList.split(',')
80     for elt in elements:
81       elt = os.path.realpath(os.path.expanduser(elt))
82       if os.path.isdir(elt):
83         configFileNames += __listDirectory(elt)
84       else:
85         if checkExistence and not os.path.isfile(elt):
86           unexisting += [elt]
87         else:
88           configFileNames += [elt]
89
90   return configFileNames, args, unexisting
91 #
92
93 def __getScriptPath(scriptName, searchPathList):
94   if searchPathList is None or len(searchPathList) == 0:
95     return None
96
97   for path in searchPathList:
98     fullName = os.path.join(path, scriptName)
99     if os.path.isfile(fullName) or os.path.isfile(fullName+".py"):
100       return fullName
101
102   return None
103 #
104
105 class ScriptAndArgs:
106   # script: the command to be run, e.g. python <script.py>
107   # args: its input parameters
108   # out: its output parameters
109   def __init__(self, script = None, args = None, out = None):
110     self.script = script
111     self.args = args
112     self.out = out
113 #
114
115 # Return an array of ScriptAndArgs objects
116 def getScriptsAndArgs(args=None, searchPathList=None):
117   if args is None:
118     args = []
119   if searchPathList is None:
120     searchPathList = sys.path
121
122   # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an]
123   scriptArgs = []
124   currentKey = None
125   argsPrefix = "args:"
126   outPrefix = "out:"
127   callPython = False
128   afterArgs = False
129   currentScript = None
130
131   for i in range(len(args)):
132     elt = args[i]
133
134     if elt.startswith(argsPrefix):
135       if not currentKey or callPython:
136         raise SalomeContextException("args list must follow corresponding script file in command line.")
137       elt = elt.replace(argsPrefix, '')
138       scriptArgs[len(scriptArgs)-1].args = elt.split(",")
139       currentKey = None
140       callPython = False
141       afterArgs = True
142     elif elt.startswith(outPrefix):
143       if (not currentKey and not afterArgs) or callPython:
144         raise SalomeContextException("out list must follow both corresponding script file and its args in command line.")
145       elt = elt.replace(outPrefix, '')
146       scriptArgs[len(scriptArgs)-1].out = elt.split(",")
147       currentKey = None
148       callPython = False
149       afterArgs = False
150     elif elt.startswith("python"):
151       callPython = True
152       afterArgs = False
153     else:
154       if not os.path.isfile(elt) and not os.path.isfile(elt+".py"):
155         eltInSearchPath = __getScriptPath(elt, searchPathList)
156         if eltInSearchPath is None or (not os.path.isfile(eltInSearchPath) and not os.path.isfile(eltInSearchPath+".py")):
157           if elt[-3:] == ".py":
158             raise SalomeContextException("Script not found: %s"%elt)
159           continue
160         elt = eltInSearchPath
161
162       if elt[-4:] != ".hdf":
163         if elt[-3:] == ".py":
164           currentScript = os.path.abspath(elt)
165         elif os.path.isfile(elt+".py"):
166           currentScript = os.path.abspath(elt+".py")
167         else:
168           currentScript = os.path.abspath(elt) # python script not necessary has .py extension
169         pass
170       if currentScript and callPython:
171         currentKey = "@PYTHONBIN@ "+currentScript
172         scriptArgs.append(ScriptAndArgs(script=currentKey))
173         callPython = False
174       elif currentScript:
175         if not os.access(currentScript, os.X_OK):
176           currentKey = "@PYTHONBIN@ "+currentScript
177           scriptArgs.append(ScriptAndArgs(script=currentKey))
178         else:
179           ispython = False
180           try:
181             fn = open(currentScript)
182             for i in xrange(10): # read only 10 first lines
183               ln = fn.readline()
184               if re.search("#!.*python"):
185                 ispython = True
186                 break
187               pass
188             fn.close()
189           except:
190             pass
191           if not ispython and currentScript[-3:] == ".py":
192             currentKey = "@PYTHONBIN@ "+currentScript
193           else:
194             currentKey = currentScript
195             pass
196           scriptArgs.append(ScriptAndArgs(script=currentKey))
197       # CLOSE elif currentScript
198       afterArgs = False
199   # end for loop
200   return scriptArgs
201 #
202
203 # Formatting scripts and args as a Bash-like command-line:
204 # script1.py [args] ; script2.py [args] ; ...
205 # scriptArgs is a list of ScriptAndArgs objects; their output parameters are omitted
206 def formatScriptsAndArgs(scriptArgs=None):
207     if scriptArgs is None:
208       return ""
209     commands = []
210     for sa_obj in scriptArgs:
211       cmd = sa_obj.script
212       if sa_obj.args:
213         cmd = " ".join([cmd]+sa_obj.args)
214       commands.append(cmd)
215
216     sep = " ; "
217     if sys.platform == "win32":
218       sep = " & "
219     command = sep.join(["%s"%x for x in commands])
220     return command
221 #
222
223 # Ensure OMNIORB_USER_PATH is defined. This variable refers to a the folder in which
224 # SALOME will write omniOrb configuration files.
225 # If OMNIORB_USER_PATH is already set, only checks write access to associated directory ;
226 # an exception is raised if check fails. It allows users for choosing a specific folder.
227 # Else the function sets OMNIORB_USER_PATH this way:
228 # - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS.
229 #   The function does not check USERS folder existence or write access. This folder
230 #   must exist ; this is the case if SALOME virtual application has been created using
231 #   appli_gen.py script.
232 # - Else OMNIORB_USER_PATH is set to user home directory.
233 def setOmniOrbUserPath():
234   omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
235   if omniorbUserPath:
236     if not os.access(omniorbUserPath, os.W_OK):
237       raise Exception("Unable to get write access to directory: %s"%omniorbUserPath)
238     pass
239   else:
240     homePath = os.path.realpath(os.path.expanduser('~'))
241     #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS")
242     defaultOmniorbUserPath = homePath
243     if os.getenv("APPLI"):
244       defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS")
245       pass
246     os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath
247 #
248
249 def getHostname():
250   return socket.gethostname().split('.')[0]
251 #