Salome HOME
841f62a65a366bf13cf02d9f04e712f9854b2809
[modules/kernel.git] / bin / runSalomeCommon.py
1 #!/usr/bin/env python3
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 # Lesser General Public License for more details.
17 #
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 #
22 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24
25 ## @package runSalome
26 # \brief Module that provides services to launch SALOME
27 #
28
29 import sys, os, string, glob, time, pickle, re
30 import setenv
31 from server import process_id, Server
32 import json
33 import subprocess
34 from salomeContextUtils import ScriptAndArgsObjectEncoder
35 import platform
36 import logging
37
38 ## Setting formatter in setVerbose() was commented because adding of handler
39 ## breaks using of root logger in other modules and cause many double lines in logs.
40 #FORMAT = '%(levelname)s : %(asctime)s : [%(filename)s:%(funcName)s:%(lineno)s] : %(message)s'
41 #logging.basicConfig(format=FORMAT)
42 logger = logging.getLogger()
43
44 class ColoredFormatter(logging.Formatter):
45     BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(30,38)
46     COLORS = { 'WARNING': YELLOW, 'INFO': WHITE, 'DEBUG': BLUE, 'CRITICAL': YELLOW, 'ERROR': RED }
47     def __init__(self, *args, **kwargs):
48         logging.Formatter.__init__(self, *args, **kwargs)
49     def format(self, record):
50         RESET_SEQ = "\033[0m"
51         COLOR_SEQ = "\033[1;%dm"
52         import inspect
53         frame = inspect.currentframe()
54         for i in range(8):
55             frame = frame.f_back
56         record.levelname = COLOR_SEQ % ColoredFormatter.COLORS[record.levelname] + record.levelname + RESET_SEQ
57         record.msg = "{} ( callsite is {} of file \"{}\" at line {} )".format(record.msg, frame.f_code.co_name,inspect.getsourcefile(frame),inspect.getlineno(frame) )
58         return logging.Formatter.format(self, record)
59
60 class BackTraceFormatter(logging.Formatter):
61     def __init__(self, *args, **kwargs):
62         logging.Formatter.__init__(self, *args, **kwargs)
63     def format(self, record):
64         import inspect
65         frame = inspect.currentframe()
66         # go upward of the stack to catch the effective callsite. Not very steady....
67         # should be replaced by an analysis of frame.f_code
68         for i in range(8):
69             frame = frame.f_back
70         record.msg = "{} ( callsite is {} of file \"{}\" at line {} )".format(record.msg, frame.f_code.co_name,inspect.getsourcefile(frame),inspect.getlineno(frame) )
71         return logging.Formatter.format(self, record)
72
73 def setVerbose(verbose):
74     from packaging import version
75     current_version = version.parse("{}.{}".format(sys.version_info.major,sys.version_info.minor))
76     version_ref = version.parse("3.5.0")
77     global logger
78     formatter = None
79     if current_version >= version_ref:
80         formatter = BackTraceFormatter('%(levelname)s : %(asctime)s : %(message)s ',style='%')
81     else:
82         formatter = logging.Formatter('%(levelname)s : %(asctime)s : %(message)s ',style='%')
83     formatter.default_time_format = '%H:%M:%S'
84     formatter.default_msec_format = "%s.%03d"
85     stream_handler = logging.StreamHandler()
86     stream_handler.setFormatter(formatter)
87     logger.addHandler(stream_handler)
88
89     verbose_map = { "0": logging.WARNING, "1": logging.INFO, "2": logging.DEBUG}
90     if verbose in verbose_map:
91         logger.setLevel(verbose_map[verbose])
92
93 # -----------------------------------------------------------------------------
94 #
95 # Class definitions to launch CORBA Servers
96 #
97
98 class InterpServer(Server):
99     def __init__(self,args):
100         self.args=args
101         if sys.platform == "win32":
102           self.CMD=['cmd', '/c', 'start cmd.exe', '/K', 'python']
103         elif sys.platform == "darwin":
104           env_ld_library_path=['env', 'DYLD_LIBRARY_PATH=' + os.getenv("LD_LIBRARY_PATH")]
105           self.CMD=['xterm', '-e'] + env_ld_library_path + ['python']
106         else:
107           env_ld_library_path=['env', 'LD_LIBRARY_PATH=' + os.getenv("LD_LIBRARY_PATH")]
108           self.CMD=['xterm', '-e'] + env_ld_library_path + ['python']
109
110     def run(self):
111         global process_id
112         command = self.CMD
113         print("INTERPSERVER::command = ", command)
114         import subprocess
115         pid = subprocess.Popen(command).pid
116         process_id[pid]=self.CMD
117         self.PID = pid
118
119 # ---
120
121 def get_cata_path(list_modules,modules_root_dir):
122     """Build a list of catalog paths (cata_path) to initialize the ModuleCatalog server
123     """
124     modules_cata={}
125     cata_path=[]
126
127     for module in list_modules:
128         if module in modules_root_dir:
129             module_root_dir=modules_root_dir[module]
130             module_cata=module+"Catalog.xml"
131             cata_file=os.path.join(module_root_dir, "share",setenv.salome_subdir, "resources",module.lower(), module_cata)
132
133             if os.path.exists(cata_file):
134                 cata_path.append(cata_file)
135                 modules_cata[module]=cata_file
136             else:
137                 cata_file=os.path.join(module_root_dir, "share",setenv.salome_subdir, "resources", module_cata)
138                 if os.path.exists(cata_file):
139                     cata_path.append(cata_file)
140                     modules_cata[module]=cata_file
141
142     for path in os.getenv("SALOME_CATALOGS_PATH","").split(os.pathsep):
143         if os.path.exists(path):
144             for cata_file in glob.glob(os.path.join(path,"*Catalog.xml")):
145                 module_name= os.path.basename(cata_file)[:-11]
146                 if module_name not in modules_cata:
147                     cata_path.append(cata_file)
148                     modules_cata[module_name]=cata_file
149
150     return cata_path
151
152 class CatalogServer(Server):
153     def __init__(self,args):
154         self.args=args
155         self.initArgs()
156         self.SCMD1=['SALOME_ModuleCatalog_Server']
157         if 'launcher' in self.args:
158             pos = args['launcher'].find(":")
159             if pos != -1:
160               self.SCMD1+=['-ORBInitRef']
161               machine = args['launcher'][0:pos]
162               port = args['launcher'][pos+1:]
163               self.SCMD1+=["NameService=corbaname::" + machine + ":" + port]
164         self.SCMD1+=['-common']
165         self.SCMD2=[]
166         home_dir=os.path.expanduser("~")
167         if home_dir is not None:
168             self.SCMD2=['-personal',os.path.join(home_dir,'Salome', 'resources', 'CatalogModulePersonnel.xml')]
169
170     def setpath(self,modules_list,modules_root_dir):
171         list_modules = modules_list[:]
172         list_modules.reverse()
173         if self.args["gui"] :
174             list_modules = ["KERNEL", "GUI"] + list_modules
175         else :
176             list_modules = ["KERNEL"] + list_modules
177
178         cata_path=get_cata_path(list_modules,modules_root_dir)
179
180         self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
181
182 # ---
183
184 class SalomeDSServer(Server):
185     def __init__(self,args):
186         self.args=args
187         self.initArgs()
188         self.CMD=['SALOMEDS_Server']
189         if 'launcher' in self.args:
190             pos = args['launcher'].find(":")
191             if pos != -1:
192               self.CMD+=['-ORBInitRef']
193               machine = args['launcher'][0:pos]
194               port = args['launcher'][pos+1:]
195               self.CMD+=["NameService=corbaname::" + machine + ":" + port]
196
197 # ---
198
199 class ConnectionManagerServer(Server):
200     def __init__(self,args):
201         self.args=args
202         self.initArgs()
203         self.CMD=['SALOME_ConnectionManagerServer']
204         if 'launcher' in self.args:
205             pos = args['launcher'].find(":")
206             if pos != -1:
207               self.CMD+=['-ORBInitRef']
208               machine = args['launcher'][0:pos]
209               port = args['launcher'][pos+1:]
210               self.CMD+=["NameService=corbaname::" + machine + ":" + port]
211
212
213 # ---
214
215 class RegistryServer(Server):
216     def __init__(self,args):
217         self.args=args
218         self.initArgs()
219         self.CMD=['SALOME_Registry_Server', '--salome_session','theSession']
220         if 'launcher' in self.args:
221             pos = args['launcher'].find(":")
222             if pos != -1:
223               self.CMD+=['-ORBInitRef']
224               machine = args['launcher'][0:pos]
225               port = args['launcher'][pos+1:]
226               self.CMD+=["NameService=corbaname::" + machine + ":" + port]
227
228 # ---
229
230 class ContainerCPPServer(Server):
231     def __init__(self,args,with_gui=False):
232         self.args=args
233         self.initArgs()
234         self.CMD=['SALOME_Container']
235         if 'launcher' in self.args:
236             pos = args['launcher'].find(":")
237             if pos != -1:
238               self.CMD+=['-ORBInitRef']
239               machine = args['launcher'][0:pos]
240               port = args['launcher'][pos+1:]
241               self.CMD+=["NameService=corbaname::" + machine + ":" + port]
242         self.CMD+=['FactoryServer']
243         if not with_gui and self.args["valgrind_session"]:
244             l = ["valgrind"]
245             val = os.getenv("VALGRIND_OPTIONS")
246             if val:
247                 l += val.split()
248                 pass
249             self.CMD = l + self.CMD
250             pass
251
252 # ---
253
254 class LoggerServer(Server):
255     def __init__(self,args):
256         self.args=args
257         self.initArgs()
258         from salome_utils import generateFileName, getLogDir
259         logfile = generateFileName( getLogDir(),
260                                     prefix="logger",
261                                     extension="log",
262                                     with_username=True,
263                                     with_hostname=True,
264                                     with_port=True)
265         print("===========================================================")
266         print("Logger server: put log to the file:")
267         print(logfile)
268         print("===========================================================")
269         self.CMD=['SALOME_Logger_Server', logfile]
270         pass
271     pass # end of LoggerServer class
272
273 # ---
274 import abc
275 import tempfile
276 class CommonSessionServer(Server):
277     def __init__(self,args,modules_list,modules_root_dir):
278         self.args = args.copy()
279         # Bug 11512 (Problems with runSalome --xterm on Mandrake and Debian Sarge)
280         #self.args['xterm']=0
281         #
282         self.initArgs()
283         self.SCMD1=[self.getSessionServerExe()]
284         if "SQUISH_PREFIX" in os.environ:
285             if platform.system() == "Windows" :
286                 self.SCMD1 = [os.path.join(os.getenv("SQUISH_PREFIX"), "bin", "dllpreload.exe"),os.path.join(os.getenv("SQUISH_SALOME_PATH"), "W64", "GUI", "bin", "salome", self.SCMD1[0])]
287             else :
288                 os.environ["LD_LIBRARY_PATH"] = os.environ["SQUISH_PREFIX"] + "/lib:" + os.environ["LD_LIBRARY_PATH"]
289         self.SCMD2=[]
290         if 'launcher' in self.args:
291             pos = args['launcher'].find(":")
292             if pos != -1:
293               self.SCMD1+=['-ORBInitRef']
294               machine = args['launcher'][0:pos]
295               port = args['launcher'][pos+1:]
296               self.SCMD1+=["NameService=corbaname::" + machine + ":" + port]
297         if 'registry' in self.args['embedded']:
298             self.SCMD1+=['--with','Registry',
299                          '(','--salome_session','theSession',')']
300         if 'moduleCatalog' in self.args['embedded']:
301             self.SCMD1+=['--with','ModuleCatalog','(','-common']
302             home_dir=os.path.expanduser("~")
303             if home_dir is not None:
304                 self.SCMD2+=['-personal',os.path.join(home_dir,'Salome','resources','CatalogModulePersonnel.xml')]
305             self.SCMD2+=[')']
306         if 'study' in self.args['embedded']:
307             self.SCMD2+=['--with','SALOMEDS','(',')']
308         if 'cppContainer' in self.args['embedded']:
309             self.SCMD2+=['--with','Container','(','FactoryServer',')']
310         if 'SalomeAppEngine' in self.args['embedded']:
311             self.SCMD2+=['--with','SalomeAppEngine','(',')']
312
313         if 'cppContainer' in self.args['standalone'] or 'cppContainer' in self.args['embedded']:
314             self.SCMD2+=['CPP']
315         if 'pyContainer' in self.args['standalone'] or 'pyContainer' in self.args['embedded']:
316             raise Exception('Python containers no longer supported')
317         if self.args['gui']:
318             session_gui = self.args.get('session_gui', True)
319             if not session_gui:
320                 self.SCMD2+=['--hide-desktop']
321             else:
322                 if not self.args['splash']:
323                     self.SCMD2+=['--hide-splash']
324                     pass
325                 if self.args['study_hdf'] is not None:
326                     self.SCMD2+=['--study-hdf=%s'%self.args['study_hdf']]
327                     pass
328                 pass
329                 if 'pyscript' in self.args and len(self.args['pyscript']) > 0:
330                     msg = json.dumps(self.args['pyscript'], cls=ScriptAndArgsObjectEncoder)
331                     self.SCMD2+=['--pyscript=%s'%(msg)]
332                     pass
333                 pass
334                 if self.args['gui_log_file'] is not None:
335                     guilogfile = self.args['gui_log_file']
336                     if os.path.exists(guilogfile) and os.path.isfile(guilogfile):
337                         try:
338                             os.remove(guilogfile)
339                         except:
340                             print("Error: cannot remove existing log file", guilogfile)
341                             guilogfile = None
342                     if guilogfile is not None:
343                         self.SCMD2+=['--gui-log-file=%s'%guilogfile]
344                     pass
345                 pass
346             pass
347         if self.args['noexcepthandler']:
348             self.SCMD2+=['--no-exception-handler']
349         if 'user_config' in self.args:
350             self.SCMD2+=['--resources=%s'%self.args['user_config']]
351         if 'modules' in self.args:
352             list_modules = []
353             #keep only modules with GUI
354             for m in modules_list:
355               if m not in modules_root_dir:
356                 list_modules.insert(0,m)
357               else:
358                 fr1 = os.path.join(modules_root_dir[m],"share","salome","resources",m.lower(),"SalomeApp.xml")
359                 fr2 = os.path.join(modules_root_dir[m],"share","salome","resources","SalomeApp.xml")
360                 if os.path.exists(fr1) or os.path.exists(fr2):
361                   list_modules.insert(0,m)
362             list_modules.reverse()
363             self.SCMD2+=['--modules (%s)' % ":".join(list_modules)]
364             pass
365         if 'language' in self.args:
366             self.SCMD2+=['--language=%s' % self.args['language']]
367         os_handle, iorfakens = tempfile.mkstemp()
368         self.iorfakens = iorfakens
369         os.close(os_handle)
370         self.SCMD2+=["--iorfakens={}".format(iorfakens)]
371         pass
372
373     @abc.abstractmethod
374     def getSessionServerExe(self):
375         pass
376     
377     def setpath(self,modules_list,modules_root_dir):
378         list_modules = modules_list[:]
379         list_modules.reverse()
380         if self.args["gui"] :
381             list_modules = ["KERNEL", "GUI"] + list_modules
382         else :
383             list_modules = ["KERNEL"] + list_modules
384
385         cata_path=get_cata_path(list_modules,modules_root_dir)
386
387         if ("gui" in self.args) & ('moduleCatalog' in self.args['embedded']):
388             #Use '::' instead ":" because drive path with "D:\" is invalid on windows platform
389             self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
390         else:
391             self.CMD=self.SCMD1 + self.SCMD2
392         if 'test' in self.args:
393             self.CMD+=['-test'] + self.args['test']
394         elif 'play' in self.args:
395             self.CMD+=['-play'] + self.args['play']
396
397         if self.args["gdb_session"] or self.args["ddd_session"]:
398             f = open(".gdbinit4salome", "w")
399             f.write("set args ")
400             args = " ".join(self.CMD[1:])
401             args = args.replace("(", "\(")
402             args = args.replace(")", "\)")
403             f.write(args)
404             f.write("\n")
405             f.close()
406             if self.args["ddd_session"]:
407                 self.CMD = ["ddd", "--command=.gdbinit4salome", self.CMD[0]]
408             elif self.args["gdb_session"]:
409                 self.CMD = ["xterm", "-e", "gdb", "--command=.gdbinit4salome", self.CMD[0]]
410                 pass
411             pass
412
413         if self.args["valgrind_session"]:
414             l = ["valgrind"]
415             val = os.getenv("VALGRIND_OPTIONS")
416             if val:
417                 l += val.split()
418                 pass
419             self.CMD = l + self.CMD
420             pass
421
422 class SessionServer(CommonSessionServer):
423     def __init__(self,args,modules_list,modules_root_dir):
424         super().__init__(args,modules_list,modules_root_dir)
425         import KernelBasis
426         KernelBasis.setSSLMode(False)
427     
428     def getSessionServerExe(self):
429         return "SALOME_Session_Server"
430 # ---
431
432 class LauncherServer(Server):
433     def __init__(self,args):
434         self.args=args
435         self.initArgs()
436         self.SCMD1=['SALOME_LauncherServer']
437         self.SCMD2=[]
438         if args["gui"] :
439             if 'registry' in self.args['embedded']:
440                 self.SCMD1+=['--with','Registry',
441                              '(','--salome_session','theSession',')']
442             if 'moduleCatalog' in self.args['embedded']:
443                 self.SCMD1+=['--with','ModuleCatalog','(','-common']
444                 home_dir=os.path.expanduser("~")
445                 if home_dir is not None:
446                     self.SCMD2=['-personal',os.path.join(home_dir,'Salome','resources','CatalogModulePersonnel.xml')]
447                 self.SCMD2+=[')']
448             if 'study' in self.args['embedded']:
449                 self.SCMD2+=['--with','SALOMEDS','(',')']
450             if 'cppContainer' in self.args['embedded']:
451                 self.SCMD2+=['--with','Container','(','FactoryServer',')']
452
453     def setpath(self,modules_list,modules_root_dir):
454         list_modules = modules_list[:]
455         list_modules.reverse()
456         if self.args["gui"] :
457             list_modules = ["KERNEL", "GUI"] + list_modules
458         else :
459             list_modules = ["KERNEL"] + list_modules
460
461         cata_path=get_cata_path(list_modules,modules_root_dir)
462
463         if ("gui" in self.args) & ('moduleCatalog' in self.args['embedded']):
464             #Use '::' instead ":" because drive path with "D:\" is invalid on windows platform
465             self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
466         else:
467             self.CMD=self.SCMD1 + self.SCMD2