Salome HOME
remove SalomeOnDemandTK
[modules/kernel.git] / bin / runSalome.py
1 #!/usr/bin/env python3
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2022-2023  CEA, EDF, OPEN CASCADE
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 setenv
28 from server import process_id, Server
29 import json
30 import subprocess
31 from salomeContextUtils import ScriptAndArgsObjectEncoder
32 import runSalomeNoServer
33 import runSalomeCommon
34 import platform
35 from launchConfigureParser import verbosity_nam, on_demand_nam
36 import logging
37 logger = logging.getLogger()
38
39 # -----------------------------------------------------------------------------
40
41 from killSalome import killAllPorts
42
43 def kill_salome(args):
44     """
45     Kill servers from previous SALOME executions, if needed;
46     depending on args 'killall' or 'portkill', kill all executions,
47     or only execution on the same CORBA port
48     """
49
50     if args['killall']:
51         killAllPorts()
52 #
53 # -----------------------------------------------------------------------------
54
55 def startGUI(clt):
56     """Salome Session Graphic User Interface activation"""
57     import Engines
58     import SALOME
59     import SALOMEDS
60     import SALOME_ModuleCatalog
61     import SALOME_Session_idl
62     session=clt.waitNS("/Kernel/Session",SALOME.Session)
63     session.GetInterface()
64
65 # -----------------------------------------------------------------------------
66
67 def startSalome(args, modules_list, modules_root_dir):
68     """Launch all SALOME servers requested by args"""
69     init_time = os.times()
70
71     logger.debug("startSalome : {} ".format(args))
72
73     ior_fakens_filename = None
74
75     # Launch  Session Server (to show splash ASAP)
76     #
77
78     if args["gui"] and not args['launcher_only']:
79         mySessionServ = runSalomeNoServer.NoSessionServer(args,args['modules'],modules_root_dir)
80         mySessionServ.setpath(modules_list,modules_root_dir)
81         mySessionServ.run()
82         ior_fakens_filename = mySessionServ.iorfakens
83         logger.debug("Rendez-vous file for to retrieve IOR of session is \"{}\"".format(ior_fakens_filename))
84
85     end_time = os.times()
86
87     #
88     # Wait until Session Server is registered in naming service
89     #
90     logger.debug("Start SALOME, elapsed time : %5.1f seconds"% (end_time[4] - init_time[4]))
91
92     #
93     # additional external python interpreters
94     #
95     nbaddi=0
96
97     try:
98         if 'interp' in args:
99             nbaddi = args['interp']
100     except Exception:
101         import traceback
102         traceback.print_exc()
103         logger.error("-------------------------------------------------------------")
104         logger.error("-- to get an external python interpreter:runSalome --interp=1")
105         logger.error("-------------------------------------------------------------")
106
107     logger.debug("additional external python interpreters: {}".format(nbaddi))
108     if nbaddi:
109         for i in range(nbaddi):
110             anInterp=runSalomeCommon.InterpServer(args)
111             anInterp.run()
112
113     # set PYTHONINSPECT variable (python interpreter in interactive mode)
114     if args['pinter']:
115         os.environ["PYTHONINSPECT"]="1"
116         try:
117             import readline
118         except ImportError:
119             pass
120
121     return ior_fakens_filename
122
123 # -----------------------------------------------------------------------------
124
125 def useSalome(args, modules_list, modules_root_dir):
126     """
127     Launch all SALOME servers requested by args,
128     save list of process, give info to user,
129     show registered objects in Naming Service.
130     """
131     global process_id
132     ior_fakens_filename = None
133     try:
134         ior_fakens_filename = startSalome(args, modules_list, modules_root_dir)
135     except Exception:
136         import traceback
137         traceback.print_exc()
138         logger.error("--- Error during Salome launch ---")
139
140     # print(process_id)
141
142     from addToKillList import addToKillList
143     from killSalomeWithPort import getPiDict
144
145     filedict = getPiDict(args['port'])
146     for pid, cmd in list(process_id.items()):
147         addToKillList(pid, cmd, args['port'])
148         pass
149
150     logger.debug("""
151     Saving of the dictionary of Salome processes in %s
152     To kill SALOME processes from a console (kill all sessions from all ports):
153       python killSalome.py
154     To kill SALOME from the present interpreter, if it is not closed :
155       killLocalPort()      --> kill this session
156                                (use CORBA port from args of runSalome)
157       givenPortKill(port)  --> kill a specific session with given CORBA port
158       killAllPorts()       --> kill all sessions
159
160     runSalome, with --killall option, starts with killing
161     the processes resulting from the previous execution.
162     """%filedict)
163
164     return ior_fakens_filename
165
166 def execScript(script_path):
167     print('executing', script_path)
168     sys.path.insert(0, os.path.realpath(os.path.dirname(script_path)))
169     exec(compile(open(script_path).read(), script_path, 'exec'),globals())
170     del sys.path[0]
171
172 # -----------------------------------------------------------------------------
173
174 def main(exeName=None):
175     """Salome launch as a main application"""
176     keep_env = not os.getenv('SALOME_PLEASE_SETUP_ENVIRONMENT_AS_BEFORE')
177     args, modules_list, modules_root_dir = setenv.get_config(exeName=exeName, keepEnvironment=keep_env)
178     runSalomeCommon.setVerbose(args[verbosity_nam])
179
180     kill_salome(args)
181     # --
182
183     # Setup extension's env in salome on demand case
184     if args[on_demand_nam]:
185         import runSalomeOnDemand
186         runSalomeOnDemand.set_ext_env()
187         # Reset up module_list and modules_root_dir, if we dont want to define SalomeAppConfig on salome.py.
188         # We must remove the "else" on "if os.sys.platform == 'win32':" in launcheConfigureParser.py too.
189         args, _, __ = setenv.get_config(exeName=exeName, keepEnvironment=keep_env)
190
191     setenv.set_env(args, modules_list, modules_root_dir, keepEnvironment=keep_env)
192     ior_fakens_filename = useSalome(args, modules_list, modules_root_dir)
193     # Management of -t <script.py>
194     toimport = []
195     env = os.environ
196     if 'gui' in args and 'session_gui' in args:
197         if not args['gui'] or not args['session_gui']:
198             if 'study_hdf' in args:
199                 toopen = args['study_hdf']
200                 if toopen:
201                     os.environ["PATH_TO_STUDY_FILE_TO_INITIATE"] = toopen
202                     logger.debug("An input Study has been specified {} -> pass it with PATH_TO_STUDY_FILE_TO_INITIATE env var".format(toopen))
203             if 'pyscript' in args:
204                 toimport = args['pyscript']
205     from salomeContextUtils import formatScriptsAndArgs
206     from addToKillList import addToKillList
207     command = formatScriptsAndArgs(toimport, escapeSpaces=True)
208     if command:
209         logger.debug("Launching following shell command : {}".format(str(command)))
210         proc = subprocess.Popen(command, shell=True, env = env)
211         addToKillList(proc.pid, command)
212         res = proc.wait()
213         if res: sys.exit(1)
214     return args, ior_fakens_filename
215
216 # -----------------------------------------------------------------------------
217
218 def foreGround(args, ior_fakens_filename):
219     # --
220     import os
221     gui_detected = False
222     dt = 0.1
223     nbtot = 200
224     nb = 0
225     if ior_fakens_filename is None:
226         logger.warn("No file set to host IOR of the fake naming server")
227         return
228     if not os.path.exists(ior_fakens_filename):
229         logger.warn("No file {} set to host IOR of the fake naming server does not exit !")
230         return
231     import CORBA
232     #import Engines
233     import SALOME
234     from time import sleep
235     orb = CORBA.ORB_init([''], CORBA.ORB_ID)
236     ior_fakens = None
237     session = None
238     while True:
239         try:
240             ior_fakens = orb.string_to_object(open(ior_fakens_filename).read())
241             session = orb.string_to_object(ior_fakens.Resolve("/Kernel/Session").decode())
242         except Exception:
243             pass
244         if ( session is not None ) and (not CORBA.is_nil(session)):
245             try:
246                 os.remove(ior_fakens_filename)
247                 logger.debug("File {} has been removed".format(ior_fakens_filename))
248             except:
249                 pass
250             logger.debug("Session in child process has been found ! yeah ! {}".format(str(session)))
251             break
252         sleep(dt)
253         nb += 1
254         logger.debug("Unfortunately Session not found into {} : Sleep and retry. {}/{}".format(ior_fakens_filename,nb,nbtot))
255         if nb == nbtot:
256             break
257
258     if session is None:
259         logger.debug("Couldn't find /Kernel/Session in the child process. Return.")
260         return
261
262     nb = 0
263     # --
264     # Wait until gui is arrived
265     # tmax = nbtot * dt
266     # --
267     session_pid = None
268     while 1:
269         try:
270             status = session.GetStatSession()
271             gui_detected = status.activeGUI
272             session_pid = session.getPID()
273             logger.debug("Process of the session under monitoring {}".format(session_pid))
274         except Exception:
275             pass
276         if gui_detected:
277             break
278         sleep(dt)
279         nb += 1
280         if nb == nbtot:
281             break
282         pass
283     # --
284     if not gui_detected:
285         logger.debug("Couldn't find active GUI in the current session. Return.")
286         return
287     # --
288     from salome_utils import getPortNumber
289     port = getPortNumber()
290     # --
291     dt = 1.0
292     try:
293         while 1:
294             try:
295                 status = session.GetStatSession()
296                 assert status.activeGUI
297             except Exception:
298                 logger.debug("Process of the session under monitoring {} has vanished !".format(session_pid))
299                 break
300             from time import sleep
301             sleep(dt)
302             pass
303         pass
304     except KeyboardInterrupt:
305         logger.debug("Keyboard requested : killing all process attached to port {}".format(port))
306     finally:
307         from killSalomeWithPort import killProcessSSL
308         killProcessSSL(port,[session_pid])
309     return
310 #
311
312 def runSalome():
313     args, ior_fakens_filename = main()
314     # --
315     test = args['gui'] and args['session_gui']
316     test = test and not args[on_demand_nam]
317     test = test or args['wake_up_session']
318     # --
319     # The next test covers the --pinter option or if var PYTHONINSPECT is set
320     # --
321     test = test and not os.environ.get('PYTHONINSPECT')
322     # --
323     # The next test covers the python -i $KERNEL_ROOT_DIR/bin/salome/runSalome.py case
324     # --
325     try:
326         from ctypes import POINTER, c_int, cast, pythonapi
327         iflag_ptr = cast(pythonapi.Py_InteractiveFlag, POINTER(c_int))
328         test = test and not iflag_ptr.contents.value
329     except Exception:
330         pass
331     # --
332 #    test = test and os.getenv("SALOME_TEST_MODE", "0") != "1"
333     test = test and args['foreground']
334     # --
335     if test:
336         from time import sleep
337         sleep(3.0)
338         foreGround(args, ior_fakens_filename)
339         pass
340     pass
341 #
342
343 # -----------------------------------------------------------------------------
344
345 if __name__ == "__main__":
346     runSalome()
347 #