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