Salome HOME
Use psutil package for cross-platform management of processes occ/psutil
authorViktor UZLOV <vuzlov@debian10-01.nnov.opencascade.com>
Tue, 27 Oct 2020 09:21:59 +0000 (12:21 +0300)
committervsr <vsr@opencascade.com>
Fri, 5 Mar 2021 09:29:49 +0000 (12:29 +0300)
bin/PortManager.py
bin/killSalome.py
bin/killSalomeWithPort.py
bin/salome_utils.py
bin/server.py
src/NamingService/SALOME_NamingServicePy.py

index aace9e17bcd9e8aac5353abb572d4aa35bd750a4..0b05bb13405d70f26ae5d18dc09885d00d89bd7c 100644 (file)
@@ -23,6 +23,9 @@
 #
 import os
 import sys
+import psutil
+
+from socket import AF_INET, SOCK_STREAM
 
 try:
   import cPickle as pickle #@UnusedImport
@@ -103,55 +106,10 @@ def __isPortUsed(port, config):
 #
 
 def __isNetworkConnectionActiveOnPort(port):
-  # :NOTE: Under windows:
-  #        netstat options -l and -t are unavailable
-  #        grep command is unavailable
-  if sys.platform == "win32":
-    cmd = ['netstat','-a','-n','-p','tcp']
-  else:
-    cmd = ['netstat','-ant']
-    pass
-
-  err = None
-  try:
-    from subprocess import Popen, PIPE, STDOUT
-    p = Popen(cmd, stdout=PIPE, stderr=STDOUT)
-    out, err = p.communicate()
-  except:
-    print("Error when trying to access active network connections.")
-    if err: print(err)
-    print("... Presumably this package is not installed...Please install netstat if available for your distribution.")
-    print("... Trying socket based approach")
-    try:
-      import socket
-      sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-      result = sock.connect_ex(("127.0.0.1", port))
-      if result == 0:
-        print("Port %r:      Closed" % (port))
-        sock.close()
-        return True
-      else:
-        sock.close()
-        return False
-    except:
-      import traceback
-      traceback.print_exc()
-      return False
-
-  from io import StringIO
-  buf = StringIO(out.decode('utf-8', 'ignore'))
-  ports = buf.readlines()
-  # search for TCP - LISTEN connections
-  import re
-  regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE );
-  for item in ports:
-    try:
-      p = int(regObj.match(item).group(1))
-      if p == port: return True
-    except:
-      pass
-  return False
-#
+  # psutil realization
+  return port in [c.laddr.port for c in psutil.net_connections(kind='inet') if \
+      (c.family, c.type, c.status) == (AF_INET, SOCK_STREAM, "LISTEN")]
+  #
 
 def getPort(preferredPort=None):
   logger.debug("GET PORT")
index d7b8c392eaf975767e73af7294a858aa47414203..6b87bb7310208ef37321f7576378bdedaaa817da 100755 (executable)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-## \file killSalome.py
-#  Stop all %SALOME servers from all sessions by killing them
-#
+## @file killSalome.py
+#  @brief Forcibly stop all running %SALOME sessions.
+
+"""
+Forcibly stop all running SALOME sessions.
+
+To stop all SALOME sessions, do the following:
+
+* in shell:
+
+    $ killSalome.py
 
-import os, sys, re, signal
+* in Python script:
 
-from killSalomeWithPort import killMyPort, getPiDict, checkUnkilledProcess
-#from salome_utils import getHostName, getShortHostName
-from salome_utils import getUserName
+    from killSalome import killAllPorts
+    killAllPorts()
+"""
+
+# pragma pylint: disable=invalid-name
+
+import os
+import os.path as osp
+import re
+import sys
+from contextlib import suppress
+from glob import glob
+
+from killSalomeWithPort import getPiDict, killMyPort, killUnkilledProcesses
 
 def killAllPorts():
     """
-    Kill all SALOME sessions belonging to the user.
+    Stop all running SALOME sessions owned by the current user.
     """
-    user = getUserName()
-    #hostname  = getHostName()
-    #shostname = getShortHostName()
-    # new-style dot-prefixed pidict file
-    #fpidict   = getPiDict('(\d*)',hidden=True)
-    #problem with WIN32 path slashes
-    fpidict   = getPiDict('#####',hidden=True)
-    dirpidict = os.path.dirname(fpidict)
-    fpidict   = os.path.basename(fpidict)
-    #if hostname in fpidict:
-    #    fpidict = fpidict.replace(hostname, shostname+".*")
-    fpidict   = fpidict.replace('#####', '(\d*)')
-    fnamere   = re.compile("^%s" % fpidict)
-    try:
-        for f in os.listdir(dirpidict):
-            mo = fnamere.match(f)
-            try:
-                killMyPort(mo.group(1))
-            except:
-                pass
-            pass
-        pass
-    except:
-        pass
-    # provide compatibility with old-style pidict file (not dot-prefixed)
-    #fpidict   = getPiDict('(\d*)',hidden=False)
-    fpidict   = getPiDict('#####',hidden=False)
-    dirpidict = os.path.dirname(fpidict)
-    fpidict   = os.path.basename(fpidict)
-    #if hostname in fpidict:
-    #    fpidict = fpidict.replace(hostname, shostname+".*")
-    fpidict = fpidict.replace('#####', '(\d*)')
-    fnamere   = re.compile("^%s$" % fpidict)
-    try:
-        for f in os.listdir(dirpidict):
-            mo = fnamere.match(f)
-            try:
-                killMyPort(mo.group(1))
-            except:
-                pass
-            pass
-        pass
-    except:
-        pass
-    # kill other processes
-    for pid in checkUnkilledProcess():
-        try:
-            os.kill(pid, signal.SIGKILL)
-        except:
-            pass
-        pass
-    if sys.platform != 'win32':
-        # delete uri files needed by ompi-server
-        cmd = "rm -f " + os.path.expanduser("~") + "/.urifile_*"
-        os.system(cmd)
-    pass
-
-if __name__ == "__main__":
+    # detect ports used by SALOME session and kill processes
+    for hidden in (True, False):
+        pidict_t = getPiDict(port='#####', hidden=hidden)
+        dir_pidict_t = osp.dirname(pidict_t)
+        fn_pidict_t = osp.basename(pidict_t).replace('#####', r'(\d*)')
+        fn_rex = re.compile('^{}'.format(fn_pidict_t))
+        with suppress(IOError):
+            for fname in os.listdir(dir_pidict_t):
+                m_res = fn_rex.match(fname)
+                if m_res:
+                    killMyPort(m_res.group(1))
+
+    # kill possibly unkilled processes
+    killUnkilledProcesses()
+
+    # other clean-up actions
+    # - delete uri files needed by ompi-server
+    for path in glob(osp.join(osp.expanduser('~'), '.urifile_*')):
+        with suppress(IOError):
+            os.remove(path)
+
+def main():
+    """
+    Main function
+    """
+    from argparse import ArgumentParser
+    parser = ArgumentParser(description='Forcibly stop all running SALOME sessions')
+    parser.parse_args()
+
     try:
         from salomeContextUtils import setOmniOrbUserPath
         setOmniOrbUserPath()
-    except Exception as e:
-        print(e)
+    except Exception as exc: # pragma pylint: disable=broad-except
+        print(exc)
         sys.exit(1)
+
     killAllPorts()
-    pass
+
+if __name__ == '__main__':
+    main()
index 26b959f30701d7b19d6c943b0d6c04680e461c8f..bb9ac64b82ea0de989734a3786c68439a26aa68a 100755 (executable)
 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-## \file killSalomeWithPort.py
-#  Stop all %SALOME servers from given sessions by killing them
+## @file killSalomeWithPort.py
+#  @brief Forcibly stop %SALOME processes from given session(s).
 #
-#  The sessions are indicated by their ports on the command line as in :
-#  \code
+#  The sessions are indicated by their ports on the command line as in below example:
+#  @code
 #  killSalomeWithPort.py 2811 2815
-#  \endcode
-#
+#  @endcode
+
+"""
+Forcibly stop given SALOME session(s).
+
+To stop one or more SALOME sessions, specify network ports they are bound to,
+for example:
+
+* in shell
+
+    $ killSalomeWithPort.py 2811 2815
+
+* in Python script:
 
-import re, os, sys, pickle, signal, glob
-import subprocess
-import shlex
-from salome_utils import verbose
+    from killSalomeWithPort import killMyPort
+    killMyPort(2811, 2815)
 
+"""
 
-def getPiDict(port,appname='salome',full=True,hidden=True,hostname=None):
+# pragma pylint: disable=invalid-name
+
+import itertools
+import os
+import os.path as osp
+import pickle
+import re
+import shutil
+import sys
+from contextlib import suppress
+from glob import glob
+from threading import Thread
+from time import sleep
+
+import psutil
+
+from salome_utils import (generateFileName, getHostName, getLogDir, getShortHostName,
+                          getUserName, killOmniNames, killPid, verbose)
+
+def getPiDict(port, appname='salome', full=True, hidden=True, hostname=None):
     """
-    Get file with list of SALOME processes.
+    Get path to the file that stores the list of SALOME processes.
+
     This file is located in the user's home directory
     and named .<user>_<host>_<port>_SALOME_pidict
     where
-    <user> is user name
-    <host> is host name
-    <port> is port number
-
-    Parameters:
-    - port    : port number
-    - appname : application name (default is 'SALOME')
-    - full    : if True, full path to the file is returned, otherwise only file name is returned
-    - hidden  : if True, file name is prefixed with . (dot) symbol; this internal parameter is used
-    to support compatibility with older versions of SALOME
+
+    - <user> is user name
+    - <host> is host name
+    - <port> is port number
+
+    :param port     : port number
+    :param appname  : application name (default: 'salome')
+    :param full     : if True, full path to the file is returned,
+                      otherwise only file name is returned
+    :param hidden   : if True, file name is prefixed with . (dot) symbol;
+                      this internal parameter is only used to support
+                      compatibility with older versions of SALOME
+    :param hostname : host name (if not given, it is auto-detected)
+    :return pidict file's name or path
     """
-    # bug fix: ensure port is an integer
-    # Note: this function is also called with port='#####' !!!
-    try:
+    # ensure port is an integer
+    # warning: this function is also called with port='#####'!!!
+    with suppress(ValueError):
         port = int(port)
-    except:
-        pass
-
-    from salome_utils import generateFileName, getLogDir
-    dir = ""
-    if not hostname:
-        hostname = os.getenv("NSHOST")
-        if hostname: hostname = hostname.split(".")[0]
-        pass
-    if full:
-        # full path to the pidict file is requested
-        if hidden:
-            # new-style dot-prefixed pidict files
-            # are in the system-dependant temporary directory
-            dir = getLogDir()
-        else:
-            # old-style non-dot-prefixed pidict files
-            # are in the user's home directory
-            dir = os.path.expanduser("~")
-            pass
-        pass
-
-    return generateFileName(dir,
-                            suffix="pidict",
+
+    # hostname (if not specified via parameter)
+    with suppress(AttributeError):
+        hostname = hostname or os.getenv('NSHOST').split('.')[0]
+
+    # directory to store pidict file (if `full` is True)
+    # old style: pidict files aren't dot-prefixed, stored in the user's home directory
+    # new style: pidict files are dot-prefixed, stored in the system-dependant temporary directory
+    pidict_dir = getLogDir() if hidden else osp.expanduser('~')
+
+    return generateFileName(pidict_dir if full else '',
+                            suffix='pidict',
                             hidden=hidden,
                             with_username=True,
-                            with_hostname=hostname or True,
+                            with_hostname=(hostname or True),
                             with_port=port,
                             with_app=appname.upper())
 
 def appliCleanOmniOrbConfig(port):
     """
-    Remove omniorb config files related to the port in SALOME application:
+    Remove omniorb config files related to given `port` in SALOME application:
     - ${OMNIORB_USER_PATH}/.omniORB_${USER}_${HOSTNAME}_${NSPORT}.cfg
     - ${OMNIORB_USER_PATH}/.omniORB_${USER}_last.cfg
     the last is removed only if the link points to the first file.
+    :param port : port number
     """
+    omniorb_user_path = os.getenv('OMNIORB_USER_PATH')
+    if not omniorb_user_path:
+        # outside application context
+        return
+
     if verbose():
-        print("clean OmniOrb config for port %s"%port)
+        print("Cleaning OmniOrb config for port {}".format(port))
 
-    from salome_utils import generateFileName, getUserName
-    omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
-    if omniorbUserPath is None:
-        #Run outside application context
-        pass
-    else:
-        omniorb_config      = generateFileName(omniorbUserPath, prefix="omniORB",
-                                               extension="cfg",
-                                               hidden=True,
-                                               with_username=True,
-                                               with_hostname=True,
-                                               with_port=port)
-        last_running_config = generateFileName(omniorbUserPath, prefix="omniORB",
-                                               with_username=True,
-                                               suffix="last",
-                                               extension="cfg",
-                                               hidden=True)
-        if os.access(last_running_config,os.F_OK):
-            if not sys.platform == 'win32':
-                pointedPath = os.readlink(last_running_config)
-                if pointedPath[0] != '/':
-                    pointedPath=os.path.join(os.path.dirname(last_running_config), pointedPath)
-                    pass
-                if pointedPath == omniorb_config:
-                    os.unlink(last_running_config)
-                    pass
-                pass
-            else:
-                os.remove(last_running_config)
-                pass
-            pass
-
-        if os.access(omniorb_config,os.F_OK):
-            os.remove(omniorb_config)
-            pass
-
-        if os.path.lexists(last_running_config):return
-
-        #try to relink last.cfg to an existing config file if any
-        files = glob.glob(os.path.join(omniorbUserPath,".omniORB_"+getUserName()+"_*.cfg"))
-        current_config=None
-        current=0
-        for f in files:
-          stat=os.stat(f)
-          if stat.st_atime > current:
-            current=stat.st_atime
-            current_config=f
-        if current_config:
-          if sys.platform == "win32":
-            import shutil
-            shutil.copyfile(os.path.normpath(current_config), last_running_config)
-            pass
-          else:
-            os.symlink(os.path.normpath(current_config), last_running_config)
-            pass
-          pass
-        pass
-    pass
-
-########## kills all salome processes with the given port ##########
+    omniorb_config = generateFileName(omniorb_user_path,
+                                      prefix='omniORB',
+                                      extension='cfg',
+                                      hidden=True,
+                                      with_username=True,
+                                      with_hostname=True,
+                                      with_port=port)
+    last_running_config = generateFileName(omniorb_user_path,
+                                           prefix='omniORB',
+                                           suffix='last',
+                                           extension='cfg',
+                                           hidden=True,
+                                           with_username=True)
+
+    if os.access(last_running_config, os.F_OK):
+        if sys.platform == 'win32' or osp.samefile(last_running_config, omniorb_config):
+            os.remove(last_running_config)
+
+    if os.access(omniorb_config, os.F_OK):
+        os.remove(omniorb_config)
+
+    if osp.lexists(last_running_config):
+        return
+
+    # try to relink last.cfg to an existing config file if any
+    cfg_files = [(cfg_file, os.stat(cfg_file)) for cfg_file in \
+                     glob(osp.join(omniorb_user_path,
+                                   '.omniORB_{}_*.cfg'.format(getUserName())))]
+    next_config = next((i[0] for i in sorted(cfg_files, key=lambda i: i[1])), None)
+    if next_config:
+        if sys.platform == 'win32':
+            shutil.copyfile(osp.normpath(next_config), last_running_config)
+        else:
+            os.symlink(osp.normpath(next_config), last_running_config)
 
 def shutdownMyPort(port, cleanup=True):
     """
     Shutdown SALOME session running on the specified port.
-    Parameters:
-    - port - port number
+    :param port    : port number
+    :param cleanup : perform additional cleanup actions (kill omniNames, etc.)
     """
-    if not port: return
-    # bug fix: ensure port is an integer
-    port = int(port)
+    if not port:
+        return
 
-    try:
+    # ensure port is an integer
+    with suppress(ValueError):
+        port = int(port)
+
+    # release port
+    with suppress(ImportError):
+        # DO NOT REMOVE NEXT LINE: it tests PortManager availability!
         from PortManager import releasePort
         releasePort(port)
-    except ImportError:
-        pass
 
-    from salome_utils import generateFileName
-
-    # set OMNIORB_CONFIG variable to the proper file
-    omniorbUserPath = os.getenv("OMNIORB_USER_PATH")
+    # set OMNIORB_CONFIG variable to the proper file (if not set yet)
+    omniorb_user_path = os.getenv('OMNIORB_USER_PATH')
     kwargs = {}
-    if omniorbUserPath is not None:
-        kwargs["with_username"]=True
+    if omniorb_user_path is not None:
+        kwargs['with_username'] = True
     else:
-        omniorbUserPath = os.path.realpath(os.path.expanduser('~'))
-    omniorb_config = generateFileName(omniorbUserPath, prefix="omniORB",
-                                      extension="cfg",
+        omniorb_user_path = osp.realpath(osp.expanduser('~'))
+    omniorb_config = generateFileName(omniorb_user_path,
+                                      prefix='omniORB',
+                                      extension='cfg',
                                       hidden=True,
                                       with_hostname=True,
                                       with_port=port,
@@ -194,281 +198,285 @@ def shutdownMyPort(port, cleanup=True):
     os.environ['NSPORT'] = str(port)
 
     # give the chance to the servers to shutdown properly
-    try:
-        import time
+    with suppress(Exception):
         from omniORB import CORBA
-
         from LifeCycleCORBA import LifeCycleCORBA
-        # shutdown all
         orb = CORBA.ORB_init([''], CORBA.ORB_ID)
-        lcc = LifeCycleCORBA(orb) # see (1)
-        print("Terminating SALOME on port %s..."%(port))
+        lcc = LifeCycleCORBA(orb) # see (1) below
+        # shutdown all
+        if verbose():
+            print("Terminating SALOME session on port {}...".format(port))
         lcc.shutdownServers()
         # give some time to shutdown to complete
-        time.sleep(1)
+        sleep(1)
         # shutdown omniNames
         if cleanup:
-          from salome_utils import killOmniNames
-          killOmniNames(port)
-          filedict=getPiDict(port)
-          __killMyPort(port, filedict)
-          from PortManager import releasePort
-          releasePort(port)
-          time.sleep(1)
-          pass
-        pass
-    except:
-        pass
-    sys.exit(0) # see (1)
-    pass
+            killOmniNames(port)
+            __killMyPort(port, getPiDict(port))
+            # DO NOT REMOVE NEXT LINE: it tests PortManager availability!
+            from PortManager import releasePort
+            releasePort(port)
+            sleep(1)
+    sys.exit(0) # see (1) below
+
 # (1) If --shutdown-servers option is set to 1, session close procedure is
 # called twice: first explicitly by salome command, second by automatic
 # atexit to handle Ctrl-C. During second call, LCC does not exist anymore and
 # a RuntimeError is raised; we explicitly exit this function with code 0 to
 # prevent parent thread from crashing.
 
+def __killProcesses(processes):
+    '''
+    Terminate and kill all given processes (inernal).
+    :param processes : list of processes, each one is an instance of psutil.Process
+    '''
+    # terminate processes
+    for process in processes:
+        process.terminate()
+    # wait a little, then check for alive
+    _, alive = psutil.wait_procs(processes, timeout=5)
+    # finally kill alive
+    for process in alive:
+        process.kill()
+
+def __killPids(pids):
+    """
+    Kill processes with given `pids`.
+    :param pids : processes IDs
+    """
+    processes = []
+    for pid in pids:
+        try:
+            processes.append(psutil.Process(pid))
+        except psutil.NoSuchProcess:
+            if verbose():
+                print("  ------------------ Process {} not found".format(pid))
+    __killProcesses(processes)
+
 def __killMyPort(port, filedict):
-    # bug fix: ensure port is an integer
-    if port:
+    """
+    Kill processes for given port (internal).
+    :param port     : port number
+    :param filedict : pidict file
+    """
+    # ensure port is an integer
+    with suppress(ValueError):
         port = int(port)
 
-    try:
-        with open(filedict, 'rb') as fpid:
-            process_ids=pickle.load(fpid)
-            for process_id in process_ids:
-                for pid, cmd in list(process_id.items()):
-                    pid = int(pid)
-                    if verbose(): print("stop process %s : %s"% (pid, cmd[0]))
-                    try:
-                        from salome_utils import killpid
-                        killpid(pid)
-                    except:
-                        if verbose(): print("  ------------------ process %s : %s not found"% (pid, cmd[0]))
-                        if pid in checkUnkilledProcess():
-                            try:
-                                killpid(pid)
-                            except:
-                                pass
-                        pass
-                    pass # for pid ...
-                pass # for process_id ...
-            # end with
-    except:
-        print("Cannot find or open SALOME PIDs file for port", port)
-        pass
+    # read pids from pidict file
+    with suppress(Exception), open(filedict, 'rb') as fpid:
+        pids_lists = pickle.load(fpid)
+        # note: pids_list is a list of tuples!
+        for pids in pids_lists:
+            __killPids(pids)
+
+    # finally remove pidict file
     os.remove(filedict)
-    pass
-#
 
 def __guessPiDictFilename(port):
-    from salome_utils import getShortHostName, getHostName
-    filedicts = [
-        # new-style dot-prefixed pidict file
-        getPiDict(port, hidden=True),
-        # provide compatibility with old-style pidict file (not dot-prefixed)
-        getPiDict(port, hidden=False),
-        # provide compatibility with old-style pidict file (short hostname)
-        getPiDict(port, hidden=True, hostname=getShortHostName()),
-        # provide compatibility with old-style pidict file (not dot-prefixed, short hostname
-        getPiDict(port, hidden=False, hostname=getShortHostName()),
-        # provide compatibility with old-style pidict file (long hostname)
-        getPiDict(port, hidden=True, hostname=getHostName()),
-        # provide compatibility with old-style pidict file (not dot-prefixed, long hostname)
-        getPiDict(port, hidden=False, hostname=getHostName())
-        ]
-
-    log_msg = ""
-    for filedict in filedicts:
-        log_msg += "Trying %s..."%filedict
-        if os.path.exists(filedict):
-            log_msg += "   ... OK\n"
-            break
-        else:
-            log_msg += "   ... not found\n"
-
-    if verbose():
-        print(log_msg)
+    """
+    Guess and return pidict file for given `port` (internal).
+    :param port : port number
+    :return pidict file's path
+    """
+    # Check all possible versions of pidict file
+    # new-style - dot-prefixed pidict file: hidden is True, auto hostname
+    # old-style - not dot-prefixed pidict file: hidden is False, auto hostname
+    # old-style - dot-prefixed pidict file: hidden is True, short hostname
+    # old-style - not dot-prefixed pidict file: hidden is False, short hostname
+    # old-style - dot-prefixed pidict file: hidden is True, long hostname
+    # old-style - not dot-prefixed pidict file: hidden is False, long hostname
+    for hostname, hidden in itertools.product((None, getShortHostName(), getHostName()),
+                                              (True, False)):
+        filedict = getPiDict(port, hidden=hidden, hostname=hostname)
+        if not osp.exists(filedict):
+            if verbose():
+                print('Trying {}... not found'.format(filedict))
+            continue
+        if verbose():
+            print('Trying {}... OK'.format(filedict))
+        return filedict
 
-    return filedict
-#
+    return None
 
-def killMyPort(port):
+def killMyPort(*ports):
     """
     Kill SALOME session running on the specified port.
-    Parameters:
-    - port - port number
+    :param ports : port numbers
     """
-    # bug fix: ensure port is an integer
-    if port:
-        port = int(port)
-
-    try:
-        import PortManager # do not remove! Test for PortManager availability!
-        filedict = getPiDict(port)
-        if not os.path.isfile(filedict): # removed by previous call, see (1)
-            if verbose():
-                print("SALOME on port %s: already removed by previous call"%port)
-            # Remove port from PortManager config file
-            try:
-                from PortManager import releasePort
+    for port in ports:
+        # ensure port is an integer
+        with suppress(ValueError):
+            port = int(port)
+
+        with suppress(Exception):
+            # DO NOT REMOVE NEXT LINE: it tests PortManager availability!
+            from PortManager import releasePort
+            # get pidict file
+            filedict = getPiDict(port)
+            if not osp.isfile(filedict): # removed by previous call, see (1) above
                 if verbose():
-                    print("Removing port from PortManager configuration file")
-                releasePort(port)
-            except ImportError:
-                pass
-            return
-    except:
-        pass
-
-    # try to shutdown session normally
-    import threading, time
-    threading.Thread(target=shutdownMyPort, args=(port,True)).start()
-    time.sleep(3) # wait a little, then kill processes (should be done if shutdown procedure hangs up)
-
-    try:
-        import PortManager # do not remove! Test for PortManager availability!
-        filedict = getPiDict(port)
-        #filedict = __guessPiDictFilename(port)
-        import glob
-        all_files = glob.glob("%s*"%filedict)
-        for f in all_files:
-            __killMyPort(port, f)
-    except ImportError:
-        filedict = __guessPiDictFilename(port)
-        __killMyPort(port, filedict)
-    #
+                    print("SALOME session on port {} is already stopped".format(port))
+                # remove port from PortManager config file
+                with suppress(ImportError):
+                    if verbose():
+                        print("Removing port from PortManager configuration file")
+                    releasePort(port)
+                return
+
+        # try to shutdown session normally
+        Thread(target=shutdownMyPort, args=(port, True)).start()
+        # wait a little...
+        sleep(3)
+        # ... then kill processes (should be done if shutdown procedure hangs up)
+        try:
+            # DO NOT REMOVE NEXT LINE: it tests PortManager availability!
+            import PortManager # pragma pylint: disable=unused-import
+            for file_path in glob('{}*'.format(getPiDict(port))):
+                __killMyPort(port, file_path)
+        except ImportError:
+            __killMyPort(port, __guessPiDictFilename(port))
 
-    appliCleanOmniOrbConfig(port)
-    pass
+        # clear-up omniOrb config files
+        appliCleanOmniOrbConfig(port)
 
 def cleanApplication(port):
     """
     Clean application running on the specified port.
-    Parameters:
-    - port - port number
+    :param port : port number
     """
-    # bug fix: ensure port is an integer
-    if port:
+    # ensure port is an integer
+    with suppress(ValueError):
         port = int(port)
 
-    try:
-        filedict=getPiDict(port)
+    # remove pidict file
+    with suppress(Exception):
+        filedict = getPiDict(port)
         os.remove(filedict)
-    except:
-      #import traceback
-      #traceback.print_exc()
-      pass
 
+    # clear-up omniOrb config files
     appliCleanOmniOrbConfig(port)
-    pass
 
 def killMyPortSpy(pid, port):
-    dt = 1.0
-    while 1:
-        from salome_utils import killpid
-        ret = killpid(pid, 0)
+    """
+    Start daemon process which watches for given process and kills session when process exits.
+    :param pid  : process ID
+    :param port : port number (to kill)
+    """
+    while True:
+        ret = killPid(int(pid), 0) # 0 is used to check process existence without actual killing it
         if ret == 0:
-            break
+            break # process does not exist: exit loop
         elif ret < 0:
-            return
-        from time import sleep
-        sleep(dt)
-        pass
-    filedict = getPiDict(port, hidden=True)
-    if not os.path.exists(filedict):
+            return # something got wrong
+        sleep(1)
+
+    filedict = getPiDict(port)
+    if not osp.exists(filedict):
         return
+
+    # check Session server
     try:
         import omniORB
         orb = omniORB.CORBA.ORB_init(sys.argv, omniORB.CORBA.ORB_ID)
         import SALOME_NamingServicePy
-        ns = SALOME_NamingServicePy.SALOME_NamingServicePy_i(orb, 3, True)
-        import SALOME #@UnresolvedImport @UnusedImport
-        session = ns.Resolve("/Kernel/Session")
+        naming_service = SALOME_NamingServicePy.SALOME_NamingServicePy_i(orb, 3, True)
+        import SALOME #@UnresolvedImport @UnusedImport # pragma pylint: disable=unused-import
+        session = naming_service.Resolve('/Kernel/Session')
         assert session
-    except:
+    except: # pragma pylint: disable=bare-except
         killMyPort(port)
         return
     try:
         status = session.GetStatSession()
-    except:
-        # -- session is in naming service but has crash
+    except: # pragma pylint: disable=bare-except
+        # -- session is in naming service but likely crashed
         status = None
-        pass
-    if status:
-        if not status.activeGUI:
-            return
-        pass
+    if status is not None and not status.activeGUI:
+        return
     killMyPort(port)
-    return
-
-def checkUnkilledProcess():
-    #check processes in system after kill
-    from salome_utils import getUserName
-    user = getUserName()
-    processes = dict()
-
-    if sys.platform != 'win32':
-
-        def _getDictfromOutput(_output, _dic, _cond = None):
-            _pids = dict(zip(list(map(int, _output[::2])), _output[1::2]))
-            if _cond:
-                _pids = {pid:cmd for pid,cmd in _pids.items() if re.match(_cond, cmd)}
-            _dic.update(_pids)
-
-        # 1. SALOME servers plus omniNames
-        cmd = 'ps --noheading -U {user} -o pid,cmd | awk \'{{printf("%s %s\\n", $1, $2)}}\''.format(user=user)
-        _getDictfromOutput(subprocess.getoutput(cmd).split(), processes, '^(SALOME_|omniNames)')
-        # 2. ghs3d
-        cmd = 'ps -fea | grep \'{user}\' | grep \'ghs3d\' | grep \'f /tmp/GHS3D_\' | grep -v \'grep\' | awk \'{{printf("%s %s\\n", $2, $8)}}\''.format(user=user)
-        _getDictfromOutput(subprocess.getoutput(cmd).split(), processes)
-        # 3. ompi-server
-        cmd = 'ps -fea | grep \'{user}\' | grep \'ompi-server\' | grep -v \'grep\' | awk \'{{printf("%s %s\\n", $2, $8)}}\''.format(user=user)
-        _getDictfromOutput(subprocess.getoutput(cmd).split(), processes)
-    else:
-        cmd = 'tasklist /fo csv | findstr /i "SALOME_ omniNames"'
-        prc = subprocess.getoutput(cmd)
-        try:
-            prc = prc.split()
-            prc = [prc[i].split(',') for i in range(0, len(prc)) if i % 2 == 0]
-            prc = dict([(int(prc[j][1].replace('"', '')), prc[j][0].replace('"', '')) for j in range(0, len(prc))])
-            processes.update(prc)
-        except:
-            pass
+
+def __checkUnkilledProcesses():
+    '''
+    Check all unkilled SALOME processes (internal).
+    :return: list of unkilled processes
+    '''
+    def _checkUserName(_process):
+        # The following is a workaround for Windows on which
+        # psutil.Process().username() returns 'usergroup' + 'username'
+        return getUserName() == _process.username()
+
+    def _getDictfromOutput(_processes, _wildcard=None):
+        for _process in psutil.process_iter(['name', 'username']):
+            with suppress(psutil.AccessDenied):
+                if _checkUserName(_process) and re.match(_wildcard, _process.info['name']):
+                    _processes.append(_process)
+
+    processes = list()
+    _getDictfromOutput(processes, '(SALOME_*)')
+    _getDictfromOutput(processes, '(omniNames)')
+    _getDictfromOutput(processes, '(ghs3d)')
+    _getDictfromOutput(processes, '(ompi-server)')
+
     return processes
 
-if __name__ == "__main__":
-    if len(sys.argv) < 2:
-        print("Usage: ")
-        print("  %s <port>" % os.path.basename(sys.argv[0]))
-        print()
-        print("Kills SALOME session running on specified <port>.")
+def killUnkilledProcesses():
+    """
+    Kill processes which could remain even after shutdowning SALOME sessions.
+    """
+    __killProcesses(__checkUnkilledProcesses())
+
+def main():
+    '''
+    Main function
+    '''
+    from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
+    formatter = lambda prog: ArgumentDefaultsHelpFormatter(prog, max_help_position=50, width=120)
+    parser = ArgumentParser(description='Forcibly stop given SALOME session(s)',
+                            formatter_class=formatter)
+    parser.add_argument('ports',
+                        help='ports to kill',
+                        nargs='*', type=int)
+    group = parser.add_mutually_exclusive_group()
+    group.add_argument('-s', '--spy',
+                       help='start daemon to watch PID and then kill given PORT',
+                       nargs=2, type=int, metavar=('PID', 'PORT'))
+    group.add_argument('-l', '--list',
+                       help='list unkilled SALOME processes',
+                       action='store_true')
+    args = parser.parse_args()
+
+    if args.ports and (args.spy or args.list):
+        print("{}: error: argument ports cannot be used with -s/--spy or -l/--list"
+              .format(parser.prog), file=sys.stderr)
         sys.exit(1)
-        pass
-    if sys.argv[1] == "--spy":
-        if len(sys.argv) > 3:
-            pid = sys.argv[2]
-            port = sys.argv[3]
-            killMyPortSpy(pid, port)
-            pass
+
+    if args.spy:
+        killMyPortSpy(*args.spy)
         sys.exit(0)
-        pass
-    elif sys.argv[1] == "--find":
-        processes = checkUnkilledProcess()
+
+    if args.list:
+        processes = __checkUnkilledProcesses()
         if processes:
             print("Unkilled processes: ")
-            print(" --------------------")
-            print(" PID   : Process name")
-            print(" --------------------")
-            for pair in processes.items():
-                print('%6d : %s' % pair)
+            print("---------------------")
+            print("   PID : Process name")
+            print("--------------------")
+            for process in processes:
+                print("{0:6} : {1}".format(process.pid, process.name()))
+        else:
+            print("No SALOME related processed found")
         sys.exit(0)
+
     try:
         from salomeContextUtils import setOmniOrbUserPath #@UnresolvedImport
         setOmniOrbUserPath()
-    except Exception as e:
-        print(e)
+    except Exception as exc: # pragma pylint: disable=broad-except
+        if verbose():
+            print(exc)
         sys.exit(1)
-    for port in sys.argv[1:]:
-        killMyPort(port)
-        pass
-    pass
+
+    killMyPort(*args.ports)
+
+if __name__ == '__main__':
+    main()
index ba151eef89e4bdbc3eac7636439d2334a928c7a2..3a5ef383acf2b6d8e32197bcb2eb86fdc58aed15 100644 (file)
-#  -*- coding: iso-8859-1 -*-\r
-# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE\r
-#\r
-# This library is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 2.1 of the License, or (at your option) any later version.\r
-#\r
-# This library is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with this library; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\r
-#\r
-# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com\r
-#\r
-\r
-# ---\r
-# File   : salome_utils.py\r
-# Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)\r
-# ---\r
-\r
-## @package salome_utils\r
-# \brief Set of utility functions used by SALOME python scripts.\r
-\r
-#\r
-# Exported functions\r
-#\r
-\r
-__all__ = [\r
-    'getORBcfgInfo',\r
-    'getHostFromORBcfg',\r
-    'getPortFromORBcfg',\r
-    'getUserName',\r
-    'getHostName',\r
-    'getShortHostName',\r
-    'getAppName',\r
-    'getPortNumber',\r
-    'getLogDir',\r
-    'getTmpDir',\r
-    'getHomeDir',\r
-    'generateFileName',\r
-    'makeTmpDir',\r
-    'uniteFiles',\r
-    ]\r
-\r
-# ---\r
-\r
-def _try_bool( arg ):\r
-    """\r
-    Check if specified parameter represents boolean value and returns its value.\r
-    String values like 'True', 'TRUE', 'YES', 'Yes', 'y', 'NO', 'false', 'n', etc\r
-    are supported.\r
-    If <arg> does not represent a boolean, an exception is raised.\r
-    """\r
-    if isinstance(arg, bool)  :\r
-        return arg\r
-    elif isinstance(arg, (str, bytes)):\r
-        v = str( arg ).lower()\r
-        if   v in [ "yes", "y", "true"  ]: return True\r
-        elif v in [ "no",  "n", "false" ]: return False\r
-        pass\r
-    raise Exception("Not boolean value")\r
-\r
-# ---\r
-\r
-def getORBcfgInfo():\r
-    """\r
-    Get omniORB current configuration.\r
-    Returns a list of three values: [ orb_version, host_name, port_number ].\r
-\r
-    The information is retrieved from the omniORB configuration file defined\r
-    by the OMNIORB_CONFIG environment variable.\r
-    If omniORB configuration file can not be accessed, a list of three empty\r
-    strings is returned.\r
-    """\r
-    import os, re\r
-    ret = [ "", "", "" ]\r
-    try:\r
-        f = open( os.getenv( "OMNIORB_CONFIG" ) )\r
-        lines = f.readlines()\r
-        f.close()\r
-        regvar = re.compile( "(ORB)?InitRef.*corbaname::(.*):(\d+)\s*$" )\r
-        for l in lines:\r
-            try:\r
-                m = regvar.match( l )\r
-                if m:\r
-                    if m.group(1) is None:\r
-                        ret[0] = "4"\r
-                    else:\r
-                        ret[0] = "3"\r
-                        pass\r
-                    ret[1] = m.group(2)\r
-                    ret[2] = m.group(3)\r
-                    break\r
-                pass\r
-            except:\r
-                pass\r
-            pass\r
-        pass\r
-    except:\r
-        pass\r
-    return ret\r
-\r
-# ---\r
-\r
-def getHostFromORBcfg():\r
-    """\r
-    Get current omniORB host.\r
-    """\r
-    return getORBcfgInfo()[1]\r
-# ---\r
-\r
-def getPortFromORBcfg():\r
-    """\r
-    Get current omniORB port.\r
-    """\r
-    return getORBcfgInfo()[2]\r
-\r
-# ---\r
-\r
-def getUserName():\r
-    """\r
-    Get user name:\r
-    1. try USER environment variable (USERNAME on windows)\r
-    2. if fails, try LOGNAME (un*x)\r
-    3. if fails return 'unknown' as default user name\r
-    """\r
-    import os, sys\r
-    if sys.platform == "win32":\r
-        return os.getenv("USERNAME", "unknown")\r
-    else:\r
-        user = os.getenv("USER")\r
-        if user:\r
-            return user\r
-        return os.getenv("LOGNAME", "unknown")\r
-# ---\r
-\r
-def getHostName():\r
-    """\r
-    Get host name:\r
-    1. try socket python module gethostname() function\r
-    2. if fails, try HOSTNAME environment variable\r
-    3. if fails, try HOST environment variable\r
-    4. if fails, return 'unknown' as default host name\r
-    """\r
-    try:\r
-        import socket\r
-        host = socket.gethostname()\r
-    except:\r
-        host = None\r
-        pass\r
-    if not host: host = os.getenv("HOSTNAME")\r
-    if not host: host = os.getenv("HOST")\r
-    if not host: host = "unknown"           # 'unknown' is default host name\r
-    try:\r
-        socket.gethostbyname(host)\r
-    except:\r
-        host = "localhost"\r
-    pass\r
-    return host\r
-\r
-# ---\r
-\r
-def getShortHostName():\r
-    """\r
-    Get short host name:\r
-    1. try socket python module gethostname() function\r
-    2. if fails, try HOSTNAME environment variable\r
-    3. if fails, try HOST environment variable\r
-    4. if fails, return 'unknown' as default host name\r
-    """\r
-    try:\r
-        return getHostName().split('.')[0]\r
-    except:\r
-        pass\r
-    return "unknown"           # 'unknown' is default host name\r
-\r
-# ---\r
-\r
-def getAppName():\r
-    """\r
-    Get application name:\r
-    1. try APPNAME environment variable\r
-    2. if fails, return 'SALOME' as default application name\r
-    """\r
-    import os\r
-    return os.getenv( "APPNAME", "SALOME" ) # 'SALOME' is default user name\r
-\r
-# ---\r
-\r
-def getPortNumber(use_default=True):\r
-    """\r
-    Get current naming server port number:\r
-    1. try NSPORT environment variable\r
-    1. if fails, try to parse config file defined by OMNIORB_CONFIG environment variable\r
-    2. if fails, return 2809 as default port number (if use_default is True) or None (id use_default is False)\r
-    """\r
-    import os\r
-    try:\r
-        return int( os.getenv( "NSPORT" ) )\r
-    except:\r
-        pass\r
-    try:\r
-        port = int( getPortFromORBcfg() )\r
-        if port is not None: return port\r
-    except:\r
-        pass\r
-    if use_default: return 2809 # '2809' is default port number\r
-    return None\r
-\r
-# ---\r
-\r
-def getHomeDir():\r
-    """\r
-    Get home directory.\r
-    """\r
-    import os\r
-    return os.path.realpath(os.path.expanduser('~'))\r
-# ---\r
-\r
-def getLogDir():\r
-    """\r
-    Get directory to be used for the log files.\r
-    """\r
-    import os\r
-    return os.path.join(getTmpDir(), "logs", getUserName())\r
-# ---\r
-\r
-def getTmpDir():\r
-    """\r
-    Get directory to be used for the temporary files.\r
-    """\r
-    import os, tempfile\r
-    f = tempfile.NamedTemporaryFile()\r
-    tmpdir = os.path.dirname(f.name)\r
-    f.close()\r
-    return tmpdir\r
-# ---\r
-\r
-def generateFileName( dir, prefix = None, suffix = None, extension = None,\r
-                      unique = False, separator = "_", hidden = False, **kwargs ):\r
-    """\r
-    Generate file name by specified parameters. If necessary, file name\r
-    can be generated to be unique.\r
-\r
-    Parameters:\r
-    - dir       : directory path\r
-    - prefix    : file prefix (not added by default)\r
-    - suffix    : file suffix (not added by default)\r
-    - extension : file extension (not added by default)\r
-    - unique    : if this parameter is True, the unique file name is generated:\r
-    in this case, if the file with the generated name already exists\r
-    in the <dir> directory, an integer suffix is added to the end of the\r
-    file name. This parameter is False by default.\r
-    - separator : separator of the words ('_' by default)\r
-    - hidden    : if this parameter is True, the file name is prepended by . (dot)\r
-    symbol. This parameter is False by default.\r
-\r
-    Other keyword parameters are:\r
-    - with_username : 'add user name' flag/option:\r
-      * boolean value can be passed to determine user name automatically\r
-      * string value to be used as user name\r
-    - with_hostname : 'add host name' flag/option:\r
-      * boolean value can be passed to determine host name automatically\r
-      * string value to be used as host name\r
-    - with_port     : 'add port number' flag/option:\r
-      * boolean value can be passed to determine port number automatically\r
-      * string value to be used as port number\r
-    - with_app      : 'add application name' flag/option:\r
-      * boolean value can be passed to determine application name automatically\r
-      * string value to be used as application name\r
-    All <with_...> parameters are optional.\r
-    """\r
-    supported = [ 'with_username', 'with_hostname', 'with_port', 'with_app' ]\r
-    from launchConfigureParser import verbose\r
-    filename = []\r
-    # separator\r
-    if separator is None:\r
-        separator = ""\r
-        pass\r
-    else:\r
-        separator = str( separator )\r
-        pass\r
-    # prefix (if specified)\r
-    if prefix is not None:\r
-        filename.append( str( prefix ) )\r
-        pass\r
-    # additional keywords\r
-    ### check unsupported parameters\r
-    for kw in kwargs:\r
-        if kw not in supported and verbose():\r
-            print('Warning! salome_utilitie.py: generateFileName(): parameter %s is not supported' % kw)\r
-            pass\r
-        pass\r
-    ### process supported keywords\r
-    for kw in supported:\r
-        if kw not in kwargs: continue\r
-        ### user name\r
-        if kw == 'with_username':\r
-            try:\r
-                # auto user name ?\r
-                if _try_bool( kwargs[kw] ): filename.append( getUserName() )\r
-                pass\r
-            except:\r
-                # user name given as parameter\r
-                filename.append( kwargs[kw] )\r
-                pass\r
-            pass\r
-        ### host name\r
-        elif kw == 'with_hostname':\r
-            try:\r
-                # auto host name ?\r
-                if _try_bool( kwargs[kw] ): filename.append( getShortHostName() )\r
-                pass\r
-            except:\r
-                # host name given as parameter\r
-                filename.append( kwargs[kw] )\r
-                pass\r
-            pass\r
-        ### port number\r
-        elif kw == 'with_port':\r
-            try:\r
-                # auto port number ?\r
-                if _try_bool( kwargs[kw] ): filename.append( str( getPortNumber() ) )\r
-                pass\r
-            except:\r
-                # port number given as parameter\r
-                filename.append( str( kwargs[kw] ) )\r
-                pass\r
-            pass\r
-        ### application name\r
-        elif kw == 'with_app':\r
-            try:\r
-                # auto application name ?\r
-                if _try_bool( kwargs[kw] ): filename.append( getAppName() )\r
-                pass\r
-            except:\r
-                # application name given as parameter\r
-                filename.append( kwargs[kw] )\r
-                pass\r
-            pass\r
-        pass\r
-    # suffix (if specified)\r
-    if suffix is not None:\r
-        filename.append( str( suffix ) )\r
-        pass\r
-    # raise an exception if file name is empty\r
-    if not filename:\r
-        raise Exception("Empty file name")\r
-    #\r
-    if extension is not None and extension.startswith("."): extension = extension[1:]\r
-    #\r
-    import os\r
-    name = separator.join( filename )\r
-    if hidden: name = "." + name                       # add dot for hidden files\r
-    if extension: name = name + "." + str( extension ) # add extension if defined\r
-    name = os.path.join( dir, name )\r
-    if unique:\r
-        # create unique file name\r
-        index = 0\r
-        while os.path.exists( name ):\r
-            index = index + 1\r
-            name = separator.join( filename ) + separator + str( index )\r
-            if hidden: name = "." + name                       # add dot for hidden files\r
-            if extension: name = name + "." + str( extension ) # add extension if defined\r
-            name = os.path.join( dir, name )\r
-            pass\r
-        pass\r
-    return os.path.normpath(name)\r
-\r
-# ---\r
-\r
-def makeTmpDir( path, mode=0o777 ):\r
-    """\r
-    Make temporary directory with the specified path.\r
-    If the directory exists then clear its contents.\r
-\r
-    Parameters:\r
-    - path : absolute path to the directory to be created.\r
-    - mode : access mode\r
-    """\r
-    import os\r
-    if os.path.exists( path ):\r
-        import sys\r
-        if sys.platform == "win32":\r
-            os.system( "rmdir /S /Q " + '"' + path + '"' )\r
-            os.system( "mkdir " + '"' + path + '"' )\r
-        else:\r
-            os.system( "rm -rf " + path + "/*" )\r
-    else:\r
-        dirs = path.split("/")\r
-        shift1 = shift2 = 0\r
-        if not dirs[0]: shift1 = 1\r
-        if dirs[-1]: shift2 = 1\r
-        for i in range(1+shift1,len(dirs)+shift2):\r
-            p = "/".join(dirs[:i])\r
-            try:\r
-                os.mkdir(p, mode)\r
-                os.chmod(p, mode)\r
-            except:\r
-                pass\r
-\r
-# ---\r
-\r
-def uniteFiles( src_file, dest_file ):\r
-    """\r
-    Unite contents of the source file with contents of the destination file\r
-    and put result of the uniting to the destination file.\r
-    If the destination file does not exist then the source file is simply\r
-    copied to its path.\r
-\r
-    Parameters:\r
-    - src_file  : absolute path to the source file\r
-    - dest_file : absolute path to the destination file\r
-    """\r
-    import os\r
-\r
-    if not os.path.exists( src_file ):\r
-        return\r
-        pass\r
-\r
-    if os.path.exists( dest_file ):\r
-        # add a symbol of new line to contents of the destination file (just in case)\r
-        dest = open( dest_file, 'r' )\r
-        dest_lines = dest.readlines()\r
-        dest.close()\r
-\r
-        dest_lines.append( "\n" )\r
-\r
-        dest = open( dest_file, 'w' )\r
-        dest.writelines( dest_lines )\r
-        dest.close()\r
-\r
-        import sys\r
-        if sys.platform == "win32":\r
-            command = "type " + '"' + src_file + '"' + " >> " + '"' + dest_file + '"'\r
-        else:\r
-            command = "cat " + src_file + " >> " + dest_file\r
-            pass\r
-        pass\r
-    else:\r
-        import sys\r
-        if sys.platform == "win32":\r
-            command = "copy " + '"' + src_file + '"' + " " + '"' + dest_file + '"' + " > nul"\r
-        else:\r
-            command = "cp " + src_file + " " + dest_file\r
-            pass\r
-        pass\r
-\r
-    os.system( command )\r
-\r
-# --\r
-\r
-_verbose = None\r
-\r
-def verbose():\r
-    """\r
-    Get verbosity level. Default verbosity level is specified via the environment variable\r
-    SALOME_VERBOSE, e.g.:\r
-    [bash %] export SALOME_VERBOSE=1\r
-    The function setVerbose() can be used to change verbosity level explicitly.\r
-    """\r
-    global _verbose\r
-    # verbose has already been called\r
-    if _verbose is not None:\r
-        return _verbose\r
-    # first time\r
-    try:\r
-        from os import getenv\r
-        _verbose = int(getenv('SALOME_VERBOSE'))\r
-    except:\r
-        _verbose = 0\r
-        pass\r
-    #\r
-    return _verbose\r
-# --\r
-\r
-def setVerbose(level):\r
-    """\r
-    Change verbosity level. The function verbose() can be used to get current verbosity level.\r
-    """\r
-    global _verbose\r
-    _verbose = level\r
-    return\r
-# --\r
-\r
-import signal\r
-def killpid(pid, sig = 9):\r
-    """\r
-    Send signal sig to the process by pid.\r
-\r
-    Parameters:\r
-    - pid : PID of process\r
-    - sig : signal for sending\r
-            Possible values of signals: \r
-            9 means kill the process\r
-            0 only check existing of the process\r
-            NOTE: Other values are not processed on Windows\r
-    Returns:\r
-     1 Success\r
-     0 Fail, no such process\r
-    -1 Fail, another reason\r
-\r
-    """\r
-    if not pid: return\r
-    import os, sys\r
-    if sig != 0:\r
-        if verbose(): print("######## killpid pid = ", pid)\r
-    try:\r
-        if sys.platform == "win32":\r
-            import ctypes\r
-            if sig == 0:\r
-                # PROCESS_QUERY_INFORMATION (0x0400)    Required to retrieve certain information about a process\r
-                SYNCHRONIZE = 0x100000\r
-                handle = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, int(pid))\r
-                waitObj = ctypes.windll.kernel32.WaitForSingleObject(handle, 0)\r
-                if waitObj:\r
-                    ret = 1\r
-                    ctypes.windll.kernel32.CloseHandle(handle)\r
-                else:\r
-                    ret = 0\r
-            if sig == 9:\r
-                # PROCESS_TERMINATE (0x0001)    Required to terminate a process using TerminateProcess.\r
-                handle = ctypes.windll.kernel32.OpenProcess(0x0001, False, int(pid))\r
-                ret = ctypes.windll.kernel32.TerminateProcess(handle, -1)\r
-                ctypes.windll.kernel32.CloseHandle(handle)\r
-                pass\r
-            pass\r
-        else:\r
-            # Default: signal.SIGKILL = 9\r
-            os.kill(int(pid),sig)\r
-            ret = 1\r
-            pass\r
-        pass\r
-    except OSError as e:\r
-        # errno.ESRCH == 3 is 'No such process'\r
-        if e.errno == 3:\r
-            ret = 0\r
-        else:\r
-            ret = -1\r
-            pass\r
-        pass\r
-    return ret\r
-# --\r
-\r
-def getOmniNamesPid(port):\r
-    """\r
-    Return OmniNames pid by port number.\r
-    """\r
-    import sys,subprocess,re\r
-    if sys.platform == "win32":\r
-        # Get process list by WMI Command Line Utility(WMIC)\r
-        # Output is formatted with each value listed on a separate line and with the name of the property:\r
-        #   ...\r
-        #   Caption=<caption0>\r
-        #   CommandLine=<commandline0>\r
-        #   ProcessId=<processid0>\r
-        #\r
-        #\r
-        #\r
-        #   Caption=<caption1>\r
-        #   CommandLine=<commandline1>\r
-        #   ProcessId=<processid1>\r
-        #   ...\r
-        cmd = 'WMIC PROCESS get Caption,Commandline,Processid /VALUE'\r
-        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)\r
-        # Get stdout\r
-        allProc = proc.communicate()[0].decode()\r
-        # find Pid of omniNames\r
-        pid = re.findall(r'Caption=.*omniNames.*\n?CommandLine=.*omniNames.*\D%s\D.*\n?ProcessId=(\d*)'%(port),allProc)[0]\r
-    else:        \r
-        cmd = "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*%s\" | awk '{print $1}'"%(port)\r
-        proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)\r
-        pid = proc.communicate()[0]\r
-        pass\r
-\r
-    return pid\r
-# --\r
-\r
-def killOmniNames(port):\r
-    """\r
-    Kill OmniNames process by port number.\r
-    """\r
-    try:\r
-        pid = getOmniNamesPid(port)\r
-        if pid: killpid(pid)\r
-    except:\r
-        pass\r
-    pass\r
-# --\r
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+## @package salome_utils
+#  @brief Set of utility functions used by SALOME python scripts.
+
+"""
+Various utilities for SALOME.
+"""
+
+# pragma pylint: disable=invalid-name
+
+import os
+import os.path as osp
+import re
+import shutil
+import socket
+import sys
+import tempfile
+from contextlib import suppress
+
+import psutil
+
+def _try_bool(arg):
+    """
+    Convert given `arg` to a boolean value.
+    String values like 'True', 'TRUE', 'YES', 'Yes', 'y', 'NO', 'false', 'n', etc.
+    are supported.
+    If `arg` does not represent a boolean, an exception is raised.
+    :param arg : value being converted
+    :return result of conversion: `True` or `False`
+    """
+    if isinstance(arg, bool):
+        return arg
+    if isinstance(arg, bytes):
+        arg = arg.decode('utf-8', errors='ignore')
+    if isinstance(arg, str):
+        if arg.lower() in ('yes', 'y', 'true', 't'):
+            return True
+        if arg.lower() in ('no', 'n', 'false', 'f'):
+            return False
+    raise ValueError('Not a boolean value')
+
+# ---
+
+def getORBcfgInfo():
+    """
+    Get current omniORB configuration.
+
+    The information is retrieved from the omniORB configuration file defined
+    by the OMNIORB_CONFIG environment variable.
+    If omniORB configuration file can not be accessed, a tuple of three empty
+    strings is returned.
+
+    :return tuple of three strings: (orb_version, host_name, port_number)
+    """
+    orb_version = ''
+    hostname = ''
+    port_number = ''
+    with suppress(Exception), open(os.getenv('OMNIORB_CONFIG')) as forb:
+        regvar = re.compile(r'(ORB)?InitRef.*corbaname::(.*):(\d+)\s*$')
+        for line in forb.readlines():
+            match = regvar.match(line)
+            if match:
+                orb_version = '4' if match.group(1) is None else '3'
+                hostname = match.group(2)
+                port_number = match.group(3)
+                break
+    return orb_version, hostname, port_number
+
+# ---
+
+def getHostFromORBcfg():
+    """
+    Get current omniORB host name.
+    :return host name
+    """
+    return getORBcfgInfo()[1]
+
+# ---
+
+def getPortFromORBcfg():
+    """
+    Get current omniORB port.
+    :return port number
+    """
+    return getORBcfgInfo()[2]
+
+# ---
+
+def getUserName():
+    """
+    Get user name.
+
+    The following procedure is perfomed to deduce user name:
+    1. try USER (USERNAME on Windows) environment variable.
+    2. if (1) fails, try LOGNAME (un*x only).
+    3. if (2) fails, return 'unknown' as default user name
+
+    :return user name
+    """
+    return os.getenv('USERNAME', 'unknown') if sys.platform == 'win32' \
+        else os.getenv('USER', os.getenv('LOGNAME', 'unknown'))
+
+# ---
+
+def getHostName():
+    """
+    Get host name.
+
+    The following procedure is perfomed to deduce host name:
+    1. try socket python module, gethostname() function
+    2. if (1) fails, try HOSTNAME environment variable
+    3. if (2) fails, try HOST environment variable
+    4. if (3) fails, tries 'unknown' as default host name
+    5. finally, checks that IP is configured for hostname; if not, returns 'localhost'
+
+    :return host name
+    """
+    host = None
+    with suppress(Exception):
+        host = socket.gethostname()
+    if not host:
+        host = os.getenv('HOSTNAME', os.getenv('HOST', 'unknown'))
+    try:
+        # the following line just checks that IP is configured for hostname
+        socket.gethostbyname(host)
+    except (TypeError, OSError):
+        host = 'localhost'
+    return host
+
+# ---
+
+def getShortHostName():
+    """
+    Get short host name (with domain stripped).
+    See `getHostName()` for more details.
+    :return short host name
+    """
+    with suppress(AttributeError, IndexError):
+        return getHostName().split('.')[0]
+    return 'unknown' # default host name
+
+# ---
+
+def getAppName():
+    """
+    Get application name.
+    The following procedure is perfomed to deduce application name:
+    1. try APPNAME environment variable
+    2. if (1) fails, return 'SALOME' as default application name
+    :return application name
+    """
+    return os.getenv('APPNAME', 'SALOME') # 'SALOME' is default user name
+
+# ---
+
+def getPortNumber(use_default=True):
+    """
+    Get currently used omniORB port.
+    The following procedure is perfomed to deduce port number:
+    1. try NSPORT environment variable
+    2. if (1) fails, try to parse config file defined by OMNIORB_CONFIG environment variable
+    3. if (2) fails, return 2809 as default port number (if use_default is `True`) or `None`
+       (if use_default is `False`)
+    :return port number
+    """
+    with suppress(TypeError, ValueError):
+        return int(os.getenv('NSPORT'))
+    with suppress(TypeError, ValueError):
+        port = int(getPortFromORBcfg())
+        if port:
+            return port
+    return 2809 if use_default else None
+
+# ---
+
+def getHomeDir():
+    """
+    Get home directory.
+    :return home directory path
+    """
+    return osp.realpath(osp.expanduser('~'))
+
+# ---
+
+def getLogDir():
+    """
+    Get directory that stores log files.
+    :return path to the log directory
+    """
+    return osp.join(getTmpDir(), 'logs', getUserName())
+
+# ---
+
+def getTmpDir():
+    """
+    Get directory to store temporary files.
+    :return temporary directory path
+    """
+    with tempfile.NamedTemporaryFile() as tmp:
+        return osp.dirname(tmp.name)
+    return None
+
+# ---
+
+# pragma pylint: disable=too-many-arguments
+def generateFileName(path, prefix=None, suffix=None, extension=None,
+                     unique=False, separator='_', hidden=False, **kwargs):
+    """
+    Generate file name.
+
+    :param path      : directory path
+    :param prefix    : file name prefix (none by default)
+    :param suffix    : file name suffix (none by default)
+    :param extension : file extension (none by default)
+    :param unique    : if `True`, function generates unique file name -
+                       in this case, if file with the generated name already
+                       exists in `path` directory, an integer suffix is appended
+                       to the file name (`False` by default)
+    :param separator : words separator ('_' by default)
+    :param hidden    : if `True`, file name is prepended with dot symbol
+                       (`False` by default)
+    :param kwargs    : additional keywrods arguments (see below)
+    :return generated file name
+
+    Additionally supported keyword parameters:
+    - with_username : use user name:
+    - with_hostname : use host name:
+    - with_port : use port number:
+    - with_app      : use application name:
+
+    Any of these keyword arguments can accept either explicit string value,
+    or `True` to automatically deduce value from current configuration.
+    """
+    filename = []
+
+    def _with_str(_str):
+        _str = '' if _str is None else str(_str)
+        if _str:
+            filename.append(_str)
+
+    def _with_kwarg(_kwarg, _func):
+        _value = kwargs.get(_kwarg, False)
+        try:
+            if _try_bool(_value):
+                filename.append(str(_func()))
+        except ValueError:
+            _with_str(_value)
+
+    _with_str(prefix)
+    _with_kwarg('with_username', getUserName)
+    _with_kwarg('with_hostname', getShortHostName)
+    _with_kwarg('with_port', getPortNumber)
+    _with_kwarg('with_app', getAppName)
+    _with_str(suffix)
+
+    # raise an exception if file name is empty
+    if not filename:
+        raise ValueError('Empty file name')
+
+    # extension
+    extension = '' if extension is None else str(extension)
+    if extension.startswith('.'):
+        extension = extension[1:]
+
+    # separator
+    separator = '' if separator is None else str(separator)
+
+    def _generate(_index=None):
+        # join all components together, add index if necessary
+        if _index is not None:
+            _name = separator.join(filename+[str(_index)])
+        else:
+            _name = separator.join(filename)
+        # prepend with dot if necessary
+        if hidden:
+            _name = '.' + _name
+        # append extension if ncessary
+        if extension:
+            _name = _name + '.' + extension
+        # now get full path
+        return osp.join(path, _name)
+
+    name = _generate()
+    if unique:
+        index = 0
+        while osp.exists(name):
+            index = index + 1
+            name = _generate(index)
+    return osp.normpath(name)
+
+# ---
+
+def cleanDir(path):
+    """
+    Clear contents of directory.
+    :param path directory path
+    """
+    if osp.exists(path):
+        for filename in os.listdir(path):
+            file_path = osp.join(path, filename)
+            with suppress(OSError):
+                if osp.isdir(file_path):
+                    shutil.rmtree(file_path)
+                else:
+                    os.unlink(file_path)
+
+# ---
+
+def makeTmpDir(path, mode=0o777):
+    """
+    Make temporary directory with the specified path.
+    If the directory exists, clear all its contents.
+    :param path : directory path
+    :param mode : access mode
+    """
+    with suppress(OSError):
+        os.makedirs(path, mode=mode, exist_ok=True)
+    cleanDir(path)
+
+# ---
+
+def uniteFiles(src_file, dest_file):
+    """
+    Join contents of `src_file` and `dest_file` and put result to `dest_file`.
+    File `dest_file` may not exist.
+    :param src_file  : source file path
+    :param dest_file : destination file path
+    """
+    if not osp.exists(src_file):
+        return
+
+    if osp.exists(dest_file):
+        with suppress(OSError), open(src_file, 'rb') as src, open(dest_file, 'ab') as dest:
+            dest.write(b'\n')
+            dest.write(src.read())
+    else:
+        with suppress(OSError):
+            shutil.copy(src_file, dest_file)
+
+# --
+
+def verbose():
+    """
+    Get current verbosity level.
+
+    Default verbosity level is specified via the environment variable SALOME_VERBOSE,
+    e.g. in bash:
+
+        $ export SALOME_VERBOSE=1
+
+    The function `setVerbose()` can be used to explicitly set verbosity level.
+
+    :return current verbosity level
+    """
+    if not hasattr(verbose, 'verbosity_level'):
+        verbose.verbosity_level = 0 # default value
+        with suppress(TypeError, ValueError):
+            # from SALOME_VERBOSE environment variable
+            verbose.verbosity_level = int(os.getenv('SALOME_VERBOSE', '0'))
+    return verbose.verbosity_level
+# --
+
+def setVerbose(level):
+    """
+    Change verbosity level.
+    The function `verbose()` can be used to get current verbosity level.
+    :param level : verbosity level
+    """
+    with suppress(TypeError, ValueError):
+        verbose.verbosity_level = int(level)
+# --
+
+def killPid(pid, sig=9):
+    """
+    Send signal `sig` to the process with given `pid`.
+
+    :param pid : PID of the process
+    :param sig : signal to send; some of possible values:
+       - 9 : kill process
+       - 0 : do nothing, just check process existence (see below)
+       NOTE: other values are not processed on Windows
+    :return result of execution:
+       -  1 : success
+       -  0 : fail, no such process
+       - -1 : fail, another reason
+    """
+    if not pid:
+        return -1
+
+    with suppress(ValueError):
+        pid = int(pid)
+
+    if sig == 0:
+        ret = 1 if psutil.pid_exists(pid) else 0
+    else:
+        if verbose():
+            print("######## killPid pid = ", pid)
+        try:
+            process = psutil.Process(pid)
+            process.terminate()
+            _, alive = psutil.wait_procs([process], timeout=5)
+            for proc in alive:
+                proc.kill()
+            ret = 1
+        except psutil.NoSuchProcess:
+            ret = 0
+        except OSError:
+            ret = -1
+    return ret
+# --
+
+def getOmniNamesPid(port):
+    """
+    Get PID of omniNames process running on given `port`.
+    :param port : port number
+    :return omniNames process's PID
+    """
+    processes = {p.info['pid']: p.info['name'] for p in psutil.process_iter(['pid', 'name'])}
+    return next((c.pid for c in psutil.net_connections(kind='inet') \
+                     if c.laddr.port == port and processes.get(c.pid) == 'omniNames'), None)
+# --
+
+def killOmniNames(port):
+    """
+    Kill omniNames process running on given `port`.
+    :param port : port number
+    """
+    with suppress(Exception):
+        killPid(getOmniNamesPid(port))
+# --
index ac1ebcef28fb3109b65f9214239bf330d2ee9531..29c9334f9f714239498563e2b73595cc07e56942 100644 (file)
-#  -*- coding: iso-8859-1 -*-\r
-# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE\r
-#\r
-# Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,\r
-# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS\r
-#\r
-# This library is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 2.1 of the License, or (at your option) any later version.\r
-#\r
-# This library is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with this library; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\r
-#\r
-# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com\r
-#\r
-\r
-import os, sys, string\r
-from salome_utils import getHostName\r
-process_id = {}\r
-\r
-# -----------------------------------------------------------------------------\r
-#\r
-# Definition des classes d'objets pour le lancement des Server CORBA\r
-#\r
-\r
-class Server:\r
-    """Generic class for CORBA server launch"""\r
-\r
-    server_launch_mode = "daemon"\r
-\r
-    def initArgs(self):\r
-        self.PID=None\r
-        self.CMD=[]\r
-        self.ARGS=[]\r
-        if self.args.get('xterm'):\r
-          if sys.platform != "win32":\r
-            self.ARGS=['xterm', '-iconic', '-sb', '-sl', '500', '-hold']\r
-          else:\r
-            self.ARGS=['cmd', '/c', 'start  cmd.exe', '/K']\r
-\r
-    def __init__(self,args):\r
-        self.args=args\r
-        self.initArgs()\r
-\r
-    @staticmethod\r
-    def set_server_launch_mode(mode):\r
-      if mode == "daemon" or mode == "fork":\r
-        Server.server_launch_mode = mode\r
-      else:\r
-        raise Exception("Unsupported server launch mode: %s" % mode)\r
-\r
-    def run(self, daemon=False):\r
-        global process_id\r
-        myargs=self.ARGS\r
-        if self.args.get('xterm'):\r
-            # (Debian) send LD_LIBRARY_PATH to children shells (xterm)\r
-          if sys.platform == "darwin":\r
-              env_ld_library_path=['env', 'DYLD_LIBRARY_PATH='\r
-                                   + os.getenv("DYLD_FALLBACK_LIBRARY_PATH")]\r
-              myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path\r
-          elif sys.platform != "win32":\r
-              env_ld_library_path=['env', 'LD_LIBRARY_PATH='\r
-                                   + os.getenv("LD_LIBRARY_PATH")]\r
-              myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path\r
-        command = myargs + self.CMD\r
-        # print("command = ", command)\r
-        if sys.platform == "win32":\r
-          import subprocess\r
-          if daemon:\r
-            DETACHED_PROCESS = 0x00000008\r
-            pid = subprocess.Popen(command, creationflags=DETACHED_PROCESS).pid\r
-          else:\r
-            pid = subprocess.Popen(command).pid\r
-        elif Server.server_launch_mode == "fork":\r
-          pid = os.spawnvp(os.P_NOWAIT, command[0], command)\r
-        else: # Server launch mode is daemon\r
-          pid=self.daemonize(command)\r
-        if pid is not None:\r
-          #store process pid if it really exists\r
-          process_id[pid]=self.CMD\r
-        self.PID = pid\r
-        return pid\r
-\r
-    def daemonize(self,args):\r
-        # to daemonize a process need to do the UNIX double-fork magic\r
-        # see Stevens, "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177)\r
-        # and UNIX Programming FAQ 1.7 How do I get my program to act like a daemon?\r
-        #     http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16\r
-        #open a pipe\r
-        c2pread, c2pwrite = os.pipe()\r
-        #do first fork\r
-        pid=os.fork()\r
-        if pid > 0:\r
-          #first parent\r
-          os.close(c2pwrite)\r
-          #receive real pid from child\r
-          data=os.read(c2pread,24) #read 24 bytes\r
-          os.waitpid(pid,0) #remove zombie\r
-          os.close(c2pread)\r
-          # return : first parent\r
-          childpid=int(data)\r
-          if childpid==-1:\r
-            return None\r
-          try:\r
-            os.kill(childpid,0)\r
-            return childpid\r
-          except:\r
-            return None\r
-\r
-        #first child\r
-        # decouple from parent environment\r
-        os.setsid()\r
-        os.close(c2pread)\r
-\r
-        # do second fork : second child not a session leader\r
-        try:\r
-          pid = os.fork()\r
-          if pid > 0:\r
-            #send real pid to parent\r
-            pid_str = "%d" % pid\r
-            os.write(c2pwrite,pid_str.encode())\r
-            os.close(c2pwrite)\r
-            # exit from second parent\r
-            os._exit(0)\r
-        except OSError as e:\r
-          print("fork #2 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr)\r
-          os.write(c2pwrite,"-1")\r
-          os.close(c2pwrite)\r
-          sys.exit(1)\r
-\r
-        #I am a daemon\r
-        os.close(0) #close stdin\r
-        os.open("/dev/null", os.O_RDWR)  # redirect standard input (0) to /dev/null\r
-        try:\r
-          os.execvp(args[0], args)\r
-        except OSError as e:\r
-          print("(%s) launch failed: %d (%s)" % (args[0],e.errno, e.strerror), file=sys.stderr)\r
-          os._exit(127)\r
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+import os, sys, string
+from salome_utils import getHostName
+process_id = {}
+
+# -----------------------------------------------------------------------------
+#
+# Definition des classes d'objets pour le lancement des Server CORBA
+#
+
+class Server:
+    """Generic class for CORBA server launch"""
+
+    server_launch_mode = "daemon"
+
+    def initArgs(self):
+        self.PID=None
+        self.CMD=[]
+        self.ARGS=[]
+        if self.args.get('xterm'):
+          if sys.platform != "win32":
+            self.ARGS=['xterm', '-iconic', '-sb', '-sl', '500', '-hold']
+          else:
+            self.ARGS=['cmd', '/c', 'start  cmd.exe', '/K']
+
+    def __init__(self,args):
+        self.args=args
+        self.initArgs()
+
+    @staticmethod
+    def set_server_launch_mode(mode):
+      if mode == "daemon" or mode == "fork":
+        Server.server_launch_mode = mode
+      else:
+        raise Exception("Unsupported server launch mode: %s" % mode)
+
+    def run(self, daemon=False):
+        global process_id
+        myargs=self.ARGS
+        if self.args.get('xterm'):
+            # (Debian) send LD_LIBRARY_PATH to children shells (xterm)
+          if sys.platform == "darwin":
+              env_ld_library_path=['env', 'DYLD_LIBRARY_PATH='
+                                   + os.getenv("DYLD_FALLBACK_LIBRARY_PATH")]
+              myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path
+          elif sys.platform != "win32":
+              env_ld_library_path=['env', 'LD_LIBRARY_PATH='
+                                   + os.getenv("LD_LIBRARY_PATH")]
+              myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path
+        command = myargs + self.CMD
+        # print("command = ", command)
+        if sys.platform == "win32":
+          import subprocess
+          if daemon:
+            DETACHED_PROCESS = 0x00000008
+            pid = subprocess.Popen(command, creationflags=DETACHED_PROCESS).pid
+          else:
+            pid = subprocess.Popen(command).pid
+        elif Server.server_launch_mode == "fork":
+          pid = os.spawnvp(os.P_NOWAIT, command[0], command)
+        else: # Server launch mode is daemon
+          pid=self.daemonize(command)
+        if pid is not None:
+          #store process pid if it really exists
+          process_id[pid]=self.CMD
+        self.PID = pid
+        return pid
+
+    def daemonize(self,args):
+        # to daemonize a process need to do the UNIX double-fork magic
+        # see Stevens, "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177)
+        # and UNIX Programming FAQ 1.7 How do I get my program to act like a daemon?
+        #     http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+        #open a pipe
+        c2pread, c2pwrite = os.pipe()
+        #do first fork
+        pid=os.fork()
+        if pid > 0:
+          #first parent
+          os.close(c2pwrite)
+          #receive real pid from child
+          data=os.read(c2pread,24) #read 24 bytes
+          os.waitpid(pid,0) #remove zombie
+          os.close(c2pread)
+          # return : first parent
+          childpid=int(data)
+          if childpid==-1:
+            return None
+          try:
+            os.kill(childpid,0)
+            return childpid
+          except:
+            return None
+
+        #first child
+        # decouple from parent environment
+        os.setsid()
+        os.close(c2pread)
+
+        # do second fork : second child not a session leader
+        try:
+          pid = os.fork()
+          if pid > 0:
+            #send real pid to parent
+            pid_str = "%d" % pid
+            os.write(c2pwrite,pid_str.encode())
+            os.close(c2pwrite)
+            # exit from second parent
+            os._exit(0)
+        except OSError as e:
+          print("fork #2 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr)
+          os.write(c2pwrite,"-1")
+          os.close(c2pwrite)
+          sys.exit(1)
+
+        #I am a daemon
+        os.close(0) #close stdin
+        os.open("/dev/null", os.O_RDWR)  # redirect standard input (0) to /dev/null
+        try:
+          os.execvp(args[0], args)
+        except OSError as e:
+          print("(%s) launch failed: %d (%s)" % (args[0],e.errno, e.strerror), file=sys.stderr)
+          os._exit(127)
index 7228423df488e358e04b566909e239dc3ae9fc48..32455869f3079231a690651d0550da5badd0e15e 100644 (file)
-#! /usr/bin/env python3\r
-#  -*- coding: iso-8859-1 -*-\r
-# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE\r
-#\r
-# Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,\r
-# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS\r
-#\r
-# This library is free software; you can redistribute it and/or\r
-# modify it under the terms of the GNU Lesser General Public\r
-# License as published by the Free Software Foundation; either\r
-# version 2.1 of the License, or (at your option) any later version.\r
-#\r
-# This library is distributed in the hope that it will be useful,\r
-# but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
-# Lesser General Public License for more details.\r
-#\r
-# You should have received a copy of the GNU Lesser General Public\r
-# License along with this library; if not, write to the Free Software\r
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA\r
-#\r
-# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com\r
-#\r
-\r
-#  SALOME NamingService : wrapping NamingService services\r
-#  File   : SALOME_NamingServicePy.py\r
-#  Author : Estelle Deville, CEA\r
-#  Module : SALOME\r
-#  $Header$\r
-## @package SALOME_NamingServicePy\r
-# \brief Module to manage SALOME naming service from python\r
-#\r
-import sys\r
-import time\r
-from omniORB import CORBA\r
-import CosNaming\r
-import string\r
-from string import *\r
-\r
-from SALOME_utilities import *\r
-#=============================================================================\r
-\r
-class SALOME_NamingServicePy_i(object):\r
-    """\r
-      A class to manage SALOME naming service from python code\r
-    """\r
-    _orb = None\r
-    _root_context=None\r
-    _current_context=None\r
-    _obj=None\r
-    \r
-    #-------------------------------------------------------------------------\r
-\r
-    def __init__(self, orb=None, steps=240, spy=False):\r
-        """\r
-        Standard Constructor, with ORB reference.\r
\r
-        Initializes the naming service root context\r
-        """\r
-        #MESSAGE ( "SALOME_NamingServicePy_i::__init__" )\r
-        if orb is None:\r
-          orb=CORBA.ORB_init([''], CORBA.ORB_ID)\r
-        self._orb = orb\r
-        # initialize root context and current context\r
-        ok = 0\r
-        while steps > 0 and ok == 0:\r
-          try:\r
-            obj =self._orb.resolve_initial_references("NameService")\r
-            self._root_context =obj._narrow(CosNaming.NamingContext)\r
-            self._current_context = self._root_context\r
-\r
-        \r
-            if self._root_context is None :\r
-              #MESSAGE ( "Name Service Reference is invalid" )\r
-              #sys.exit(1)\r
-              MESSAGE(" Name service not found")\r
-            else:\r
-              ok = 1\r
-          except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-            MESSAGE(" Name service not found")\r
-          time.sleep(0.25)\r
-          steps = steps - 1\r
-        if steps == 0 and self._root_context is None: \r
-          MESSAGE ( "Name Service Reference is invalid" )\r
-          if spy:\r
-            raise ValueError("Name Service Reference is invalid")\r
-          else:\r
-            sys.exit(1)\r
-\r
-    #-------------------------------------------------------------------------\r
-\r
-    def Register(self,ObjRef, Path):\r
-        """ ns.Register(object,pathname )  \r
-        \r
-        register a CORBA object under a pathname\r
-        """\r
-\r
-        MESSAGE ( "SALOME_NamingServicePy_i::Register" )\r
-        _not_exist = 0\r
-        path_list = list(Path)\r
-        if path_list[0]=='/':\r
-            self._current_context = self._root_context\r
-            #delete first '/' before split\r
-            Path=Path[1:]\r
-\r
-        result_resolve_path = Path.split('/')\r
-        if len(result_resolve_path)>1:\r
-            # A directory is treated (not only an object name)\r
-            # We had to test if the directory where ObjRef should be recorded \r
-            # is already done\r
-            # If not, the new context has to be created\r
-            _context_name = []\r
-            for i in range(len(result_resolve_path)-1):\r
-                _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))\r
-            \r
-            try:\r
-                obj = self._current_context.resolve(_context_name)\r
-                self._current_context = obj._narrow(CosNaming.NamingContext)\r
-            except CosNaming.NamingContext.NotFound as ex:\r
-                _not_exist = 1\r
-            except CosNaming.NamingContext.InvalidName as ex:\r
-                MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" )\r
-            except CosNaming.NamingContext.CannotProceed as ex:\r
-                MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" )\r
-            except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-                MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )\r
-\r
-            if _not_exist:\r
-                # at least one context of the complete path is not created, we had\r
-                # to create it or them\r
-                _context_name = []\r
-                for i in range(len(result_resolve_path)-1):\r
-                    _context_name = [CosNaming.NameComponent(result_resolve_path[i],"dir")]\r
-\r
-                    try:\r
-                        obj = self._current_context.resolve(_context_name)\r
-                        self._current_context = obj._narrow(CosNaming.NamingContext)\r
-                    except CosNaming.NamingContext.NotFound as ex:\r
-                        #This context is not created. It will be done\r
-                        self._current_context = self._current_context.bind_new_context(_context_name)\r
-\r
-        #The current directory is now the directory where the object should \r
-        #be recorded\r
-         \r
-        _context_name = [CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")]\r
-        try:\r
-            self._current_context.bind(_context_name,ObjRef)\r
-        except CosNaming.NamingContext.NotFound as ex:\r
-            MESSAGE ( "Register : CosNaming.NamingContext.NotFound" )\r
-        except CosNaming.NamingContext.InvalidName as ex:\r
-            MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" )\r
-        except CosNaming.NamingContext.CannotProceed as ex:\r
-            MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" )\r
-        except CosNaming.NamingContext.AlreadyBound as ex:\r
-            MESSAGE ( "Register : CosNaming.NamingContext.AlreadyBound, object will be rebind" )\r
-            self._current_context.rebind(_context_name,ObjRef)\r
-        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-            MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )\r
-\r
-    #-------------------------------------------------------------------------\r
-\r
-    def Resolve(self, Path):\r
-        """ ns.Resolve(pathname) -> object\r
-\r
-        find a CORBA object (ior) by its pathname\r
-        """\r
-        #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" )\r
-        path_list = list(Path)\r
-        if path_list[0]=='/':\r
-            self._current_context = self._root_context\r
-            #delete first '/' before split\r
-            Path=Path[1:]\r
-\r
-        result_resolve_path = Path.split('/')\r
-        _context_name=[]\r
-        for i in range(len(result_resolve_path)-1):\r
-            _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))\r
-        _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object"))\r
-        try:\r
-            self._obj = self._current_context.resolve(_context_name)\r
-        except CosNaming.NamingContext.NotFound as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" )\r
-            self._obj = None\r
-        except CosNaming.NamingContext.InvalidName as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" )\r
-            self._obj = None\r
-        except CosNaming.NamingContext.CannotProceed as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" )\r
-            self._obj = None\r
-        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-            MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )\r
-            self._obj = None\r
-        return self._obj\r
-\r
-    #-------------------------------------------------------------------------\r
-\r
-    def Resolve_Dir(self, Path):\r
-        """ ns.Resolve_Dir(pathname) -> dir\r
-\r
-        find a CORBA object (ior) by its pathname\r
-        """\r
-        #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" )\r
-        path_list = list(Path)\r
-        if path_list[0]=='/':\r
-            self._current_context = self._root_context\r
-            #delete first '/' before split\r
-            Path=Path[1:]\r
-\r
-        result_resolve_path = Path.split('/')\r
-        _context_name=[]\r
-        for i in range(len(result_resolve_path)-1):\r
-            _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))\r
-        _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"dir"))\r
-        print(_context_name)\r
-        return None\r
-        try:\r
-            self._obj = self._current_context.resolve(_context_name)\r
-        except CosNaming.NamingContext.NotFound as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" )\r
-            self._obj = None\r
-        except CosNaming.NamingContext.InvalidName as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" )\r
-            self._obj = None\r
-        except CosNaming.NamingContext.CannotProceed as ex:\r
-            MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" )\r
-            self._obj = None\r
-        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-            MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )\r
-            self._obj = None\r
-        return self._obj\r
-\r
-\r
-    #-------------------------------------------------------------------------\r
-\r
-    def Create_Directory(self,ObjRef, Path):\r
-        """ ns.Create_Directory(ObjRef, Path) \r
-\r
-        create a sub directory \r
-        """\r
-        MESSAGE ( "SALOME_NamingServicePy_i::Create_Directory" )\r
-        _not_exist = 0\r
-        path_list = list(Path)\r
-        if path_list[0]=='/':\r
-            self._current_context = self._root_context\r
-            #delete first '/' before split\r
-            Path=Path[1:]\r
-\r
-        result_resolve_path = Path.split('/')\r
-        _context_name = []\r
-        for i in range(len(result_resolve_path)):\r
-            _context_name[CosNaming.NameComponent(result_resolve_path[i],"dir")]            \r
-            try:\r
-                obj = self._current_context.resolve(_context_name)\r
-                self._current_context = obj._narrow(CosNaming.NamingContext)\r
-            except CosNaming.NamingContext.NotFound as ex:\r
-                self._current_context = self._current_context.bind_new_context(_context_name)\r
-            except CosNaming.NamingContext.InvalidName as ex:\r
-                MESSAGE ( "Create_Directory : CosNaming.NamingContext.InvalidName" )\r
-            except CosNaming.NamingContext.CannotProceed as ex:\r
-                MESSAGE ( "Create_Directory : CosNaming.NamingContext.CannotProceed" )\r
-            except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):\r
-                MESSAGE ( "Create_Directory : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )\r
\r
-    def Destroy_Name(self,Path):\r
-      """ ns.Destroy_Name(Path) \r
-\r
-        remove a name in naming service\r
-      """\r
-      resolve_path=Path.split('/')\r
-      if resolve_path[0] == '': del resolve_path[0]\r
-      dir_path=resolve_path[:-1]\r
-      context_name=[]\r
-      for e in dir_path:\r
-         context_name.append(CosNaming.NameComponent(e,"dir"))\r
-      context_name.append(CosNaming.NameComponent(resolve_path[-1],"object"))\r
-      \r
-      try:\r
-        self._root_context.unbind(context_name)\r
-      except CosNaming.NamingContext.NotFound as ex:\r
-        return\r
-      except CORBA.Exception as ex:\r
-        return\r
-\r
-    def Destroy_FullDirectory(self,Path):\r
-      """ ns.Destroy_FullDirectory(Path)\r
-\r
-        remove recursively a directory\r
-      """\r
-      context_name=[]\r
-      for e in Path.split('/'):\r
-        if e == '':continue\r
-        context_name.append(CosNaming.NameComponent(e,"dir"))\r
-\r
-      try:\r
-        context=self._root_context.resolve(context_name)\r
-      except CosNaming.NamingContext.NotFound as ex:\r
-        return\r
-      except CORBA.Exception as ex:\r
-        return\r
-\r
-      bl,bi=context.list(0)\r
-      if bi is not None:\r
-         ok,b=bi.next_one()\r
-         while(ok):\r
-            for s in b.binding_name :\r
-               if s.kind == "object":\r
-                  context.unbind([s])\r
-               elif s.kind == "dir":\r
-                  context.unbind([s])\r
-            ok,b=bi.next_one()\r
-\r
-      context.destroy()\r
-      self._root_context.unbind(context_name)\r
+#! /usr/bin/env python3
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2007-2020  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+#  SALOME NamingService : wrapping NamingService services
+#  File   : SALOME_NamingServicePy.py
+#  Author : Estelle Deville, CEA
+#  Module : SALOME
+#  $Header$
+## @package SALOME_NamingServicePy
+# \brief Module to manage SALOME naming service from python
+#
+import sys
+import time
+from omniORB import CORBA
+import CosNaming
+import string
+from string import *
+
+from SALOME_utilities import *
+#=============================================================================
+
+class SALOME_NamingServicePy_i(object):
+    """
+      A class to manage SALOME naming service from python code
+    """
+    _orb = None
+    _root_context=None
+    _current_context=None
+    _obj=None
+    
+    #-------------------------------------------------------------------------
+
+    def __init__(self, orb=None, steps=240, spy=False):
+        """
+        Standard Constructor, with ORB reference.
+        Initializes the naming service root context
+        """
+        #MESSAGE ( "SALOME_NamingServicePy_i::__init__" )
+        if orb is None:
+          orb=CORBA.ORB_init([''], CORBA.ORB_ID)
+        self._orb = orb
+        # initialize root context and current context
+        ok = 0
+        while steps > 0 and ok == 0:
+          try:
+            obj =self._orb.resolve_initial_references("NameService")
+            self._root_context =obj._narrow(CosNaming.NamingContext)
+            self._current_context = self._root_context
+
+        
+            if self._root_context is None :
+              #MESSAGE ( "Name Service Reference is invalid" )
+              #sys.exit(1)
+              MESSAGE(" Name service not found")
+            else:
+              ok = 1
+          except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+            MESSAGE(" Name service not found")
+          time.sleep(0.25)
+          steps = steps - 1
+        if steps == 0 and self._root_context is None: 
+          MESSAGE ( "Name Service Reference is invalid" )
+          if spy:
+            raise ValueError("Name Service Reference is invalid")
+          else:
+            sys.exit(1)
+
+    #-------------------------------------------------------------------------
+
+    def Register(self,ObjRef, Path):
+        """ ns.Register(object,pathname )  
+        
+        register a CORBA object under a pathname
+        """
+
+        MESSAGE ( "SALOME_NamingServicePy_i::Register" )
+        _not_exist = 0
+        path_list = list(Path)
+        if path_list[0]=='/':
+            self._current_context = self._root_context
+            #delete first '/' before split
+            Path=Path[1:]
+
+        result_resolve_path = Path.split('/')
+        if len(result_resolve_path)>1:
+            # A directory is treated (not only an object name)
+            # We had to test if the directory where ObjRef should be recorded 
+            # is already done
+            # If not, the new context has to be created
+            _context_name = []
+            for i in range(len(result_resolve_path)-1):
+                _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))
+            
+            try:
+                obj = self._current_context.resolve(_context_name)
+                self._current_context = obj._narrow(CosNaming.NamingContext)
+            except CosNaming.NamingContext.NotFound as ex:
+                _not_exist = 1
+            except CosNaming.NamingContext.InvalidName as ex:
+                MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" )
+            except CosNaming.NamingContext.CannotProceed as ex:
+                MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" )
+            except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+                MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )
+
+            if _not_exist:
+                # at least one context of the complete path is not created, we had
+                # to create it or them
+                _context_name = []
+                for i in range(len(result_resolve_path)-1):
+                    _context_name = [CosNaming.NameComponent(result_resolve_path[i],"dir")]
+
+                    try:
+                        obj = self._current_context.resolve(_context_name)
+                        self._current_context = obj._narrow(CosNaming.NamingContext)
+                    except CosNaming.NamingContext.NotFound as ex:
+                        #This context is not created. It will be done
+                        self._current_context = self._current_context.bind_new_context(_context_name)
+
+        #The current directory is now the directory where the object should 
+        #be recorded
+         
+        _context_name = [CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")]
+        try:
+            self._current_context.bind(_context_name,ObjRef)
+        except CosNaming.NamingContext.NotFound as ex:
+            MESSAGE ( "Register : CosNaming.NamingContext.NotFound" )
+        except CosNaming.NamingContext.InvalidName as ex:
+            MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" )
+        except CosNaming.NamingContext.CannotProceed as ex:
+            MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" )
+        except CosNaming.NamingContext.AlreadyBound as ex:
+            MESSAGE ( "Register : CosNaming.NamingContext.AlreadyBound, object will be rebind" )
+            self._current_context.rebind(_context_name,ObjRef)
+        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+            MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )
+
+    #-------------------------------------------------------------------------
+
+    def Resolve(self, Path):
+        """ ns.Resolve(pathname) -> object
+
+        find a CORBA object (ior) by its pathname
+        """
+        #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" )
+        path_list = list(Path)
+        if path_list[0]=='/':
+            self._current_context = self._root_context
+            #delete first '/' before split
+            Path=Path[1:]
+
+        result_resolve_path = Path.split('/')
+        _context_name=[]
+        for i in range(len(result_resolve_path)-1):
+            _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))
+        _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object"))
+        try:
+            self._obj = self._current_context.resolve(_context_name)
+        except CosNaming.NamingContext.NotFound as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" )
+            self._obj = None
+        except CosNaming.NamingContext.InvalidName as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" )
+            self._obj = None
+        except CosNaming.NamingContext.CannotProceed as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" )
+            self._obj = None
+        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+            MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )
+            self._obj = None
+        return self._obj
+
+    #-------------------------------------------------------------------------
+
+    def Resolve_Dir(self, Path):
+        """ ns.Resolve_Dir(pathname) -> dir
+
+        find a CORBA object (ior) by its pathname
+        """
+        #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" )
+        path_list = list(Path)
+        if path_list[0]=='/':
+            self._current_context = self._root_context
+            #delete first '/' before split
+            Path=Path[1:]
+
+        result_resolve_path = Path.split('/')
+        _context_name=[]
+        for i in range(len(result_resolve_path)-1):
+            _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir"))
+        _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"dir"))
+        print(_context_name)
+        return None
+        try:
+            self._obj = self._current_context.resolve(_context_name)
+        except CosNaming.NamingContext.NotFound as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" )
+            self._obj = None
+        except CosNaming.NamingContext.InvalidName as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" )
+            self._obj = None
+        except CosNaming.NamingContext.CannotProceed as ex:
+            MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" )
+            self._obj = None
+        except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+            MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )
+            self._obj = None
+        return self._obj
+
+
+    #-------------------------------------------------------------------------
+
+    def Create_Directory(self,ObjRef, Path):
+        """ ns.Create_Directory(ObjRef, Path) 
+
+        create a sub directory 
+        """
+        MESSAGE ( "SALOME_NamingServicePy_i::Create_Directory" )
+        _not_exist = 0
+        path_list = list(Path)
+        if path_list[0]=='/':
+            self._current_context = self._root_context
+            #delete first '/' before split
+            Path=Path[1:]
+
+        result_resolve_path = Path.split('/')
+        _context_name = []
+        for i in range(len(result_resolve_path)):
+            _context_name[CosNaming.NameComponent(result_resolve_path[i],"dir")]            
+            try:
+                obj = self._current_context.resolve(_context_name)
+                self._current_context = obj._narrow(CosNaming.NamingContext)
+            except CosNaming.NamingContext.NotFound as ex:
+                self._current_context = self._current_context.bind_new_context(_context_name)
+            except CosNaming.NamingContext.InvalidName as ex:
+                MESSAGE ( "Create_Directory : CosNaming.NamingContext.InvalidName" )
+            except CosNaming.NamingContext.CannotProceed as ex:
+                MESSAGE ( "Create_Directory : CosNaming.NamingContext.CannotProceed" )
+            except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE):
+                MESSAGE ( "Create_Directory : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" )
+    def Destroy_Name(self,Path):
+      """ ns.Destroy_Name(Path) 
+
+        remove a name in naming service
+      """
+      resolve_path=Path.split('/')
+      if resolve_path[0] == '': del resolve_path[0]
+      dir_path=resolve_path[:-1]
+      context_name=[]
+      for e in dir_path:
+         context_name.append(CosNaming.NameComponent(e,"dir"))
+      context_name.append(CosNaming.NameComponent(resolve_path[-1],"object"))
+      
+      try:
+        self._root_context.unbind(context_name)
+      except CosNaming.NamingContext.NotFound as ex:
+        return
+      except CORBA.Exception as ex:
+        return
+
+    def Destroy_FullDirectory(self,Path):
+      """ ns.Destroy_FullDirectory(Path)
+
+        remove recursively a directory
+      """
+      context_name=[]
+      for e in Path.split('/'):
+        if e == '':continue
+        context_name.append(CosNaming.NameComponent(e,"dir"))
+
+      try:
+        context=self._root_context.resolve(context_name)
+      except CosNaming.NamingContext.NotFound as ex:
+        return
+      except CORBA.Exception as ex:
+        return
+
+      bl,bi=context.list(0)
+      if bi is not None:
+         ok,b=bi.next_one()
+         while(ok):
+            for s in b.binding_name :
+               if s.kind == "object":
+                  context.unbind([s])
+               elif s.kind == "dir":
+                  context.unbind([s])
+            ok,b=bi.next_one()
+
+      context.destroy()
+      self._root_context.unbind(context_name)