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=None):
235 pos = args.index("--") # raise a ValueError if not found
236 short_args = args[:pos]
237 extra_args = args[pos:] # include "--"
243 return short_args, extra_args
246 # Return an array of ScriptAndArgs objects
247 def getScriptsAndArgs(args=None, searchPathList=None):
250 short_args, extra_args = getShortAndExtraArgs(args)
253 if searchPathList is None:
254 searchPathList = sys.path
256 # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an]
265 for i in range(len(args)):
266 elt = os.path.expanduser(args[i])
267 isDriver = (elt == "driver") # special case for YACS scheme execution
269 if elt.startswith(argsPrefix):
270 if not currentKey or callPython:
271 raise SalomeContextException("args list must follow corresponding script file in command line.")
272 elt = elt.replace(argsPrefix, '')
273 scriptArgs[len(scriptArgs)-1].args = [os.path.expanduser(x) for x in elt.split(",")]
277 elif elt.startswith(outPrefix):
278 if (not currentKey and not afterArgs) or callPython:
279 raise SalomeContextException("out list must follow both corresponding script file and its args in command line.")
280 elt = elt.replace(outPrefix, '')
281 scriptArgs[len(scriptArgs)-1].out = [os.path.expanduser(x) for x in elt.split(",")]
285 elif elt.startswith("python"):
289 if not os.path.isfile(elt) and not os.path.isfile(elt+".py"):
290 eltInSearchPath = __getScriptPath(elt, searchPathList)
291 if eltInSearchPath is None or (not os.path.isfile(eltInSearchPath) and not os.path.isfile(eltInSearchPath+".py")):
292 if elt[-3:] == ".py":
293 raise SalomeContextException("Script not found: %s"%elt)
294 scriptArgs.append(ScriptAndArgs(script=elt))
296 elt = eltInSearchPath
298 if elt[-4:] != ".hdf":
299 if elt[-3:] == ".py" or isDriver:
300 currentScript = os.path.abspath(elt)
301 elif os.path.isfile(elt+".py"):
302 currentScript = os.path.abspath(elt+".py")
304 currentScript = os.path.abspath(elt) # python script not necessary has .py extension
307 if currentScript and callPython:
308 currentKey = "@PYTHONBIN@ "+currentScript
309 scriptArgs.append(ScriptAndArgs(script=currentKey))
313 currentKey = currentScript
314 scriptArgs.append(ScriptAndArgs(script=currentKey))
316 elif not os.access(currentScript, os.X_OK):
317 currentKey = "@PYTHONBIN@ "+currentScript
318 scriptArgs.append(ScriptAndArgs(script=currentKey))
322 fn = open(currentScript)
323 for i in xrange(10): # read only 10 first lines
325 if re.search("#!.*python"):
332 if not ispython and currentScript[-3:] == ".py":
333 currentKey = "@PYTHONBIN@ "+currentScript
335 currentKey = currentScript
337 scriptArgs.append(ScriptAndArgs(script=currentKey))
338 # CLOSE elif currentScript
342 if len(extra_args) > 1: # syntax: -- program [options] [arguments]
343 command = extra_args[1]
344 command_args = extra_args[2:]
345 scriptArgs.append(ScriptAndArgs(script=command, args=command_args))
351 # Formatting scripts and args as a Bash-like command-line:
352 # script1.py [args] ; script2.py [args] ; ...
353 # scriptArgs is a list of ScriptAndArgs objects; their output parameters are omitted
354 def formatScriptsAndArgs(scriptArgs=None):
355 if scriptArgs is None:
358 for sa_obj in scriptArgs:
361 cmd = " ".join([cmd]+sa_obj.args)
365 if sys.platform == "win32":
367 command = sep.join(["%s"%x for x in commands])
371 # Ensure OMNIORB_USER_PATH is defined. This variable refers to a folder in which
372 # SALOME will write omniOrb configuration files.
373 # If OMNIORB_USER_PATH is already set, only checks write access to associated directory ;
374 # an exception is raised if check fails. It allows users for choosing a specific folder.
375 # Else the function sets OMNIORB_USER_PATH this way:
376 # - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS.
377 # The function does not check USERS folder existence or write access. This folder
378 # must exist ; this is the case if SALOME virtual application has been created using
379 # appli_gen.py script.
380 # - Else OMNIORB_USER_PATH is set to user home directory.
381 def setOmniOrbUserPath():
382 omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
384 if not os.access(omniorbUserPath, os.W_OK):
385 raise Exception("Unable to get write access to directory: %s"%omniorbUserPath)
388 homePath = os.path.realpath(os.path.expanduser('~'))
389 #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS")
390 defaultOmniorbUserPath = homePath
391 if os.getenv("APPLI"):
392 defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS")
394 os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath
398 return socket.gethostname().split('.')[0]