3 # Copyright (C) 2013-2015 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
31 Define a specific exception class to manage exceptions related to SalomeContext
33 class SalomeContextException(Exception):
34 """Report error messages to the user interface of SalomeContext."""
37 def __listDirectory(path):
39 for root, dirs, files in os.walk(path):
40 cfgFiles = glob.glob(os.path.join(root,'*.cfg'))
43 shFiles = glob.glob(os.path.join(root,'*.sh'))
45 no_ext = os.path.splitext(f)[0]
46 if not os.path.isfile(no_ext+".cfg"):
52 def __getConfigFileNamesDefault():
53 absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
54 if not absoluteAppliPath:
57 envdDir = absoluteAppliPath + '/env.d'
58 if not os.path.isdir(envdDir):
61 return __listDirectory(envdDir)
64 def __getEnvironmentFileNames(args, optionPrefix, checkExistence):
65 # special case: extra configuration/environment files are provided by user
66 # Search for command-line argument(s) <optionPrefix>=file1,file2,..., filen
67 # Search for command-line argument(s) <optionPrefix>=dir1,dir2,..., dirn
68 configArgs = [ str(x) for x in args if str(x).startswith(optionPrefix) ]
70 args = [ x for x in args if not x.startswith(optionPrefix) ]
71 allLists = [ x.replace(optionPrefix, '') for x in configArgs ]
75 for currentList in allLists:
76 elements = currentList.split(',')
78 elt = os.path.realpath(os.path.expanduser(elt))
79 if os.path.isdir(elt):
80 configFileNames += __listDirectory(elt)
82 if checkExistence and not os.path.isfile(elt):
85 configFileNames += [elt]
87 return configFileNames, args, unexisting
90 def __validate_pair(ob):
92 if not (len(ob) == 2):
93 #print "Unexpected result:", ob
99 def __get_environment_from_batch_command(env_cmd, initial=None):
101 Take a command (either a single command or list of arguments)
102 and return the environment created after running that command.
103 Note that if the command must be a batch file or .cmd file, or the
104 changes to the environment will not be captured.
106 If initial is supplied, it is used as the initial environment passed
107 to the child process.
109 #if not isinstance(env_cmd, (list, tuple)):
110 # env_cmd = [env_cmd]
111 # construct the command that will alter the environment
112 #env_cmd = subprocess.list2cmdline(env_cmd)
113 # create a tag so we can tell in the output when the proc is done
114 tag = 'Done running command'
115 # construct a command to do accomplish this
116 cmd = '{env_cmd} && echo "{tag}"'.format(**vars())
119 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=initial, shell=True)
120 # parse the output sent to stdout
122 # consume whatever output occurs until the tag is reached
123 #consume(itertools.takewhile(lambda l: tag not in l, lines))
124 # define a way to handle each KEY=VALUE line
125 handle_line = lambda l: l.rstrip().split('=',1)
126 # parse key/values into pairs
127 #pairs = map(handle_line, lines)
131 line = lines.readline()
133 if tag in line or cpt > 1000:
136 pairs.append(line.rstrip().split('=',1))
137 # make sure the pairs are valid
138 valid_pairs = filter(__validate_pair, pairs)
139 # construct a dictionary of the pairs
140 result = dict(valid_pairs)
141 # let the process finish
145 def __subtract(ref, dic):
147 for key,val in ref.items():
148 if not dic.has_key(key):
151 # compare values types
152 if (type(dic[key]) != type(val)):
156 if isinstance(val, basestring):
157 tolist1 = dic[key].split(os.pathsep)
158 tolist2 = val.split(os.pathsep)
159 diff = list(set(tolist2)-set(tolist1))
161 result[key] = os.pathsep.join(diff)
168 def getConfigFileNames(args, checkExistence=False):
169 configOptionPrefix = "--config="
170 configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ]
171 if len(configArgs) == 0:
172 configFileNames, unexist1 = __getConfigFileNamesDefault(), []
174 # get configuration filenames
175 configFileNames, args, unexist1 = __getEnvironmentFileNames(args, configOptionPrefix, checkExistence)
177 # get extra environment
178 extraEnvFileNames, args, unexist2 = __getEnvironmentFileNames(args, "--extra_env=", checkExistence)
179 before = __get_environment_from_batch_command("env")
181 for filename in extraEnvFileNames:
182 after.update(__get_environment_from_batch_command(filename))
185 extraEnv = __subtract(after,before)
186 return configFileNames, extraEnv, args, unexist1+unexist2
189 def __getScriptPath(scriptName, searchPathList):
190 scriptName = os.path.expanduser(scriptName)
191 if os.path.isabs(scriptName):
194 if searchPathList is None or len(searchPathList) == 0:
197 for path in searchPathList:
198 fullName = os.path.join(path, scriptName)
199 if os.path.isfile(fullName) or os.path.isfile(fullName+".py"):
206 # script: the command to be run, e.g. python <script.py>
207 # args: its input parameters
208 # out: its output parameters
209 def __init__(self, script=None, args=None, out=None):
215 msg = "\n# Script: %s\n"%self.script
216 msg += " * Input: %s\n"%self.args
217 msg += " * Output: %s\n"%self.out
221 class ScriptAndArgsObjectEncoder(json.JSONEncoder):
222 def default(self, obj):
223 if isinstance(obj, ScriptAndArgs):
224 # to be easily parsed in GUI module (SalomeApp_Application)
225 # Do not export output arguments
226 return {obj.script:obj.args or []}
228 return json.JSONEncoder.default(self, obj)
231 def getShortAndExtraArgs(args=[]):
233 pos = args.index("--") # raise a ValueError if not found
234 short_args = args[:pos]
235 extra_args = args[pos:] # include "--"
241 return short_args, extra_args
244 # Return an array of ScriptAndArgs objects
245 def getScriptsAndArgs(args=[], searchPathList=None):
246 short_args, extra_args = getShortAndExtraArgs(args)
249 if searchPathList is None:
250 searchPathList = sys.path
252 # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an]
261 for i in range(len(args)):
262 elt = os.path.expanduser(args[i])
263 isDriver = (elt == "driver") # special case for YACS scheme execution
265 if elt.startswith(argsPrefix):
266 if not currentKey or callPython:
267 raise SalomeContextException("args list must follow corresponding script file in command line.")
268 elt = elt.replace(argsPrefix, '')
269 scriptArgs[len(scriptArgs)-1].args = [os.path.expanduser(x) for x in elt.split(",")]
273 elif elt.startswith(outPrefix):
274 if (not currentKey and not afterArgs) or callPython:
275 raise SalomeContextException("out list must follow both corresponding script file and its args in command line.")
276 elt = elt.replace(outPrefix, '')
277 scriptArgs[len(scriptArgs)-1].out = [os.path.expanduser(x) for x in elt.split(",")]
281 elif elt.startswith("python"):
285 if not os.path.isfile(elt) and not os.path.isfile(elt+".py"):
286 eltInSearchPath = __getScriptPath(elt, searchPathList)
287 if eltInSearchPath is None or (not os.path.isfile(eltInSearchPath) and not os.path.isfile(eltInSearchPath+".py")):
288 if elt[-3:] == ".py":
289 raise SalomeContextException("Script not found: %s"%elt)
290 scriptArgs.append(ScriptAndArgs(script=elt))
292 elt = eltInSearchPath
294 if elt[-4:] != ".hdf":
295 if elt[-3:] == ".py" or isDriver:
296 currentScript = os.path.abspath(elt)
297 elif os.path.isfile(elt+".py"):
298 currentScript = os.path.abspath(elt+".py")
300 currentScript = os.path.abspath(elt) # python script not necessary has .py extension
303 if currentScript and callPython:
304 currentKey = "@PYTHONBIN@ "+currentScript
305 scriptArgs.append(ScriptAndArgs(script=currentKey))
309 currentKey = currentScript
310 scriptArgs.append(ScriptAndArgs(script=currentKey))
312 elif not os.access(currentScript, os.X_OK):
313 currentKey = "@PYTHONBIN@ "+currentScript
314 scriptArgs.append(ScriptAndArgs(script=currentKey))
318 fn = open(currentScript)
319 for i in xrange(10): # read only 10 first lines
321 if re.search("#!.*python"):
328 if not ispython and currentScript[-3:] == ".py":
329 currentKey = "@PYTHONBIN@ "+currentScript
331 currentKey = currentScript
333 scriptArgs.append(ScriptAndArgs(script=currentKey))
334 # CLOSE elif currentScript
338 if len(extra_args) > 1: # syntax: -- program [options] [arguments]
339 command = extra_args[1]
340 command_args = extra_args[2:]
341 scriptArgs.append(ScriptAndArgs(script=command, args=command_args))
347 # Formatting scripts and args as a Bash-like command-line:
348 # script1.py [args] ; script2.py [args] ; ...
349 # scriptArgs is a list of ScriptAndArgs objects; their output parameters are omitted
350 def formatScriptsAndArgs(scriptArgs=None):
351 if scriptArgs is None:
354 for sa_obj in scriptArgs:
357 cmd = " ".join([cmd]+sa_obj.args)
361 if sys.platform == "win32":
363 command = sep.join(["%s"%x for x in commands])
367 # Ensure OMNIORB_USER_PATH is defined. This variable refers to a folder in which
368 # SALOME will write omniOrb configuration files.
369 # If OMNIORB_USER_PATH is already set, only checks write access to associated directory ;
370 # an exception is raised if check fails. It allows users for choosing a specific folder.
371 # Else the function sets OMNIORB_USER_PATH this way:
372 # - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS.
373 # The function does not check USERS folder existence or write access. This folder
374 # must exist ; this is the case if SALOME virtual application has been created using
375 # appli_gen.py script.
376 # - Else OMNIORB_USER_PATH is set to user home directory.
377 def setOmniOrbUserPath():
378 omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
380 if not os.access(omniorbUserPath, os.W_OK):
381 raise Exception("Unable to get write access to directory: %s"%omniorbUserPath)
384 homePath = os.path.realpath(os.path.expanduser('~'))
385 #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS")
386 defaultOmniorbUserPath = homePath
387 if os.getenv("APPLI"):
388 defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS")
390 os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath
394 return socket.gethostname().split('.')[0]