]> SALOME platform Git repositories - modules/kernel.git/blob - bin/runSalomeSL.py
Salome HOME
Small memory leak in kernel TOOLSDS/SALOMEDS_Tool.cxx
[modules/kernel.git] / bin / runSalomeSL.py
1 #!/usr/bin/env python3
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2021  CEA/DEN, EDF R&D
4 #
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.
9 #
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.
14 #
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
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 ## @package runSalome
23 # \brief Module that provides services to launch SALOME
24 #
25
26 import sys, os, string, glob, time, pickle, re
27 import orbmodule
28 import setenv
29 from launchConfigureParser import verbose
30 from server import process_id, Server
31 import json
32 import subprocess
33 from salomeContextUtils import ScriptAndArgsObjectEncoder
34 import platform
35
36 # -----------------------------------------------------------------------------
37
38 from killSalome import killAllPorts
39
40 def killLocalPort():
41     """
42     kill servers from a previous SALOME execution, if needed,
43     on the CORBA port given in args of runSalome
44     """
45
46     from killSalomeWithPort import killMyPort
47     my_port=str(args['port'])
48     try:
49         killMyPort(my_port)
50     except:
51         print("problem in killLocalPort()")
52         pass
53     pass
54
55 def givenPortKill(port):
56     """
57     kill servers from a previous SALOME execution, if needed,
58     on the same CORBA port
59     """
60
61     from killSalomeWithPort import killMyPort
62     my_port=port
63     try:
64         killMyPort(my_port)
65     except:
66         print("problem in LocalPortKill(), killMyPort(%s)"%port)
67         pass
68     pass
69
70 def kill_salome(args):
71     """
72     Kill servers from previous SALOME executions, if needed;
73     depending on args 'killall' or 'portkill', kill all executions,
74     or only execution on the same CORBA port
75     """
76
77     if args['killall']:
78         killAllPorts()
79     elif args['portkill']:
80         givenPortKill(str(args['port']))
81
82 # -----------------------------------------------------------------------------
83 #
84 # Class definitions to launch CORBA Servers
85 #
86
87 class InterpServer(Server):
88     def __init__(self,args):
89         self.args=args
90         if sys.platform == "win32":
91           self.CMD=['cmd', '/c', 'start cmd.exe', '/K', 'python']
92         elif sys.platform == "darwin":
93           env_ld_library_path=['env', 'DYLD_LIBRARY_PATH=' + os.getenv("LD_LIBRARY_PATH")]
94           self.CMD=['xterm', '-e'] + env_ld_library_path + ['python']
95         else:
96           env_ld_library_path=['env', 'LD_LIBRARY_PATH=' + os.getenv("LD_LIBRARY_PATH")]
97           self.CMD=['xterm', '-e'] + env_ld_library_path + ['python']
98
99     def run(self):
100         global process_id
101         command = self.CMD
102         print("INTERPSERVER::command = ", command)
103         import subprocess
104         pid = subprocess.Popen(command).pid
105         process_id[pid]=self.CMD
106         self.PID = pid
107
108 # ---
109
110 def get_cata_path(list_modules,modules_root_dir):
111     """Build a list of catalog paths (cata_path) to initialize the ModuleCatalog server
112     """
113     modules_cata={}
114     cata_path=[]
115
116     for module in list_modules:
117         if module in modules_root_dir:
118             module_root_dir=modules_root_dir[module]
119             module_cata=module+"Catalog.xml"
120             cata_file=os.path.join(module_root_dir, "share",setenv.salome_subdir, "resources",module.lower(), module_cata)
121
122             if os.path.exists(cata_file):
123                 cata_path.append(cata_file)
124                 modules_cata[module]=cata_file
125             else:
126                 cata_file=os.path.join(module_root_dir, "share",setenv.salome_subdir, "resources", module_cata)
127                 if os.path.exists(cata_file):
128                     cata_path.append(cata_file)
129                     modules_cata[module]=cata_file
130
131     for path in os.getenv("SALOME_CATALOGS_PATH","").split(os.pathsep):
132         if os.path.exists(path):
133             for cata_file in glob.glob(os.path.join(path,"*Catalog.xml")):
134                 module_name= os.path.basename(cata_file)[:-11]
135                 if module_name not in modules_cata:
136                     cata_path.append(cata_file)
137                     modules_cata[module_name]=cata_file
138
139     return cata_path
140
141
142 class LoggerServer(Server):
143     def __init__(self,args):
144         self.args=args
145         self.initArgs()
146         from salome_utils import generateFileName, getLogDir
147         logfile = generateFileName( getLogDir(),
148                                     prefix="logger",
149                                     extension="log",
150                                     with_username=True,
151                                     with_hostname=True,
152                                     with_port=True)
153         print("===========================================================")
154         print("Logger server: put log to the file:")
155         print(logfile)
156         print("===========================================================")
157         self.CMD=['SALOME_Logger_Server', logfile]
158         pass
159     pass # end of LoggerServer class
160
161 # ---
162
163 class SessionServer(Server):
164     def __init__(self,args,modules_list,modules_root_dir):
165         self.args = args.copy()
166         # Bug 11512 (Problems with runSalome --xterm on Mandrake and Debian Sarge)
167         #self.args['xterm']=0
168         #
169         self.initArgs()
170         self.SCMD1=['SALOME_Session_Server_No_Server']
171         if "SQUISH_PREFIX" in os.environ:
172             if platform.system() == "Windows" :
173                 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])]
174             else :
175                 os.environ["LD_LIBRARY_PATH"] = os.environ["SQUISH_PREFIX"] + "/lib:" + os.environ["LD_LIBRARY_PATH"]
176         self.SCMD2=[]
177         if 'launcher' in self.args:
178             pos = args['launcher'].find(":")
179             if pos != -1:
180               self.SCMD1+=['-ORBInitRef']
181               machine = args['launcher'][0:pos]
182               port = args['launcher'][pos+1:]
183               self.SCMD1+=["NameService=corbaname::" + machine + ":" + port]
184         if 'registry' in self.args['embedded']:
185             self.SCMD1+=['--with','Registry',
186                          '(','--salome_session','theSession',')']
187         if 'moduleCatalog' in self.args['embedded']:
188             self.SCMD1+=['--with','ModuleCatalog','(','-common']
189             home_dir=os.path.expanduser("~")
190             #if home_dir is not None:
191             #    self.SCMD2+=['-personal',os.path.join(home_dir,'Salome','resources','CatalogModulePersonnel.xml')]
192             self.SCMD2+=[')']
193         if 'study' in self.args['embedded']:
194             self.SCMD2+=['--with','SALOMEDS','(',')']
195         if 'cppContainer' in self.args['embedded']:
196             self.SCMD2+=['--with','Container','(','FactoryServer',')']
197         if 'SalomeAppEngine' in self.args['embedded']:
198             self.SCMD2+=['--with','SalomeAppEngine','(',')']
199
200         if 'cppContainer' in self.args['standalone'] or 'cppContainer' in self.args['embedded']:
201             self.SCMD2+=['CPP']
202         if 'pyContainer' in self.args['standalone'] or 'pyContainer' in self.args['embedded']:
203             raise Exception('Python containers no longer supported')
204         if self.args['gui']:
205             session_gui = self.args.get('session_gui', True)
206             if not session_gui:
207                 self.SCMD2+=['--hide-desktop']
208             else:
209                 if not self.args['splash']:
210                     self.SCMD2+=['--hide-splash']
211                     pass
212                 if self.args['study_hdf'] is not None:
213                     self.SCMD2+=['--study-hdf=%s'%self.args['study_hdf']]
214                     pass
215                 pass
216                 if 'pyscript' in self.args and len(self.args['pyscript']) > 0:
217                     msg = json.dumps(self.args['pyscript'], cls=ScriptAndArgsObjectEncoder)
218                     self.SCMD2+=['--pyscript=%s'%(msg)]
219                     pass
220                 pass
221             pass
222         if self.args['noexcepthandler']:
223             self.SCMD2+=['--no-exception-handler']
224         if 'user_config' in self.args:
225             self.SCMD2+=['--resources=%s'%self.args['user_config']]
226         if 'modules' in self.args:
227             list_modules = []
228             #keep only modules with GUI
229             for m in modules_list:
230               if m not in modules_root_dir:
231                 list_modules.insert(0,m)
232               else:
233                 fr1 = os.path.join(modules_root_dir[m],"share","salome","resources",m.lower(),"SalomeApp.xml")
234                 fr2 = os.path.join(modules_root_dir[m],"share","salome","resources","SalomeApp.xml")
235                 if os.path.exists(fr1) or os.path.exists(fr2):
236                   list_modules.insert(0,m)
237             list_modules.reverse()
238             self.SCMD2+=['--modules (%s)' % ":".join(list_modules)]
239             pass
240         if 'language' in self.args:
241             self.SCMD2+=['--language=%s' % self.args['language']]
242         #print(self.SCMD1)
243         #print(self.SCMD2)
244         pass
245
246     def setpath(self,modules_list,modules_root_dir):
247         list_modules = modules_list[:]
248         list_modules.reverse()
249         if self.args["gui"] :
250             list_modules = ["KERNEL", "GUI"] + list_modules
251         else :
252             list_modules = ["KERNEL"] + list_modules
253
254         cata_path=get_cata_path(list_modules,modules_root_dir)
255
256         if ("gui" in self.args) & ('moduleCatalog' in self.args['embedded']):
257             #Use '::' instead ":" because drive path with "D:\" is invalid on windows platform
258             self.CMD=self.SCMD1 + ['"' + '"::"'.join(cata_path) + '"'] + self.SCMD2
259         else:
260             self.CMD=self.SCMD1 + self.SCMD2
261         if 'test' in self.args:
262             self.CMD+=['-test'] + self.args['test']
263         elif 'play' in self.args:
264             self.CMD+=['-play'] + self.args['play']
265
266         if self.args["gdb_session"] or self.args["ddd_session"]:
267             f = open(".gdbinit4salome", "w")
268             f.write("set args ")
269             args = " ".join(self.CMD[1:])
270             args = args.replace("(", "\(")
271             args = args.replace(")", "\)")
272             f.write(args)
273             f.write("\n")
274             f.close()
275             if self.args["ddd_session"]:
276                 self.CMD = ["ddd", "--command=.gdbinit4salome", self.CMD[0]]
277             elif self.args["gdb_session"]:
278                 self.CMD = ["xterm", "-e", "gdb", "--command=.gdbinit4salome", self.CMD[0]]
279                 pass
280             pass
281
282         if self.args["valgrind_session"]:
283             l = ["valgrind"]
284             val = os.getenv("VALGRIND_OPTIONS")
285             if val:
286                 l += val.split()
287                 pass
288             self.CMD = l + self.CMD
289             pass
290 #
291 # -----------------------------------------------------------------------------
292
293 def startGUI(clt):
294     """Salome Session Graphic User Interface activation"""
295     import Engines
296     import SALOME
297     import SALOMEDS
298     import SALOME_ModuleCatalog
299     import SALOME_Session_idl
300     session=clt.waitNS("/Kernel/Session",SALOME.Session)
301     session.GetInterface()
302
303 # -----------------------------------------------------------------------------
304
305 def startSalome(args, modules_list, modules_root_dir):
306     #print(400*"*")
307     #print(args)
308     """Launch all SALOME servers requested by args"""
309     init_time = os.times()
310
311     if verbose(): print("startSalome ", args)
312
313     #
314     # Set server launch command
315     #
316     if 'server_launch_mode' in args:
317         Server.set_server_launch_mode(args['server_launch_mode'])
318
319     #
320     # Wake up session option
321     #
322     if args['wake_up_session']:
323         if "OMNIORB_CONFIG" not in os.environ:
324             from salome_utils import generateFileName
325             omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
326             kwargs={}
327             if omniorbUserPath is not None:
328                 kwargs["with_username"]=True
329
330             last_running_config = generateFileName(omniorbUserPath, prefix="omniORB",
331                                                    suffix="last",
332                                                    extension="cfg",
333                                                    hidden=True,
334                                                    **kwargs)
335             os.environ['OMNIORB_CONFIG'] = last_running_config
336             pass
337         pass
338
339     #
340     # Initialisation ORB and Naming Service
341     #
342
343     addToPidict(args)
344
345     #
346     # Wake up session option
347     #
348     if args['wake_up_session']:
349         import Engines
350         import SALOME
351         import SALOMEDS
352         import SALOME_ModuleCatalog
353         import SALOME_Session_idl
354         session = clt.waitNS("/Kernel/Session",SALOME.Session)
355         status = session.GetStatSession()
356         if status.activeGUI:
357             from salome_utils import getPortNumber
358             port = getPortNumber()
359             msg  = "Warning :"
360             msg += "\n"
361             msg += "Session GUI for port number %s is already active."%(port)
362             msg += "\n"
363             msg += "If you which to wake up another session,"
364             msg += "\n"
365             msg += "please use variable OMNIORB_CONFIG"
366             msg += "\n"
367             msg += "to get the correct session object in naming service."
368             sys.stdout.write(msg+"\n")
369             sys.stdout.flush()
370             return clt
371         session.GetInterface()
372         args["session_object"] = session
373         return clt
374
375     # Launch Logger Server (optional)
376     # and wait until it is registered in naming service
377     #
378
379     if args['logger']:
380         myServer=LoggerServer(args)
381         myServer.run()
382         clt.waitLogger("Logger")
383         addToPidict(args)
384
385
386     from Utils_Identity import getShortHostName
387
388     if os.getenv("HOSTNAME") == None:
389         if os.getenv("HOST") == None:
390             os.environ["HOSTNAME"]=getShortHostName()
391         else:
392             os.environ["HOSTNAME"]=os.getenv("HOST")
393
394     theComputer = getShortHostName()
395
396     # ASV start GUI without Loader
397     #if args['gui']:
398     #    session.GetInterface()
399
400     #
401     # additional external python interpreters
402     #
403     nbaddi=0
404
405     try:
406         if 'interp' in args:
407             nbaddi = args['interp']
408     except:
409         import traceback
410         traceback.print_exc()
411         print("-------------------------------------------------------------")
412         print("-- to get an external python interpreter:runSalome --interp=1")
413         print("-------------------------------------------------------------")
414
415     if verbose(): print("additional external python interpreters: ", nbaddi)
416     if nbaddi:
417         for i in range(nbaddi):
418             print("i=",i)
419             anInterp=InterpServer(args)
420             anInterp.run()
421
422     # set PYTHONINSPECT variable (python interpreter in interactive mode)
423     if args['pinter']:
424         os.environ["PYTHONINSPECT"]="1"
425         try:
426             import readline
427         except ImportError:
428             pass
429
430 # -----------------------------------------------------------------------------
431
432 def useSalome(args, modules_list, modules_root_dir):
433     """
434     Launch all SALOME servers requested by args,
435     save list of process, give info to user,
436     show registered objects in Naming Service.
437     """
438     global process_id
439
440     clt=None
441     try:
442         startSalome(args, modules_list, modules_root_dir)
443     except:
444         import traceback
445         traceback.print_exc()
446         print()
447         print()
448         print("--- Error during Salome launch ---")
449
450     # print(process_id)
451
452     from addToKillList import addToKillList
453     from killSalomeWithPort import getPiDict
454
455     filedict = getPiDict(args['port'])
456     for pid, cmd in list(process_id.items()):
457         addToKillList(pid, cmd, args['port'])
458         pass
459         
460     import salome
461     salome.standalone()
462
463     SalomeAppSLConfig=os.getenv("SalomeAppConfig","")
464     os.putenv("SalomeAppSLConfig", SalomeAppSLConfig)
465
466
467     if args["gui"] and not args['launcher_only']:
468         mySessionServ = SessionServer(args,args['modules'],modules_root_dir)
469         mySessionServ.setpath(modules_list,modules_root_dir)
470         mySessionServ.run()
471         addToPidict(args)
472
473
474     if verbose(): print("""
475     Saving of the dictionary of Salome processes in %s
476     To kill SALOME processes from a console (kill all sessions from all ports):
477       python killSalome.py
478     To kill SALOME from the present interpreter, if it is not closed :
479       killLocalPort()      --> kill this session
480                                (use CORBA port from args of runSalome)
481       givenPortKill(port)  --> kill a specific session with given CORBA port
482       killAllPorts()       --> kill all sessions
483
484     runSalome, with --killall option, starts with killing
485     the processes resulting from the previous execution.
486     """%filedict)
487
488     #
489     #  Print Naming Service directory list
490     #
491
492     if clt != None:
493         if verbose():
494             print()
495             print(" --- registered objects tree in Naming Service ---")
496             clt.showNS()
497             pass
498
499         # run python scripts, passed as command line arguments
500         toimport = []
501         if 'gui' in args and 'session_gui' in args:
502             if not args['gui'] or not args['session_gui']:
503                 if 'study_hdf' in args:
504                     toopen = args['study_hdf']
505                     if toopen:
506                         import salome
507                         salome.salome_init(path=toopen)
508                 if 'pyscript' in args:
509                     toimport = args['pyscript']
510         from salomeContextUtils import formatScriptsAndArgs
511         command = formatScriptsAndArgs(toimport, escapeSpaces=True)
512         if command:
513             proc = subprocess.Popen(command, shell=True)
514             addToKillList(proc.pid, command, args['port'])
515             res = proc.wait()
516             if res: sys.exit(1) # if there's an error when executing script, we should explicitly exit
517
518     return clt
519
520 def execScript(script_path):
521     print('executing', script_path)
522     sys.path.insert(0, os.path.realpath(os.path.dirname(script_path)))
523     exec(compile(open(script_path).read(), script_path, 'exec'),globals())
524     del sys.path[0]
525
526 # -----------------------------------------------------------------------------
527
528 def registerEnv(args, modules_list, modules_root_dir):
529     """
530     Register args, modules_list, modules_root_dir in a file
531     for further use, when SALOME is launched embedded in an other application.
532     """
533     from salome_utils import getTmpDir
534     fileEnv = getTmpDir()
535     from salome_utils import getUserName
536     fileEnv += getUserName() + "_" + str(args['port']) \
537             + '_' + args['appname'].upper() + '_env'
538     fenv=open(fileEnv,'w')
539     pickle.dump((args, modules_list, modules_root_dir),fenv)
540     fenv.close()
541     os.environ["SALOME_LAUNCH_CONFIG"] = fileEnv
542
543 # -----------------------------------------------------------------------------
544
545 def no_main():
546     """Salome Launch, when embedded in other application"""
547     fileEnv = os.environ["SALOME_LAUNCH_CONFIG"]
548     fenv=open(fileEnv,'r')
549     args, modules_list, modules_root_dir = pickle.load(fenv)
550     fenv.close()
551     kill_salome(args)
552     from searchFreePort import searchFreePort
553     searchFreePort(args, 0)
554     clt = useSalome(args, modules_list, modules_root_dir)
555     return clt
556
557 # -----------------------------------------------------------------------------
558
559 def addToPidict(args):
560     global process_id
561     from addToKillList import addToKillList
562     for pid, cmd in list(process_id.items()):
563         addToKillList(pid, cmd, args['port'])
564
565 # -----------------------------------------------------------------------------
566
567 def main(exeName=None):
568     """Salome launch as a main application"""
569
570     from salome_utils import getHostName
571     keep_env = not os.getenv('SALOME_PLEASE_SETUP_ENVIRONMENT_AS_BEFORE')
572     args, modules_list, modules_root_dir = setenv.get_config(exeName=exeName, keepEnvironment=keep_env)
573     print("runSalome running on %s" % getHostName())
574
575     # --
576     #setenv.main()
577     setenv.set_env(args, modules_list, modules_root_dir, keepEnvironment=keep_env)
578     clt = useSalome(args, modules_list, modules_root_dir)
579     return clt,args
580
581 # -----------------------------------------------------------------------------
582
583 def foreGround(clt, args):
584     # --
585     if "session_object" not in args:
586         return
587     session = args["session_object"]
588     # --
589     # Wait until gui is arrived
590     # tmax = nbtot * dt
591     # --
592     gui_detected = False
593     dt = 0.1
594     nbtot = 100
595     nb = 0
596     session_pid = None
597     while 1:
598         try:
599             status = session.GetStatSession()
600             gui_detected = status.activeGUI
601             session_pid = session.getPID()
602         except:
603             pass
604         if gui_detected:
605             break
606         from time import sleep
607         sleep(dt)
608         nb += 1
609         if nb == nbtot:
610             break
611         pass
612     # --
613     if not gui_detected:
614         return
615     # --
616     from salome_utils import getPortNumber
617     port = getPortNumber()
618     # --
619     server = Server({})
620     if sys.platform == "win32":
621       server.CMD = [os.getenv("PYTHONBIN"), "-m", "killSalomeWithPort", "--spy", "%s"%(session_pid or os.getpid()), "%s"%(port)]
622     else:
623       server.CMD = ["killSalomeWithPort.py", "--spy", "%s"%(session_pid or os.getpid()), "%s"%(port)]
624     server.run(True)
625     # os.system("killSalomeWithPort.py --spy %s %s &"%(os.getpid(), port))
626     # --
627     dt = 1.0
628     try:
629         while 1:
630             try:
631                 status = session.GetStatSession()
632                 assert status.activeGUI
633             except:
634                 break
635             from time import sleep
636             sleep(dt)
637             pass
638         pass
639     except KeyboardInterrupt:
640         from killSalomeWithPort import killMyPort
641         killMyPort(port)
642         pass
643     return
644 #
645
646 def runSalome():
647     clt,args = main()
648     # --
649     test = args['gui'] and args['session_gui']
650     test = test or args['wake_up_session']
651     # --
652     # The next test covers the --pinter option or if var PYTHONINSPECT is set
653     # --
654     test = test and not os.environ.get('PYTHONINSPECT')
655     # --
656     # The next test covers the python -i $KERNEL_ROOT_DIR/bin/salome/runSalome.py case
657     # --
658     try:
659         from ctypes import POINTER, c_int, cast, pythonapi
660         iflag_ptr = cast(pythonapi.Py_InteractiveFlag, POINTER(c_int))
661         test = test and not iflag_ptr.contents.value
662     except:
663         pass
664     # --
665 #    test = test and os.getenv("SALOME_TEST_MODE", "0") != "1"
666     test = test and args['foreground']
667     # --
668     if test:
669         from time import sleep
670         sleep(3.0)
671         foreGround(clt, args)
672         pass
673     pass
674 #
675
676 # -----------------------------------------------------------------------------
677
678 if __name__ == "__main__":
679     runSalome()
680 #