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 item in set(ref).difference(set(dic)):
148 result[item] = ref[item]
152 def getConfigFileNames(args, checkExistence=False):
153 configOptionPrefix = "--config="
154 configArgs = [ str(x) for x in args if str(x).startswith(configOptionPrefix) ]
155 if len(configArgs) == 0:
156 configFileNames, unexist1 = __getConfigFileNamesDefault(), []
158 # get configuration filenames
159 configFileNames, args, unexist1 = __getEnvironmentFileNames(args, configOptionPrefix, checkExistence)
161 # get extra environment
162 extraEnvFileNames, args, unexist2 = __getEnvironmentFileNames(args, "--extra_env=", checkExistence)
163 before = __get_environment_from_batch_command("env")
165 for filename in extraEnvFileNames:
166 after.update(__get_environment_from_batch_command(filename))
169 extraEnv = __subtract(after,before)
170 return configFileNames, extraEnv, args, unexist1+unexist2
173 def __getScriptPath(scriptName, searchPathList):
174 scriptName = os.path.expanduser(scriptName)
175 if os.path.isabs(scriptName):
178 if searchPathList is None or len(searchPathList) == 0:
181 for path in searchPathList:
182 fullName = os.path.join(path, scriptName)
183 if os.path.isfile(fullName) or os.path.isfile(fullName+".py"):
190 # script: the command to be run, e.g. python <script.py>
191 # args: its input parameters
192 # out: its output parameters
193 def __init__(self, script=None, args=None, out=None):
199 msg = "\n# Script: %s\n"%self.script
200 msg += " * Input: %s\n"%self.args
201 msg += " * Output: %s\n"%self.out
205 class ScriptAndArgsObjectEncoder(json.JSONEncoder):
206 def default(self, obj):
207 if isinstance(obj, ScriptAndArgs):
208 # to be easily parsed in GUI module (SalomeApp_Application)
209 # Do not export output arguments
210 return {obj.script:obj.args or []}
212 return json.JSONEncoder.default(self, obj)
215 def getShortAndExtraArgs(args=[]):
217 pos = args.index("--") # raise a ValueError if not found
218 short_args = args[:pos]
219 extra_args = args[pos:] # include "--"
225 return short_args, extra_args
228 # Return an array of ScriptAndArgs objects
229 def getScriptsAndArgs(args=[], searchPathList=None):
230 short_args, extra_args = getShortAndExtraArgs(args)
233 if searchPathList is None:
234 searchPathList = sys.path
236 # Syntax of args: script.py [args:a1,a2=val,an] ... script.py [args:a1,a2=val,an]
245 for i in range(len(args)):
246 elt = os.path.expanduser(args[i])
247 isDriver = (elt == "driver") # special case for YACS scheme execution
249 if elt.startswith(argsPrefix):
250 if not currentKey or callPython:
251 raise SalomeContextException("args list must follow corresponding script file in command line.")
252 elt = elt.replace(argsPrefix, '')
253 scriptArgs[len(scriptArgs)-1].args = [os.path.expanduser(x) for x in elt.split(",")]
257 elif elt.startswith(outPrefix):
258 if (not currentKey and not afterArgs) or callPython:
259 raise SalomeContextException("out list must follow both corresponding script file and its args in command line.")
260 elt = elt.replace(outPrefix, '')
261 scriptArgs[len(scriptArgs)-1].out = [os.path.expanduser(x) for x in elt.split(",")]
265 elif elt.startswith("python"):
269 if not os.path.isfile(elt) and not os.path.isfile(elt+".py"):
270 eltInSearchPath = __getScriptPath(elt, searchPathList)
271 if eltInSearchPath is None or (not os.path.isfile(eltInSearchPath) and not os.path.isfile(eltInSearchPath+".py")):
272 if elt[-3:] == ".py":
273 raise SalomeContextException("Script not found: %s"%elt)
274 scriptArgs.append(ScriptAndArgs(script=elt))
276 elt = eltInSearchPath
278 if elt[-4:] != ".hdf":
279 if elt[-3:] == ".py" or isDriver:
280 currentScript = os.path.abspath(elt)
281 elif os.path.isfile(elt+".py"):
282 currentScript = os.path.abspath(elt+".py")
284 currentScript = os.path.abspath(elt) # python script not necessary has .py extension
287 if currentScript and callPython:
288 currentKey = "@PYTHONBIN@ "+currentScript
289 scriptArgs.append(ScriptAndArgs(script=currentKey))
293 currentKey = currentScript
294 scriptArgs.append(ScriptAndArgs(script=currentKey))
296 elif not os.access(currentScript, os.X_OK):
297 currentKey = "@PYTHONBIN@ "+currentScript
298 scriptArgs.append(ScriptAndArgs(script=currentKey))
302 fn = open(currentScript)
303 for i in xrange(10): # read only 10 first lines
305 if re.search("#!.*python"):
312 if not ispython and currentScript[-3:] == ".py":
313 currentKey = "@PYTHONBIN@ "+currentScript
315 currentKey = currentScript
317 scriptArgs.append(ScriptAndArgs(script=currentKey))
318 # CLOSE elif currentScript
322 if len(extra_args) > 1: # syntax: -- program [options] [arguments]
323 command = extra_args[1]
324 command_args = extra_args[2:]
325 scriptArgs.append(ScriptAndArgs(script=command, args=command_args))
331 # Formatting scripts and args as a Bash-like command-line:
332 # script1.py [args] ; script2.py [args] ; ...
333 # scriptArgs is a list of ScriptAndArgs objects; their output parameters are omitted
334 def formatScriptsAndArgs(scriptArgs=None):
335 if scriptArgs is None:
338 for sa_obj in scriptArgs:
341 cmd = " ".join([cmd]+sa_obj.args)
345 if sys.platform == "win32":
347 command = sep.join(["%s"%x for x in commands])
351 # Ensure OMNIORB_USER_PATH is defined. This variable refers to a folder in which
352 # SALOME will write omniOrb configuration files.
353 # If OMNIORB_USER_PATH is already set, only checks write access to associated directory ;
354 # an exception is raised if check fails. It allows users for choosing a specific folder.
355 # Else the function sets OMNIORB_USER_PATH this way:
356 # - If APPLI environment variable is set, OMNIORB_USER_PATH is set to ${APPLI}/USERS.
357 # The function does not check USERS folder existence or write access. This folder
358 # must exist ; this is the case if SALOME virtual application has been created using
359 # appli_gen.py script.
360 # - Else OMNIORB_USER_PATH is set to user home directory.
361 def setOmniOrbUserPath():
362 omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
364 if not os.access(omniorbUserPath, os.W_OK):
365 raise Exception("Unable to get write access to directory: %s"%omniorbUserPath)
368 homePath = os.path.realpath(os.path.expanduser('~'))
369 #defaultOmniorbUserPath = os.path.join(homePath, ".salomeConfig/USERS")
370 defaultOmniorbUserPath = homePath
371 if os.getenv("APPLI"):
372 defaultOmniorbUserPath = os.path.join(homePath, os.getenv("APPLI"), "USERS")
374 os.environ["OMNIORB_USER_PATH"] = defaultOmniorbUserPath
378 return socket.gethostname().split('.')[0]