]> SALOME platform Git repositories - modules/kernel.git/blob - bin/launchConfigureParser.py
Salome HOME
Imp PAL13554 : -file option of runSalome
[modules/kernel.git] / bin / launchConfigureParser.py
1 # Copyright (C) 2005  OPEN CASCADE, CEA, EDF R&D, LEG
2 #           PRINCIPIA R&D, EADS CCR, Lip6, BV, CEDRAT
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License.
7 #
8 # This library is distributed in the hope that it will be useful
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # Lesser General Public License for more details.
12 #
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 import os, glob, string, sys, re
21 import xml.sax
22
23 # names of tags in XML configuration file
24 doc_tag = "document"
25 sec_tag = "section"
26 par_tag = "parameter"
27
28 # names of attributes in XML configuration file
29 nam_att = "name"
30 val_att = "value"
31
32 # certain values in XML configuration file ("launch" section)
33 lanch_nam      = "launch"
34 help_nam       = "help"
35 gui_nam        = "gui"
36 splash_nam     = "splash"
37 logger_nam     = "logger"
38 xterm_nam      = "xterm"
39 file_nam       = "file"
40 portkill_nam   = "portkill"
41 killall_nam    = "killall"
42 modules_nam    = "modules"
43 embedded_nam   = "embedded"
44 standalone_nam = "standalone"
45 containers_nam = "containers"
46 key_nam        = "key"
47 interp_nam     = "interp"
48 except_nam     = "noexcepthandler"
49 terminal_nam   = "terminal"
50 case_nam       = "test"
51
52 # values in XML configuration file giving specific module parameters (<module_name> section)
53 # which are stored in opts with key <module_name>_<parameter> (eg SMESH_plugins)
54 plugins_nam    = "plugins"
55
56 # values passed as arguments, NOT read from XML config file, but set from within this script
57 appname_nam    = "appname"
58 port_nam       = "port"
59 appname        = "SalomeApp"
60 script_nam     = "pyscript"
61
62 # values of boolean type (must be '0' or '1').
63 # xml_parser.boolValue() is used for correct setting
64 boolKeys = ( gui_nam, splash_nam, logger_nam, file_nam, xterm_nam, portkill_nam, killall_nam, interp_nam, except_nam )
65
66 # values of list type
67 listKeys = ( containers_nam, embedded_nam, key_nam, modules_nam, standalone_nam, plugins_nam )
68
69 ###
70 # Get the application version
71 # Uses GUI_ROOT_DIR (or KERNEL_ROOT_DIR in batch mode) +/bin/salome/VERSION file
72 ###
73 def version():
74     try:
75         filename = None
76         root_dir = os.environ.get( 'KERNEL_ROOT_DIR', '' ) # KERNEL_ROOT_DIR or "" if not found
77         if root_dir and os.path.exists( root_dir + "/bin/salome/VERSION" ):
78             filename = root_dir + "/bin/salome/VERSION"
79         root_dir = os.environ.get( 'GUI_ROOT_DIR', '' )    # GUI_ROOT_DIR "" if not found
80         if root_dir and os.path.exists( root_dir + "/bin/salome/VERSION" ):
81             filename = root_dir + "/bin/salome/VERSION"
82         if filename:
83             str = open( filename, "r" ).readline() # str = "THIS IS SALOME - SALOMEGUI VERSION: 3.0.0"
84             match = re.search( r':\s+([a-zA-Z0-9.]+)\s*$', str )
85             if match :
86                 return match.group( 1 )
87     except:
88         pass
89     return ''
90
91 ###
92 # Calculate and return configuration file unique ID
93 # For example: for SALOME version 3.1.0a1 the id is 300999701
94 ###
95 def version_id( fname ):
96     vers = fname.split(".")
97     major   = int(vers[0])
98     minor   = int(vers[1])
99     mr = re.search(r'^([0-9]+)([A-Za-z]?)([0-9]*)',vers[2])
100     release = dev = 0
101     if mr:
102         release = int(mr.group(1))
103         dev1 = dev2 = 0
104         if len(mr.group(2)): dev1 = ord(mr.group(2))
105         if len(mr.group(3)): dev2 = int(mr.group(3))
106         dev = dev1 * 100 + dev2
107     else:
108         return None
109     ver = major
110     ver = ver * 100 + minor
111     ver = ver * 100 + release
112     ver = ver * 10000
113     if dev > 0: ver = ver - 10000 + dev
114     return ver
115
116 ###
117 # Get user configuration file name
118 ###
119 def userFile():
120     v = version()
121     if not v:
122         return ""        # not unknown version
123     filename = "%s/.%src.%s" % (os.environ['HOME'], appname, v)
124     if os.path.exists(filename):
125         return filename  # user preferences file for the current version exists
126     # initial id
127     id0 = version_id( v )
128     # get all existing user preferences files
129     files = glob.glob( os.environ['HOME'] + "/." + appname + "rc.*" )
130     f2v = {}
131     for file in files:
132         match = re.search( r'\.%src\.([a-zA-Z0-9.]+)$'%appname, file )
133         if match: f2v[file] = match.group(1)
134     last_file = ""
135     last_version = 0
136     for file in f2v:
137         ver = version_id( f2v[file] )
138         if ver and abs(last_version-id0) > abs(ver-id0):
139             last_version = ver
140             last_file = file
141     return last_file
142
143 # -----------------------------------------------------------------------------
144
145 ###
146 # XML reader for launch configuration file usage
147 ###
148
149 section_to_skip = ""
150
151 class xml_parser:
152     def __init__(self, fileName, _opts ):
153         print "Configure parser: processing %s ..." % fileName
154         self.space = []
155         self.opts = _opts
156         self.section = section_to_skip
157         parser = xml.sax.make_parser()
158         parser.setContentHandler(self)
159         parser.parse(fileName)
160         pass
161
162     def boolValue( self, str ):
163         if str in ("yes", "y", "1"):
164             return 1
165         elif str in ("no", "n", "0"):
166             return 0
167         else:
168             return str
169         pass
170
171     def startElement(self, name, attrs):
172         self.space.append(name)
173         self.current = None
174
175         # if we are analyzing "section" element and its "name" attribute is
176         # either "launch" or module name -- set section_name
177         if self.space == [doc_tag, sec_tag] and nam_att in attrs.getNames():
178             section_name = attrs.getValue( nam_att )
179             if section_name == lanch_nam:
180                 self.section = section_name # launch section
181             elif self.opts.has_key( modules_nam ) and \
182                  section_name in self.opts[ modules_nam ]:
183                 self.section = section_name # <module> section
184             else:
185                 self.section = section_to_skip # any other section
186             pass
187
188         # if we are analyzing "parameter" elements - children of either
189         # "section launch" or "section "<module>"" element, then store them
190         # in self.opts assiciative array (key = [<module>_ + ] value of "name" attribute)
191         elif self.section != section_to_skip           and \
192              self.space == [doc_tag, sec_tag, par_tag] and \
193              nam_att in attrs.getNames()               and \
194              val_att in attrs.getNames():
195             nam = attrs.getValue( nam_att )
196             val = attrs.getValue( val_att )
197             if self.section == lanch_nam: # key for launch section
198                 key = nam
199             else:                         # key for <module> section
200                 key = self.section + "_" + nam
201             if nam in boolKeys:
202                 self.opts[key] = self.boolValue( val )  # assign boolean value: 0 or 1
203             elif nam in listKeys:
204                 self.opts[key] = val.split( ',' )       # assign list value: []
205             else:
206                 self.opts[key] = val;
207             pass
208         pass
209
210     def endElement(self, name):
211         p = self.space.pop()
212         self.current = None
213         if self.section != section_to_skip and name == sec_tag:
214             self.section = section_to_skip
215         pass
216
217     def characters(self, content):
218         pass
219
220     def processingInstruction(self, target, data):
221         pass
222
223     def setDocumentLocator(self, locator):
224         pass
225
226     def startDocument(self):
227         self.read = None
228         pass
229
230     def endDocument(self):
231         self.read = None
232         pass
233
234 # -----------------------------------------------------------------------------
235
236 ###
237 # Command line options parser
238 ###
239 def options_parser(line):
240   source = line
241   list = []
242   for delimiter in [" ", ",", "="]:
243     for o in source:
244       list += string.split(o, delimiter)
245       pass
246     source = list
247     list = []
248     pass
249
250   result = {}
251   i = 0
252   while i < len(source):
253     if source[i][0] != '-':
254       key = None
255     elif source[i][1] == '-':
256       key = source[i][2:]
257     else:
258       key = source[i][1:]
259       pass
260
261     if key is None and not result:
262         raise Exception()
263     result[key] = []
264     if key:
265       i += 1
266       pass
267     while i < len(source) and source[i][0] != '-':
268       result[key].append(source[i])
269       i += 1
270       pass
271     pass
272   return result
273
274 # -----------------------------------------------------------------------------
275
276 ###
277 # Get the environment
278 ###
279
280 # this attribute is obsolete
281 args = []
282 def get_env():
283     ###
284     # Collect launch configuration files:
285     # - The environment variable "<appname>Config" (SalomeAppConfig) which can
286     #   define a list of directories (separated by ':' or ';' symbol) is checked
287     # - If the environment variable "<appname>Config" is not set, only
288     #   ${GUI_ROOT_DIR}/share/salome/resources/gui is inspected
289     # - ${GUI_ROOT_DIR}/share/salome/resources/gui directory is always inspected
290     #   so it is not necessary to put it in the "<appname>Config" variable
291     # - The directories which are inspected are checked for files "<appname>.xml"
292     #  (SalomeApp.xml) which define SALOME configuration
293     # - These directories are analyzed beginning from the last one in the list,
294     #   so the first directory listed in "<appname>Config" environment variable 
295     #   has higher priority: it means that if some configuration options
296     #   is found in the next analyzed cofiguration file - it will be replaced
297     # - The last configuration file which is parsed is user configuration file
298     #   situated in the home directory: "~/.<appname>rc[.<version>]" (~/SalomeApprc.3.2.0)
299     #   (if it exists)
300     # - Command line options have the highest priority and replace options
301     #   specified in configuration file(s)
302     ###
303
304     global args
305     config_var = appname+'Config'
306
307     # set resources variable SaloemAppConfig if it is not set yet 
308     dirs = []
309     if os.getenv(config_var):
310         dirs += re.split('[;|:]', os.getenv(config_var))
311     if os.getenv("GUI_ROOT_DIR") and os.path.isdir( os.getenv("GUI_ROOT_DIR") + "/share/salome/resources/gui" ):
312         dirs += [os.getenv("GUI_ROOT_DIR") + "/share/salome/resources/gui"]
313     os.environ[config_var] = ":".join(dirs)
314
315     dirs.reverse() # reverse order, like in "path" variable - FILO-style processing
316
317     _opts = {} # associative array of options to be filled
318
319     # parse SalomeApp.xml files in directories specified by SalomeAppConfig env variable
320     for dir in dirs:
321         filename = dir+'/'+appname+'.xml'
322         if not os.path.exists(filename):
323             print "Configure parser: Warning : could not find configuration file %s" % filename
324         else:
325             try:
326                 p = xml_parser(filename, _opts)
327                 _opts = p.opts
328             except:
329                 print "Configure parser: Error : can not read configuration file %s" % filename
330             pass
331
332     # parse .SalomeApprc.<version> file in user's home directory if it exists
333     # if user file for the current version is not found the nearest to it is used
334     filename = userFile()
335     if not filename or not os.path.exists(filename):
336         print "Configure parser: Warning : could not find user configuration file"
337     else:
338         try:
339             p = xml_parser(filename, _opts)
340             _opts = p.opts
341         except:
342             print 'Configure parser: Error : can not read user configuration file'
343
344     args = _opts
345
346     # set default values for options which are NOT set in config files
347     for aKey in listKeys:
348         if not args.has_key( aKey ):
349             args[aKey]=[]
350
351     for aKey in boolKeys:
352         if not args.has_key( aKey ):
353             args[aKey]=0
354
355     if args[file_nam]:
356         afile=args[file_nam]
357         args[file_nam]=[afile]
358
359     args[appname_nam] = appname
360
361     # get the port number
362     my_port = 2809
363     try:
364       file = open(os.environ["OMNIORB_CONFIG"], "r")
365       s = file.read()
366       while len(s):
367         l = string.split(s, ":")
368         if string.split(l[0], " ")[0] == "ORBInitRef" or string.split(l[0], " ")[0] == "InitRef" :
369           my_port = int(l[len(l)-1])
370           pass
371         s = file.read()
372         pass
373     except:
374       pass
375
376     args[port_nam] = my_port
377
378     # read command-line options
379     # each option given in command line overrides the option from xml config file
380     cmd_opts = {}
381     try:
382         cmd_opts = options_parser(sys.argv[1:])
383         kernel_root_dir=os.environ["KERNEL_ROOT_DIR"]
384     except:
385         cmd_opts["h"] = 1
386         pass
387
388     # check if all command line options are correct
389     short_opts = ("h","g","l","f","x","m","e","s","c","p","k","t","i","r","z")
390     long_opts = (help_nam,gui_nam,logger_nam,file_nam,xterm_nam,modules_nam,
391                  embedded_nam,standalone_nam,containers_nam,portkill_nam,
392                  killall_nam,terminal_nam,interp_nam,except_nam,splash_nam,
393                  case_nam)
394     opterror=0
395     for opt in cmd_opts:
396         if opt not in short_opts and opt not in long_opts:
397             print "Configure parser: Error : command line error : -%s" % opt
398             opterror=1
399
400     if opterror == 1:
401         cmd_opts["h"] = 1
402
403     if cmd_opts.has_key("h") or cmd_opts.has_key(help_nam):
404         print """
405         USAGE: runSalome.py [options]
406
407         Command line options:
408
409         --gui             (-g)                 Launch in GUI mode [default].
410         --terminal        (-t)                 Launching without GUI (in the terminal mode).
411         --terminal=<python_script>[,...]       Launching without GUI (in the terminal mode) and 
412                (-t=<python_script>[,...])      additionally import python script(s).
413         --logger          (-l)                 Redirect messages to the CORBA collector.
414         --file=<file>     (-f=<file>)          Redirect messages to the log file.
415         --xterm           (-x)                 Launch each SALOME server in own xterm console.
416         --modules=<module1>,<module2>,...      SALOME module list (where <module1>, <module2> 
417               (-m=<module1>,<module2>,...)     are the names of SALOME modules which should be
418                                                available in the SALOME session).
419         --embedded=<server1>,<server2>,...     CORBA servers to be launched in the Session
420                (-e=<server1>,<server2>,...)    embedded mode.
421                                                Valid values for <serverN>: registry, study,
422                                                moduleCatalog, cppContainer
423                                                [default: all mentioned].
424         --standalone=<server1>,<server2>,...   CORBA servers to be launched in the standalone
425                  (-s=<server1>,<server2>,...)  mode (as separate processes).
426                                                Valid values for <serverN>: registry, study,
427                                                moduleCatalog, cppContainer, pyContainer,
428                                                supervContainer
429                                                [default: pyContainer,supervContainer].
430         --containers=<container1>,...          [obsolete] SALOME containers to be launched.
431                  (-c=<container1>,...)         Valid values: cpp, python, superv
432                                                [default: use --embedded and --standalone
433                                                parameters].
434         --portkill        (-p)                 Kill SALOME with the current port.
435         --killall         (-k)                 Kill all running SALOME sessions.
436         --interp=<N>      (-i=<N>)             The number of additional xterm sessions to open.
437                                                In each xterm session SALOME environment is set
438                                                properly.
439         --splash          (-z)                 Display splash screen.
440         --noexcepthandler (-r)                 Disable centralized exception handling
441                                                mechanism.
442         --test=<hdf_file_andor_python_scripts> HDF file to be opened on GUI starting and/or
443                                                Python script(s) to be imported in the GUI
444                                                study. The files can appear in arbitrary order.
445                                                If the HDF file is given it is opened, otherwise
446                                                the new empty study is created.
447                                                Python scripts are imported in the order of
448                                                their appearance.
449                                                This option is avaiable only in GUI mode,
450                                                for batch mode use --terminal(-t) option.
451         --help            (-h)                 Print this help info
452
453         For each SALOME module, the environment variable <moduleN>_ROOT_DIR must be set.
454         KERNEL_ROOT_DIR is mandatory.
455         """
456         sys.exit(1)
457         pass
458
459     # apply command-line options to the arguments
460     BATCHMODE_FORCED = False
461     args[script_nam] = []
462     for opt in cmd_opts:
463         if   opt in [ 'g', gui_nam ] :
464             if not BATCHMODE_FORCED: args[gui_nam] = 1
465         elif opt in [ 't', terminal_nam ] :
466             args[gui_nam] = 0
467             args[script_nam] = cmd_opts[opt]
468             BATCHMODE_FORCED = True
469         elif opt in [ 'z', splash_nam ] :
470             args[splash_nam] = 1
471         elif opt in [ 'r', except_nam ] :
472             args[except_nam] = 1
473         elif opt in [ 'l', logger_nam ] :
474             args[logger_nam] = 1
475         elif opt in [ 'f', file_nam ] :
476             args[file_nam] = cmd_opts[opt]
477         elif opt in [ 'x', xterm_nam ] :
478             args[xterm_nam] = 1
479         elif opt in [ 'i', interp_nam ] :
480             args[interp_nam] = cmd_opts[opt]
481         elif opt in [ 'm', modules_nam ] :
482             args[modules_nam] = cmd_opts[opt]
483         elif opt in [ 'e', embedded_nam ] :
484             args[embedded_nam] = cmd_opts[opt]
485         elif opt in [ 's', standalone_nam ] :
486             args[standalone_nam] = cmd_opts[opt]
487         elif opt in [ 'c', containers_nam ] :
488             args[containers_nam] = cmd_opts[opt]
489         elif opt in [ 'p', portkill_nam ] :
490             args[portkill_nam] = 1
491         elif opt in [ 'k', killall_nam ] :
492             args[killall_nam] = 1
493         elif opt in [ case_nam ] :
494            args[case_nam] = cmd_opts[opt]
495         pass
496
497     # if --modules (-m) command line option is not given
498     # try SALOME_MODULES environment variable
499     if not cmd_opts.has_key( "m" ) and \
500        not cmd_opts.has_key( modules_nam ) and \
501            os.getenv( "SALOME_MODULES" ):
502         args[modules_nam] = re.split( "[:;,]", os.getenv( "SALOME_MODULES" ) )
503         pass
504
505     # disable signals handling
506     if args[except_nam] == 1:
507         os.environ["NOT_INTERCEPT_SIGNALS"] = "1"
508         pass
509
510     # now modify SalomeAppConfig environment variable
511     # to take into account the SALOME modules
512     dirs = re.split('[;|:]', os.environ[config_var] )
513
514     for m in args[modules_nam]:
515         if m not in ["KERNEL", "GUI", ""] and os.getenv("%s_ROOT_DIR"%m):
516             d1 = os.getenv("%s_ROOT_DIR"%m) + "/share/salome/resources/" + m.lower()
517             d2 = os.getenv("%s_ROOT_DIR"%m) + "/share/salome/resources"
518             if os.path.exists( "%s/%s.xml"%(d1, appname) ):
519                 dirs.append( d1 )
520             elif os.path.exists( "%s/%s.xml"%(d2, appname) ):
521                 dirs.append( d2 )
522     os.environ[config_var] = ":".join(dirs)
523
524     # return arguments
525     return args