3 # Copyright (C) 2010-2013 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 import src.debug as DBG
29 parser = src.options.Options()
31 parser.add_option('n', 'name', 'string', 'name', _('Optional: The name of the'
32 ' launcher (default is APPLICATION.profile.launcher_name)'))
33 parser.add_option('e', 'exe', 'string', 'path_exe', _('Use this option to generate a launcher which sets'
34 ' the environment and call the executable given as argument'
35 ' (its relative path to application workdir, or an exe name present in appli PATH)'))
36 parser.add_option('c', 'catalog', 'string', 'catalog',
37 _('Optional: The resources catalog to use'))
38 parser.add_option('', 'gencat', 'string', 'gencat',
39 _("Optional: Create a resources catalog for the specified machines "
40 "(separated with ',') \n\tNOTICE: this command will ssh to retrieve"
41 " information to each machine in the list"))
42 parser.add_option('', 'use_mesa', 'boolean', 'use_mesa',
43 _("Optional: Create a launcher that will use mesa products\n\t"
44 "It can be usefull whan salome is used on a remote machine through ssh"))
45 parser.add_option('', 'no_path_init', 'boolean', 'no_path_init',
46 _("Optional: Create a launcher that will not reinitilise all path variables\n\t"
47 "By default only PATH is not reinitialised (its value is inherited from "
48 "user's environment)\n\tUse no_path_init option to suppress the reinitilisation"
49 " of every paths (LD_LIBRARY_PATH, PYTHONPATH, ...)"))
52 def generate_launch_file(config,
60 '''Generates the launcher file.
62 :param config Config: The global configuration
63 :param logger Logger: The logger instance to use for the display
65 :param launcher_name str: The name of the launcher to generate
66 :param path_exe str: The executable to use (either a relative path to
67 application workdir, or an exe name in the path)
68 :param pathlauncher str: The path to the launcher to generate
69 :param display boolean: If False, do not print anything in the terminal
70 :param additional_env dict: The dict giving additional
72 :return: The launcher file path.
75 # build the launcher path, delete it if it exists
76 filepath = os.path.join(pathlauncher, launcher_name)
77 if os.path.exists(filepath):
81 salome_application_name=None
85 #case of a launcher based upon an executable
87 if os.path.basename(path_exe) != path_exe:
88 # for a relative (to workdir) path
89 # build absolute path of exe and check it
90 exepath=os.path.join(config.APPLICATION.workdir, path_exe)
91 if not os.path.exists(exepath):
92 raise src.SatException(_("cannot find executable given : %s" % exepath))
96 # select the shell for the launcher (bast/bat)
97 # and build the command used to launch the exe
98 if src.architecture.is_windows():
100 cmd="\n\nrem Launch exe with user arguments\n%s " % exepath + "%*"
103 cmd='\n\n# Launch exe with user arguments\n%s "$*"' % exepath
106 #case of a salome python2/3 launcher
109 # get KERNEL bin installation path
110 # (in order for the launcher to get python salomeContext API)
111 kernel_cfg = src.product.get_product_config(config, "KERNEL")
112 if not src.product.check_installation(config, kernel_cfg):
113 raise src.SatException(_("KERNEL is not installed"))
114 kernel_root_dir = kernel_cfg.install_dir
115 # set kernel bin dir (considering fhs property)
116 if src.get_property_in_product_cfg(kernel_cfg, "fhs"):
117 bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin")
119 bin_kernel_install_dir = os.path.join(kernel_root_dir,"bin","salome")
121 # Add two sat variables used by fileEnviron to choose the right launcher header
122 # and do substitutions
123 additional_env['sat_bin_kernel_install_dir'] = bin_kernel_install_dir
124 if "python3" in config.APPLICATION and config.APPLICATION.python3 == "yes":
125 additional_env['sat_python_version'] = 3
127 additional_env['sat_python_version'] = 2
129 # check if the application contains an application module
130 l_product_info = src.product.get_products_infos(config.APPLICATION.products.keys(),
132 for prod_name, prod_info in l_product_info:
133 # look for a salome application
134 if src.get_property_in_product_cfg(prod_info, "is_salome_application") == "yes":
135 salome_application_name=prod_info.install_dir
138 # if the application contains an application module, we set ABSOLUTE_APPLI_PATH to it.
139 # if not we set it to KERNEL_INSTALL_DIR, which is sufficient, except for salome test
140 if salome_application_name:
141 app_root_dir=salome_application_name
142 elif kernel_root_dir:
143 app_root_dir=kernel_root_dir
145 # Add the APPLI and ABSOLUTE_APPLI_PATH variable
146 additional_env['APPLI'] = filepath
148 additional_env['ABSOLUTE_APPLI_PATH'] = app_root_dir
150 # create an environment file writer
151 writer = src.environment.FileEnvWriter(config,
157 # Display some information
159 # Write the launcher file
160 logger.write(_("Generating launcher for %s :\n") %
161 src.printcolors.printcLabel(config.VARS.application), 1)
162 logger.write(" %s\n" % src.printcolors.printcLabel(filepath), 1)
165 writer.write_env_file(filepath,
168 additional_env=additional_env,
169 no_path_init=no_path_init)
172 # ... and append the launch of the exe
174 with open(filepath, "a") as exe_launcher:
175 exe_launcher.write(cmd)
177 # change the rights in order to make the file executable for everybody
189 def generate_catalog(machines, config, logger):
190 """Generates an xml catalog file from a list of machines.
192 :param machines List: The list of machines to add in the catalog
193 :param config Config: The global configuration
194 :param logger Logger: The logger instance to use for the display
196 :return: The catalog file path.
199 # remove empty machines
200 machines = map(lambda l: l.strip(), machines)
201 machines = filter(lambda l: len(l) > 0, machines)
204 src.printcolors.print_value(logger, _("Generate Resources Catalog"),
205 ", ".join(machines), 4)
207 # The command to execute on each machine in order to get some information
208 cmd = '"cat /proc/cpuinfo | grep MHz ; cat /proc/meminfo | grep MemTotal"'
209 user = getpass.getuser()
211 # Create the catalog path
212 catfile = src.get_tmp_filename(config, "CatalogResources.xml")
213 with open(catfile, 'w') as catalog:
215 catalog.write("<!DOCTYPE ResourcesCatalog>\n<resources>\n")
217 if not src.architecture.is_windows():
218 logger.write(" ssh %s " % (k + " ").ljust(20, '.'), 4)
221 # Verify that the machine is accessible
222 ssh_cmd = 'ssh -o "StrictHostKeyChecking no" %s %s' % (k, cmd)
223 p = subprocess.Popen(ssh_cmd, shell=True,
224 stdin=subprocess.PIPE,
225 stdout=subprocess.PIPE,
226 stderr=subprocess.PIPE)
229 machine_access = (p.returncode == 0)
230 if not machine_access: # The machine is not accessible
231 logger.write(src.printcolors.printc(src.KO_STATUS) + "\n", 4)
233 src.printcolors.printcWarning(p.stderr.read()), 2)
235 # The machine is accessible, write the corresponding section on
237 logger.write(src.printcolors.printc(src.OK_STATUS) + "\n", 4)
238 lines = p.stdout.readlines()
239 freq = lines[0][:-1].split(':')[-1].split('.')[0].strip()
240 nb_proc = len(lines) -1
241 memory = lines[-1].split(':')[-1].split()[0].strip()
242 memory = int(memory) / 1000
244 catalog.write(" <machine\n")
245 catalog.write(" protocol=\"ssh\"\n")
246 catalog.write(" nbOfNodes=\"1\"\n")
247 catalog.write(" mode=\"interactif\"\n")
248 catalog.write(" OS=\"LINUX\"\n")
250 if (not src.architecture.is_windows()) and machine_access :
251 catalog.write(" CPUFreqMHz=\"%s\"\n" % freq)
252 catalog.write(" nbOfProcPerNode=\"%s\"\n" % nb_proc)
253 catalog.write(" memInMB=\"%s\"\n" % memory)
255 catalog.write(" userName=\"%s\"\n" % user)
256 catalog.write(" name=\"%s\"\n" % k)
257 catalog.write(" hostname=\"%s\"\n" % k)
258 catalog.write(" >\n")
259 catalog.write(" </machine>\n")
261 catalog.write("</resources>\n")
264 def copy_catalog(config, catalog_path):
265 """Copy the xml catalog file into the right location
267 :param config Config: The global configuration
268 :param catalog_path str: the catalog file path
269 :return: The environment dictionary corresponding to the file path.
272 # Verify the existence of the file
273 if not os.path.exists(catalog_path):
274 raise IOError(_("Catalog not found: %s") % catalog_path)
275 # Get the application directory and copy catalog inside
276 out_dir = config.APPLICATION.workdir
277 new_catalog_path = os.path.join(out_dir, "CatalogResources.xml")
279 if catalog_path != new_catalog_path:
280 shutil.copy(catalog_path, new_catalog_path)
281 additional_environ = {'USER_CATALOG_RESOURCES_FILE' : new_catalog_path}
282 return additional_environ
286 ##################################################
289 # Describes the command
291 return _("The launcher command generates a SALOME launcher.\n\nexample:"
292 "\nsat launcher SALOME-master")
296 def run(args, runner, logger):
299 (options, args) = parser.parse_args(args)
301 # Verify that the command was called with an application
302 src.check_config_has_application( runner.cfg )
304 # Determine the launcher name (from option, profile section or by default "salome")
306 launcher_name = options.name
308 launcher_name = src.get_launcher_name(runner.cfg)
310 no_path_initialisation=False
311 if options.no_path_init:
312 no_path_initialisation = True
314 # set the launcher path
315 launcher_path = runner.cfg.APPLICATION.workdir
317 # Copy a catalog if the option is called
318 additional_environ = {}
320 additional_environ = copy_catalog(runner.cfg, options.catalog)
322 # Generate a catalog of resources if the corresponding option was called
324 catalog_path = generate_catalog(options.gencat.split(","),
327 additional_environ = copy_catalog(runner.cfg, catalog_path)
329 # activate mesa use in the generated launcher
331 src.activate_mesa_property(runner.cfg)
333 # option -e has precedence over section profile
334 if not options.path_exe and src.get_launcher_exe(runner.cfg):
335 options.path_exe=src.get_launcher_exe(runner.cfg)
337 # Generate the launcher
338 generate_launch_file(runner.cfg,
343 additional_env = additional_environ,
344 no_path_init = no_path_initialisation )