]> SALOME platform Git repositories - modules/kernel.git/blob - bin/salomeContext.py
Salome HOME
[EDF30062] : new activate-custom-overrides option in driver
[modules/kernel.git] / bin / salomeContext.py
1 #! /usr/bin/env python3
2 # Copyright (C) 2013-2024  CEA, EDF, OPEN CASCADE
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 import os
22 import sys
23 import logging
24 import configparser
25
26 from parseConfigFile import parseConfigFile
27
28 import tempfile
29 import pickle
30 import subprocess
31 import sys
32 import platform
33
34 from salomeContextUtils import SalomeContextException
35
36 def usage():
37   msg = '''\
38 Usage: salome [command] [options] [--config=<file,folder,...>] [--with-env-modules=<env_module1,env_module2,...>]
39
40 Commands:
41 =========
42     start           Start a new SALOME instance. Start a single SALOME_Session_Server_No_Server
43                     process with environment relevant to the application and hosting all servants in it.
44     context         Initialize SALOME context. Current environment is extended.
45     shell           Initialize SALOME context, attached to the last created SALOME
46                     instance if any, and executes scripts passed as command arguments.
47                     User works in a Shell terminal. SALOME environment is set but
48                     application is not started.
49     test            Run SALOME tests.
50     info            Display some information about SALOME.
51     doc <module(s)> Show online module documentation (if available).
52                     Module names must be separated by blank characters.
53     help            Show this message.
54     remote          run command in SALOME environment from remote call, ssh or rsh.
55     withsession     Start a new SWS SALOME instance with multiple servers hosting all servants.
56     connect         In SWS context, Connect a Python console to the active SALOME instance.
57     kill <port(s)>  In SWS context, Terminate SALOME instances running on given ports for current user.
58                     Port numbers must be separated by blank characters.
59     killall         Terminate *all* SALOME running SWS instances for current user.
60                     Do not start a new one.
61
62 If no command is given, default is start.
63
64 Command options:
65 ================
66     Use salome <command> --help to show help on command. Available for the
67     following commands: start, shell, connect, test, info.
68
69 --config=<file,folder,...>
70 ==========================
71     Initialize SALOME context from a list of context files and/or a list
72     of folders containing context files. The list is comma-separated, without
73     any blank characters.
74
75 --with-env-modules=<env_module1,env_module2,...>
76 ================================================
77     Initialize SALOME context with the provided additional environment modules.
78     The list is comma-separated, without any blank characters.
79 '''
80
81   print(msg)
82 #
83
84 """
85 The SalomeContext class in an API to configure SALOME context then
86 start SALOME using a single python command.
87
88 """
89 class SalomeContext:
90   """
91   Initialize context from a list of configuration files
92   identified by their names.
93   These files should be in appropriate .cfg format.
94   """
95   def __init__(self, configFileNames=0):
96     self.getLogger().setLevel(logging.INFO)
97     #it could be None explicitly (if user use multiples setVariable...for standalone)
98     if configFileNames is None:
99        return
100     configFileNames = configFileNames or []
101     if len(configFileNames) == 0:
102       raise SalomeContextException("No configuration files given")
103
104     reserved=['PATH', 'DYLD_FALLBACK_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH', 'INCLUDE', 'LIBPATH', 'SALOME_PLUGINS_PATH', 'LIBRARY_PATH', 'QT_PLUGIN_PATH']
105     for filename in configFileNames:
106       basename, extension = os.path.splitext(filename)
107       if extension == ".cfg":
108         self.__setContextFromConfigFile(filename, reserved)
109       else:
110         self.getLogger().error("Unrecognized extension for configuration file: %s", filename)
111   #
112
113   def __loadEnvModules(self, env_modules):
114     modulecmd = os.getenv('LMOD_CMD')
115     if not modulecmd:
116       raise SalomeContextException("Module environment not present")
117       return
118     try:
119       out, err = subprocess.Popen([modulecmd, "python", "try-load"] + env_modules, stdout=subprocess.PIPE).communicate()
120       exec(out)  # define specific environment variables
121     except Exception:
122       raise SalomeContextException("Failed to load env modules: %s ..." % ' '.join(env_modules))
123       pass
124   #
125
126   def runSalome(self, args):
127     import os
128     # Run this module as a script, in order to use appropriate Python interpreter
129     # according to current path (initialized from context files).
130     env_modules_option = "--with-env-modules="
131     env_modules_l = [x for x in args if x.startswith(env_modules_option)]
132     if env_modules_l:
133       env_modules = env_modules_l[-1][len(env_modules_option):].split(',')
134       self.__loadEnvModules(env_modules)
135       args = [x for x in args if not x.startswith(env_modules_option)]
136     else:
137       env_modules = os.getenv("SALOME_ENV_MODULES", None)
138       if env_modules:
139         self.__loadEnvModules(env_modules.split(','))
140
141     absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
142     env_copy = os.environ.copy()
143     selfBytes= pickle.dumps(self, protocol=0)
144     argsBytes= pickle.dumps(args, protocol=0)
145     proc = subprocess.Popen(['python3', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), selfBytes.decode('latin1'), argsBytes.decode('latin1')], shell=False, close_fds=True, env=env_copy)
146     out, err = proc.communicate()
147     return out, err, proc.returncode
148   #
149
150   """Append value to PATH environment variable"""
151   def addToPath(self, value):
152     self.addToVariable('PATH', value)
153   #
154
155   """Append value to LD_LIBRARY_PATH environment variable"""
156   def addToLdLibraryPath(self, value):
157     if sys.platform == 'win32':
158       self.addToVariable('PATH', value)
159     elif  sys.platform == 'darwin':
160       if "LAPACK" in value:
161         self.addToVariable('DYLD_FALLBACK_LIBRARY_PATH', value)
162       else:
163         self.addToVariable('DYLD_LIBRARY_PATH', value)
164     else:
165       self.addToVariable('LD_LIBRARY_PATH', value)
166   #
167
168   """Append value to DYLD_LIBRARY_PATH environment variable"""
169   def addToDyldLibraryPath(self, value):
170     self.addToVariable('DYLD_LIBRARY_PATH', value)
171   #
172
173   """Append value to PYTHONPATH environment variable"""
174   def addToPythonPath(self, value):
175     self.addToVariable('PYTHONPATH', value)
176   #
177
178   """Set environment variable to value"""
179   def setVariable(self, name, value, overwrite=False):
180     env = os.getenv(name, '')
181     if env and not overwrite:
182       self.getLogger().error("Environment variable already existing (and not overwritten): %s=%s", name, value)
183       return
184
185     if env:
186       self.getLogger().debug("Overwriting environment variable: %s=%s", name, value)
187
188     value = os.path.expandvars(value) # expand environment variables
189     self.getLogger().debug("Set environment variable: %s=%s", name, value)
190     os.environ[name] = value
191   #
192
193   def setDefaultValue(self, name, value):
194     """ Set environment variable only if it is undefined."""
195     env = os.getenv(name, '')
196     if not env:
197       value = os.path.expandvars(value) # expand environment variables
198       self.getLogger().debug("Set environment variable: %s=%s", name, value)
199       os.environ[name] = value
200
201   """Unset environment variable"""
202   def unsetVariable(self, name):
203     if name in os.environ:
204       del os.environ[name]
205   #
206
207   """Prepend value to environment variable"""
208   def addToVariable(self, name, value, separator=os.pathsep):
209     if value == '':
210       return
211
212     value = os.path.expandvars(value) # expand environment variables
213     self.getLogger().debug("Add to %s: %s", name, value)
214     env = os.getenv(name, None)
215     if env is None:
216       os.environ[name] = value
217     else:
218       os.environ[name] = value + separator + env
219   #
220
221   """Append a variable"""
222   def appendVariable(self, name, value, separator=os.pathsep):
223     if value == '':
224       return
225
226     value = os.path.expandvars(value) # expand environment variables
227     env = os.getenv(name, None)
228     if env is None:
229       os.environ[name] = value
230     else:
231       os.environ[name] = env + separator + value
232     return
233
234   """Remove value from environment variable"""
235   def removeFromVariable(self, name, value, separator=os.pathsep):
236     if value == '':
237       return
238
239     value = os.path.expandvars(value) # expand environment variables
240     self.getLogger().debug("Remove from %s: %s", name, value)
241     env = os.getenv(name, None)
242     if env == value:
243       env = ''
244     else:
245       # env = env.removeprefix(value + separator) (Python >= 3.9)
246       str = value + separator
247       if env.startswith(str):
248         env = env[len(str):]
249       # env = env.removesuffix(separator + value) (Python >= 3.9)
250       str = separator + value
251       if env.endswith(str):
252         env = env[:-len(str)]
253       env = env.replace(separator + value + separator, ':')
254
255     os.environ[name] = env
256   #
257
258   ###################################
259   # This begins the private section #
260   ###################################
261
262   def __parseArguments(self, args):
263     if len(args) == 0 or args[0].startswith("-"):
264       return None, args
265
266     command = args[0]
267     options = args[1:]
268
269     availableCommands = {
270       'start'   : '_sessionless',
271       'withsession' : '_runAppli',
272       'context' : '_setContext',
273       'shell'   : '_runSession',
274       'remote'  : '_runRemote',
275       'connect' : '_runConsole',
276       'kill'    : '_kill',
277       'killall' : '_killAll',
278       'test'    : '_runTests',
279       'info'    : '_showInfo',
280       'doc'     : '_showDoc',
281       'help'    : '_usage',
282       'coffee'  : '_makeCoffee',
283       'car'     : '_getCar',
284       }
285
286     if command not in availableCommands:
287       command = "start"
288       options = args
289
290     return availableCommands[command], options
291   #
292
293   """
294   Run SALOME!
295   Args consist in a mandatory command followed by optional parameters.
296   See usage for details on commands.
297   """
298   def _startSalome(self, args):
299     import os
300     import sys
301     try:
302       from setenv import add_path
303       absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH')
304       path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome"))
305       add_path(path, "PYTHONPATH")
306       path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome", "appliskel"))
307       add_path(path, "PYTHONPATH")
308
309     except Exception:
310       pass
311
312     command, options = self.__parseArguments(args)
313     sys.argv = options
314
315     if command is None:
316       if args and args[0] in ["-h","--help","help"]:
317         usage()
318         return 0
319       # try to default to "start" command
320       command = "_sessionless"
321
322     try:
323       res = getattr(self, command)(options) # run appropriate method
324       return res or 0
325     except SystemExit as ex:
326       if ex.code != 0:
327         self.getLogger().error("SystemExit %s in method %s.", ex.code, command)
328       return ex.code
329     except SalomeContextException as e:
330       self.getLogger().error(e)
331       return 1
332     except Exception:
333       self.getLogger().error("Unexpected error:")
334       import traceback
335       traceback.print_exc()
336       return 1
337   #
338
339   def __setContextFromConfigFile(self, filename, reserved=None):
340     mesa_root_dir = "MESA_ROOT_DIR"
341     if reserved is None:
342       reserved = []
343     try:
344       configInfo = parseConfigFile(filename, reserved)
345       unsetVars = configInfo.unsetVariables
346       configVars = configInfo.outputVariables
347       reservedDict = configInfo.reservedValues
348       defaultValues = configInfo.defaultValues
349     except SalomeContextException as e:
350       msg = "%s"%e
351       self.getLogger().error(msg)
352       return 1
353
354     # unset variables
355     for var in unsetVars:
356       self.unsetVariable(var)
357
358     # mesa stuff
359     if "MESA_GL_VERSION_OVERRIDE" in os.environ:
360       configVarsDict = {k:v for (k,v) in configVars}
361       if mesa_root_dir in configVarsDict:
362         path_to_mesa_lib = os.path.join(configVarsDict[mesa_root_dir],"lib")
363         if os.name == "posix":
364           self.addToVariable("LD_LIBRARY_PATH",path_to_mesa_lib)
365         else:
366           self.addToVariable("PATH",path_to_mesa_lib)
367
368     # set context
369     for reserved in reservedDict:
370       a = [_f for _f in reservedDict[reserved] if _f] # remove empty elements
371       a = [ os.path.realpath(x) for x in a ]
372       reformattedVals = os.pathsep.join(a)
373       if reserved in ["INCLUDE", "LIBPATH"]:
374         self.addToVariable(reserved, reformattedVals, separator=' ')
375       else:
376         self.addToVariable(reserved, reformattedVals)
377       pass
378
379
380     for key,val in configVars:
381       self.setVariable(key, val, overwrite=True)
382       pass
383
384     for key,val in defaultValues:
385       self.setDefaultValue(key, val)
386       pass
387
388     pythonpath = os.getenv('PYTHONPATH','').split(os.pathsep)
389     pythonpath = [ os.path.realpath(x) for x in pythonpath ]
390     sys.path[:0] = pythonpath
391   #
392
393   def _runAppli(self, args=None):
394     if args is None:
395       args = []
396     # Initialize SALOME environment
397     sys.argv = ['runSalomeOld'] + args
398     import setenv
399     setenv.main(True, exeName="salome withsession")
400
401     import runSalomeOld
402     runSalomeOld.runSalome()
403     return 0
404   #
405
406   def _sessionless(self, args=None):
407     if args is None:
408       args = []
409     sys.argv = ['runSalome'] + args
410     import setenv
411     setenv.main(True, exeName="salome withsession")
412
413     import runSalome
414     runSalome.runSalome()
415     return 0
416   #
417
418   def _setContext(self, args=None):
419     salome_context_set = os.getenv("SALOME_CONTEXT_SET")
420     if salome_context_set:
421       print("***")
422       print("*** SALOME context has already been set.")
423       print("*** Enter 'exit' (only once!) to leave SALOME context.")
424       print("***")
425       return 0
426
427     os.environ["SALOME_CONTEXT_SET"] = "yes"
428     print("***")
429     print("*** SALOME context is now set.")
430     print("*** Enter 'exit' (only once!) to leave SALOME context.")
431     print("***")
432
433     if sys.platform == 'win32':
434       cmd = ['cmd.exe']
435     else:
436       cmd = ["/bin/bash"]
437     proc = subprocess.Popen(cmd, shell=False, close_fds=True)
438     proc.communicate()
439     return proc.returncode
440   #
441
442   def _runSession(self, args=None):
443     if args is None:
444       args = []
445     sys.argv = ['runSession'] + args
446     import runSession
447     params, args = runSession.configureSession(args, exe="salome shell")
448
449     sys.argv = ['runSession'] + args
450     import setenv
451     setenv.main(True)
452
453     return runSession.runSession(params, args)
454   #
455
456   def _runRemote(self, args=None):
457     if args is None:
458       args = []
459 #   complete salome environment
460     sys.argv = ['runRemote']
461     import setenv
462     setenv.main(True)
463
464     import runRemote
465     return runRemote.runRemote(args)
466   #
467
468   def _runConsole(self, args=None):
469     if args is None:
470       args = []
471     # Initialize SALOME environment
472     sys.argv = ['runConsole']
473     import setenv
474     setenv.main(True)
475
476     import runConsole
477     return runConsole.connect(args)
478   #
479
480   def _kill(self, args=None):
481     if args is None:
482       args = []
483     ports = args
484     if not ports:
485       print("Port number(s) not provided to command: salome kill <port(s)>")
486       return 1
487
488     import subprocess
489     sys.argv = ['kill']
490     import setenv
491     setenv.main(True)
492     if os.getenv("NSHOST") == "no_host":
493       os.unsetenv("NSHOST")
494     for port in ports:
495       if sys.platform == "win32":
496         proc = subprocess.Popen([os.getenv("PYTHONBIN"), "-m", "killSalomeWithPort", str(port)])
497       else:
498         proc = subprocess.Popen(["killSalomeWithPort.py", str(port)])
499       proc.communicate()
500     return 0
501   #
502
503   def _killAll(self, unused=None):
504     sys.argv = ['killAll']
505     import setenv
506     setenv.main(True)
507     if os.getenv("NSHOST") == "no_host":
508       os.unsetenv("NSHOST")
509     try:
510       import PortManager # mandatory
511       import subprocess
512       ports = PortManager.getBusyPorts()['this']
513
514       if ports:
515         for port in ports:
516           if sys.platform == "win32":
517             proc = subprocess.Popen([os.getenv("PYTHONBIN"), "-m", "killSalomeWithPort", str(port)])
518           else:
519             proc = subprocess.Popen(["killSalomeWithPort.py", str(port)])
520           proc.communicate()
521     except ImportError:
522       # :TODO: should be declared obsolete
523       from killSalome import killAllPorts
524       killAllPorts()
525       pass
526     from addToKillList import killList
527     killList()
528     return 0
529   #
530
531   def _runTests(self, args=None):
532     if args is None:
533       args = []
534     sys.argv = ['runTests']
535     import setenv
536     setenv.main(True)
537
538     import runTests
539     return runTests.runTests(args, exe="salome test")
540   #
541
542   def _showSoftwareVersions(self, softwares=None):
543     config = configparser.SafeConfigParser()
544     absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH')
545     filename = os.path.join(absoluteAppliPath, "sha1_collections.txt")
546     versions = {}
547     max_len = 0
548     with open(filename) as f:
549       for line in f:
550         try:
551           software, version, sha1 = line.split()
552           versions[software.upper()] = version
553           if len(software) > max_len:
554             max_len = len(software)
555         except Exception:
556           pass
557         pass
558       pass
559     if softwares:
560       for soft in softwares:
561         if soft.upper() in versions:
562           print(soft.upper().rjust(max_len), versions[soft.upper()])
563     else:
564       import collections
565       od = collections.OrderedDict(sorted(versions.items()))
566       for name, version in od.items():
567         print(name.rjust(max_len), versions[name])
568     pass
569
570   def _showInfo(self, args=None):
571     if args is None:
572       args = []
573
574     usage = "Usage: salome info [options]"
575     epilog  = """\n
576 Display some information about SALOME.\n
577 Available options are:
578     -p,--ports                     Show the list of busy ports (running SALOME instances).
579     -s,--softwares [software(s)]   Show the list and versions of SALOME softwares.
580                                    Software names must be separated by blank characters.
581                                    If no software is given, show version of all softwares.
582     -v,--version                   Show running SALOME version.
583     -h,--help                      Show this message.
584 """
585     if not args:
586       args = ["--version"]
587
588     if "-h" in args or "--help" in args:
589       print(usage + epilog)
590       return 0
591
592     if "-p" in args or "--ports" in args:
593       import PortManager
594       ports = PortManager.getBusyPorts()
595       this_ports = ports['this']
596       other_ports = ports['other']
597       if this_ports or other_ports:
598           print("SALOME instances are running on the following ports:")
599           if this_ports:
600               print("   This application:", this_ports)
601           else:
602               print("   No SALOME instances of this application")
603           if other_ports:
604               print("   Other applications:", other_ports)
605           else:
606               print("   No SALOME instances of other applications")
607       else:
608           print("No SALOME instances are running")
609
610     if "-s" in args or "--softwares" in args:
611       if "-s" in args:
612         index = args.index("-s")
613       else:
614         index = args.index("--softwares")
615       indexEnd=index+1
616       while indexEnd < len(args) and args[indexEnd][0] != "-":
617         indexEnd = indexEnd + 1
618       self._showSoftwareVersions(softwares=args[index+1:indexEnd])
619
620     if "-v" in args or "--version" in args:
621       print("Running with python", platform.python_version())
622       return self._sessionless(["--version"])
623
624     return 0
625   #
626
627   def _showDoc(self, args=None):
628     if args is None:
629       args = []
630
631     modules = args
632     if not modules:
633       print("Module(s) not provided to command: salome doc <module(s)>")
634       return 1
635
636     appliPath = os.getenv("ABSOLUTE_APPLI_PATH")
637     if not appliPath:
638       raise SalomeContextException("Unable to find application path. Please check that the variable ABSOLUTE_APPLI_PATH is set.")
639     baseDir = os.path.join(appliPath, "share", "doc", "salome")
640     for module in modules:
641       docfile = os.path.join(baseDir, "gui", module.upper(), "index.html")
642       if not os.path.isfile(docfile):
643         docfile = os.path.join(baseDir, "tui", module.upper(), "index.html")
644       if not os.path.isfile(docfile):
645         docfile = os.path.join(baseDir, "dev", module.upper(), "index.html")
646       if os.path.isfile(docfile):
647         out, err = subprocess.Popen(["xdg-open", docfile]).communicate()
648       else:
649         print("Online documentation is not accessible for module:", module)
650
651   def _usage(self, unused=None):
652     usage()
653   #
654
655   def _makeCoffee(self, unused=None):
656     print("                        (")
657     print("                          )     (")
658     print("                   ___...(-------)-....___")
659     print("               .-\"\"       )    (          \"\"-.")
660     print("         .-\'``\'|-._             )         _.-|")
661     print("        /  .--.|   `\"\"---...........---\"\"`   |")
662     print("       /  /    |                             |")
663     print("       |  |    |                             |")
664     print("        \\  \\   |                             |")
665     print("         `\\ `\\ |                             |")
666     print("           `\\ `|            SALOME           |")
667     print("           _/ /\\            4 EVER           /")
668     print("          (__/  \\             <3            /")
669     print("       _..---\"\"` \\                         /`\"\"---.._")
670     print("    .-\'           \\                       /          \'-.")
671     print("   :               `-.__             __.-\'              :")
672     print("   :                  ) \"\"---...---\"\" (                 :")
673     print("    \'._               `\"--...___...--\"`              _.\'")
674     print("      \\\"\"--..__                              __..--\"\"/")
675     print("       \'._     \"\"\"----.....______.....----\"\"\"     _.\'")
676     print("          `\"\"--..,,_____            _____,,..--\"\"`")
677     print("                        `\"\"\"----\"\"\"`")
678     print("")
679     print("                    SALOME is working for you; what else?")
680     print("")
681   #
682
683   def _getCar(self, unused=None):
684     print("                                              _____________")
685     print("                                  ..---:::::::-----------. ::::;;.")
686     print("                               .\'\"\"\"\"\"\"                  ;;   \\  \":.")
687     print("                            .\'\'                          ;     \\   \"\\__.")
688     print("                          .\'                            ;;      ;   \\\\\";")
689     print("                        .\'                              ;   _____;   \\\\/")
690     print("                      .\'                               :; ;\"     \\ ___:\'.")
691     print("                    .\'--...........................    : =   ____:\"    \\ \\")
692     print("               ..-\"\"                               \"\"\"\'  o\"\"\"     ;     ; :")
693     print("          .--\"\"  .----- ..----...    _.-    --.  ..-\"     ;       ;     ; ;")
694     print("       .\"\"_-     \"--\"\"-----\'\"\"    _-\"        .-\"\"         ;        ;    .-.")
695     print("    .\'  .\'   SALOME             .\"         .\"              ;       ;   /. |")
696     print("   /-./\'         4 EVER <3    .\"          /           _..  ;       ;   ;;;|")
697     print("  :  ;-.______               /       _________==.    /_  \\ ;       ;   ;;;;")
698     print("  ;  / |      \"\"\"\"\"\"\"\"\"\"\".---.\"\"\"\"\"\"\"          :    /\" \". |;       ; _; ;;;")
699     print(" /\"-/  |                /   /                  /   /     ;|;      ;-\" | ;\';")
700     print(":-  :   \"\"\"----______  /   /              ____.   .  .\"\'. ;;   .-\"..T\"   .")
701     print("\'. \"  ___            \"\":   \'\"\"\"\"\"\"\"\"\"\"\"\"\"\"    .   ; ;    ;; ;.\" .\"   \'--\"")
702     print(" \",   __ \"\"\"  \"\"---... :- - - - - - - - - \' \'  ; ;  ;    ;;\"  .\"")
703     print("  /. ;  \"\"\"---___                             ;  ; ;     ;|.\"\"")
704     print(" :  \":           \"\"\"----.    .-------.       ;   ; ;     ;:")
705     print("  \\  \'--__               \\   \\        \\     /    | ;     ;;")
706     print("   \'-..   \"\"\"\"---___      :   .______..\\ __/..-\"\"|  ;   ; ;")
707     print("       \"\"--..       \"\"\"--\"        m l s         .   \". . ;")
708     print("             \"\"------...                  ..--\"\"      \" :")
709     print("                        \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"    \\        /")
710     print("                                               \"------\"")
711     print("")
712     print("                                Drive your simulation properly with SALOME!")
713     print("")
714   #
715
716   # Add the following two methods since logger is not pickable
717   # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
718   def __getstate__(self):
719     d = dict(self.__dict__)
720     if hasattr(self, '_logger'):
721       del d['_logger']
722     return d
723   #
724   def __setstate__(self, d):
725     self.__dict__.update(d) # I *think* this is a safe way to do it
726   #
727   # Excluding self._logger from pickle operation imply using the following method to access logger
728   def getLogger(self):
729     if not hasattr(self, '_logger'):
730       self._logger = logging.getLogger(__name__)
731       #self._logger.setLevel(logging.DEBUG)
732       #self._logger.setLevel(logging.WARNING)
733       self._logger.setLevel(logging.ERROR)
734     return self._logger
735   #
736
737 if __name__ == "__main__":
738   if len(sys.argv) == 3:
739     context = pickle.loads(sys.argv[1].encode('latin1'))
740     args = pickle.loads(sys.argv[2].encode('latin1'))
741
742     status = context._startSalome(args)
743     sys.exit(status)
744   else:
745     usage()
746 #