Salome HOME
sat #18867 : pour les url des bases git : substitution des references par leur valeur...
[tools/sat.git] / commands / launcher.py
index 537aecbabaf0df364eca0df3de68ed307272893c..aec0ff8eb8c4fa6a08ed0c2fce76bccc8ea02278 100644 (file)
-#!/usr/bin/env python\r
-#-*- coding:utf-8 -*-\r
-#  Copyright (C) 2010-2013  CEA/DEN\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.\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
-import os\r
-import platform\r
-import shutil\r
-import getpass\r
-import subprocess\r
-import stat\r
-\r
-import src\r
-\r
-parser = src.options.Options()\r
-\r
-parser.add_option('n', 'name', 'string', 'name', _('The name of the launcher '\r
-                            '(default is APPLICATION.profile.launcher_name)'))\r
-parser.add_option('c', 'catalog', 'string', 'catalog',\r
-    _('The resources catalog to use'))\r
-parser.add_option('', 'gencat', 'string', 'gencat',\r
-    _("Create a resources catalog for the specified machines "\r
-      "(separated with ',') \n\tNOTICE: this command will ssh to retrieve"\r
-      " information to each machine in the list"))\r
-\r
-def generate_launch_file(config,\r
-                         logger,\r
-                         env_info=None,\r
-                         pathlauncher=None,\r
-                         display=True,\r
-                         additional_env={}):\r
-    '''Generates the launcher file.\r
-    \r
-    :param config Config: The global configuration\r
-    :param logger Logger: The logger instance to use for the display \r
-                          and logging\r
-    :param env_info str: The list of products to add in the files.\r
-    :param pathlauncher str: The path to the launcher to generate\r
-    :param src_root str: The path to the directory where the sources are\r
-    :param display boolean: If False, do not print anything in the terminal\r
-    :param additional_env dict: The dict giving additional \r
-                                environment variables\r
-    :return: The launcher file path.\r
-    :rtype: str\r
-    '''\r
-    # Get the application directory and the profile directory\r
-    out_dir = config.APPLICATION.workdir\r
-    profile = config.APPLICATION.profile\r
-    profile_install_dir = get_profile_dir(config)\r
-    \r
-    # Compute the default launcher path if it is not provided in pathlauncher\r
-    # parameter\r
-    if pathlauncher is None:\r
-        filepath = os.path.join( os.path.join( profile_install_dir,\r
-                                               'bin',\r
-                                               'salome' ),\r
-                                 profile['launcher_name'] )\r
-    else:\r
-        filepath = os.path.join(pathlauncher, profile['launcher_name'])\r
-\r
-    # Remove the file if it exists in order to replace it\r
-    if os.path.exists(filepath):\r
-        os.remove(filepath)\r
-\r
-    # Add the APPLI variable\r
-    additional_env['APPLI'] = filepath\r
-\r
-    # Get the launcher template\r
-    withProfile = src.fileEnviron.withProfile.replace( "PROFILE_INSTALL_DIR",\r
-                                                       profile_install_dir )\r
-    before, after = withProfile.split(\r
-                                "# here your local standalone environment\n")\r
-\r
-    # create an environment file writer\r
-    writer = src.environment.FileEnvWriter(config,\r
-                                           logger,\r
-                                           out_dir,\r
-                                           src_root=None,\r
-                                           env_info=env_info)\r
-\r
-    # Display some information\r
-    if display:\r
-        # Write the launcher file\r
-        logger.write(_("Generating launcher for %s :\n") % \r
-                     src.printcolors.printcLabel(config.VARS.application), 1)\r
-        logger.write("  %s\n" % src.printcolors.printcLabel(filepath), 1)\r
-    \r
-    # open the file and write into it\r
-    launch_file = open(filepath, "w")\r
-    launch_file.write(before)\r
-    # Write\r
-    writer.write_cfgForPy_file(launch_file, additional_env=additional_env)\r
-    launch_file.write(after)\r
-    launch_file.close()\r
-    \r
-    # change the rights in order to make the file executable for everybody\r
-    os.chmod(filepath,\r
-             stat.S_IRUSR |\r
-             stat.S_IRGRP |\r
-             stat.S_IROTH |\r
-             stat.S_IWUSR |\r
-             stat.S_IXUSR |\r
-             stat.S_IXGRP |\r
-             stat.S_IXOTH)\r
-    return filepath\r
-\r
-def generate_launch_link(config,\r
-                         logger,\r
-                         launcherPath,\r
-                         pathlauncher=None,\r
-                         display=True,\r
-                         packageLauncher=False):\r
-    '''Generates the launcher link that sources Python \r
-       and call the actual launcher.\r
-    \r
-    :param config Config: The global configuration\r
-    :param logger Logger: The logger instance to use for the display \r
-                          and logging\r
-    :param launcherPath str: The path to the launcher to call\r
-    :param pathlauncher str: The path to the launcher (link) to generate\r
-    :param display boolean: If False, do not print anything in the terminal\r
-    :param packageLauncher boolean: if True, use a relative path (for package)\r
-    :return: The launcher link file path.\r
-    :rtype: str\r
-    '''\r
-    if pathlauncher is None:\r
-        # Make an executable file that sources python, then launch the launcher\r
-        # produced by generate_launch_file method\r
-        sourceLauncher = os.path.join(config.APPLICATION.workdir,\r
-                                      config.APPLICATION.profile.launcher_name)\r
-    else:\r
-        sourceLauncher = os.path.join(pathlauncher,\r
-                                      config.APPLICATION.profile.launcher_name)\r
-\r
-    # Change the extension for the windows case\r
-    if platform.system() == "Windows" :\r
-            sourceLauncher += '.bat'\r
-\r
-    # display some information\r
-    if display:\r
-        logger.write(_("\nGenerating the executable that sources"\r
-                       " python and runs the launcher :\n") , 1)\r
-        logger.write("  %s\n" %src.printcolors.printcLabel(sourceLauncher), 1)\r
-\r
-    # open the file to write\r
-    f = open(sourceLauncher, "w")\r
-\r
-    # Write the set up of the environment\r
-    if platform.system() == "Windows" :\r
-        shell = 'bat'\r
-    else:\r
-        shell = 'bash'\r
-        \r
-    # Write the Python environment files\r
-    env = src.environment.SalomeEnviron( config, \r
-                        src.fileEnviron.get_file_environ( f, shell, config ) )\r
-    env.set_a_product( "Python", logger)\r
-\r
-    # Write the call to the original launcher\r
-    f.write( "\n\n")\r
-    if packageLauncher:\r
-        cmd = os.path.join('${out_dir_Path}', launcherPath)\r
-    else:\r
-        cmd = launcherPath\r
-\r
-    if platform.system() == "Windows" :\r
-        cmd = 'python ' + cmd + ' %*'\r
-    else:\r
-        cmd = cmd + ' $*'\r
-    \r
-    f.write( cmd )\r
-    f.write( "\n\n")\r
-\r
-    # Write the cleaning of the environment\r
-    env.finish(True)\r
-\r
-    # Close new launcher\r
-    f.close()\r
-    os.chmod(sourceLauncher,\r
-             stat.S_IRUSR |\r
-             stat.S_IRGRP |\r
-             stat.S_IROTH |\r
-             stat.S_IWUSR |\r
-             stat.S_IWGRP |\r
-             stat.S_IWOTH |\r
-             stat.S_IXUSR |\r
-             stat.S_IXGRP |\r
-             stat.S_IXOTH)\r
-    return sourceLauncher\r
-\r
-def generate_catalog(machines, config, logger):\r
-    """Generates an xml catalog file from a list of machines.\r
-    \r
-    :param machines List: The list of machines to add in the catalog   \r
-    :param config Config: The global configuration\r
-    :param logger Logger: The logger instance to use for the display \r
-                          and logging\r
-    :return: The catalog file path.\r
-    :rtype: str\r
-    """\r
-    # remove empty machines\r
-    machines = map(lambda l: l.strip(), machines)\r
-    machines = filter(lambda l: len(l) > 0, machines)\r
-    \r
-    # log something\r
-    src.printcolors.print_value(logger, _("Generate Resources Catalog"),\r
-                                ", ".join(machines), 4)\r
-    \r
-    # The command to execute on each machine in order to get some information\r
-    cmd = '"cat /proc/cpuinfo | grep MHz ; cat /proc/meminfo | grep MemTotal"'\r
-    user = getpass.getuser()\r
-\r
-    # Create the catalog path\r
-    catfile = src.get_tmp_filename(config, "CatalogResources.xml")\r
-    catalog = file(catfile, "w")\r
-    \r
-    # Write into it\r
-    catalog.write("<!DOCTYPE ResourcesCatalog>\n<resources>\n")\r
-    for k in machines:\r
-        logger.write("    ssh %s " % (k + " ").ljust(20, '.'), 4)\r
-        logger.flush()\r
-\r
-        # Verify that the machine is accessible\r
-        ssh_cmd = 'ssh -o "StrictHostKeyChecking no" %s %s' % (k, cmd)\r
-        p = subprocess.Popen(ssh_cmd, shell=True,\r
-                stdin=subprocess.PIPE,\r
-                stdout=subprocess.PIPE,\r
-                stderr=subprocess.PIPE)\r
-        p.wait()\r
-\r
-        if p.returncode != 0: # The machine is not accessible\r
-            logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 4)\r
-            logger.write("    " + \r
-                         src.printcolors.printcWarning(p.stderr.read()), 2)\r
-        else:\r
-            # The machine is accessible, write the corresponding section on\r
-            # the xml file\r
-            logger.write(src.printcolors.printc(src.OK_STATUS) + "\n", 4)\r
-            lines = p.stdout.readlines()\r
-            freq = lines[0][:-1].split(':')[-1].split('.')[0].strip()\r
-            nb_proc = len(lines) -1\r
-            memory = lines[-1].split(':')[-1].split()[0].strip()\r
-            memory = int(memory) / 1000\r
-\r
-            catalog.write("    <machine\n")\r
-            catalog.write("        protocol=\"ssh\"\n")\r
-            catalog.write("        nbOfNodes=\"1\"\n")\r
-            catalog.write("        mode=\"interactif\"\n")\r
-            catalog.write("        OS=\"LINUX\"\n")\r
-            catalog.write("        CPUFreqMHz=\"%s\"\n" % freq)\r
-            catalog.write("        nbOfProcPerNode=\"%s\"\n" % nb_proc)\r
-            catalog.write("        memInMB=\"%s\"\n" % memory)\r
-            catalog.write("        userName=\"%s\"\n" % user)\r
-            catalog.write("        name=\"%s\"\n" % k)\r
-            catalog.write("        hostname=\"%s\"\n" % k)\r
-            catalog.write("    >\n")\r
-            catalog.write("    </machine>\n")\r
-\r
-    catalog.write("</resources>\n")\r
-    catalog.close()\r
-    return catfile\r
-\r
-def copy_catalog(config, catalog_path):\r
-    """Copy the xml catalog file into the right location\r
-    \r
-    :param config Config: The global configuration\r
-    :param catalog_path str: the catalog file path\r
-    :return: The environment dictionary corresponding to the file path.\r
-    :rtype: Dict\r
-    """\r
-    # Verify the existence of the file\r
-    if not os.path.exists(catalog_path):\r
-        raise IOError(_("Catalog not found: %s") % catalog_path)\r
-    # Compute the location where to copy the file\r
-    profile_dir = get_profile_dir(config)\r
-    new_catalog_path = os.path.join(profile_dir, "CatalogResources.xml")\r
-    # Do the copy\r
-    shutil.copy(catalog_path, new_catalog_path)\r
-    additional_environ = {'USER_CATALOG_RESOURCES_FILE' : new_catalog_path}\r
-    return additional_environ\r
-\r
-def get_profile_dir(config):\r
-    """Get the profile directory from the config\r
-    \r
-    :param config Config: The global configuration\r
-    :return: The profile install directory\r
-    :rtype: Str\r
-    """\r
-    profile_name = config.APPLICATION.profile.product\r
-    profile_info = src.product.get_product_config(config, profile_name)\r
-    return profile_info.install_dir\r
-\r
-def finish_profile_install(config, launcherPath):\r
-    """Add some symlinks required for SALOME\r
-    \r
-    :param config Config: The global configuration\r
-    :param launcherPath str: the launcher file path\r
-    """\r
-    # Create a USERS directory\r
-    profile_dir = get_profile_dir(config)\r
-    user_dir = os.path.join(profile_dir, 'USERS')\r
-    if not os.path.exists(user_dir):\r
-        os.makedirs(user_dir)\r
-    # change rights of USERS directory\r
-    os.chmod(user_dir,\r
-             stat.S_IRUSR |\r
-             stat.S_IRGRP |\r
-             stat.S_IROTH |\r
-             stat.S_IWUSR |\r
-             stat.S_IWGRP |\r
-             stat.S_IWOTH |\r
-             stat.S_IXUSR |\r
-             stat.S_IXGRP |\r
-             stat.S_IXOTH)\r
-\r
-    # create a link in root directory to the launcher\r
-    if platform.system() != "Windows" :
-        link_path = os.path.join(config.APPLICATION.workdir, 'salome')\r
-        if not os.path.exists(link_path):\r
-            try:\r
-                os.symlink(launcherPath, link_path)\r
-            except OSError:\r
-                os.remove(link_path)\r
-                os.symlink(launcherPath, link_path)\r
-\r
-        link_path = os.path.join(profile_dir, 'salome')\r
-        if not os.path.exists(link_path):\r
-            try:\r
-                os.symlink(launcherPath, link_path)\r
-            except OSError:\r
-                os.remove(link_path)\r
-                os.symlink(launcherPath, link_path)
-\r
-##################################################\r
-\r
-##\r
-# Describes the command\r
-def description():\r
-    return _("The launcher command generates a salome launcher.")\r
-\r
-##\r
-# Runs the command.\r
-def run(args, runner, logger):\r
-\r
-    # check for product\r
-    (options, args) = parser.parse_args(args)\r
-\r
-    # Verify that the command was called with an application\r
-    src.check_config_has_application( runner.cfg )\r
-    \r
-    # Verify that the APPLICATION section has a profile section\r
-    src.check_config_has_profile( runner.cfg )\r
-\r
-    # Verify that the profile is installed\r
-    if not src.product.check_installation(\r
-                                src.product.get_product_config(\r
-                                    runner.cfg,\r
-                                    runner.cfg.APPLICATION.profile.product)):\r
-        msg = _("The profile of the application is not correctly installed.")\r
-        logger.write(src.printcolors.printcError(msg), 1)\r
-        return 1\r
-\r
-    # Change the name of the file to create \r
-    # if the corresponding option was called\r
-    if options.name:\r
-        runner.cfg.APPLICATION.profile['launcher_name'] = options.name\r
-\r
-    # Copy a catalog if the option is called\r
-    additional_environ = {}\r
-    if options.catalog:\r
-        additional_environ = copy_catalog(runner.cfg, options.catalog)\r
-\r
-    # Generate a catalog of resources if the corresponding option was called\r
-    if options.gencat:\r
-        catalog_path  = generate_catalog(options.gencat.split(","),\r
-                                         runner.cfg,\r
-                                         logger)\r
-        additional_environ = copy_catalog(runner.cfg, catalog_path)\r
-\r
-    # Generate the launcher\r
-    launcherPath = generate_launch_file( runner.cfg,\r
-                                         logger,\r
-                                         additional_env = additional_environ )\r
-\r
-    # Create the link (bash file that sources python and then call \r
-    # the actual launcher) to the launcher\r
-    generate_launch_link( runner.cfg, logger, launcherPath)\r
-\r
-    # Add some links\r
-    finish_profile_install(runner.cfg, launcherPath)\r
-\r
-    return 0\r
+#!/usr/bin/env python
+#-*- coding:utf-8 -*-
+#  Copyright (C) 2010-2013  CEA/DEN
+#
+#  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.
+#
+#  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
+
+import os
+import platform
+import shutil
+import getpass
+import subprocess
+import stat
+
+import src
+import src.debug as DBG
+
+parser = src.options.Options()
+
+parser.add_option('n', 'name', 'string', 'name', _('Optional: The name of the'
+                  ' launcher (default is APPLICATION.profile.launcher_name)'))
+parser.add_option('e', 'exe', 'string', 'path_exe', _('Use this option to generate a launcher which sets'
+                  ' the environment and call the executable given as argument'
+                  ' (its relative path to application workdir, or an exe name present in appli PATH)'))
+parser.add_option('c', 'catalog', 'string', 'catalog',
+                  _('Optional: The resources catalog to use'))
+parser.add_option('', 'gencat', 'string', 'gencat',
+                  _("Optional: Create a resources catalog for the specified machines "
+                  "(separated with ',') \n\tNOTICE: this command will ssh to retrieve"
+                  " information to each machine in the list"))
+parser.add_option('', 'use_mesa', 'boolean', 'use_mesa',
+                  _("Optional: Create a launcher that will use mesa products\n\t"
+                  "It can be usefull whan salome is used on a remote machine through ssh"))
+parser.add_option('', 'no_path_init', 'boolean', 'no_path_init',
+                 _("Optional: Create a launcher that will not reinitilise all path variables\n\t"
+                   "By default only PATH is not reinitialised (its value is inherited from "
+                   "user's environment)\n\tUse no_path_init option to suppress the reinitilisation"
+                   " of every paths (LD_LIBRARY_PATH, PYTHONPATH, ...)"))
+
+
+def generate_launch_file(config,
+                         logger,
+                         launcher_name,
+                         pathlauncher,
+                         path_exe,
+                         display=True,
+                         additional_env={},
+                         no_path_init=False):
+    '''Generates the launcher file.
+    
+    :param config Config: The global configuration
+    :param logger Logger: The logger instance to use for the display 
+                          and logging
+    :param launcher_name str: The name of the launcher to generate
+    :param path_exe str: The executable to use (either a relative path to 
+                         application workdir, or an exe name in the path)
+    :param pathlauncher str: The path to the launcher to generate
+    :param display boolean: If False, do not print anything in the terminal
+    :param additional_env dict: The dict giving additional 
+                                environment variables
+    :return: The launcher file path.
+    :rtype: str
+    '''
+    # build the launcher path, delete it if it exists
+    filepath = os.path.join(pathlauncher, launcher_name)
+    if os.path.exists(filepath):
+        os.remove(filepath)
+    kernel_root_dir=None
+    cmd=None
+    salome_application_name=None
+    app_root_dir=None
+
+    if path_exe:
+        #case of a launcher based upon an executable
+        
+        if os.path.basename(path_exe) != path_exe:
+            # for a relative (to workdir) path 
+            # build absolute path of exe and check it
+            exepath=os.path.join(config.APPLICATION.workdir, path_exe)
+            if not os.path.exists(exepath):
+                raise src.SatException(_("cannot find executable given : %s" % exepath))
+        else:
+            exepath=path_exe 
+
+        # select the shell for the launcher (bast/bat)
+        # and build the command used to launch the exe
+        if src.architecture.is_windows():
+            shell="bat"
+            cmd="\n\nrem Launch exe with user arguments\n%s " % exepath + "%*"
+        else:
+            shell="bash"
+            cmd='\n\n# Launch exe with user arguments\n%s "$*"' % exepath
+
+    else:
+        #case of a salome python2/3 launcher
+        shell="cfgForPy"
+
+        # get KERNEL bin installation path 
+        # (in order for the launcher to get python salomeContext API)
+        kernel_cfg = src.product.get_product_config(config, "KERNEL")
+        if not src.product.check_installation(config, kernel_cfg):
+            raise src.SatException(_("KERNEL is not installed"))
+        kernel_root_dir = kernel_cfg.install_dir
+        # set kernel bin dir (considering fhs property)
+        if src.get_property_in_product_cfg(kernel_cfg, "fhs"):
+            bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin") 
+        else:
+            bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin","salome") 
+
+        # Add two sat variables used by fileEnviron to choose the right launcher header 
+        # and do substitutions
+        additional_env['sat_bin_kernel_install_dir'] = bin_kernel_install_dir
+        if "python3" in config.APPLICATION and config.APPLICATION.python3 == "yes":
+            additional_env['sat_python_version'] = 3
+        else:
+            additional_env['sat_python_version'] = 2
+
+    # check if the application contains an application module
+    l_product_info = src.product.get_products_infos(config.APPLICATION.products.keys(),
+                                                    config)
+    for prod_name, prod_info in l_product_info:
+        # look for a salome application
+        if src.get_property_in_product_cfg(prod_info, "is_salome_application") == "yes":
+            salome_application_name=prod_info.install_dir
+            continue
+
+    # if the application contains an application module, we set ABSOLUTE_APPLI_PATH to it.
+    # if not we set it to KERNEL_INSTALL_DIR, which is sufficient, except for salome test
+    if salome_application_name:
+        app_root_dir=salome_application_name
+    elif kernel_root_dir:
+        app_root_dir=kernel_root_dir
+
+    # Add the APPLI and ABSOLUTE_APPLI_PATH variable
+    additional_env['APPLI'] = filepath
+    if app_root_dir:
+        additional_env['ABSOLUTE_APPLI_PATH'] = app_root_dir
+
+    # create an environment file writer
+    writer = src.environment.FileEnvWriter(config,
+                                           logger,
+                                           pathlauncher,
+                                           src_root=None,
+                                           env_info=None)
+
+    # Display some information
+    if display:
+        # Write the launcher file
+        logger.write(_("Generating launcher for %s :\n") % 
+                     src.printcolors.printcLabel(config.VARS.application), 1)
+        logger.write("  %s\n" % src.printcolors.printcLabel(filepath), 1)
+    
+    # Write the launcher
+    writer.write_env_file(filepath, 
+                          False,  # for launch
+                          shell,
+                          additional_env=additional_env,
+                          no_path_init=no_path_init)
+    
+
+    # ... and append the launch of the exe 
+    if cmd:
+        with open(filepath, "a") as exe_launcher:
+            exe_launcher.write(cmd)
+
+    # change the rights in order to make the file executable for everybody
+    os.chmod(filepath,
+             stat.S_IRUSR |
+             stat.S_IRGRP |
+             stat.S_IROTH |
+             stat.S_IWUSR |
+             stat.S_IXUSR |
+             stat.S_IXGRP |
+             stat.S_IXOTH)
+    return filepath
+
+
+def generate_catalog(machines, config, logger):
+    """Generates an xml catalog file from a list of machines.
+    
+    :param machines List: The list of machines to add in the catalog   
+    :param config Config: The global configuration
+    :param logger Logger: The logger instance to use for the display 
+                          and logging
+    :return: The catalog file path.
+    :rtype: str
+    """
+    # remove empty machines
+    machines = map(lambda l: l.strip(), machines)
+    machines = filter(lambda l: len(l) > 0, machines)
+    
+    # log something
+    src.printcolors.print_value(logger, _("Generate Resources Catalog"),
+                                ", ".join(machines), 4)
+    
+    # The command to execute on each machine in order to get some information
+    cmd = '"cat /proc/cpuinfo | grep MHz ; cat /proc/meminfo | grep MemTotal"'
+    user = getpass.getuser()
+
+    # Create the catalog path
+    catfile = src.get_tmp_filename(config, "CatalogResources.xml")
+    with open(catfile, 'w') as catalog:
+        # Write into it
+        catalog.write("<!DOCTYPE ResourcesCatalog>\n<resources>\n")
+        for k in machines:
+            if not src.architecture.is_windows(): 
+                logger.write("    ssh %s " % (k + " ").ljust(20, '.'), 4)
+                logger.flush()
+
+                # Verify that the machine is accessible
+                ssh_cmd = 'ssh -o "StrictHostKeyChecking no" %s %s' % (k, cmd)
+                p = subprocess.Popen(ssh_cmd, shell=True,
+                        stdin=subprocess.PIPE,
+                        stdout=subprocess.PIPE,
+                        stderr=subprocess.PIPE)
+                p.wait()
+
+                machine_access = (p.returncode == 0) 
+                if not machine_access: # The machine is not accessible
+                    logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 4)
+                    logger.write("    " + 
+                                 src.printcolors.printcWarning(p.stderr.read()), 2)
+                else:
+                    # The machine is accessible, write the corresponding section on
+                    # the xml file
+                    logger.write(src.printcolors.printc(src.OK_STATUS) + "\n", 4)
+                    lines = p.stdout.readlines()
+                    freq = lines[0][:-1].split(':')[-1].split('.')[0].strip()
+                    nb_proc = len(lines) -1
+                    memory = lines[-1].split(':')[-1].split()[0].strip()
+                    memory = int(memory) / 1000
+
+            catalog.write("    <machine\n")
+            catalog.write("        protocol=\"ssh\"\n")
+            catalog.write("        nbOfNodes=\"1\"\n")
+            catalog.write("        mode=\"interactif\"\n")
+            catalog.write("        OS=\"LINUX\"\n")
+
+            if (not src.architecture.is_windows()) and machine_access :
+                catalog.write("        CPUFreqMHz=\"%s\"\n" % freq)
+                catalog.write("        nbOfProcPerNode=\"%s\"\n" % nb_proc)
+                catalog.write("        memInMB=\"%s\"\n" % memory)
+
+            catalog.write("        userName=\"%s\"\n" % user)
+            catalog.write("        name=\"%s\"\n" % k)
+            catalog.write("        hostname=\"%s\"\n" % k)
+            catalog.write("    >\n")
+            catalog.write("    </machine>\n")
+
+        catalog.write("</resources>\n")
+    return catfile
+
+def copy_catalog(config, catalog_path):
+    """Copy the xml catalog file into the right location
+    
+    :param config Config: The global configuration
+    :param catalog_path str: the catalog file path
+    :return: The environment dictionary corresponding to the file path.
+    :rtype: Dict
+    """
+    # Verify the existence of the file
+    if not os.path.exists(catalog_path):
+        raise IOError(_("Catalog not found: %s") % catalog_path)
+    # Get the application directory and copy catalog inside
+    out_dir = config.APPLICATION.workdir
+    new_catalog_path = os.path.join(out_dir, "CatalogResources.xml")
+    # Do the copy
+    if catalog_path != new_catalog_path:
+        shutil.copy(catalog_path, new_catalog_path)
+    additional_environ = {'USER_CATALOG_RESOURCES_FILE' : new_catalog_path}
+    return additional_environ
+
+
+
+##################################################
+
+##
+# Describes the command
+def description():
+    return _("The launcher command generates a SALOME launcher.\n\nexample:"
+             "\nsat launcher SALOME-master")
+
+##
+# Runs the command.
+def run(args, runner, logger):
+
+    # check for product
+    (options, args) = parser.parse_args(args)
+
+    # Verify that the command was called with an application
+    src.check_config_has_application( runner.cfg )
+    
+    # Determine the launcher name (from option, profile section or by default "salome")
+    if options.name:
+        launcher_name = options.name
+    else:
+        launcher_name = src.get_launcher_name(runner.cfg)
+
+    no_path_initialisation=False
+    if options.no_path_init:
+        no_path_initialisation = True
+        
+    # set the launcher path
+    launcher_path = runner.cfg.APPLICATION.workdir
+
+    # Copy a catalog if the option is called
+    additional_environ = {}
+    if options.catalog:
+        additional_environ = copy_catalog(runner.cfg, options.catalog)
+
+    # Generate a catalog of resources if the corresponding option was called
+    if options.gencat:
+        catalog_path  = generate_catalog(options.gencat.split(","),
+                                         runner.cfg,
+                                         logger)
+        additional_environ = copy_catalog(runner.cfg, catalog_path)
+
+    # activate mesa use in the generated launcher
+    if options.use_mesa:
+        src.activate_mesa_property(runner.cfg)
+
+    # option -e has precedence over section profile
+    if not options.path_exe and src.get_launcher_exe(runner.cfg):
+        options.path_exe=src.get_launcher_exe(runner.cfg)
+
+    # Generate the launcher
+    generate_launch_file(runner.cfg,
+                         logger,
+                         launcher_name,
+                         launcher_path,
+                         options.path_exe,
+                         additional_env = additional_environ,
+                         no_path_init = no_path_initialisation )
+
+    return 0