Salome HOME
c5d44584ac4171f4f8af5360aca27dd43bc5aeda
[modules/kernel.git] / bin / runSalomeCommon.py
1 #!/usr/bin/env python3
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2023  CEA/DEN, EDF R&D, 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             pass
335         if self.args['noexcepthandler']:
336             self.SCMD2+=['--no-exception-handler']
337         if 'user_config' in self.args:
338             self.SCMD2+=['--resources=%s'%self.args['user_config']]
339         if 'modules' in self.args:
340             list_modules = []
341             #keep only modules with GUI
342             for m in modules_list:
343               if m not in modules_root_dir:
344                 list_modules.insert(0,m)
345               else:
346                 fr1 = os.path.join(modules_root_dir[m],"share","salome","resources",m.lower(),"SalomeApp.xml")
347                 fr2 = os.path.join(modules_root_dir[m],"share","salome","resources","SalomeApp.xml")
348                 if os.path.exists(fr1) or os.path.exists(fr2):
349                   list_modules.insert(0,m)
350             list_modules.reverse()
351             self.SCMD2+=['--modules (%s)' % ":".join(list_modules)]
352             pass
353         if 'language' in self.args:
354             self.SCMD2+=['--language=%s' % self.args['language']]
355         os_handle, iorfakens = tempfile.mkstemp()
356         self.iorfakens = iorfakens
357         os.close(os_handle)
358         self.SCMD2+=["--iorfakens={}".format(iorfakens)]
359         pass
360
361     @abc.abstractmethod
362     def getSessionServerExe(self):
363         pass
364     
365     def setpath(self,modules_list,modules_root_dir):
366         list_modules = modules_list[:]
367         list_modules.reverse()
368         if self.args["gui"] :
369             list_modules = ["KERNEL", "GUI"] + list_modules
370         else :
371             list_modules = ["KERNEL"] + list_modules
372
373         cata_path=get_cata_path(list_modules,modules_root_dir)
374
375         if ("gui" in self.args) & ('moduleCatalog' in self.args['embedded']):
376             #Use '::' instead ":" because drive path with "D:\" is invalid on windows platform
377             self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
378         else:
379             self.CMD=self.SCMD1 + self.SCMD2
380         if 'test' in self.args:
381             self.CMD+=['-test'] + self.args['test']
382         elif 'play' in self.args:
383             self.CMD+=['-play'] + self.args['play']
384
385         if self.args["gdb_session"] or self.args["ddd_session"]:
386             f = open(".gdbinit4salome", "w")
387             f.write("set args ")
388             args = " ".join(self.CMD[1:])
389             args = args.replace("(", "\(")
390             args = args.replace(")", "\)")
391             f.write(args)
392             f.write("\n")
393             f.close()
394             if self.args["ddd_session"]:
395                 self.CMD = ["ddd", "--command=.gdbinit4salome", self.CMD[0]]
396             elif self.args["gdb_session"]:
397                 self.CMD = ["xterm", "-e", "gdb", "--command=.gdbinit4salome", self.CMD[0]]
398                 pass
399             pass
400
401         if self.args["valgrind_session"]:
402             l = ["valgrind"]
403             val = os.getenv("VALGRIND_OPTIONS")
404             if val:
405                 l += val.split()
406                 pass
407             self.CMD = l + self.CMD
408             pass
409
410 class SessionServer(CommonSessionServer):
411     def __init__(self,args,modules_list,modules_root_dir):
412         super().__init__(args,modules_list,modules_root_dir)
413         import KernelBasis
414         KernelBasis.setSSLMode(False)
415     
416     def getSessionServerExe(self):
417         return "SALOME_Session_Server"
418 # ---
419
420 class LauncherServer(Server):
421     def __init__(self,args):
422         self.args=args
423         self.initArgs()
424         self.SCMD1=['SALOME_LauncherServer']
425         self.SCMD2=[]
426         if args["gui"] :
427             if 'registry' in self.args['embedded']:
428                 self.SCMD1+=['--with','Registry',
429                              '(','--salome_session','theSession',')']
430             if 'moduleCatalog' in self.args['embedded']:
431                 self.SCMD1+=['--with','ModuleCatalog','(','-common']
432                 home_dir=os.path.expanduser("~")
433                 if home_dir is not None:
434                     self.SCMD2=['-personal',os.path.join(home_dir,'Salome','resources','CatalogModulePersonnel.xml')]
435                 self.SCMD2+=[')']
436             if 'study' in self.args['embedded']:
437                 self.SCMD2+=['--with','SALOMEDS','(',')']
438             if 'cppContainer' in self.args['embedded']:
439                 self.SCMD2+=['--with','Container','(','FactoryServer',')']
440
441     def setpath(self,modules_list,modules_root_dir):
442         list_modules = modules_list[:]
443         list_modules.reverse()
444         if self.args["gui"] :
445             list_modules = ["KERNEL", "GUI"] + list_modules
446         else :
447             list_modules = ["KERNEL"] + list_modules
448
449         cata_path=get_cata_path(list_modules,modules_root_dir)
450
451         if ("gui" in self.args) & ('moduleCatalog' in self.args['embedded']):
452             #Use '::' instead ":" because drive path with "D:\" is invalid on windows platform
453             self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
454         else:
455             self.CMD=self.SCMD1 + self.SCMD2