From 31dfbb5e84868ca4b169d24b8d4794bb3d10b38e Mon Sep 17 00:00:00 2001 From: Christian Van Wambeke Date: Mon, 2 Apr 2018 22:13:30 +0200 Subject: [PATCH] fix class all commands, set as PYCONF, set getParserWithHelp --- commands/application.py | 322 ++++++------ commands/check.py | 148 +++--- commands/clean.py | 226 +++++---- commands/compile.py | 271 +++++----- commands/config.py | 318 ++++++------ commands/config_old.py | 985 ------------------------------------ commands/configure.py | 159 +++--- commands/environ.py | 141 +++--- commands/find_duplicates.py | 315 ++++++------ commands/generate.py | 233 +++++---- commands/init.py | 150 +++--- commands/job.py | 73 ++- commands/jobs.py | 513 ++++++++++--------- commands/launcher.py | 143 +++--- commands/log.py | 379 +++++++------- commands/make.py | 145 +++--- commands/makeinstall.py | 140 ++--- commands/package.py | 598 +++++++++++----------- commands/patch.py | 168 +++--- commands/prepare.py | 261 +++++----- commands/profile.py | 197 ++++---- commands/run.py | 58 ++- commands/script.py | 161 +++--- commands/shell.py | 66 ++- commands/source.py | 171 ++++--- commands/template.py | 280 +++++----- commands/test.py | 463 +++++++++-------- src/compilation.py | 5 +- src/configManager.py | 84 +-- src/environment.py | 6 +- src/product.py | 16 +- src/salomeTools.py | 12 +- src/test_module.py | 12 +- test/test_100_satHelp.py | 6 +- 34 files changed, 3374 insertions(+), 3851 deletions(-) delete mode 100644 commands/config_old.py diff --git a/commands/application.py b/commands/application.py index c372474..6e7626a 100644 --- a/commands/application.py +++ b/commands/application.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,40 +17,183 @@ # 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 stat import sys import shutil import subprocess import getpass +""" from src import ElementTree as etree -import src - -parser = src.options.Options() -parser.add_option( - 'n', 'name', 'string', 'name', - _('Optional: The name of the application (default is APPLICATION.virtual_app.name or ' - 'runAppli)') ) -parser.add_option( - 'c', 'catalog', 'string', 'catalog', - _('Optional: The resources catalog to use') ) -parser.add_option( - 't', 'target', 'string', 'target', - _('Optional: The directory where to create the application (default is ' - 'APPLICATION.workdir)') ) -parser.add_option( - '', 'gencat', 'string', 'gencat', - _("""\ + +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The application command creates a SALOME application. + + WARNING: + It works only for SALOME 6. + Use the 'launcher' command for newer versions of SALOME + + examples: + >> sat application SALOME-6.6.0 + """ + + name = "application" + + def getParser(self): + """Define all options for command 'sat application '""" + parser = self.getParserWithHelp() + parser.add_option('n', 'name', 'string', 'name', + _("""\ +Optional: The name of the application + (default is APPLICATION.virtual_app.name or runAppli)""") ) + parser.add_option('c', 'catalog', 'string', 'catalog', + _('Optional: The resources catalog to use') ) + parser.add_option('t', 'target', 'string', 'target', + _("""\ +Optional: The directory where to create the application + (default is APPLICATION.workdir)""") ) + parser.add_option('', 'gencat', 'string', 'gencat', + _("""\ Optional: Create a resources catalog for the specified machines (separated with ',') +NOTICE: this command will ssh to retrieve information to each machine in the list""") ) + parser.add_option('m', 'module', 'list2', 'modules', + _("Optional: the restricted list of module(s) to include in the application") ) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat application '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check for product + src.check_config_has_application( runner.cfg ) + + application = src.printcolors.printcLabel(runner.cfg.VARS.application) + logger.write(_("Building application for %s\n") % application, 1) + + # if section APPLICATION.virtual_app does not exists create one + if "virtual_app" not in runner.cfg.APPLICATION: + msg = _("The section APPLICATION.virtual_app is not defined in the product.") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # get application dir + target_dir = runner.cfg.APPLICATION.workdir + if options.target: + target_dir = options.target + + # set list of modules + if options.modules: + runner.cfg.APPLICATION.virtual_app['modules'] = options.modules + + # set name and application_name + if options.name: + runner.cfg.APPLICATION.virtual_app['name'] = options.name + runner.cfg.APPLICATION.virtual_app['application_name'] = options.name + "_appdir" + + application_name = src.get_cfg_param(runner.cfg.APPLICATION.virtual_app, + "application_name", + runner.cfg.APPLICATION.virtual_app.name + "_appdir") + appli_dir = os.path.join(target_dir, application_name) + + src.printcolors.print_value(logger, + _("Application directory"), + appli_dir, + 3) + + # get catalog + catalog, catalog_src = "", "" + if options.catalog: + # use catalog specified in the command line + catalog = options.catalog + elif options.gencat: + # generate catalog for given list of computers + catalog_src = options.gencat + catalog = generate_catalog(options.gencat.split(","), + runner.cfg,logger) + elif 'catalog' in runner.cfg.APPLICATION.virtual_app: + # use catalog specified in the product + if runner.cfg.APPLICATION.virtual_app.catalog.endswith(".xml"): + # catalog as a file + catalog = runner.cfg.APPLICATION.virtual_app.catalog + else: + # catalog as a list of computers + catalog_src = runner.cfg.APPLICATION.virtual_app.catalog + mlist = filter(lambda l: len(l.strip()) > 0, + runner.cfg.APPLICATION.virtual_app.catalog.split(",")) + if len(mlist) > 0: + catalog = generate_catalog(runner.cfg.APPLICATION.virtual_app.catalog.split(","), + runner.cfg, logger) + + # display which catalog is used + if len(catalog) > 0: + catalog = os.path.realpath(catalog) + if len(catalog_src) > 0: + src.printcolors.print_value(logger, + _("Resources Catalog"), + catalog_src, + 3) + else: + src.printcolors.print_value(logger, + _("Resources Catalog"), + catalog, + 3) + + logger.write("\n", 3, False) + + details = [] + + # remove previous application + if os.path.exists(appli_dir): + write_step(logger, _("Removing previous application directory")) + rres = src.KO_STATUS + try: + shutil.rmtree(appli_dir) + rres = src.OK_STATUS + finally: + logger.write(src.printcolors.printc(rres) + "\n", 3, False) + + # generate the application + try: + try: # try/except/finally not supported in all version of python + retcode = create_application(runner.cfg, appli_dir, catalog, logger) + except Exception as exc: + details.append(str(exc)) + raise + finally: + logger.write("\n", 3, False) + + return RCO.ReturnCode("OK") + - NOTICE: this command will ssh to retrieve information to each machine in the list""") ) -parser.add_option( - 'm', 'module', 'list2', 'modules', - _("Optional: the restricted list of module(s) to include in the " - "application") ) -## # Creates an alias for runAppli. def make_alias(appli_path, alias_path, force=False): assert len(alias_path) > 0, "Bad name for alias" @@ -376,133 +520,3 @@ def generate_catalog(machines, config, logger): catalog.close() return catfile -################################################## - -## -# Describes the command -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the application command description. - :rtype: str - ''' - return _("""\ -The application command creates a SALOME application. - -WARNING: - It works only for SALOME 6. - Use the 'launcher' command for newer versions of SALOME - -example: ->> sat application SALOME-6.6.0""") - -## -# Runs the command. -def run(args, runner, logger): - '''method that is called when salomeTools is called with application - parameter. - ''' - - (options, args) = parser.parse_args(args) - - # check for product - src.check_config_has_application( runner.cfg ) - - application = src.printcolors.printcLabel(runner.cfg.VARS.application) - logger.write(_("Building application for %s\n") % application, 1) - - # if section APPLICATION.virtual_app does not exists create one - if "virtual_app" not in runner.cfg.APPLICATION: - msg = _("The section APPLICATION.virtual_app is not defined in the product.") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # get application dir - target_dir = runner.cfg.APPLICATION.workdir - if options.target: - target_dir = options.target - - # set list of modules - if options.modules: - runner.cfg.APPLICATION.virtual_app['modules'] = options.modules - - # set name and application_name - if options.name: - runner.cfg.APPLICATION.virtual_app['name'] = options.name - runner.cfg.APPLICATION.virtual_app['application_name'] = options.name + "_appdir" - - application_name = src.get_cfg_param(runner.cfg.APPLICATION.virtual_app, - "application_name", - runner.cfg.APPLICATION.virtual_app.name + "_appdir") - appli_dir = os.path.join(target_dir, application_name) - - src.printcolors.print_value(logger, - _("Application directory"), - appli_dir, - 3) - - # get catalog - catalog, catalog_src = "", "" - if options.catalog: - # use catalog specified in the command line - catalog = options.catalog - elif options.gencat: - # generate catalog for given list of computers - catalog_src = options.gencat - catalog = generate_catalog(options.gencat.split(","), - runner.cfg,logger) - elif 'catalog' in runner.cfg.APPLICATION.virtual_app: - # use catalog specified in the product - if runner.cfg.APPLICATION.virtual_app.catalog.endswith(".xml"): - # catalog as a file - catalog = runner.cfg.APPLICATION.virtual_app.catalog - else: - # catalog as a list of computers - catalog_src = runner.cfg.APPLICATION.virtual_app.catalog - mlist = filter(lambda l: len(l.strip()) > 0, - runner.cfg.APPLICATION.virtual_app.catalog.split(",")) - if len(mlist) > 0: - catalog = generate_catalog(runner.cfg.APPLICATION.virtual_app.catalog.split(","), - runner.cfg, logger) - - # display which catalog is used - if len(catalog) > 0: - catalog = os.path.realpath(catalog) - if len(catalog_src) > 0: - src.printcolors.print_value(logger, - _("Resources Catalog"), - catalog_src, - 3) - else: - src.printcolors.print_value(logger, - _("Resources Catalog"), - catalog, - 3) - - logger.write("\n", 3, False) - - details = [] - - # remove previous application - if os.path.exists(appli_dir): - write_step(logger, _("Removing previous application directory")) - rres = src.KO_STATUS - try: - shutil.rmtree(appli_dir) - rres = src.OK_STATUS - finally: - logger.write(src.printcolors.printc(rres) + "\n", 3, False) - - # generate the application - try: - try: # try/except/finally not supported in all version of python - retcode = create_application(runner.cfg, appli_dir, catalog, logger) - except Exception as exc: - details.append(str(exc)) - raise - finally: - logger.write("\n", 3, False) - - return retcode - diff --git a/commands/check.py b/commands/check.py index feaac84..d2b2b1e 100644 --- a/commands/check.py +++ b/commands/check.py @@ -1,6 +1,7 @@ #!/usr/bin/env python + #-*- coding:utf-8 -*- -# Copyright (C) 2010-2012 CEA/DEN +# Copyright (C) 2010-2018 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,17 +17,92 @@ # 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 src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand -import src +CHECK_PROPERTY = "has_unit_tests" -# Define all possible option for the check command : sat check -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to configure.\n' - 'This option can be passed several time to configure several products.')) +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The check command executes the 'check' command in the build directory of + all the products of the application. + It is possible to reduce the list of products to check + by using the --products option + + examples: + >> sat check SALOME --products KERNEL,GUI,GEOM + """ + + name = "check" + + def getParser(self): + """Define all options for the check command 'sat check '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _("""\ +Optional: products to configure. + This option can be passed several time to configure several products.""")) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat check '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) + + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + # Print some informations + logger.write(_('Executing the check command in the build ' + 'directories of the application %s\n') % \ + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + info = [(_("BUILD directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] + src.print_info(logger, info) + + # Call the function that will loop over all the products and execute + # the right command(s) + res = check_all_products(runner.cfg, products_infos, logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nCheck: %(status)s (%(1)d/%(2)d)\n") % \ + { 'status': src.printcolors.printc(final_status), + '1': nb_products - res, + '2': nb_products }, 1) + + return res -CHECK_PROPERTY = "has_unit_tests" def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from @@ -194,57 +270,3 @@ WARNING: The product %(name)s is defined as having tests. return res -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the check command description. - :rtype: str - ''' - return _("""\ -The check command executes the 'check' command in the build directory of -all the products of the application. -It is possible to reduce the list of products to check -by using the --products option - -example: ->> sat check SALOME-master --products KERNEL,GUI,GEOM""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with check parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - # Print some informations - logger.write(_('Executing the check command in the build ' - 'directories of the application %s\n') % \ - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - info = [(_("BUILD directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] - src.print_info(logger, info) - - # Call the function that will loop over all the products and execute - # the right command(s) - res = check_all_products(runner.cfg, products_infos, logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nCheck: %(status)s (%(1)d/%(2)d)\n") % \ - { 'status': src.printcolors.printc(final_status), - '1': nb_products - res, - '2': nb_products }, 1) - - return res diff --git a/commands/clean.py b/commands/clean.py index 26415bf..570a1c2 100644 --- a/commands/clean.py +++ b/commands/clean.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -18,7 +19,6 @@ import re -import src import src.debug as DBG import src.returnCode as RCO from src.salomeTools import _BaseCommand @@ -32,6 +32,122 @@ except NameError: PROPERTY_EXPRESSION = "^.+:.+$" +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The clean command suppresses the source, build, or install directories + of the application products. + Use the options to define what directories you want to suppress and + to reduce the list of products + + examples: + >> sat clean SALOME --build --install --properties is_salome_module:yes + """ + + name = "clean" + + def getParser(self): + """Define all options for the command 'sat clean '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: Products to clean. This option can be' + ' passed several time to clean several products.')) + parser.add_option('', 'properties', 'string', 'properties', + _('Optional: Filter the products by their properties.\n' + '\tSyntax: --properties :')) + parser.add_option('s', 'sources', 'boolean', 'sources', + _("Optional: Clean the product source directories.")) + parser.add_option('b', 'build', 'boolean', 'build', + _("Optional: Clean the product build directories.")) + parser.add_option('i', 'install', 'boolean', 'install', + _("Optional: Clean the product install directories.")) + parser.add_option('a', 'all', 'boolean', 'all', + _("Optional: Clean the product source, build and install directories.")) + parser.add_option('', 'sources_without_dev', 'boolean', 'sources_without_dev', + _("Optional: do not clean the products in development mode.")) + return parser + + + def run(self, cmd_arguments): + """method called for command 'sat clean '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( config ) + + # Verify the --properties option + if options.properties: + oExpr = re.compile(PROPERTY_EXPRESSION) + if not oExpr.search(options.properties): + msg = _('WARNING: the "--properties" options must have the ' + 'following syntax:\n--properties :') + logger.write(src.printcolors.printcWarning(msg), 1) + logger.write("\n", 1) + options.properties = None + + + # Get the list of products to threat + products_infos = self.get_products_list(options, config, logger) + + # Construct the list of directories to suppress + l_dir_to_suppress = [] + if options.all: + l_dir_to_suppress += (get_source_directories(products_infos, + options.sources_without_dev) + + get_build_directories(products_infos) + + get_install_directories(products_infos)) + else: + if options.install: + l_dir_to_suppress += get_install_directories(products_infos) + + if options.build: + l_dir_to_suppress += get_build_directories(products_infos) + + if options.sources or options.sources_without_dev: + l_dir_to_suppress += get_source_directories(products_infos, + options.sources_without_dev) + + if len(l_dir_to_suppress) == 0: + logger.write(src.printcolors.printcWarning(_("Nothing to suppress\n"))) + sat_command = (config.VARS.salometoolsway + + config.VARS.sep + + "sat -h clean") + logger.write(_("Please specify what you want to suppress: tap '%s'\n") % sat_command) + return RCO.ReturnCode("KO", "specify what you want to suppress") + + # Check with the user if he really wants to suppress the directories + if not runner.options.batch: + logger.write(_("Remove the following directories ?\n"), 1) + for directory in l_dir_to_suppress: + logger.write(" %s\n" % directory, 1) + rep = input(_("Are you sure you want to continue? [Yes/No] ")) + if rep.upper() != _("YES"): + return RCO.ReturnCode("OK", "user do not want to continue") + + # Suppress the list of paths + suppress_directories(l_dir_to_suppress, logger) + + return RCO.ReturnCode("OK", "clean done") + def get_source_directories(products_infos, without_dev): '''Returns the list of directory source paths corresponding to the list of @@ -115,111 +231,3 @@ def suppress_directories(l_paths, logger): path.rm() logger.write('%s\n' % src.printcolors.printc(src.OK_STATUS), 3) - -######################################################################## -# Command class for command 'sat config etc.' -######################################################################## -class Command(_BaseCommand): - - def getParser(self): - # Define all possible option for the clean command : sat clean - parser = src.options.Options() - parser.add_option('p', 'products', 'list2', 'products', - _('Optional: Products to clean. This option can be' - ' passed several time to clean several products.')) - parser.add_option('', 'properties', 'string', 'properties', - _('Optional: Filter the products by their properties.\n' - '\tSyntax: --properties :')) - parser.add_option('s', 'sources', 'boolean', 'sources', - _("Optional: Clean the product source directories.")) - parser.add_option('b', 'build', 'boolean', 'build', - _("Optional: Clean the product build directories.")) - parser.add_option('i', 'install', 'boolean', 'install', - _("Optional: Clean the product install directories.")) - parser.add_option('a', 'all', 'boolean', 'all', - _("Optional: Clean the product source, build and install directories.")) - parser.add_option('', 'sources_without_dev', 'boolean', 'sources_without_dev', - _("Optional: do not clean the products in development mode.")) - return parser - - def description(self): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the clean command description. - :rtype: str - ''' - return _("""\ - The clean command suppress the source, build, or install directories - of the application products. - Use the options to define what directories you want to suppress and - to reduce the list of products - - example: - >> sat clean SALOME-master --build --install --properties is_salome_module:yes""") - - def run(self, args): - '''method that is called when salomeTools is called with clean parameter. - ''' - runner = self.getRunner() - config = self.getConfig() - logger = self.getLogger() - - # Parse the options - (options, argsc) = self.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( config ) - - # Verify the --properties option - if options.properties: - oExpr = re.compile(PROPERTY_EXPRESSION) - if not oExpr.search(options.properties): - msg = _('WARNING: the "--properties" options must have the ' - 'following syntax:\n--properties :') - logger.write(src.printcolors.printcWarning(msg), 1) - logger.write("\n", 1) - options.properties = None - - - # Get the list of products to threat - products_infos = self.get_products_list(options, config, logger) - - # Construct the list of directories to suppress - l_dir_to_suppress = [] - if options.all: - l_dir_to_suppress += (get_source_directories(products_infos, - options.sources_without_dev) + - get_build_directories(products_infos) + - get_install_directories(products_infos)) - else: - if options.install: - l_dir_to_suppress += get_install_directories(products_infos) - - if options.build: - l_dir_to_suppress += get_build_directories(products_infos) - - if options.sources or options.sources_without_dev: - l_dir_to_suppress += get_source_directories(products_infos, - options.sources_without_dev) - - if len(l_dir_to_suppress) == 0: - logger.write(src.printcolors.printcWarning(_("Nothing to suppress\n"))) - sat_command = (config.VARS.salometoolsway + - config.VARS.sep + - "sat -h clean") - logger.write(_("Please specify what you want to suppress: tap '%s'\n") % sat_command) - return RCO.ReturnCode("KO", "specify what you want to suppress") - - # Check with the user if he really wants to suppress the directories - if not runner.options.batch: - logger.write(_("Remove the following directories ?\n"), 1) - for directory in l_dir_to_suppress: - logger.write(" %s\n" % directory, 1) - rep = input(_("Are you sure you want to continue? [Yes/No] ")) - if rep.upper() != _("YES"): - return RCO.ReturnCode("OK", "user do not want to continue") - - # Suppress the list of paths - suppress_directories(l_dir_to_suppress, logger) - - return RCO.ReturnCode("OK", "clean done") diff --git a/commands/compile.py b/commands/compile.py index 72fabf0..3af9d59 100644 --- a/commands/compile.py +++ b/commands/compile.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,9 +17,12 @@ # 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 src +import os +import src.debug as DBG +import src.returnCode as RCO +import src.pyconf as PYCONF +from src.salomeTools import _BaseCommand # Compatibility python 2/3 for input function # input stays input for python 3 and input = raw_input for python 2 @@ -27,46 +31,145 @@ try: except NameError: pass -# Define all possible option for the compile command : sat compile -parser = src.options.Options() -parser.add_option( - 'p', 'products', 'list2', 'products', - _('Optional: products to configure. This option can be passed several time to configure several products.')) -parser.add_option( - '', 'with_fathers', 'boolean', 'fathers', - _("Optional: build all necessary products to the given product (KERNEL is build before building GUI)."), - False) -parser.add_option( - '', 'with_children', 'boolean', 'children', - _("Optional: build all products using the given product (all SMESH plugins are build after SMESH)."), - False) -parser.add_option( - '', 'clean_all', 'boolean', 'clean_all', - _("Optional: clean BUILD dir and INSTALL dir before building product."), - False) -parser.add_option( - '', 'clean_install', 'boolean', 'clean_install', - _("Optional: clean INSTALL dir before building product."), False) -parser.add_option( - '', 'make_flags', 'string', 'makeflags', - _("Optional: add extra options to the 'make' command.")) -parser.add_option( - '', 'show', 'boolean', 'no_compile', - _("Optional: DO NOT COMPILE just show if products are installed or not."), - False) -parser.add_option( - '', 'stop_first_fail', 'boolean', 'stop_first_fail', _( - "Optional: Stops the command at first product compilation fail."), - False) -parser.add_option( - '', 'check', 'boolean', 'check', - _("Optional: execute the unit tests after compilation"), - False) -parser.add_option( - '', 'clean_build_after', 'boolean', 'clean_build_after', - _('Optional: remove the build directory after successful compilation'), - False) +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The compile command constructs the products of the application + + examples: + >> sat compile SALOME --products KERNEL,GUI,MEDCOUPLING --clean_all + """ + + name = "compile" + + def getParser(self): + """Define all options for the command 'sat compile '""" + parser = self.getParserWithHelp() + parser.add_option( + 'p', 'products', 'list2', 'products', + _('Optional: products to configure. This option can be passed several time to configure several products.')) + parser.add_option( + '', 'with_fathers', 'boolean', 'fathers', + _("Optional: build all necessary products to the given product (KERNEL is build before building GUI)."), + False) + parser.add_option( + '', 'with_children', 'boolean', 'children', + _("Optional: build all products using the given product (all SMESH plugins are build after SMESH)."), + False) + parser.add_option( + '', 'clean_all', 'boolean', 'clean_all', + _("Optional: clean BUILD dir and INSTALL dir before building product."), + False) + parser.add_option( + '', 'clean_install', 'boolean', 'clean_install', + _("Optional: clean INSTALL dir before building product."), False) + parser.add_option( + '', 'make_flags', 'string', 'makeflags', + _("Optional: add extra options to the 'make' command.")) + parser.add_option( + '', 'show', 'boolean', 'no_compile', + _("Optional: DO NOT COMPILE just show if products are installed or not."), + False) + parser.add_option( + '', 'stop_first_fail', 'boolean', 'stop_first_fail', _( + "Optional: Stops the command at first product compilation fail."), + False) + parser.add_option( + '', 'check', 'boolean', 'check', + _("Optional: execute the unit tests after compilation"), + False) + parser.add_option( + '', 'clean_build_after', 'boolean', 'clean_build_after', + _('Optional: remove the build directory after successful compilation'), + False) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat compile '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + # Warn the user if he invoked the clean_all option + # without --products option + if (options.clean_all and + options.products is None and + not runner.options.batch): + rep = input(_("You used --clean_all without specifying a product" + " are you sure you want to continue? [Yes/No] ")) + if rep.upper() != _("YES").upper(): + return 0 + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) + + # Print some informations + logger.write(_('Executing the compile commands in the build ' + 'directories of the products of the application %s\n') % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + info = [ + (_("SOURCE directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'SOURCES')), + (_("BUILD directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD')) + ] + src.print_info(logger, info) + + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + if options.fathers: + # Extend the list with all recursive dependencies of the given products + products_infos = extend_with_fathers(runner.cfg, products_infos) + + if options.children: + # Extend the list with all products that use the given products + products_infos = extend_with_children(runner.cfg, products_infos) + + # Sort the list regarding the dependencies of the products + products_infos = sort_products(runner.cfg, products_infos) + + + # Call the function that will loop over all the products and execute + # the right command(s) + res = compile_all_products(runner, runner.cfg, options, products_infos, logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nCompilation: %(status)s (%(1)d/%(2)d)\n") % + { 'status': src.printcolors.printc(final_status), + '1': nb_products - res, + '2': nb_products }, 1) + + code = res + if code != 0: + code = 1 + return code + + def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from configuration regarding the passed options. @@ -444,7 +547,7 @@ def compile_product(sat, p_name_info, config, options, logger, header, len_end): p_name, p_info = p_name_info - # Get the build procedure from the product configuration. + # Get the build procedure from the product configuration. # It can be : # build_sources : autotools -> build_configure, configure, make, make install # build_sources : cmake -> cmake, make, make install @@ -618,11 +721,11 @@ def add_compile_config_file(p_info, config): :param config Config: The global configuration ''' # Create the compile config - compile_cfg = src.pyconf.Config() + compile_cfg = PYCONF.Config() for prod_name in p_info.depend: if prod_name not in compile_cfg: compile_cfg.addMapping(prod_name, - src.pyconf.Mapping(compile_cfg), + PYCONF.Mapping(compile_cfg), "") prod_dep_info = src.product.get_product_config(config, prod_name, False) compile_cfg[prod_name] = prod_dep_info.version @@ -632,83 +735,3 @@ def add_compile_config_file(p_info, config): compile_cfg.__save__(f) f.close() -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the compile command description. - :rtype: str - ''' - return _("""\ -The compile command constructs the products of the application - -example: ->> sat compile SALOME-master --products KERNEL,GUI,MEDCOUPLING --clean_all""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with compile parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # Warn the user if he invoked the clean_all option - # without --products option - if (options.clean_all and - options.products is None and - not runner.options.batch): - rep = input(_("You used --clean_all without specifying a product" - " are you sure you want to continue? [Yes/No] ")) - if rep.upper() != _("YES").upper(): - return 0 - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Print some informations - logger.write(_('Executing the compile commands in the build ' - 'directories of the products of the application %s\n') % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - info = [ - (_("SOURCE directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'SOURCES')), - (_("BUILD directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD')) - ] - src.print_info(logger, info) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - if options.fathers: - # Extend the list with all recursive dependencies of the given products - products_infos = extend_with_fathers(runner.cfg, products_infos) - - if options.children: - # Extend the list with all products that use the given products - products_infos = extend_with_children(runner.cfg, products_infos) - - # Sort the list regarding the dependencies of the products - products_infos = sort_products(runner.cfg, products_infos) - - - # Call the function that will loop over all the products and execute - # the right command(s) - res = compile_all_products(runner, runner.cfg, options, products_infos, logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nCompilation: %(status)s (%(1)d/%(2)d)\n") % - { 'status': src.printcolors.printc(final_status), - '1': nb_products - res, - '2': nb_products }, 1) - - code = res - if code != 0: - code = 1 - return code diff --git a/commands/config.py b/commands/config.py index 07c2cf2..dc05d84 100644 --- a/commands/config.py +++ b/commands/config.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,23 +17,14 @@ # 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 datetime -import shutil -import sys""" -import src import src.debug as DBG -import src.loggingSat as LOG import src.returnCode as RCO from src.salomeTools import _BaseCommand -import src.configManager as CFGMGR - ######################################################################## -# Command class for command 'sat config etc.' +# Command class ######################################################################## class Command(_BaseCommand): """\ @@ -51,10 +43,8 @@ class Command(_BaseCommand): name = "config" def getParser(self): - # Define all possible option for config command : sat config - parser = src.options.Options() - parser.add_option('h', 'help', 'boolean', 'help', - _("shows help on command.")) + """Define all options for command 'sat config '""" + parser = self.getParserWithHelp() parser.add_option('v', 'value', 'string', 'value', _("Optional: print the value of CONFIG_VARIABLE.")) parser.add_option('d', 'debug', 'string', 'debug', @@ -80,158 +70,158 @@ class Command(_BaseCommand): return parser def run(self, cmd_arguments): - """method that is called when salomeTools is called with config parameter.""" - argList = self.assumeAsList(cmd_arguments) + """method called for command 'sat config '""" + argList = self.assumeAsList(cmd_arguments) - # print general help and returns - if len(argList) == 0: - self.print_help() - return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) - - self._options, remaindersArgs = self.parseArguments(argList) + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) - if self._options.help: - self.print_help() - return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) - - # shortcuts - runner = self.getRunner() - config = self.getConfig() - logger = self.getLogger() - options = self.getOptions() - - # Only useful for completion mechanism : print the keys of the config - if options.schema: - get_config_children(config, args) - return RCO.ReturnCode("OK", "completion mechanism") - - # case : print a value of the config - if options.value: - if options.value == ".": - # if argument is ".", print all the config - for val in sorted(config.keys()): - print_value(config, val, not options.no_label, logger) - else: - print_value(config, options.value, not options.no_label, logger, - level=0, show_full_path=False) + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() - if options.debug: - print_debug(config, str(options.debug), not options.no_label, logger, - level=0, show_full_path=False) - - # case : edit user pyconf file or application file - elif options.edit: - editor = config.USER.editor - if ('APPLICATION' not in config and - 'open_application' not in config): # edit user pyconf - usercfg = os.path.join(config.VARS.personalDir, 'SAT.pyconf') - logger.write(_("Opening %s\n") % usercfg, 3) - src.system.show_in_editor(editor, usercfg, logger) - else: - # search for file .pyconf and open it - for path in config.PATHS.APPLICATIONPATH: - pyconf_path = os.path.join(path, config.VARS.application + ".pyconf") - if os.path.exists(pyconf_path): - logger.write(_("Opening %s\n") % pyconf_path, 3) - src.system.show_in_editor(editor, pyconf_path, logger) - break - - # case : give information about the product in parameter - elif options.info: - src.check_config_has_application(config) - if options.info in config.APPLICATION.products: - show_product_info(config, options.info, logger) - return RCO.ReturnCode("OK", "options.info") - raise src.SatException( - _("%(product_name)s is not a product of %(application_name)s.") % \ - {'product_name' : options.info, 'application_name' : config.VARS.application} ) - - # case : copy an existing .pyconf - # to ~/.salomeTools/Applications/LOCAL_.pyconf - elif options.copy: - # product is required - src.check_config_has_application( config ) - - # get application file path - source = config.VARS.application + '.pyconf' - source_full_path = "" - for path in config.PATHS.APPLICATIONPATH: - # ignore personal directory - if path == config.VARS.personalDir: - continue - # loop on all directories that can have pyconf applications - zz = os.path.join(path, source) - if os.path.exists(zz): - source_full_path = zz - break - - if len(source_full_path) == 0: - raise src.SatException( - _("Config file for product %s not found\n") % source ) - else: - if len(args) > 0: - # a name is given as parameter, use it - dest = args[0] - elif 'copy_prefix' in config.INTERNAL.config: - # use prefix - dest = (config.INTERNAL.config.copy_prefix - + config.VARS.application) - else: - # use same name as source - dest = config.VARS.application - - # the full path - dest_file = os.path.join( - config.VARS.personalDir, 'Applications', dest + '.pyconf' ) - if os.path.exists(dest_file): - raise src.SatException( - _("A personal application '%s' already exists") % dest ) - - # perform the copy - shutil.copyfile(source_full_path, dest_file) - logger.write(_("%s has been created.\n") % dest_file) - - # case : display all the available pyconf applications - elif options.list: - lproduct = list() - # search in all directories that can have pyconf applications - for path in config.PATHS.APPLICATIONPATH: - # print a header - if not options.no_label: - logger.write("------ %s\n" % src.printcolors.printcHeader(path)) - - if not os.path.exists(path): - logger.write(src.printcolors.printcError( - _("Directory not found")) + "\n" ) - else: - for f in sorted(os.listdir(path)): - # ignore file that does not ends with .pyconf - if not f.endswith('.pyconf'): - continue - - appliname = f[:-len('.pyconf')] - if appliname not in lproduct: - lproduct.append(appliname) - if path.startswith(config.VARS.personalDir) \ - and not options.no_label: - logger.write("%s*\n" % appliname) - else: - logger.write("%s\n" % appliname) - - logger.write("\n") + # Only useful for completion mechanism : print the keys of the config + if options.schema: + get_config_children(config, args) + return RCO.ReturnCode("OK", "completion mechanism") + + # case : print a value of the config + if options.value: + if options.value == ".": + # if argument is ".", print all the config + for val in sorted(config.keys()): + print_value(config, val, not options.no_label, logger) + else: + print_value(config, options.value, not options.no_label, logger, + level=0, show_full_path=False) - # case : give a synthetic view of all patches used in the application - elif options.show_patchs: - src.check_config_has_application(config) - # Print some informations - logger.write(_('Show the patchs of application %s\n') % \ - src.printcolors.printcLabel(config.VARS.application), 3) - logger.write("\n", 2, False) - show_patchs(config, logger) - - # case: print all the products name of the application (internal use for completion) - elif options.completion: - for product_name in config.APPLICATION.products.keys(): - logger.write("%s\n" % product_name) + if options.debug: + print_debug(config, str(options.debug), not options.no_label, logger, + level=0, show_full_path=False) + + # case : edit user pyconf file or application file + elif options.edit: + editor = config.USER.editor + if ('APPLICATION' not in config and + 'open_application' not in config): # edit user pyconf + usercfg = os.path.join(config.VARS.personalDir, 'SAT.pyconf') + logger.write(_("Opening %s\n") % usercfg, 3) + src.system.show_in_editor(editor, usercfg, logger) + else: + # search for file .pyconf and open it + for path in config.PATHS.APPLICATIONPATH: + pyconf_path = os.path.join(path, config.VARS.application + ".pyconf") + if os.path.exists(pyconf_path): + logger.write(_("Opening %s\n") % pyconf_path, 3) + src.system.show_in_editor(editor, pyconf_path, logger) + break + + # case : give information about the product in parameter + elif options.info: + src.check_config_has_application(config) + if options.info in config.APPLICATION.products: + show_product_info(config, options.info, logger) + return RCO.ReturnCode("OK", "options.info") + raise src.SatException( + _("%(product_name)s is not a product of %(application_name)s.") % \ + {'product_name' : options.info, 'application_name' : config.VARS.application} ) + + # case : copy an existing .pyconf + # to ~/.salomeTools/Applications/LOCAL_.pyconf + elif options.copy: + # product is required + src.check_config_has_application( config ) + + # get application file path + source = config.VARS.application + '.pyconf' + source_full_path = "" + for path in config.PATHS.APPLICATIONPATH: + # ignore personal directory + if path == config.VARS.personalDir: + continue + # loop on all directories that can have pyconf applications + zz = os.path.join(path, source) + if os.path.exists(zz): + source_full_path = zz + break + + if len(source_full_path) == 0: + raise src.SatException( + _("Config file for product %s not found\n") % source ) + else: + if len(args) > 0: + # a name is given as parameter, use it + dest = args[0] + elif 'copy_prefix' in config.INTERNAL.config: + # use prefix + dest = (config.INTERNAL.config.copy_prefix + + config.VARS.application) + else: + # use same name as source + dest = config.VARS.application + + # the full path + dest_file = os.path.join( + config.VARS.personalDir, 'Applications', dest + '.pyconf' ) + if os.path.exists(dest_file): + raise src.SatException( + _("A personal application '%s' already exists") % dest ) - return RCO.ReturnCode("OK") + # perform the copy + shutil.copyfile(source_full_path, dest_file) + logger.write(_("%s has been created.\n") % dest_file) + + # case : display all the available pyconf applications + elif options.list: + lproduct = list() + # search in all directories that can have pyconf applications + for path in config.PATHS.APPLICATIONPATH: + # print a header + if not options.no_label: + logger.write("------ %s\n" % src.printcolors.printcHeader(path)) + + if not os.path.exists(path): + logger.write(src.printcolors.printcError( + _("Directory not found")) + "\n" ) + else: + for f in sorted(os.listdir(path)): + # ignore file that does not ends with .pyconf + if not f.endswith('.pyconf'): + continue + + appliname = f[:-len('.pyconf')] + if appliname not in lproduct: + lproduct.append(appliname) + if path.startswith(config.VARS.personalDir) \ + and not options.no_label: + logger.write("%s*\n" % appliname) + else: + logger.write("%s\n" % appliname) + + logger.write("\n") + + # case : give a synthetic view of all patches used in the application + elif options.show_patchs: + src.check_config_has_application(config) + # Print some informations + logger.write(_('Show the patchs of application %s\n') % \ + src.printcolors.printcLabel(config.VARS.application), 3) + logger.write("\n", 2, False) + show_patchs(config, logger) + + # case: print all the products name of the application (internal use for completion) + elif options.completion: + for product_name in config.APPLICATION.products.keys(): + logger.write("%s\n" % product_name) + + return RCO.ReturnCode("OK") diff --git a/commands/config_old.py b/commands/config_old.py deleted file mode 100644 index cb9f033..0000000 --- a/commands/config_old.py +++ /dev/null @@ -1,985 +0,0 @@ -#!/usr/bin/env python -#-*- coding:utf-8 -*- -# Copyright (C) 2010-2012 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 datetime -import shutil -import sys - -import src -import src.debug as DBG - -# Define all possible option for config command : sat config -parser = src.options.Options() -parser.add_option('v', 'value', 'string', 'value', - _("Optional: print the value of CONFIG_VARIABLE.")) -parser.add_option('d', 'debug', 'string', 'debug', - _("Optional: print the debugging value of CONFIG_VARIABLE.")) -parser.add_option('e', 'edit', 'boolean', 'edit', - _("Optional: edit the product configuration file.")) -parser.add_option('i', 'info', 'string', 'info', - _("Optional: get information on a product.")) -parser.add_option('l', 'list', 'boolean', 'list', - _("Optional: list all available applications.")) -parser.add_option('', 'show_patchs', 'boolean', 'show_patchs', - _("Optional: synthetic view of all patches used in the application")) -parser.add_option('c', 'copy', 'boolean', 'copy', - _("""Optional: copy a config file (.pyconf) to the personal config files directory. -\tWarning: the included files are not copied. -\tIf a name is given the new config file takes the given name.""")) -parser.add_option('n', 'no_label', 'boolean', 'no_label', - _("Internal use: do not print labels, Works only with --value and --list.")) -parser.add_option('', 'completion', 'boolean', 'completion', - _("Internal use: print only keys, works only with --value.")) -parser.add_option('s', 'schema', 'boolean', 'schema', - _("Internal use.")) - -class ConfigOpener: - '''Class that helps to find an application pyconf - in all the possible directories (pathList) - ''' - def __init__(self, pathList): - '''Initialization - - :param pathList list: The list of paths where to search a pyconf. - ''' - self.pathList = pathList - - def __call__(self, name): - if os.path.isabs(name): - return src.pyconf.ConfigInputStream(open(name, 'rb')) - else: - return src.pyconf.ConfigInputStream( - open(os.path.join( self.get_path(name), name ), 'rb') ) - raise IOError(_("Configuration file '%s' not found") % name) - - def get_path( self, name ): - '''The method that returns the entire path of the pyconf searched - :param name str: The name of the searched pyconf. - ''' - for path in self.pathList: - if os.path.exists(os.path.join(path, name)): - return path - raise IOError(_("Configuration file '%s' not found") % name) - -class ConfigManager: - '''Class that manages the read of all the configuration files of salomeTools - ''' - def __init__(self, datadir=None): - pass - - def _create_vars(self, application=None, command=None, datadir=None): - '''Create a dictionary that stores all information about machine, - user, date, repositories, etc... - - :param application str: The application for which salomeTools is called. - :param command str: The command that is called. - :param datadir str: The repository that contain external data - for salomeTools. - :return: The dictionary that stores all information. - :rtype: dict - ''' - var = {} - var['user'] = src.architecture.get_user() - var['salometoolsway'] = os.path.dirname( - os.path.dirname(os.path.abspath(__file__))) - var['srcDir'] = os.path.join(var['salometoolsway'], 'src') - var['internal_dir'] = os.path.join(var['srcDir'], 'internal_config') - var['sep']= os.path.sep - - # datadir has a default location - var['datadir'] = os.path.join(var['salometoolsway'], 'data') - if datadir is not None: - var['datadir'] = datadir - - var['personalDir'] = os.path.join(os.path.expanduser('~'), - '.salomeTools') - src.ensure_path_exists(var['personalDir']) - - var['personal_applications_dir'] = os.path.join(var['personalDir'], - "Applications") - src.ensure_path_exists(var['personal_applications_dir']) - - var['personal_products_dir'] = os.path.join(var['personalDir'], - "products") - src.ensure_path_exists(var['personal_products_dir']) - - var['personal_archives_dir'] = os.path.join(var['personalDir'], - "Archives") - src.ensure_path_exists(var['personal_archives_dir']) - - var['personal_jobs_dir'] = os.path.join(var['personalDir'], - "Jobs") - src.ensure_path_exists(var['personal_jobs_dir']) - - var['personal_machines_dir'] = os.path.join(var['personalDir'], - "Machines") - src.ensure_path_exists(var['personal_machines_dir']) - - # read linux distributions dictionary - distrib_cfg = src.pyconf.Config(os.path.join(var['srcDir'], - 'internal_config', - 'distrib.pyconf')) - - # set platform parameters - dist_name = src.architecture.get_distribution( - codes=distrib_cfg.DISTRIBUTIONS) - dist_version = src.architecture.get_distrib_version(dist_name, - codes=distrib_cfg.VERSIONS) - dist = dist_name + dist_version - - var['dist_name'] = dist_name - var['dist_version'] = dist_version - var['dist'] = dist - var['python'] = src.architecture.get_python_version() - - var['nb_proc'] = src.architecture.get_nb_proc() - node_name = platform.node() - var['node'] = node_name - var['hostname'] = node_name - - # set date parameters - dt = datetime.datetime.now() - var['date'] = dt.strftime('%Y%m%d') - var['datehour'] = dt.strftime('%Y%m%d_%H%M%S') - var['hour'] = dt.strftime('%H%M%S') - - var['command'] = str(command) - var['application'] = str(application) - - # Root dir for temporary files - var['tmp_root'] = os.sep + 'tmp' + os.sep + var['user'] - # particular win case - if src.architecture.is_windows() : - var['tmp_root'] = os.path.expanduser('~') + os.sep + 'tmp' - - return var - - def get_command_line_overrides(self, options, sections): - '''get all the overwrites that are in the command line - - :param options: the options from salomeTools class - initialization (like -l5 or --overwrite) - :param sections str: The config section to overwrite. - :return: The list of all the overwrites to apply. - :rtype: list - ''' - # when there are no options or not the overwrite option, - # return an empty list - if options is None or options.overwrite is None: - return [] - - over = [] - for section in sections: - # only overwrite the sections that correspond to the option - over.extend(filter(lambda l: l.startswith(section + "."), - options.overwrite)) - return over - - def get_config(self, application=None, options=None, command=None, - datadir=None): - '''get the config from all the configuration files. - - :param application str: The application for which salomeTools is called. - :param options class Options: The general salomeToos - options (--overwrite or -l5, for example) - :param command str: The command that is called. - :param datadir str: The repository that contain - external data for salomeTools. - :return: The final config. - :rtype: class 'src.pyconf.Config' - ''' - - # create a ConfigMerger to handle merge - merger = src.pyconf.ConfigMerger()#MergeHandler()) - - # create the configuration instance - cfg = src.pyconf.Config() - - # ===================================================================== - # create VARS section - var = self._create_vars(application=application, command=command, - datadir=datadir) - # add VARS to config - cfg.VARS = src.pyconf.Mapping(cfg) - for variable in var: - cfg.VARS[variable] = var[variable] - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["VARS"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - # ===================================================================== - # Load INTERNAL config - # read src/internal_config/salomeTools.pyconf - src.pyconf.streamOpener = ConfigOpener([ - os.path.join(cfg.VARS.srcDir, 'internal_config')]) - try: - internal_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.srcDir, - 'internal_config', 'salomeTools.pyconf'))) - except src.pyconf.ConfigError as e: - raise src.SatException(_("Error in configuration file:" - " salomeTools.pyconf\n %(error)s") % \ - {'error': str(e) }) - - merger.merge(cfg, internal_cfg) - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["INTERNAL"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - # ===================================================================== - # Load LOCAL config file - # search only in the data directory - src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir]) - try: - local_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.datadir, - 'local.pyconf')), - PWD = ('LOCAL', cfg.VARS.datadir) ) - except src.pyconf.ConfigError as e: - raise src.SatException(_("Error in configuration file: " - "local.pyconf\n %(error)s") % \ - {'error': str(e) }) - except IOError as error: - e = str(error) - raise src.SatException( e ); - merger.merge(cfg, local_cfg) - - # When the key is "default", put the default value - if cfg.LOCAL.base == "default": - cfg.LOCAL.base = os.path.abspath( - os.path.join(cfg.VARS.salometoolsway, - "..", - "BASE")) - if cfg.LOCAL.workdir == "default": - cfg.LOCAL.workdir = os.path.abspath( - os.path.join(cfg.VARS.salometoolsway, - "..")) - if cfg.LOCAL.log_dir == "default": - cfg.LOCAL.log_dir = os.path.abspath( - os.path.join(cfg.VARS.salometoolsway, - "..", - "LOGS")) - - if cfg.LOCAL.archive_dir == "default": - cfg.LOCAL.archive_dir = os.path.abspath( - os.path.join(cfg.VARS.salometoolsway, - "..", - "ARCHIVES")) - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["LOCAL"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - # ===================================================================== - # Load the PROJECTS - projects_cfg = src.pyconf.Config() - projects_cfg.addMapping("PROJECTS", - src.pyconf.Mapping(projects_cfg), - "The projects\n") - projects_cfg.PROJECTS.addMapping("projects", - src.pyconf.Mapping(cfg.PROJECTS), - "The projects definition\n") - - for project_pyconf_path in cfg.PROJECTS.project_file_paths: - if not os.path.exists(project_pyconf_path): - msg = _("WARNING: The project file %s cannot be found. " - "It will be ignored\n") % project_pyconf_path - sys.stdout.write(msg) - continue - project_name = os.path.basename(project_pyconf_path)[:-len(".pyconf")] - try: - project_pyconf_dir = os.path.dirname(project_pyconf_path) - project_cfg = src.pyconf.Config(open(project_pyconf_path), - PWD=("", project_pyconf_dir)) - except Exception as e: - msg = _("ERROR: Error in configuration file: %(file_path)s\n %(error)s\n") % \ - {'file_path' : project_pyconf_path, 'error': str(e) } - sys.stdout.write(msg) - continue - projects_cfg.PROJECTS.projects.addMapping(project_name, - src.pyconf.Mapping(projects_cfg.PROJECTS.projects), - "The %s project\n" % project_name) - projects_cfg.PROJECTS.projects[project_name]=project_cfg - projects_cfg.PROJECTS.projects[project_name]["file_path"] = \ - project_pyconf_path - - merger.merge(cfg, projects_cfg) - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["PROJECTS"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - # ===================================================================== - # Create the paths where to search the application configurations, - # the product configurations, the products archives, - # the jobs configurations and the machines configurations - cfg.addMapping("PATHS", src.pyconf.Mapping(cfg), "The paths\n") - cfg.PATHS["APPLICATIONPATH"] = src.pyconf.Sequence(cfg.PATHS) - cfg.PATHS.APPLICATIONPATH.append(cfg.VARS.personal_applications_dir, "") - - cfg.PATHS["PRODUCTPATH"] = src.pyconf.Sequence(cfg.PATHS) - cfg.PATHS.PRODUCTPATH.append(cfg.VARS.personal_products_dir, "") - cfg.PATHS["ARCHIVEPATH"] = src.pyconf.Sequence(cfg.PATHS) - cfg.PATHS.ARCHIVEPATH.append(cfg.VARS.personal_archives_dir, "") - cfg.PATHS["JOBPATH"] = src.pyconf.Sequence(cfg.PATHS) - cfg.PATHS.JOBPATH.append(cfg.VARS.personal_jobs_dir, "") - cfg.PATHS["MACHINEPATH"] = src.pyconf.Sequence(cfg.PATHS) - cfg.PATHS.MACHINEPATH.append(cfg.VARS.personal_machines_dir, "") - - # initialise the path with local directory - cfg.PATHS["ARCHIVEPATH"].append(cfg.LOCAL.archive_dir, "") - - # Loop over the projects in order to complete the PATHS variables - for project in cfg.PROJECTS.projects: - for PATH in ["APPLICATIONPATH", - "PRODUCTPATH", - "ARCHIVEPATH", - "JOBPATH", - "MACHINEPATH"]: - if PATH not in cfg.PROJECTS.projects[project]: - continue - cfg.PATHS[PATH].append(cfg.PROJECTS.projects[project][PATH], "") - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["PATHS"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - # ===================================================================== - # Load APPLICATION config file - if application is not None: - # search APPLICATION file in all directories in configPath - cp = cfg.PATHS.APPLICATIONPATH - src.pyconf.streamOpener = ConfigOpener(cp) - do_merge = True - try: - application_cfg = src.pyconf.Config(application + '.pyconf') - except IOError as e: - raise src.SatException(_("%s, use 'config --list' to get the" - " list of available applications.") % e) - except src.pyconf.ConfigError as e: - if (not ('-e' in parser.parse_args()[1]) - or ('--edit' in parser.parse_args()[1]) - and command == 'config'): - raise src.SatException( - _("Error in configuration file: (1)s.pyconf\n %(2)s") % \ - { 'application': application, 'error': str(e) } ) - else: - sys.stdout.write(src.printcolors.printcWarning( - "There is an error in the file %s.pyconf.\n" % \ - cfg.VARS.application)) - do_merge = False - except Exception as e: - if ( not('-e' in parser.parse_args()[1]) or - ('--edit' in parser.parse_args()[1]) and - command == 'config' ): - sys.stdout.write(src.printcolors.printcWarning("%s\n" % str(e))) - raise src.SatException( - _("Error in configuration file: %s.pyconf\n") % application ) - else: - sys.stdout.write(src.printcolors.printcWarning( - "ERROR: in file %s.pyconf. Opening the file with the default viewer\n" % \ - cfg.VARS.application)) - sys.stdout.write("\n%s\n" % src.printcolors.printcWarning(str(e))) - do_merge = False - - else: - cfg['open_application'] = 'yes' - - # ===================================================================== - # Load product config files in PRODUCTS section - products_cfg = src.pyconf.Config() - products_cfg.addMapping("PRODUCTS", - src.pyconf.Mapping(products_cfg), - "The products\n") - if application is not None: - src.pyconf.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH) - for product_name in application_cfg.APPLICATION.products.keys(): - # Loop on all files that are in softsDir directory - # and read their config - product_file_name = product_name + ".pyconf" - product_file_path = src.find_file_in_lpath(product_file_name, cfg.PATHS.PRODUCTPATH) - if product_file_path: - products_dir = os.path.dirname(product_file_path) - try: - prod_cfg = src.pyconf.Config(open(product_file_path), - PWD=("", products_dir)) - prod_cfg.from_file = product_file_path - products_cfg.PRODUCTS[product_name] = prod_cfg - except Exception as e: - msg = _( - "WARNING: Error in configuration file: %(prod)s\n %(error)s" % \ - {'prod' : product_name, 'error': str(e) }) - sys.stdout.write(msg) - - merger.merge(cfg, products_cfg) - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["PRODUCTS"]): - exec('cfg.' + rule) # this cannot be factorized because of the exec - - if do_merge: - merger.merge(cfg, application_cfg) - - # default launcher name ('salome') - if ('profile' in cfg.APPLICATION and - 'launcher_name' not in cfg.APPLICATION.profile): - cfg.APPLICATION.profile.launcher_name = 'salome' - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, - ["APPLICATION"]): - # this cannot be factorized because of the exec - exec('cfg.' + rule) - - # ===================================================================== - # load USER config - self.set_user_config_file(cfg) - user_cfg_file = self.get_user_config_file() - user_cfg = src.pyconf.Config(open(user_cfg_file)) - merger.merge(cfg, user_cfg) - - # apply overwrite from command line if needed - for rule in self.get_command_line_overrides(options, ["USER"]): - exec('cfg.' + rule) # this cannot be factorize because of the exec - - return cfg - - def set_user_config_file(self, config): - '''Set the user config file name and path. - If necessary, build it from another one or create it from scratch. - - :param config class 'src.pyconf.Config': The global config - (containing all pyconf). - ''' - # get the expected name and path of the file - self.config_file_name = 'SAT.pyconf' - self.user_config_file_path = os.path.join(config.VARS.personalDir, - self.config_file_name) - - # if pyconf does not exist, create it from scratch - if not os.path.isfile(self.user_config_file_path): - self.create_config_file(config) - - def create_config_file(self, config): - '''This method is called when there are no user config file. - It build it from scratch. - - :param config class 'src.pyconf.Config': The global config. - :return: the config corresponding to the file created. - :rtype: config class 'src.pyconf.Config' - ''' - - cfg_name = self.get_user_config_file() - - user_cfg = src.pyconf.Config() - # - user_cfg.addMapping('USER', src.pyconf.Mapping(user_cfg), "") - - user_cfg.USER.addMapping('cvs_user', config.VARS.user, - "This is the user name used to access salome cvs base.\n") - user_cfg.USER.addMapping('svn_user', config.VARS.user, - "This is the user name used to access salome svn base.\n") - user_cfg.USER.addMapping('output_verbose_level', 3, - "This is the default output_verbose_level you want." - " 0=>no output, 5=>debug.\n") - user_cfg.USER.addMapping('publish_dir', - os.path.join(os.path.expanduser('~'), - 'websupport', - 'satreport'), - "") - user_cfg.USER.addMapping('editor', - 'vi', - "This is the editor used to " - "modify configuration files\n") - user_cfg.USER.addMapping('browser', - 'firefox', - "This is the browser used to " - "read html documentation\n") - user_cfg.USER.addMapping('pdf_viewer', - 'evince', - "This is the pdf_viewer used " - "to read pdf documentation\n") -# CNC 25/10/17 : plus nécessaire a priori -# user_cfg.USER.addMapping("base", -# src.pyconf.Reference( -# user_cfg, -# src.pyconf.DOLLAR, -# 'workdir + $VARS.sep + "BASE"'), -# "The products installation base (could be " -# "ignored if this key exists in the local.pyconf" -# " file of salomTools).\n") - - # - src.ensure_path_exists(config.VARS.personalDir) - src.ensure_path_exists(os.path.join(config.VARS.personalDir, - 'Applications')) - - f = open(cfg_name, 'w') - user_cfg.__save__(f) - f.close() - - return user_cfg - - def get_user_config_file(self): - '''Get the user config file - :return: path to the user config file. - :rtype: str - ''' - if not self.user_config_file_path: - raise src.SatException( - _("Error in get_user_config_file: missing user config file path") ) - return self.user_config_file_path - -def check_path(path, ext=[]): - '''Construct a text with the input path and "not found" if it does not - exist. - - :param path Str: the path to check. - :param ext List: An extension. Verify that the path extension - is in the list - :return: The string of the path with information - :rtype: Str - ''' - # check if file exists - if not os.path.exists(path): - return "'%s' %s" % (path, src.printcolors.printcError(_("** not found"))) - - # check extension - if len(ext) > 0: - fe = os.path.splitext(path)[1].lower() - if fe not in ext: - return "'%s' %s" % (path, src.printcolors.printcError(_("** bad extension"))) - - return path - -def show_product_info(config, name, logger): - '''Display on the terminal and logger information about a product. - - :param config Config: the global configuration. - :param name Str: The name of the product - :param logger Logger: The logger instance to use for the display - ''' - - logger.write(_("%s is a product\n") % src.printcolors.printcLabel(name), 2) - pinfo = src.product.get_product_config(config, name) - - if "depend" in pinfo: - src.printcolors.print_value(logger, - "depends on", - ', '.join(pinfo.depend), 2) - - if "opt_depend" in pinfo: - src.printcolors.print_value(logger, - "optional", - ', '.join(pinfo.opt_depend), 2) - - # information on pyconf - logger.write("\n", 2) - logger.write(src.printcolors.printcLabel("configuration:") + "\n", 2) - if "from_file" in pinfo: - src.printcolors.print_value(logger, - "pyconf file path", - pinfo.from_file, - 2) - if "section" in pinfo: - src.printcolors.print_value(logger, - "section", - pinfo.section, - 2) - - # information on prepare - logger.write("\n", 2) - logger.write(src.printcolors.printcLabel("prepare:") + "\n", 2) - - is_dev = src.product.product_is_dev(pinfo) - method = pinfo.get_source - if is_dev: - method += " (dev)" - src.printcolors.print_value(logger, "get method", method, 2) - - if method == 'cvs': - src.printcolors.print_value(logger, "server", pinfo.cvs_info.server, 2) - src.printcolors.print_value(logger, "base module", - pinfo.cvs_info.module_base, 2) - src.printcolors.print_value(logger, "source", pinfo.cvs_info.source, 2) - src.printcolors.print_value(logger, "tag", pinfo.cvs_info.tag, 2) - - elif method == 'svn': - src.printcolors.print_value(logger, "repo", pinfo.svn_info.repo, 2) - - elif method == 'git': - src.printcolors.print_value(logger, "repo", pinfo.git_info.repo, 2) - src.printcolors.print_value(logger, "tag", pinfo.git_info.tag, 2) - - elif method == 'archive': - src.printcolors.print_value(logger, - "get from", - check_path(pinfo.archive_info.archive_name), - 2) - - if 'patches' in pinfo: - for patch in pinfo.patches: - src.printcolors.print_value(logger, "patch", check_path(patch), 2) - - if src.product.product_is_fixed(pinfo): - src.printcolors.print_value(logger, "install_dir", - check_path(pinfo.install_dir), 2) - - if src.product.product_is_native(pinfo) or src.product.product_is_fixed(pinfo): - return - - # information on compilation - if src.product.product_compiles(pinfo): - logger.write("\n", 2) - logger.write(src.printcolors.printcLabel("compile:") + "\n", 2) - src.printcolors.print_value(logger, - "compilation method", - pinfo.build_source, - 2) - - if pinfo.build_source == "script" and "compil_script" in pinfo: - src.printcolors.print_value(logger, - "Compilation script", - pinfo.compil_script, - 2) - - if 'nb_proc' in pinfo: - src.printcolors.print_value(logger, "make -j", pinfo.nb_proc, 2) - - src.printcolors.print_value(logger, - "source dir", - check_path(pinfo.source_dir), - 2) - if 'install_dir' in pinfo: - src.printcolors.print_value(logger, - "build dir", - check_path(pinfo.build_dir), - 2) - src.printcolors.print_value(logger, - "install dir", - check_path(pinfo.install_dir), - 2) - else: - logger.write(" %s\n" % src.printcolors.printcWarning(_("no install dir")) , 2) - else: - logger.write("\n", 2) - msg = _("This product does not compile") - logger.write("%s\n" % msg, 2) - - # information on environment - logger.write("\n", 2) - logger.write(src.printcolors.printcLabel("environ :") + "\n", 2) - if "environ" in pinfo and "env_script" in pinfo.environ: - src.printcolors.print_value(logger, - "script", - check_path(pinfo.environ.env_script), - 2) - - zz = src.environment.SalomeEnviron(config, - src.fileEnviron.ScreenEnviron(logger), - False) - zz.set_python_libdirs() - zz.set_a_product(name, logger) - -def show_patchs(config, logger): - '''Prints all the used patchs in the application. - - :param config Config: the global configuration. - :param logger Logger: The logger instance to use for the display - ''' - len_max = max([len(p) for p in config.APPLICATION.products]) + 2 - for product in config.APPLICATION.products: - product_info = src.product.get_product_config(config, product) - if src.product.product_has_patches(product_info): - logger.write("%s: " % product, 1) - logger.write(src.printcolors.printcInfo( - " " * (len_max - len(product) -2) + - "%s\n" % product_info.patches[0]), - 1) - if len(product_info.patches) > 1: - for patch in product_info.patches[1:]: - logger.write(src.printcolors.printcInfo(len_max*" " + - "%s\n" % patch), 1) - logger.write("\n", 1) - -def print_value(config, path, show_label, logger, level=0, show_full_path=False): - '''Prints a value from the configuration. Prints recursively the values - under the initial path. - - :param config class 'src.pyconf.Config': The configuration - from which the value is displayed. - :param path str : the path in the configuration of the value to print. - :param show_label boolean: if True, do a basic display. - (useful for bash completion) - :param logger Logger: the logger instance - :param level int: The number of spaces to add before display. - :param show_full_path : - ''' - - # Make sure that the path does not ends with a point - if path.endswith('.'): - path = path[:-1] - - # display all the path or not - if show_full_path: - vname = path - else: - vname = path.split('.')[-1] - - # number of spaces before the display - tab_level = " " * level - - # call to the function that gets the value of the path. - try: - val = config.getByPath(path) - except Exception as e: - logger.write(tab_level) - logger.write("%s: ERROR %s\n" % (src.printcolors.printcLabel(vname), - src.printcolors.printcError(str(e)))) - return - - # in this case, display only the value - if show_label: - logger.write(tab_level) - logger.write("%s: " % src.printcolors.printcLabel(vname)) - - # The case where the value has under values, - # do a recursive call to the function - if dir(val).__contains__('keys'): - if show_label: logger.write("\n") - for v in sorted(val.keys()): - print_value(config, path + '.' + v, show_label, logger, level + 1) - elif val.__class__ == src.pyconf.Sequence or isinstance(val, list): - # in this case, value is a list (or a Sequence) - if show_label: logger.write("\n") - index = 0 - for v in val: - print_value(config, path + "[" + str(index) + "]", - show_label, logger, level + 1) - index = index + 1 - else: # case where val is just a str - logger.write("%s\n" % val) - -def print_debug(config, aPath, show_label, logger, level=0, show_full_path=False): - path = str(aPath) - if path == "." : - val = config - path = "" - else: - if path.endswith('.'): # Make sure that the path does not ends with a point - path = path[:-1] - val = config.getByPath(path) - - outStream = DBG.OutStream() - DBG.saveConfigDbg(val, outStream, path=path) - res = outStream.value - logger.write(res) - return - - -def get_config_children(config, args): - '''Gets the names of the children of the given parameter. - Useful only for completion mechanism - - :param config Config: The configuration where to read the values - :param args: The path in the config from which get the keys - ''' - vals = [] - rootkeys = config.keys() - - if len(args) == 0: - # no parameter returns list of root keys - vals = rootkeys - else: - parent = args[0] - pos = parent.rfind('.') - if pos < 0: - # Case where there is only on key as parameter. - # For example VARS - vals = [m for m in rootkeys if m.startswith(parent)] - else: - # Case where there is a part from a key - # for example VARS.us (for VARS.user) - head = parent[0:pos] - tail = parent[pos+1:] - try: - a = config.getByPath(head) - if dir(a).__contains__('keys'): - vals = map(lambda x: head + '.' + x, - [m for m in a.keys() if m.startswith(tail)]) - except: - pass - - for v in sorted(vals): - sys.stdout.write("%s\n" % v) - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the config command description. - :rtype: str - ''' - return _("""\ -The config command allows manipulation and operation on config files. - -example: ->> sat config SALOME-master --info ParaView""") - - -def run(args, runner, logger): - '''method that is called when salomeTools is called with config parameter. - ''' - # Parse the options - (options, args) = parser.parse_args(args) - - # Only useful for completion mechanism : print the keys of the config - if options.schema: - get_config_children(runner.cfg, args) - return - - # case : print a value of the config - if options.value: - if options.value == ".": - # if argument is ".", print all the config - for val in sorted(runner.cfg.keys()): - print_value(runner.cfg, val, not options.no_label, logger) - else: - print_value(runner.cfg, options.value, not options.no_label, logger, - level=0, show_full_path=False) - - if options.debug: - print_debug(runner.cfg, str(options.debug), not options.no_label, logger, - level=0, show_full_path=False) - - # case : edit user pyconf file or application file - elif options.edit: - editor = runner.cfg.USER.editor - if ('APPLICATION' not in runner.cfg and - 'open_application' not in runner.cfg): # edit user pyconf - usercfg = os.path.join(runner.cfg.VARS.personalDir, 'SAT.pyconf') - logger.write(_("Opening %s\n") % usercfg, 3) - src.system.show_in_editor(editor, usercfg, logger) - else: - # search for file .pyconf and open it - for path in runner.cfg.PATHS.APPLICATIONPATH: - pyconf_path = os.path.join(path, runner.cfg.VARS.application + ".pyconf") - if os.path.exists(pyconf_path): - logger.write(_("Opening %s\n") % pyconf_path, 3) - src.system.show_in_editor(editor, pyconf_path, logger) - break - - # case : give information about the product in parameter - elif options.info: - src.check_config_has_application(runner.cfg) - if options.info in runner.cfg.APPLICATION.products: - show_product_info(runner.cfg, options.info, logger) - return - raise src.SatException( - _("%(product_name)s is not a product of %(application_name)s.") % \ - {'product_name' : options.info, 'application_name' : runner.cfg.VARS.application} ) - - # case : copy an existing .pyconf - # to ~/.salomeTools/Applications/LOCAL_.pyconf - elif options.copy: - # product is required - src.check_config_has_application( runner.cfg ) - - # get application file path - source = runner.cfg.VARS.application + '.pyconf' - source_full_path = "" - for path in runner.cfg.PATHS.APPLICATIONPATH: - # ignore personal directory - if path == runner.cfg.VARS.personalDir: - continue - # loop on all directories that can have pyconf applications - zz = os.path.join(path, source) - if os.path.exists(zz): - source_full_path = zz - break - - if len(source_full_path) == 0: - raise src.SatException( - _("Config file for product %s not found\n") % source ) - else: - if len(args) > 0: - # a name is given as parameter, use it - dest = args[0] - elif 'copy_prefix' in runner.cfg.INTERNAL.config: - # use prefix - dest = (runner.cfg.INTERNAL.config.copy_prefix - + runner.cfg.VARS.application) - else: - # use same name as source - dest = runner.cfg.VARS.application - - # the full path - dest_file = os.path.join( - runner.cfg.VARS.personalDir, 'Applications', dest + '.pyconf' ) - if os.path.exists(dest_file): - raise src.SatException( - _("A personal application '%s' already exists") % dest ) - - # perform the copy - shutil.copyfile(source_full_path, dest_file) - logger.write(_("%s has been created.\n") % dest_file) - - # case : display all the available pyconf applications - elif options.list: - lproduct = list() - # search in all directories that can have pyconf applications - for path in runner.cfg.PATHS.APPLICATIONPATH: - # print a header - if not options.no_label: - logger.write("------ %s\n" % src.printcolors.printcHeader(path)) - - if not os.path.exists(path): - logger.write(src.printcolors.printcError( - _("Directory not found")) + "\n" ) - else: - for f in sorted(os.listdir(path)): - # ignore file that does not ends with .pyconf - if not f.endswith('.pyconf'): - continue - - appliname = f[:-len('.pyconf')] - if appliname not in lproduct: - lproduct.append(appliname) - if path.startswith(runner.cfg.VARS.personalDir) \ - and not options.no_label: - logger.write("%s*\n" % appliname) - else: - logger.write("%s\n" % appliname) - - logger.write("\n") - # case : give a synthetic view of all patches used in the application - elif options.show_patchs: - src.check_config_has_application(runner.cfg) - # Print some informations - logger.write(_('Show the patchs of application %s\n') % \ - src.printcolors.printcLabel(runner.cfg.VARS.application), 3) - logger.write("\n", 2, False) - show_patchs(runner.cfg, logger) - - # case: print all the products name of the application (internal use for completion) - elif options.completion: - for product_name in runner.cfg.APPLICATION.products.keys(): - logger.write("%s\n" % product_name) - - diff --git a/commands/configure.py b/commands/configure.py index 96aa1e0..3a365d6 100644 --- a/commands/configure.py +++ b/commands/configure.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,17 +17,97 @@ # 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 src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The configure command executes in the build directory commands + corresponding to the compilation mode of the application products. + The possible compilation modes are 'cmake', 'autotools', or 'script'. + + Here are the commands to be run: + autotools: >> build_configure and configure + cmake: >> cmake + script: (do nothing) + + examples: + >> sat configure SALOME --products KERNEL,GUI,PARAVIS + """ + + name = "configure" + + def getParser(self): + """Define all options for command 'sat configure '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products to configure. This option can be' + ' passed several time to configure several products.')) + parser.add_option('o', 'option', 'string', 'option', + _('Optional: Option to add to the configure or cmake command.'), "") + return parser + + def run(self, cmd_arguments): + """method called for command 'sat configure '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) + + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + # Print some informations + logger.write(_('Configuring the sources of the application %s\n') % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + info = [(_("BUILD directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] + src.print_info(logger, info) + + # Call the function that will loop over all the products and execute + # the right command(s) + if options.option is None: + options.option = "" + res = configure_all_products(runner.cfg, products_infos, options.option, logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nConfiguration: %(status)s (%(valid_result)d/%(nb_products)d)\n") % \ + { 'status': src.printcolors.printc(final_status), + 'valid_result': nb_products - res, + 'nb_products': nb_products }, 1) + + return res -# Define all possible option for configure command : sat configure -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to configure. This option can be' - ' passed several time to configure several products.')) -parser.add_option('o', 'option', 'string', 'option', - _('Optional: Option to add to the configure or cmake command.'), "") def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from @@ -169,63 +250,3 @@ def configure_product(p_name_info, conf_option, config, logger): logger.write("\n", 3, False) return res - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the configure command description. - :rtype: str - ''' - return _("""\ -The configure command executes in the build directory commands -corresponding to the compilation mode of the application products. -The possible compilation modes are 'cmake', 'autotools', or 'script'. - -Here are the commands to be run: - autotools: >> build_configure and configure - cmake: >> cmake - script: (do nothing) - -example: ->> sat configure SALOME-master --products KERNEL,GUI,PARAVIS""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with make parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - # Print some informations - logger.write(_('Configuring the sources of the application %s\n') % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - info = [(_("BUILD directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] - src.print_info(logger, info) - - # Call the function that will loop over all the products and execute - # the right command(s) - if options.option is None: - options.option = "" - res = configure_all_products(runner.cfg, products_infos, options.option, logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nConfiguration: %(status)s (%(valid_result)d/%(nb_products)d)\n") % \ - { 'status': src.printcolors.printc(final_status), - 'valid_result': nb_products - res, - 'nb_products': nb_products }, 1) - - return res diff --git a/commands/environ.py b/commands/environ.py index a4fd5be..87ebfc8 100644 --- a/commands/environ.py +++ b/commands/environ.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,28 +17,93 @@ # 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 src -parser = src.options.Options() -parser.add_option('', 'shell', 'list2', 'shell', - _("Optional: Generates the environment files for the given format: " - "bash (default), bat (for windows), cfg (salome context file) or all."), []) -parser.add_option('p', 'products', 'list2', 'products', - _("Optional: Includes only the specified products.")) -parser.add_option('', 'prefix', 'string', 'prefix', - _("Optional: Specifies the prefix for the environment files."), "env") -parser.add_option('t', 'target', 'string', 'out_dir', - _("Optional: Specifies the directory path where to put the environment " - "files."), - None) +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand # list of available shells with extensions C_SHELLS = { "bash": "sh", "bat": "bat", "cfg" : "cfg" } C_ALL_SHELL = [ "bash", "bat", "cfg" ] +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The environ command generates the environment files of your application. + + examples: + >> sat environ SALOME + """ + + name = "environ" + + def getParser(self): + """Define all options for command 'sat environ '""" + parser = self.getParserWithHelp() + parser.add_option('', 'shell', 'list2', 'shell', + _("Optional: Generates the environment files for the given format: " + "bash (default), bat (for windows), cfg (salome context file) or all."), []) + parser.add_option('p', 'products', 'list2', 'products', + _("Optional: Includes only the specified products.")) + parser.add_option('', 'prefix', 'string', 'prefix', + _("Optional: Specifies the prefix for the environment files."), "env") + parser.add_option('t', 'target', 'string', 'out_dir', + _("Optional: Specifies the directory path where to put the environment files."), + None) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat environ '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command was called with an application + src.check_config_has_application( runner.cfg ) + + if options.products is None: + environ_info = None + else: + # add products specified by user (only products + # included in the application) + environ_info = filter(lambda l: + l in runner.cfg.APPLICATION.products.keys(), + options.products) + + if options.shell == []: + shell = ["bash"] + if src.architecture.is_windows(): + shell = ["bat"] + else: + shell = options.shell + + out_dir = options.out_dir + if out_dir: + out_dir = os.path.abspath(out_dir) + + write_all_source_files(runner.cfg, logger, out_dir=out_dir, shells=shell, + prefix=options.prefix, env_info=environ_info) + logger.write("\n", 3, False) + #TODO return code + ## # Writes all the environment files def write_all_source_files(config, @@ -110,46 +176,3 @@ def write_all_source_files(config, shell.name)) return files - -################################################## - -## -# Describes the command -def description(): - return _("""\ -The environ command generates the environment files of your application. - -example: ->> sat environ SALOME-master""") - -## -# Runs the command. -def run(args, runner, logger): - (options, args) = parser.parse_args(args) - - # check that the command was called with an application - src.check_config_has_application( runner.cfg ) - - if options.products is None: - environ_info = None - else: - # add products specified by user (only products - # included in the application) - environ_info = filter(lambda l: - l in runner.cfg.APPLICATION.products.keys(), - options.products) - - if options.shell == []: - shell = ["bash"] - if src.architecture.is_windows(): - shell = ["bat"] - else: - shell = options.shell - - out_dir = options.out_dir - if out_dir: - out_dir = os.path.abspath(out_dir) - - write_all_source_files(runner.cfg, logger, out_dir=out_dir, shells=shell, - prefix=options.prefix, env_info=environ_info) - logger.write("\n", 3, False) diff --git a/commands/find_duplicates.py b/commands/find_duplicates.py index 7ad3100..24684d6 100644 --- a/commands/find_duplicates.py +++ b/commands/find_duplicates.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,42 +17,11 @@ # 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 src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand -# create a parser for command line options -parser = src.options.Options() -parser.add_option( - "s", - "sources", - "boolean", - "sources", - _("Search the duplicate files in the SOURCES directory.") ) -parser.add_option( - "p", - "path", - "list2", - "path", - _("Optional: Search the duplicate files in the given directory paths.") ) -parser.add_option( - "", - "exclude-file", - "list2", - "exclude_file", - _("Optional: Override the default list of filtered files.") ) -parser.add_option( - "", - "exclude-extension", - "list2", - "exclude_extension", - _("Optional: Override the default list of filtered extensions.") ) -parser.add_option( - "", - "exclude-path", - "list2", - "exclude_path", - _("Optional: Override the default list of filtered paths.") ) default_extension_ignored = \ 'html png txt js xml cmake gif m4 in pyo pyc doctree css'.split() @@ -61,121 +31,78 @@ default_files_ignored = \ default_directories_ignored = [] -def list_directory(lpath, extension_ignored, files_ignored, directories_ignored): - '''Make the list of all files and paths that are not filtered - - :param lpath List: The list of path to of the directories where to - search for duplicates - :param extension_ignored List: The list of extensions to ignore - :param files_ignored List: The list of files to ignore - :param directories_ignored List: The list of directory paths to ignore - :return: files_arb_out is the list of [file, path] - and files_out is is the list of files - :rtype: List, List - ''' - files_out = [] - files_arb_out=[] - for path in lpath: - for root, __, files in os.walk(path): - for fic in files: - extension = fic.split('.')[-1] - if (extension not in extension_ignored and - fic not in files_ignored): - in_ignored_dir = False - for rep in directories_ignored: - if rep in root: - in_ignored_dir = True - if not in_ignored_dir: - files_out.append([fic]) - files_arb_out.append([fic, root]) - return files_arb_out, files_out - -def format_list_of_str(l_str): - '''Make a list from a string - - :param l_str List or Str: The variable to format - :return: the formatted variable - :rtype: List - ''' - if not isinstance(l_str, list): - return l_str - return ",".join(l_str) -def print_info(logger, info, level=2): - '''Format a display - - :param logger Logger: The logger instance - :param info List: the list of tuple to display - :param valMax float: the maximum value of the variable - :param level int: the verbose level that will be used - ''' - smax = max(map(lambda l: len(l[0]), info)) - for i in info: - sp = " " * (smax - len(i[0])) - src.printcolors.print_value(logger, - sp + i[0], - format_list_of_str(i[1]), - 2) - logger.write("\n", level) - -class Progress_bar: - "Create a progress bar in the terminal" - - def __init__(self, name, valMin, valMax, logger, length = 50): - '''Initialization of the progress bar. - - :param name str: The name of the progress bar - :param valMin float: the minimum value of the variable - :param valMax float: the maximum value of the variable - :param logger Logger: the logger instance - :param length int: the lenght of the progress bar - ''' - self.name = name - self.valMin = valMin - self.valMax = valMax - self.length = length - self.logger = logger - if (self.valMax - self.valMin) <= 0 or length <= 0: - out_err = _('ERROR: Wrong init values for the progress bar\n') - raise src.SatException(out_err) - - def display_value_progression(self,val): - '''Display the progress bar. - - :param val float: val must be between valMin and valMax. - ''' - if val < self.valMin or val > self.valMax: - self.logger.write(src.printcolors.printcWarning(_( - 'WARNING : wrong value for the progress bar.\n')), 3) - else: - perc = (float(val-self.valMin) / (self.valMax - self.valMin)) * 100. - nb_equals = int(perc * self.length / 100) - out = '\r %s : %3d %% [%s%s]' % (self.name, perc, nb_equals*'=', - (self.length - nb_equals)*' ' ) - self.logger.write(out, 3) - self.logger.flush() - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the find_duplicates command description. - :rtype: str - ''' - return _("""\ -The find_duplicates command search recursively for all duplicates files -in INSTALL directory (or the optionally given directory) and -prints the found files to the terminal. +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The find_duplicates command search recursively for all duplicates files + in INSTALL directory (or the optionally given directory) and + prints the found files to the terminal. + + examples: + >> sat find_duplicates --path /tmp + """ + + name = "find_duplicates" + + def getParser(self): + """Define all options for command 'sat find_duplicates '""" + parser = self.getParserWithHelp() + parser.add_option( + "s", + "sources", + "boolean", + "sources", + _("Search the duplicate files in the SOURCES directory.") ) + parser.add_option( + "p", + "path", + "list2", + "path", + _("Optional: Search the duplicate files in the given directory paths.") ) + parser.add_option( + "", + "exclude-file", + "list2", + "exclude_file", + _("Optional: Override the default list of filtered files.") ) + parser.add_option( + "", + "exclude-extension", + "list2", + "exclude_extension", + _("Optional: Override the default list of filtered extensions.") ) + parser.add_option( + "", + "exclude-path", + "list2", + "exclude_path", + _("Optional: Override the default list of filtered paths.") ) + return parser -example: ->> sat find_duplicates --path /tmp""") + def run(self, cmd_arguments): + """method called for command 'sat find_duplicates '""" + argList = self.assumeAsList(cmd_arguments) -def run(args, runner, logger): - '''method that is called when salomeTools is called with find_duplicates - parameter. - ''' - # parse the arguments - (options, args) = parser.parse_args(args) + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + # Determine the directory path where to search # for duplicates files regarding the options if options.path: @@ -298,3 +225,99 @@ def run(args, runner, logger): logger.write("\n", 1) return 0 + + +def list_directory(lpath, extension_ignored, files_ignored, directories_ignored): + """Make the list of all files and paths that are not filtered + + :param lpath List: The list of path to of the directories where to + search for duplicates + :param extension_ignored List: The list of extensions to ignore + :param files_ignored List: The list of files to ignore + :param directories_ignored List: The list of directory paths to ignore + :return: files_arb_out is the list of [file, path] + and files_out is is the list of files + :rtype: List, List + """ + files_out = [] + files_arb_out=[] + for path in lpath: + for root, __, files in os.walk(path): + for fic in files: + extension = fic.split('.')[-1] + if (extension not in extension_ignored and + fic not in files_ignored): + in_ignored_dir = False + for rep in directories_ignored: + if rep in root: + in_ignored_dir = True + if not in_ignored_dir: + files_out.append([fic]) + files_arb_out.append([fic, root]) + return files_arb_out, files_out + +def format_list_of_str(l_str): + '''Make a list from a string + + :param l_str List or Str: The variable to format + :return: the formatted variable + :rtype: List + ''' + if not isinstance(l_str, list): + return l_str + return ",".join(l_str) + +def print_info(logger, info, level=2): + '''Format a display + + :param logger Logger: The logger instance + :param info List: the list of tuple to display + :param valMax float: the maximum value of the variable + :param level int: the verbose level that will be used + ''' + smax = max(map(lambda l: len(l[0]), info)) + for i in info: + sp = " " * (smax - len(i[0])) + src.printcolors.print_value(logger, + sp + i[0], + format_list_of_str(i[1]), + 2) + logger.write("\n", level) + +class Progress_bar: + "Create a progress bar in the terminal" + + def __init__(self, name, valMin, valMax, logger, length = 50): + '''Initialization of the progress bar. + + :param name str: The name of the progress bar + :param valMin float: the minimum value of the variable + :param valMax float: the maximum value of the variable + :param logger Logger: the logger instance + :param length int: the lenght of the progress bar + ''' + self.name = name + self.valMin = valMin + self.valMax = valMax + self.length = length + self.logger = logger + if (self.valMax - self.valMin) <= 0 or length <= 0: + out_err = _('ERROR: Wrong init values for the progress bar\n') + raise src.SatException(out_err) + + def display_value_progression(self,val): + '''Display the progress bar. + + :param val float: val must be between valMin and valMax. + ''' + if val < self.valMin or val > self.valMax: + self.logger.write(src.printcolors.printcWarning(_( + 'WARNING : wrong value for the progress bar.\n')), 3) + else: + perc = (float(val-self.valMin) / (self.valMax - self.valMin)) * 100. + nb_equals = int(perc * self.length / 100) + out = '\r %s : %3d %% [%s%s]' % (self.name, perc, nb_equals*'=', + (self.length - nb_equals)*' ' ) + self.logger.write(out, 3) + self.logger.flush() + diff --git a/commands/generate.py b/commands/generate.py index df0814a..b79735d 100644 --- a/commands/generate.py +++ b/commands/generate.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,19 +17,129 @@ # 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 sys -import shutil -import imp -import subprocess -import src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand +import src.pyconf as PYCONF + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The generate command generates SALOME modules from 'pure cpp' products. + WARNING: this command NEEDS YACSGEN to run. + + examples: + >> sat generate SALOME --products FLICACPP + """ + + name = "generate" + + def getParser(self): + """Define all options for command 'sat generate '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _("Optional: the list of products to generate")) + parser.add_option('', 'yacsgen', 'string', 'yacsgen', + _("Optional: path to YACSGEN's module_generator package")) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat generate '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # Check that the command has been called with an application + src.check_config_has_application(runner.cfg) + + logger.write(_('Generation of SALOME modules for application %s\n') % \ + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + status = src.KO_STATUS + + # verify that YACSGEN is available + yacsgen_dir = check_yacsgen(runner.cfg, options.yacsgen, logger) + + if isinstance(yacsgen_dir, tuple): + # The check failed + __, error = yacsgen_dir + msg = _("Error: %s") % error + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Make the generator module visible by python + sys.path.insert(0, yacsgen_dir) + + src.printcolors.print_value(logger, _("YACSGEN dir"), yacsgen_dir, 3) + logger.write("\n", 2) + products = runner.cfg.APPLICATION.products + if options.products: + products = options.products + + details = [] + nbgen = 0 + + context = build_context(runner.cfg, logger) + for product in products: + header = _("Generating %s") % src.printcolors.printcLabel(product) + header += " %s " % ("." * (20 - len(product))) + logger.write(header, 3) + logger.flush() + + if product not in runner.cfg.PRODUCTS: + logger.write(_("Unknown product\n"), 3, False) + continue + + pi = src.product.get_product_config(runner.cfg, product) + if not src.product.product_is_generated(pi): + logger.write(_("not a generated product\n"), 3, False) + continue -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _("Optional: the list of products to generate")) -parser.add_option('', 'yacsgen', 'string', 'yacsgen', - _("Optional: path to YACSGEN's module_generator package")) + nbgen += 1 + try: + result = generate_component_list(runner.cfg, + pi, + context, + logger) + except Exception as exc: + result = str(exc) + + if result != src.OK_STATUS: + result = _("ERROR: %s") % result + details.append([product, result]) + + if len(details) == 0: + status = src.OK_STATUS + else: #if config.USER.output_level != 3: + logger.write("\n", 2, False) + logger.write(_("The following modules were not generated correctly:\n"), 2) + for d in details: + logger.write(" %s: %s\n" % (d[0], d[1]), 2, False) + logger.write("\n", 2, False) + + if status == src.OK_STATUS: + return 0 + return len(details) + def generate_component_list(config, product_info, context, logger): res = "?" @@ -66,7 +177,7 @@ def generate_component(config, compo, product_info, context, header, logger): src.printcolors.print_value(logger, "cpp_path", cpp_path, 4) # create a product_info at runtime - compo_info = src.pyconf.Mapping(config) + compo_info = PYCONF.Mapping(config) compo_info.name = compo compo_info.nb_proc = 1 generate_dir = os.path.join(config.APPLICATION.workdir, "GENERATED") @@ -79,7 +190,7 @@ def generate_component(config, compo, product_info, context, header, logger): compo_info.depend.append(product_info.name, "") # add cpp module compo_info.opt_depend = product_info.opt_depend - config.PRODUCTS.addMapping(compo, src.pyconf.Mapping(config), "") + config.PRODUCTS.addMapping(compo, PYCONF.Mapping(config), "") config.PRODUCTS[compo].default = compo_info builder = src.compilation.Builder(config, logger, compo_info, check_src=False) @@ -300,97 +411,3 @@ def check_yacsgen(config, directory, logger): return (False, _("The python module module_generator was not found in YACSGEN")) - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the generate command description. - :rtype: str - ''' - return _("""\ -The generate command generates SALOME modules from 'pure cpp' products. -WARNING: this command NEEDS YACSGEN to run. - -example: ->> sat generate SALOME-master --products FLICACPP""") - - -def run(args, runner, logger): - '''method that is called when salomeTools is called with generate parameter. - ''' - - # Check that the command has been called with an application - src.check_config_has_application(runner.cfg) - - logger.write(_('Generation of SALOME modules for application %s\n') % \ - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - (options, args) = parser.parse_args(args) - - status = src.KO_STATUS - - # verify that YACSGEN is available - yacsgen_dir = check_yacsgen(runner.cfg, options.yacsgen, logger) - - if isinstance(yacsgen_dir, tuple): - # The check failed - __, error = yacsgen_dir - msg = _("Error: %s") % error - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # Make the generator module visible by python - sys.path.insert(0, yacsgen_dir) - - src.printcolors.print_value(logger, _("YACSGEN dir"), yacsgen_dir, 3) - logger.write("\n", 2) - products = runner.cfg.APPLICATION.products - if options.products: - products = options.products - - details = [] - nbgen = 0 - - context = build_context(runner.cfg, logger) - for product in products: - header = _("Generating %s") % src.printcolors.printcLabel(product) - header += " %s " % ("." * (20 - len(product))) - logger.write(header, 3) - logger.flush() - - if product not in runner.cfg.PRODUCTS: - logger.write(_("Unknown product\n"), 3, False) - continue - - pi = src.product.get_product_config(runner.cfg, product) - if not src.product.product_is_generated(pi): - logger.write(_("not a generated product\n"), 3, False) - continue - - nbgen += 1 - try: - result = generate_component_list(runner.cfg, - pi, - context, - logger) - except Exception as exc: - result = str(exc) - - if result != src.OK_STATUS: - result = _("ERROR: %s") % result - details.append([product, result]) - - if len(details) == 0: - status = src.OK_STATUS - else: #if config.USER.output_level != 3: - logger.write("\n", 2, False) - logger.write(_("The following modules were not generated correctly:\n"), 2) - for d in details: - logger.write(" %s: %s\n" % (d[0], d[1]), 2, False) - logger.write("\n", 2, False) - - if status == src.OK_STATUS: - return 0 - return len(details) - diff --git a/commands/init.py b/commands/init.py index 7c14b7d..9493114 100644 --- a/commands/init.py +++ b/commands/init.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,27 +17,92 @@ # 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 src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand +import src.pyconf as PYCONF + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The init command Changes the local settings of SAT + """ + + name = "init" + + def getParser(self): + """Define all options for command 'sat init '""" + parser = self.getParserWithHelp() + parser.add_option('b', 'base', 'string', 'base', + _('Optional: The path to the products base')) + parser.add_option('w', 'workdir', 'string', 'workdir', + _('Optional: The path to the working directory ' + '(where to install the applications')) + parser.add_option('a', 'archive_dir', 'string', 'archive_dir', + _('Optional: The path to the local archive directory ' + '(where to install local source archives')) + parser.add_option('v', 'VCS', 'string', 'VCS', + _('Optional: The address of the repository of SAT ' + '(only informative)')) + parser.add_option('t', 'tag', 'string', 'tag', + _('Optional: The tag of SAT (only informative)')) + parser.add_option('l', 'log_dir', 'string', 'log_dir', + _('Optional: The directory where to put all the logs of SAT')) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat init '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # Print some informations + logger.write(_('Local Settings of SAT %s\n\n') % \ + src.printcolors.printcLabel(runner.cfg.VARS.salometoolsway), 1) + + res = 0 + + # Set the options corresponding to a directory + for opt in [("base" , options.base), + ("workdir", options.workdir), + ("log_dir", options.log_dir), + ("archive_dir", options.archive_dir)]: + key, value = opt + if value: + res_check = check_path(value, logger) + res += res_check + if res_check == 0: + res_set = set_local_value(runner.cfg, key, value, logger) + res += res_set + + # Set the options corresponding to an informative value + for opt in [("VCS", options.VCS), ("tag", options.tag)]: + key, value = opt + res_set = set_local_value(runner.cfg, key, value, logger) + res += res_set + + display_local_values(runner.cfg, logger) + + return res -# Define all possible option for the init command : sat init -parser = src.options.Options() -parser.add_option('b', 'base', 'string', 'base', - _('Optional: The path to the products base')) -parser.add_option('w', 'workdir', 'string', 'workdir', - _('Optional: The path to the working directory ' - '(where to install the applications')) -parser.add_option('a', 'archive_dir', 'string', 'archive_dir', - _('Optional: The path to the local archive directory ' - '(where to install local source archives')) -parser.add_option('v', 'VCS', 'string', 'VCS', - _('Optional: The address of the repository of SAT ' - '(only informative)')) -parser.add_option('t', 'tag', 'string', 'tag', - _('Optional: The tag of SAT (only informative)')) -parser.add_option('l', 'log_dir', 'string', 'log_dir', - _('Optional: The directory where to put all the logs of SAT')) def set_local_value(config, key, value, logger): """ Edit the site.pyconf file and change a value. @@ -51,7 +117,7 @@ def set_local_value(config, key, value, logger): local_file_path = os.path.join(config.VARS.datadir, "local.pyconf") # Update the local.pyconf file try: - local_cfg = src.pyconf.Config(local_file_path) + local_cfg = PYCONF.Config(local_file_path) local_cfg.LOCAL[key] = value ff = open(local_file_path, 'w') local_cfg.__save__(ff, 1) @@ -112,47 +178,3 @@ def check_path(path_to_check, logger): return 1 return 0 - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the init command description. - :rtype: str - ''' - return _("Changes the local settings of SAT.") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with init parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # Print some informations - logger.write(_('Local Settings of SAT %s\n\n') % \ - src.printcolors.printcLabel(runner.cfg.VARS.salometoolsway), 1) - - res = 0 - - # Set the options corresponding to a directory - for opt in [("base" , options.base), - ("workdir", options.workdir), - ("log_dir", options.log_dir), - ("archive_dir", options.archive_dir)]: - key, value = opt - if value: - res_check = check_path(value, logger) - res += res_check - if res_check == 0: - res_set = set_local_value(runner.cfg, key, value, logger) - res += res_set - - # Set the options corresponding to an informative value - for opt in [("VCS", options.VCS), ("tag", options.tag)]: - key, value = opt - res_set = set_local_value(runner.cfg, key, value, logger) - res += res_set - - display_local_values(runner.cfg, logger) - - return res diff --git a/commands/job.py b/commands/job.py index 4f6b891..d07e93d 100644 --- a/commands/job.py +++ b/commands/job.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,36 +17,56 @@ # 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 src -import src.salomeTools -# Define all possible option for the make command : sat make -parser = src.options.Options() -parser.add_option( - 'j', 'jobs_config', 'string', 'jobs_cfg', - _('Mandatory: The name of the config file that contains the jobs configuration') ) -parser.add_option( - '', 'name', 'string', 'job', - _('Mandatory: The job name from which to execute commands.'), "" ) +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the job command description. - :rtype: str - ''' - return _("Executes the commands of the job defined" - " in the jobs configuration file\n\nexample:\nsat job " - "--jobs_config my_jobs --name my_job") +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The job command executes the commands of the job defined + in the jobs configuration file\ + + examples: + >> sat job --jobs_config my_jobs --name my_job" + """ -def run(args, runner, logger): - '''method that is called when salomeTools is called with job parameter. - ''' + name = "job" + + def getParser(self): + """Define all options for command 'sat job '""" + parser = self.getParserWithHelp() + parser.add_option( + 'j', 'jobs_config', 'string', 'jobs_cfg', + _('Mandatory: The name of the config file that contains the jobs configuration') ) + parser.add_option( + '', 'name', 'string', 'job', + _('Mandatory: The job name from which to execute commands.'), "" ) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat job '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) - # Parse the options - (options, args) = parser.parse_args(args) + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() l_cfg_dir = runner.cfg.PATHS.JOBPATH diff --git a/commands/jobs.py b/commands/jobs.py index 0516243..1c4e4e0 100644 --- a/commands/jobs.py +++ b/commands/jobs.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -26,10 +27,14 @@ import csv import shutil import itertools import re -import paramiko -import src +# import paramiko later + import src.ElementTree as etree +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand +import src.pyconf as PYCONF STYLESHEET_GLOBAL = "jobs_global_report.xsl" STYLESHEET_BOARD = "jobs_board_report.xsl" @@ -37,33 +42,270 @@ STYLESHEET_BOARD = "jobs_board_report.xsl" DAYS_SEPARATOR = "," CSV_DELIMITER = ";" -parser = src.options.Options() +_PARAMIKO = [] + +def getParamiko(logger=None): + if len(_PARAMIKO) == 0: + try: + import paramiko as PARAMIKO + _PARAMIKO.append(PARAMIKO) + return PARAMIKO + except Exception as e: + if logger is not None: + logger.critical("Problem import paramiko. No jobs if not 'pip install paramiko'") + return None + else: + return _PARAMIKO[0] + + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The jobs command command launches maintenances that are described in + the dedicated jobs configuration file. + + examples: + >> sat jobs --name my_jobs --publish + """ + + name = "jobs" + + def getParser(self): + """Define all options for command 'sat jobs '""" + parser = self.getParserWithHelp() + parser.add_option( + 'n', 'name', 'list2', 'jobs_cfg', + _('Mandatory: The name of the config file that contains the jobs configuration. Can be a list.') ) + parser.add_option( + 'o', 'only_jobs', 'list2', 'only_jobs', + _('Optional: the list of jobs to launch, by their name. ') ) + parser.add_option( + 'l', 'list', 'boolean', 'list', + _('Optional: list all available config files.') ) + parser.add_option( + 't', 'test_connection', 'boolean', 'test_connection', + _("Optional: try to connect to the machines. Not executing the jobs."), + False ) + parser.add_option( + 'p', 'publish', 'boolean', 'publish', + _("Optional: generate an xml file that can be read in a browser to display the jobs status."), + False ) + parser.add_option( + 'i', 'input_boards', 'string', 'input_boards', _("Optional: " + "the path to csv file that contain the expected boards."), + "" ) + parser.add_option( + '', 'completion', 'boolean', 'no_label', + _("Optional (internal use): do not print labels, Works only with --list."), + False ) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat jobs '""" + argList = self.assumeAsList(cmd_arguments) -parser.add_option( - 'n', 'name', 'list2', 'jobs_cfg', - _('Mandatory: The name of the config file that contains the jobs configuration. Can be a list.') ) -parser.add_option( - 'o', 'only_jobs', 'list2', 'only_jobs', - _('Optional: the list of jobs to launch, by their name. ') ) -parser.add_option( - 'l', 'list', 'boolean', 'list', - _('Optional: list all available config files.') ) -parser.add_option( - 't', 'test_connection', 'boolean', 'test_connection', - _("Optional: try to connect to the machines. Not executing the jobs."), - False ) -parser.add_option( - 'p', 'publish', 'boolean', 'publish', - _("Optional: generate an xml file that can be read in a browser to display the jobs status."), - False ) -parser.add_option( - 'i', 'input_boards', 'string', 'input_boards', _("Optional: " - "the path to csv file that contain the expected boards."), - "" ) -parser.add_option( - '', 'completion', 'boolean', 'no_label', - _("Optional (internal use): do not print labels, Works only with --list."), - False ) + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + l_cfg_dir = runner.cfg.PATHS.JOBPATH + + # list option : display all the available config files + if options.list: + for cfg_dir in l_cfg_dir: + if not options.no_label: + logger.write("------ %s\n" % + src.printcolors.printcHeader(cfg_dir)) + if not os.path.exists(cfg_dir): + continue + for f in sorted(os.listdir(cfg_dir)): + if not f.endswith('.pyconf'): + continue + cfilename = f[:-7] + logger.write("%s\n" % cfilename) + return 0 + + # Make sure the jobs_config option has been called + if not options.jobs_cfg: + message = _("The option --jobs_config is required\n") + src.printcolors.printcError(message) + return 1 + + # Find the file in the directories, unless it is a full path + # merge all in a config + merger = PYCONF.ConfigMerger() + config_jobs = PYCONF.Config() + l_conf_files_path = [] + for config_file in options.jobs_cfg: + found, file_jobs_cfg = get_config_file_path(config_file, l_cfg_dir) + if not found: + msg = _("""\ +The file configuration %s was not found. +Use the --list option to get the possible files.""") % config_file + logger.write("%s\n" % src.printcolors.printcError(msg), 1) + return 1 + l_conf_files_path.append(file_jobs_cfg) + # Read the config that is in the file + one_config_jobs = src.read_config_from_a_file(file_jobs_cfg) + merger.merge(config_jobs, one_config_jobs) + + info = [ + (_("Platform"), runner.cfg.VARS.dist), + (_("Files containing the jobs configuration"), l_conf_files_path) + ] + src.print_info(logger, info) + + if options.only_jobs: + l_jb = PYCONF.Sequence() + for jb in config_jobs.jobs: + if jb.name in options.only_jobs: + l_jb.append(jb, + "Job that was given in only_jobs option parameters\n") + config_jobs.jobs = l_jb + + # Parse the config jobs in order to develop all the factorized jobs + develop_factorized_jobs(config_jobs) + + # Make a unique file that contain all the jobs in order to use it + # on every machine + name_pyconf = "_".join([os.path.basename(path)[:-len('.pyconf')] + for path in l_conf_files_path]) + ".pyconf" + path_pyconf = src.get_tmp_filename(runner.cfg, name_pyconf) + #Save config + f = file( path_pyconf , 'w') + config_jobs.__save__(f) + + # log the paramiko problems + log_dir = src.get_log_path(runner.cfg) + paramiko_log_dir_path = os.path.join(log_dir, "JOBS") + src.ensure_path_exists(paramiko_log_dir_path) + paramiko = getParamiko(logger) + paramiko.util.log_to_file(os.path.join(paramiko_log_dir_path, + logger.txtFileName)) + + # Initialization + today_jobs = Jobs(runner, + logger, + path_pyconf, + config_jobs) + + # SSH connection to all machines + today_jobs.ssh_connection_all_machines() + if options.test_connection: + return 0 + + gui = None + if options.publish: + logger.write(src.printcolors.printcInfo( + _("Initialize the xml boards : ")), 5) + logger.flush() + + # Copy the stylesheets in the log directory + log_dir = log_dir + xsl_dir = os.path.join(runner.cfg.VARS.srcDir, 'xsl') + files_to_copy = [] + files_to_copy.append(os.path.join(xsl_dir, STYLESHEET_GLOBAL)) + files_to_copy.append(os.path.join(xsl_dir, STYLESHEET_BOARD)) + files_to_copy.append(os.path.join(xsl_dir, "command.xsl")) + files_to_copy.append(os.path.join(xsl_dir, "running.gif")) + for file_path in files_to_copy: + # OP We use copy instead of copy2 to update the creation date + # So we can clean the LOGS directories easily + shutil.copy(file_path, log_dir) + + # Instanciate the Gui in order to produce the xml files that contain all + # the boards + gui = Gui(log_dir, + today_jobs.ljobs, + today_jobs.ljobs_not_today, + runner.cfg.VARS.datehour, + logger, + file_boards = options.input_boards) + + logger.write(src.printcolors.printcSuccess("OK"), 5) + logger.write("\n\n", 5) + logger.flush() + + # Display the list of the xml files + logger.write(src.printcolors.printcInfo(("Here is the list of published" + " files :\n")), 4) + logger.write("%s\n" % gui.xml_global_file.logFile, 4) + for board in gui.d_xml_board_files.keys(): + file_path = gui.d_xml_board_files[board].logFile + file_name = os.path.basename(file_path) + logger.write("%s\n" % file_path, 4) + logger.add_link(file_name, "board", 0, board) + + logger.write("\n", 4) + + today_jobs.gui = gui + + interruped = False + try: + # Run all the jobs contained in config_jobs + today_jobs.run_jobs() + except KeyboardInterrupt: + interruped = True + logger.write("\n\n%s\n\n" % + (src.printcolors.printcWarning(_("Forced interruption"))), 1) + except Exception as e: + msg = _("CRITICAL ERROR: The jobs loop has been interrupted\n") + logger.write("\n\n%s\n" % src.printcolors.printcError(msg) ) + logger.write("%s\n" % str(e)) + # get stack + __, __, exc_traceback = sys.exc_info() + fp = tempfile.TemporaryFile() + traceback.print_tb(exc_traceback, file=fp) + fp.seek(0) + stack = fp.read() + logger.write("\nTRACEBACK:\n%s\n" % stack.replace('"',"'"), 1) + + finally: + res = 0 + if interruped: + res = 1 + msg = _("Killing the running jobs and trying to get the corresponding logs\n") + logger.write(src.printcolors.printcWarning(msg)) + + # find the potential not finished jobs and kill them + for jb in today_jobs.ljobs: + if not jb.has_finished(): + res = 1 + try: + jb.kill_remote_process() + except Exception as e: + msg = _("Failed to kill job %(1)s: %(2)s\n") % {"1": jb.name, "2": e} + logger.write(src.printcolors.printcWarning(msg)) + if jb.res_job != "0": + res = 1 + if interruped: + if today_jobs.gui: + today_jobs.gui.last_update(_("Forced interruption")) + else: + if today_jobs.gui: + today_jobs.gui.last_update() + # Output the results + today_jobs.write_all_results() + # Remove the temporary pyconf file + if os.path.exists(path_pyconf): + os.remove(path_pyconf) + return res + class Machine(object): '''Class to manage a ssh connection on a machine @@ -82,7 +324,8 @@ class Machine(object): self.user = user self.password = passwd self.sat_path = sat_path - self.ssh = paramiko.SSHClient() + self.paramiko = getParamiko() + self.ssh = self.paramiko.SSHClient() self._connection_successful = None def connect(self, logger): @@ -95,18 +338,18 @@ class Machine(object): self._connection_successful = False self.ssh.load_system_host_keys() - self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + self.ssh.set_missing_host_key_policy(self.paramiko.AutoAddPolicy()) try: self.ssh.connect(self.host, port=self.port, username=self.user, password = self.password) - except paramiko.AuthenticationException: + except self.paramiko.AuthenticationException: message = src.KO_STATUS + _("Authentication failed") - except paramiko.BadHostKeyException: + except self.paramiko.BadHostKeyException: message = (src.KO_STATUS + _("The server's host key could not be verified")) - except paramiko.SSHException: + except self.paramiko.SSHException: message = ( _("SSHException error connecting or " "establishing an SSH session")) except: @@ -205,7 +448,7 @@ WARNING : trying to ask if the connection to try: # Does not wait the end of the command (stdin, stdout, stderr) = self.ssh.exec_command(command) - except paramiko.SSHException: + except self.paramiko.SSHException: message = src.KO_STATUS + _( ": the server failed to execute the command\n") logger.write( src.printcolors.printcError(message)) @@ -1671,7 +1914,7 @@ def develop_factorized_jobs(config_jobs): # machine : ["CO7.2 physique", ["CO6.4 physique", $MONDAY, $TUESDAY ], "FD22"] name_job = jb.name for machine in jb.machine: - new_job = src.pyconf.deepCopyMapping(jb) + new_job = PYCONF.deepCopyMapping(jb) # case where there is a jobs on the machine corresponding to all # days in when variable. if type(machine) == type(""): @@ -1686,201 +1929,3 @@ def develop_factorized_jobs(config_jobs): config_jobs.jobs = developed_jobs_list - -## -# Describes the command -def description(): - return _("""\ -The jobs command launches maintenances that are described in -the dedicated jobs configuration file. - -example: ->> sat jobs --name my_jobs --publish""") - -## -# Runs the command. -def run(args, runner, logger): - - (options, args) = parser.parse_args(args) - - l_cfg_dir = runner.cfg.PATHS.JOBPATH - - # list option : display all the available config files - if options.list: - for cfg_dir in l_cfg_dir: - if not options.no_label: - logger.write("------ %s\n" % - src.printcolors.printcHeader(cfg_dir)) - if not os.path.exists(cfg_dir): - continue - for f in sorted(os.listdir(cfg_dir)): - if not f.endswith('.pyconf'): - continue - cfilename = f[:-7] - logger.write("%s\n" % cfilename) - return 0 - - # Make sure the jobs_config option has been called - if not options.jobs_cfg: - message = _("The option --jobs_config is required\n") - src.printcolors.printcError(message) - return 1 - - # Find the file in the directories, unless it is a full path - # merge all in a config - merger = src.pyconf.ConfigMerger() - config_jobs = src.pyconf.Config() - l_conf_files_path = [] - for config_file in options.jobs_cfg: - found, file_jobs_cfg = get_config_file_path(config_file, l_cfg_dir) - if not found: - msg = _("""\ -The file configuration %s was not found. -Use the --list option to get the possible files.""") % config_file - logger.write("%s\n" % src.printcolors.printcError(msg), 1) - return 1 - l_conf_files_path.append(file_jobs_cfg) - # Read the config that is in the file - one_config_jobs = src.read_config_from_a_file(file_jobs_cfg) - merger.merge(config_jobs, one_config_jobs) - - info = [ - (_("Platform"), runner.cfg.VARS.dist), - (_("Files containing the jobs configuration"), l_conf_files_path) - ] - src.print_info(logger, info) - - if options.only_jobs: - l_jb = src.pyconf.Sequence() - for jb in config_jobs.jobs: - if jb.name in options.only_jobs: - l_jb.append(jb, - "Job that was given in only_jobs option parameters\n") - config_jobs.jobs = l_jb - - # Parse the config jobs in order to develop all the factorized jobs - develop_factorized_jobs(config_jobs) - - # Make a unique file that contain all the jobs in order to use it - # on every machine - name_pyconf = "_".join([os.path.basename(path)[:-len('.pyconf')] - for path in l_conf_files_path]) + ".pyconf" - path_pyconf = src.get_tmp_filename(runner.cfg, name_pyconf) - #Save config - f = file( path_pyconf , 'w') - config_jobs.__save__(f) - - # log the paramiko problems - log_dir = src.get_log_path(runner.cfg) - paramiko_log_dir_path = os.path.join(log_dir, "JOBS") - src.ensure_path_exists(paramiko_log_dir_path) - paramiko.util.log_to_file(os.path.join(paramiko_log_dir_path, - logger.txtFileName)) - - # Initialization - today_jobs = Jobs(runner, - logger, - path_pyconf, - config_jobs) - - # SSH connection to all machines - today_jobs.ssh_connection_all_machines() - if options.test_connection: - return 0 - - gui = None - if options.publish: - logger.write(src.printcolors.printcInfo( - _("Initialize the xml boards : ")), 5) - logger.flush() - - # Copy the stylesheets in the log directory - log_dir = log_dir - xsl_dir = os.path.join(runner.cfg.VARS.srcDir, 'xsl') - files_to_copy = [] - files_to_copy.append(os.path.join(xsl_dir, STYLESHEET_GLOBAL)) - files_to_copy.append(os.path.join(xsl_dir, STYLESHEET_BOARD)) - files_to_copy.append(os.path.join(xsl_dir, "command.xsl")) - files_to_copy.append(os.path.join(xsl_dir, "running.gif")) - for file_path in files_to_copy: - # OP We use copy instead of copy2 to update the creation date - # So we can clean the LOGS directories easily - shutil.copy(file_path, log_dir) - - # Instanciate the Gui in order to produce the xml files that contain all - # the boards - gui = Gui(log_dir, - today_jobs.ljobs, - today_jobs.ljobs_not_today, - runner.cfg.VARS.datehour, - logger, - file_boards = options.input_boards) - - logger.write(src.printcolors.printcSuccess("OK"), 5) - logger.write("\n\n", 5) - logger.flush() - - # Display the list of the xml files - logger.write(src.printcolors.printcInfo(("Here is the list of published" - " files :\n")), 4) - logger.write("%s\n" % gui.xml_global_file.logFile, 4) - for board in gui.d_xml_board_files.keys(): - file_path = gui.d_xml_board_files[board].logFile - file_name = os.path.basename(file_path) - logger.write("%s\n" % file_path, 4) - logger.add_link(file_name, "board", 0, board) - - logger.write("\n", 4) - - today_jobs.gui = gui - - interruped = False - try: - # Run all the jobs contained in config_jobs - today_jobs.run_jobs() - except KeyboardInterrupt: - interruped = True - logger.write("\n\n%s\n\n" % - (src.printcolors.printcWarning(_("Forced interruption"))), 1) - except Exception as e: - msg = _("CRITICAL ERROR: The jobs loop has been interrupted\n") - logger.write("\n\n%s\n" % src.printcolors.printcError(msg) ) - logger.write("%s\n" % str(e)) - # get stack - __, __, exc_traceback = sys.exc_info() - fp = tempfile.TemporaryFile() - traceback.print_tb(exc_traceback, file=fp) - fp.seek(0) - stack = fp.read() - logger.write("\nTRACEBACK:\n%s\n" % stack.replace('"',"'"), 1) - - finally: - res = 0 - if interruped: - res = 1 - msg = _("Killing the running jobs and trying to get the corresponding logs\n") - logger.write(src.printcolors.printcWarning(msg)) - - # find the potential not finished jobs and kill them - for jb in today_jobs.ljobs: - if not jb.has_finished(): - res = 1 - try: - jb.kill_remote_process() - except Exception as e: - msg = _("Failed to kill job %(1)s: %(2)s\n") % {"1": jb.name, "2": e} - logger.write(src.printcolors.printcWarning(msg)) - if jb.res_job != "0": - res = 1 - if interruped: - if today_jobs.gui: - today_jobs.gui.last_update(_("Forced interruption")) - else: - if today_jobs.gui: - today_jobs.gui.last_update() - # Output the results - today_jobs.write_all_results() - # Remove the temporary pyconf file - if os.path.exists(path_pyconf): - os.remove(path_pyconf) - return res diff --git a/commands/launcher.py b/commands/launcher.py index 6143dcd..6f65a5c 100644 --- a/commands/launcher.py +++ b/commands/launcher.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,27 +17,88 @@ # 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 +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The launcher command generates a SALOME launcher. + + examples: + >> sat launcher SALOME + """ + + name = "launcher" + + def getParser(self): + """Define all possible options for command 'sat launcher '""" + parser = self.getParserWithHelp() + return parser + + def run(self, cmd_arguments): + """method called for command 'sat launcher '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() -parser = src.options.Options() + # 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) + + # 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) + + # Generate the launcher + launcherPath = generate_launch_file( runner.cfg, + logger, + launcher_name, + launcher_path, + additional_env = additional_environ ) + + return 0 -parser.add_option( - 'n', 'name', 'string', 'name', - _('Optional: The name of the launcher (default is APPLICATION.profile.launcher_name)') ) -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" - " NOTICE: this command will ssh to retrieve information to each machine in the list") ) def generate_launch_file(config, logger, @@ -215,56 +277,3 @@ def copy_catalog(config, 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. - -example: ->> sat 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) - - # 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) - - # Generate the launcher - launcherPath = generate_launch_file( runner.cfg, - logger, - launcher_name, - launcher_path, - additional_env = additional_environ ) - - return 0 diff --git a/commands/log.py b/commands/log.py index d3eb1ca..4ab5d44 100644 --- a/commands/log.py +++ b/commands/log.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,6 +17,7 @@ # 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 shutil import re @@ -23,6 +25,10 @@ import glob import datetime import stat +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + # Compatibility python 2/3 for input function # input stays input for python 3 and input = raw_input for python 2 try: @@ -30,29 +36,205 @@ try: except NameError: pass -import src +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The log command gives access to the logs produced by the salomeTools commands. + + examples: + >> sat log + """ + + name = "log" + + def getParser(self): + """Define all options for command 'sat log '""" + parser = self.getParserWithHelp() + parser.add_option( + 't', 'terminal', 'boolean', 'terminal', + "Optional: Show sat instances logs, no browser.") + parser.add_option( + 'l', 'last', 'boolean', 'last', + "Show the log of the last launched command.") + parser.add_option( + 'x', 'last_terminal', 'boolean', 'last_terminal', + """Optional: Show compile log of products, no browser.""") + parser.add_option( + 'f', 'full', 'boolean', 'full', + "Optional: Show the logs of ALL the launched commands.") + parser.add_option( + 'c', 'clean', 'int', 'clean', + "Optional: Erase the n most ancient log files.") + parser.add_option( + 'n', 'no_browser', 'boolean', 'no_browser', + "Optional: Do not launch the browser at the end of the command. Only update the hat file.") + return parser + + def run(self, cmd_arguments): + """method called for command 'sat log '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + + # get the log directory. + logDir = src.get_log_path(runner.cfg) + + # Print a header + nb_files_log_dir = len(glob.glob(os.path.join(logDir, "*"))) + info = [("log directory", logDir), + ("number of log files", nb_files_log_dir)] + src.print_info(logger, info) + + # If the clean options is invoked, + # do nothing but deleting the concerned files. + if options.clean: + nbClean = options.clean + # get the list of files to remove + lLogs = src.logger.list_log_file(logDir, + src.logger.log_all_command_file_expression) + nbLogFiles = len(lLogs) + # Delete all if the invoked number is bigger than the number of log files + if nbClean > nbLogFiles: + nbClean = nbLogFiles + # Get the list to delete and do the removing + lLogsToDelete = sorted(lLogs)[:nbClean] + for filePath, __, __, __, __, __, __ in lLogsToDelete: + # remove the xml log file + remove_log_file(filePath, logger) + # remove also the corresponding txt file in OUT directory + txtFilePath = os.path.join(os.path.dirname(filePath), + 'OUT', + os.path.basename(filePath)[:-len('.xml')] + '.txt') + remove_log_file(txtFilePath, logger) + # remove also the corresponding pyconf (do not exist 2016-06) + # file in OUT directory + pyconfFilePath = os.path.join(os.path.dirname(filePath), + 'OUT', + os.path.basename(filePath)[:-len('.xml')] + '.pyconf') + remove_log_file(pyconfFilePath, logger) + + + logger.write(src.printcolors.printcSuccess("OK\n")) + logger.write("%i logs deleted.\n" % nbClean) + return 0 + + # determine the commands to show in the hat log + notShownCommands = list(runner.cfg.INTERNAL.log.not_shown_commands) + if options.full: + notShownCommands = [] + + # Find the stylesheets Directory and files + xslDir = os.path.join(runner.cfg.VARS.srcDir, 'xsl') + xslCommand = os.path.join(xslDir, "command.xsl") + xslHat = os.path.join(xslDir, "hat.xsl") + xsltest = os.path.join(xslDir, "test.xsl") + imgLogo = os.path.join(xslDir, "LOGO-SAT.png") + + # copy the stylesheets in the log directory + # OP We use copy instead of copy2 to update the creation date + # So we can clean the LOGS directories easily + shutil.copy(xslCommand, logDir) + shutil.copy(xslHat, logDir) + src.ensure_path_exists(os.path.join(logDir, "TEST")) + shutil.copy(xsltest, os.path.join(logDir, "TEST")) + shutil.copy(imgLogo, logDir) + + # If the last option is invoked, just, show the last log file + if options.last_terminal: + src.check_config_has_application(runner.cfg) + rootLogDir = os.path.join(runner.cfg.APPLICATION.workdir, 'LOGS') + src.ensure_path_exists(rootLogDir) + log_dirs = os.listdir(rootLogDir) + if log_dirs == []: + raise Exception("log directory empty") + log_dirs= sorted(log_dirs) + show_last_logs(logger, runner.cfg, log_dirs) + return 0 + + # If the last option is invoked, just, show the last log file + if options.last: + lastLogFilePath = get_last_log_file( + logDir, notShownCommands + ["config"]) + if lastLogFilePath is None: + raise Exception("last log file not found in '%s'" % logDir) + if options.terminal: + # Show the log corresponding to the selected command call + print_log_command_in_terminal(lastLogFilePath, logger) + else: + # open the log xml file in the user editor + src.system.show_in_editor(runner.cfg.USER.browser, + lastLogFilePath, logger) + return 0 -# Define all possible option for log command : sat log -parser = src.options.Options() -parser.add_option( - 't', 'terminal', 'boolean', 'terminal', - "Optional: Show sat instances logs, no browser.") -parser.add_option( - 'l', 'last', 'boolean', 'last', - "Show the log of the last launched command.") -parser.add_option( - 'x', 'last_terminal', 'boolean', 'last_terminal', - """Optional: Show compile log of products, no browser.""") -parser.add_option( - 'f', 'full', 'boolean', 'full', - "Optional: Show the logs of ALL the launched commands.") -parser.add_option( - 'c', 'clean', 'int', 'clean', - "Optional: Erase the n most ancient log files.") -parser.add_option( - 'n', 'no_browser', 'boolean', 'no_browser', - "Optional: Do not launch the browser at the end of the command. Only update the hat file.") + # If the user asks for a terminal display + if options.terminal: + # Parse the log directory in order to find + # all the files corresponding to the commands + lLogs = src.logger.list_log_file(logDir, + src.logger.log_macro_command_file_expression) + lLogsFiltered = [] + for filePath, __, date, __, hour, cmd, __ in lLogs: + showLog, cmdAppli, __ = src.logger.show_command_log(filePath, cmd, + runner.cfg.VARS.application, notShownCommands) + if showLog: + lLogsFiltered.append((filePath, date, hour, cmd, cmdAppli)) + + lLogsFiltered = sorted(lLogsFiltered) + nb_logs = len(lLogsFiltered) + index = 0 + # loop on all files and print it with date, time and command name + for __, date, hour, cmd, cmdAppli in lLogsFiltered: + num = src.printcolors.printcLabel("%2d" % (nb_logs - index)) + logger.write("%s: %13s %s %s %s\n" % + (num, cmd, date, hour, cmdAppli), 1, False) + index += 1 + + # ask the user what for what command he wants to be displayed + x = -1 + while (x < 0): + x = ask_value(nb_logs) + if x > 0: + index = len(lLogsFiltered) - int(x) + # Show the log corresponding to the selected command call + print_log_command_in_terminal(lLogsFiltered[index][0], logger) + x = 0 + + return 0 + + # Create or update the hat xml that gives access to all the commands log files + logger.write(_("Generating the hat log file (can be long) ... "), 3) + xmlHatFilePath = os.path.join(logDir, 'hat.xml') + src.logger.update_hat_xml(logDir, + application = runner.cfg.VARS.application, + notShownCommands = notShownCommands) + logger.write(src.printcolors.printc("OK"), 3) + logger.write("\n", 3) + + # open the hat xml in the user editor + if not options.no_browser: + logger.write(_("\nOpening the log file\n"), 3) + src.system.show_in_editor(runner.cfg.USER.browser, xmlHatFilePath, logger) + return 0 + def get_last_log_file(logDir, notShownCommands): '''Used in case of last option. Get the last log command file path. @@ -207,158 +389,3 @@ def ask_value(nb): x = -1 return x - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the log command description. - :rtype: str - ''' - return _("Gives access to the logs produced by the salomeTools commands.\n" - "\nexample:\nsat log") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with log parameter. - ''' - # Parse the options - (options, args) = parser.parse_args(args) - - # get the log directory. - logDir = src.get_log_path(runner.cfg) - - # Print a header - nb_files_log_dir = len(glob.glob(os.path.join(logDir, "*"))) - info = [("log directory", logDir), - ("number of log files", nb_files_log_dir)] - src.print_info(logger, info) - - # If the clean options is invoked, - # do nothing but deleting the concerned files. - if options.clean: - nbClean = options.clean - # get the list of files to remove - lLogs = src.logger.list_log_file(logDir, - src.logger.log_all_command_file_expression) - nbLogFiles = len(lLogs) - # Delete all if the invoked number is bigger than the number of log files - if nbClean > nbLogFiles: - nbClean = nbLogFiles - # Get the list to delete and do the removing - lLogsToDelete = sorted(lLogs)[:nbClean] - for filePath, __, __, __, __, __, __ in lLogsToDelete: - # remove the xml log file - remove_log_file(filePath, logger) - # remove also the corresponding txt file in OUT directory - txtFilePath = os.path.join(os.path.dirname(filePath), - 'OUT', - os.path.basename(filePath)[:-len('.xml')] + '.txt') - remove_log_file(txtFilePath, logger) - # remove also the corresponding pyconf (do not exist 2016-06) - # file in OUT directory - pyconfFilePath = os.path.join(os.path.dirname(filePath), - 'OUT', - os.path.basename(filePath)[:-len('.xml')] + '.pyconf') - remove_log_file(pyconfFilePath, logger) - - - logger.write(src.printcolors.printcSuccess("OK\n")) - logger.write("%i logs deleted.\n" % nbClean) - return 0 - - # determine the commands to show in the hat log - notShownCommands = list(runner.cfg.INTERNAL.log.not_shown_commands) - if options.full: - notShownCommands = [] - - # Find the stylesheets Directory and files - xslDir = os.path.join(runner.cfg.VARS.srcDir, 'xsl') - xslCommand = os.path.join(xslDir, "command.xsl") - xslHat = os.path.join(xslDir, "hat.xsl") - xsltest = os.path.join(xslDir, "test.xsl") - imgLogo = os.path.join(xslDir, "LOGO-SAT.png") - - # copy the stylesheets in the log directory - # OP We use copy instead of copy2 to update the creation date - # So we can clean the LOGS directories easily - shutil.copy(xslCommand, logDir) - shutil.copy(xslHat, logDir) - src.ensure_path_exists(os.path.join(logDir, "TEST")) - shutil.copy(xsltest, os.path.join(logDir, "TEST")) - shutil.copy(imgLogo, logDir) - - # If the last option is invoked, just, show the last log file - if options.last_terminal: - src.check_config_has_application(runner.cfg) - rootLogDir = os.path.join(runner.cfg.APPLICATION.workdir, 'LOGS') - src.ensure_path_exists(rootLogDir) - log_dirs = os.listdir(rootLogDir) - if log_dirs == []: - raise Exception("log directory empty") - log_dirs= sorted(log_dirs) - show_last_logs(logger, runner.cfg, log_dirs) - return 0 - - # If the last option is invoked, just, show the last log file - if options.last: - lastLogFilePath = get_last_log_file( - logDir, notShownCommands + ["config"]) - if lastLogFilePath is None: - raise Exception("last log file not found in '%s'" % logDir) - if options.terminal: - # Show the log corresponding to the selected command call - print_log_command_in_terminal(lastLogFilePath, logger) - else: - # open the log xml file in the user editor - src.system.show_in_editor(runner.cfg.USER.browser, - lastLogFilePath, logger) - return 0 - - # If the user asks for a terminal display - if options.terminal: - # Parse the log directory in order to find - # all the files corresponding to the commands - lLogs = src.logger.list_log_file(logDir, - src.logger.log_macro_command_file_expression) - lLogsFiltered = [] - for filePath, __, date, __, hour, cmd, __ in lLogs: - showLog, cmdAppli, __ = src.logger.show_command_log(filePath, cmd, - runner.cfg.VARS.application, notShownCommands) - if showLog: - lLogsFiltered.append((filePath, date, hour, cmd, cmdAppli)) - - lLogsFiltered = sorted(lLogsFiltered) - nb_logs = len(lLogsFiltered) - index = 0 - # loop on all files and print it with date, time and command name - for __, date, hour, cmd, cmdAppli in lLogsFiltered: - num = src.printcolors.printcLabel("%2d" % (nb_logs - index)) - logger.write("%s: %13s %s %s %s\n" % - (num, cmd, date, hour, cmdAppli), 1, False) - index += 1 - - # ask the user what for what command he wants to be displayed - x = -1 - while (x < 0): - x = ask_value(nb_logs) - if x > 0: - index = len(lLogsFiltered) - int(x) - # Show the log corresponding to the selected command call - print_log_command_in_terminal(lLogsFiltered[index][0], logger) - x = 0 - - return 0 - - # Create or update the hat xml that gives access to all the commands log files - logger.write(_("Generating the hat log file (can be long) ... "), 3) - xmlHatFilePath = os.path.join(logDir, 'hat.xml') - src.logger.update_hat_xml(logDir, - application = runner.cfg.VARS.application, - notShownCommands = notShownCommands) - logger.write(src.printcolors.printc("OK"), 3) - logger.write("\n", 3) - - # open the hat xml in the user editor - if not options.no_browser: - logger.write(_("\nOpening the log file\n"), 3) - src.system.show_in_editor(runner.cfg.USER.browser, xmlHatFilePath, logger) - return 0 diff --git a/commands/make.py b/commands/make.py index 8e87292..4878685 100644 --- a/commands/make.py +++ b/commands/make.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -19,15 +20,89 @@ import os import re -import src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The make command executes the 'make' command in the build directory. + + examples: + >> sat make SALOME --products Python,KERNEL,GUI + """ + + name = "make" + + def getParser(self): + """Define all options for the command 'sat make '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products to configure. This option can be' + ' passed several time to configure several products.')) + parser.add_option('o', 'option', 'string', 'option', + _('Optional: Option to add to the make command.'), "") + return parser + + def run(self, cmd_arguments): + """method called for command 'sat make '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) + + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + # Print some informations + logger.write( + _('Executing the make command in the build directories of the application %s\n') % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + info = [(_("BUILD directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] + src.print_info(logger, info) + + # Call the function that will loop over all the products and execute + # the right command(s) + if options.option is None: + options.option = "" + res = make_all_products(runner.cfg, products_infos, options.option, logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nMake: %(status)s (%(1)d/%(2)d)\n") % + { 'status': src.printcolors.printc(final_status), + '1': nb_products - res, + '2': nb_products }, 1) + + return res -# Define all possible option for the make command : sat make -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to configure. This option can be' - ' passed several time to configure several products.')) -parser.add_option('o', 'option', 'string', 'option', - _('Optional: Option to add to the make command.'), "") def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from @@ -194,57 +269,3 @@ def get_nb_proc(product_info, config, make_option): assert nbproc > 0 return nbproc, new_make_option - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the make command description. - :rtype: str - ''' - return _("""\ -The make command executes the 'make' command in the build directory. - -example: ->> sat make SALOME-master --products Python,KERNEL,GUI""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with make parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - # Print some informations - logger.write( - _('Executing the make command in the build directories of the application %s\n') % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - info = [(_("BUILD directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] - src.print_info(logger, info) - - # Call the function that will loop over all the products and execute - # the right command(s) - if options.option is None: - options.option = "" - res = make_all_products(runner.cfg, products_infos, options.option, logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nMake: %(status)s (%(1)d/%(2)d)\n") % - { 'status': src.printcolors.printc(final_status), - '1': nb_products - res, - '2': nb_products }, 1) - - return res diff --git a/commands/makeinstall.py b/commands/makeinstall.py index a3ac68a..2851759 100644 --- a/commands/makeinstall.py +++ b/commands/makeinstall.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,15 +17,87 @@ # 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 src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The makeinstall command executes the 'make install' command in the build directory. + In case of product constructed using a script (build_source : 'script'), + then the makeinstall command do nothing. + + examples: + >> sat makeinstall SALOME --products KERNEL,GUI + """ + + name = "makeinstall" + + def getParser(self): + """Define all options for the command 'sat makeinstall '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products to install. This option can be' + ' passed several time to install several products.')) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat makeinstall '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) -# Define all possible option for the makeinstall command : sat makeinstall -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to install. This option can be' - ' passed several time to install several products.')) + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + # Print some informations + logger.write(_('Executing the make install command in the build directories of the application %s\n') % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + info = [(_("BUILD directory"), + os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] + src.print_info(logger, info) + + # Call the function that will loop over all the products and execute + # the right command(s) + res = makeinstall_all_products(runner.cfg, products_infos, logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nMake install: %(status)s (%(1)d/%(2)d)\n") % \ + { 'status': src.printcolors.printc(final_status), + '1': nb_products - res, + '2': nb_products }, 1) + + return res + def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from @@ -156,56 +229,3 @@ def makeinstall_product(p_name_info, config, logger): logger.write("\n", 3, False) return res - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the makeinstall command description. - :rtype: str - ''' - return _("""\ -The makeinstall command executes the 'make install' command in the build directory. -In case of product constructed using a script (build_source : 'script'), -then the makeinstall command do nothing. - -example: ->> sat makeinstall SALOME-master --products KERNEL,GUI""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with makeinstall parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - # Print some informations - logger.write(_('Executing the make install command in the build directories of the application %s\n') % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - info = [(_("BUILD directory"), - os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] - src.print_info(logger, info) - - # Call the function that will loop over all the products and execute - # the right command(s) - res = makeinstall_all_products(runner.cfg, products_infos, logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nMake install: %(status)s (%(1)d/%(2)d)\n") % \ - { 'status': src.printcolors.printc(final_status), - '1': nb_products - res, - '2': nb_products }, 1) - - return res diff --git a/commands/package.py b/commands/package.py index d23e0d0..868fa48 100644 --- a/commands/package.py +++ b/commands/package.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -24,9 +25,12 @@ import tarfile import codecs import string -import src +from commands.application import get_SALOME_modules -from application import get_SALOME_modules +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand +import src.pyconf as PYCONF BINARY = "binary" SOURCE = "Source" @@ -39,7 +43,8 @@ PROJECT_DIR = "PROJECT" IGNORED_DIRS = [".git", ".svn"] IGNORED_EXTENSIONS = [] -PROJECT_TEMPLATE = """#!/usr/bin/env python +PROJECT_TEMPLATE = """\ +#!/usr/bin/env python #-*- coding:utf-8 -*- # The path to the archive root directory @@ -59,7 +64,8 @@ JOBPATH : $project_path + "jobs/" MACHINEPATH : $project_path + "machines/" """ -LOCAL_TEMPLATE = ("""#!/usr/bin/env python +LOCAL_TEMPLATE = ("""\ +#!/usr/bin/env python #-*- coding:utf-8 -*- LOCAL : @@ -78,33 +84,296 @@ project_file_paths : [$VARS.salometoolsway + $VARS.sep + \"..\" + $VARS.sep""" """ + \"""" + PROJECT_DIR + """\" + $VARS.sep + "project.pyconf"] } """) + + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The package command creates an archive. + There are 4 kinds of archive, which can be mixed: + 1- The binary archive. It contains all the product installation directories and a launcher. + 2- The sources archive. It contains the products archives, + a project corresponding to the application and salomeTools. + 3- The project archive. It contains a project (give the project file path as argument). + 4- The salomeTools archive. It contains salomeTools. + + examples: + >> sat package SALOME --binaries --sources + """ + + name = "package" + + def getParser(self): + """Define all options for command 'sat package '""" + parser = self.getParserWithHelp() + parser.add_option('b', 'binaries', 'boolean', 'binaries', + _('Optional: Produce a binary package.'), False) + parser.add_option('f', 'force_creation', 'boolean', 'force_creation', + _('Optional: Only binary package: produce the archive even if ' + 'there are some missing products.'), False) + parser.add_option('s', 'sources', 'boolean', 'sources', + _('Optional: Produce a compilable archive of the sources of the ' + 'application.'), False) + parser.add_option('', 'with_vcs', 'boolean', 'with_vcs', + _('Optional: Only source package: do not make archive of vcs products.'), + False) + parser.add_option('p', 'project', 'string', 'project', + _('Optional: Produce an archive that contains a project.'), "") + parser.add_option('t', 'salometools', 'boolean', 'sat', + _('Optional: Produce an archive that contains salomeTools.'), False) + parser.add_option('n', 'name', 'string', 'name', + _('Optional: The name or full path of the archive.'), None) + parser.add_option('', 'add_files', 'list2', 'add_files', + _('Optional: The list of additional files to add to the archive.'), []) + parser.add_option('', 'without_commercial', 'boolean', 'without_commercial', + _('Optional: do not add commercial licence.'), False) + parser.add_option('', 'without_property', 'string', 'without_property', + _('Optional: Filter the products by their properties.\n' + '\tSyntax: --without_property :')) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat package '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # Check that a type of package is called, and only one + all_option_types = (options.binaries, + options.sources, + options.project not in ["", None], + options.sat) + + # Check if no option for package type + if all_option_types.count(True) == 0: + msg = _("ERROR: needs a type for the package\n" + " Use one of the following options:\n" + " --binaries, --sources, --project or --salometools") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # The repository where to put the package if not Binary or Source + package_default_path = runner.cfg.LOCAL.workdir + + # if the package contains binaries or sources: + if options.binaries or options.sources: + # Check that the command has been called with an application + src.check_config_has_application(runner.cfg) + + # Display information + logger.write(_("Packaging application %s\n") % \ + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + # Get the default directory where to put the packages + package_default_path = os.path.join(runner.cfg.APPLICATION.workdir, "PACKAGE") + src.ensure_path_exists(package_default_path) + + # if the package contains a project: + if options.project: + # check that the project is visible by SAT + if options.project not in runner.cfg.PROJECTS.project_file_paths: + local_path = os.path.join(runner.cfg.VARS.salometoolsway, + "data", + "local.pyconf") + msg = _("ERROR: the project %(proj)s is not visible by salomeTools." + "\nPlease add it in the %(local)s file.") % \ + {"proj" : options.project, "local" : local_path} + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Remove the products that are filtered by the --without_property option + if options.without_property: + [prop, value] = options.without_property.split(":") + update_config(runner.cfg, prop, value) + + # get the name of the archive or build it + if options.name: + if os.path.basename(options.name) == options.name: + # only a name (not a path) + archive_name = options.name + dir_name = package_default_path + else: + archive_name = os.path.basename(options.name) + dir_name = os.path.dirname(options.name) + + # suppress extension + if archive_name[-len(".tgz"):] == ".tgz": + archive_name = archive_name[:-len(".tgz")] + if archive_name[-len(".tar.gz"):] == ".tar.gz": + archive_name = archive_name[:-len(".tar.gz")] + + else: + archive_name="" + dir_name = package_default_path + if options.binaries or options.sources: + archive_name = runner.cfg.APPLICATION.name -# Define all possible option for the package command : sat package -parser = src.options.Options() -parser.add_option('b', 'binaries', 'boolean', 'binaries', - _('Optional: Produce a binary package.'), False) -parser.add_option('f', 'force_creation', 'boolean', 'force_creation', - _('Optional: Only binary package: produce the archive even if ' - 'there are some missing products.'), False) -parser.add_option('s', 'sources', 'boolean', 'sources', - _('Optional: Produce a compilable archive of the sources of the ' - 'application.'), False) -parser.add_option('', 'with_vcs', 'boolean', 'with_vcs', - _('Optional: Only source package: do not make archive of vcs products.'), - False) -parser.add_option('p', 'project', 'string', 'project', - _('Optional: Produce an archive that contains a project.'), "") -parser.add_option('t', 'salometools', 'boolean', 'sat', - _('Optional: Produce an archive that contains salomeTools.'), False) -parser.add_option('n', 'name', 'string', 'name', - _('Optional: The name or full path of the archive.'), None) -parser.add_option('', 'add_files', 'list2', 'add_files', - _('Optional: The list of additional files to add to the archive.'), []) -parser.add_option('', 'without_commercial', 'boolean', 'without_commercial', - _('Optional: do not add commercial licence.'), False) -parser.add_option('', 'without_property', 'string', 'without_property', - _('Optional: Filter the products by their properties.\n' - '\tSyntax: --without_property :')) + if options.binaries: + archive_name += "-"+runner.cfg.VARS.dist + + if options.sources: + archive_name += "-SRC" + if options.with_vcs: + archive_name += "-VCS" + + if options.project: + project_name, __ = os.path.splitext( + os.path.basename(options.project)) + archive_name += ("PROJECT-" + project_name) + + if options.sat: + archive_name += ("salomeTools_" + runner.cfg.INTERNAL.sat_version) + if len(archive_name)==0: # no option worked + msg = _("Error: Cannot name the archive\n" + " check if at least one of the following options was " + "selected: --binaries, --sources, --project or" + " --salometools") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + path_targz = os.path.join(dir_name, archive_name + ".tgz") + + src.printcolors.print_value(logger, "Package path", path_targz, 2) + + # Create a working directory for all files that are produced during the + # package creation and that will be removed at the end of the command + tmp_working_dir = os.path.join(runner.cfg.VARS.tmp_root, + runner.cfg.VARS.datehour) + src.ensure_path_exists(tmp_working_dir) + logger.write("\n", 5) + logger.write(_("The temporary working directory: %s\n") % tmp_working_dir, 5) + + logger.write("\n", 3) + + msg = _("Preparation of files to add to the archive") + logger.write(src.printcolors.printcLabel(msg), 2) + logger.write("\n", 2) + + d_files_to_add={} # content of the archive + + # a dict to hold paths that will need to be substitute for users recompilations + d_paths_to_substitute={} + + if options.binaries: + d_bin_files_to_add = binary_package(runner.cfg, + logger, + options, + tmp_working_dir) + # for all binaries dir, store the substitution that will be required + # for extra compilations + for key in d_bin_files_to_add: + if key.endswith("(bin)"): + source_dir = d_bin_files_to_add[key][0] + path_in_archive = d_bin_files_to_add[key][1].replace("BINARIES-" + runner.cfg.VARS.dist,"INSTALL") + if os.path.basename(source_dir)==os.path.basename(path_in_archive): + # if basename is the same we will just substitute the dirname + d_paths_to_substitute[os.path.dirname(source_dir)]=\ + os.path.dirname(path_in_archive) + else: + d_paths_to_substitute[source_dir]=path_in_archive + + d_files_to_add.update(d_bin_files_to_add) + + if options.sources: + d_files_to_add.update(source_package(runner, + runner.cfg, + logger, + options, + tmp_working_dir)) + if options.binaries: + # for archives with bin and sources we provide a shell script able to + # install binaries for compilation + file_install_bin=produce_install_bin_file(runner.cfg,logger, + tmp_working_dir, + d_paths_to_substitute, + "install_bin.sh") + d_files_to_add.update({"install_bin" : (file_install_bin, "install_bin.sh")}) + logger.write("substitutions that need to be done later : \n", 5) + logger.write(str(d_paths_to_substitute), 5) + logger.write("\n", 5) + else: + # --salomeTool option is not considered when --sources is selected, as this option + # already brings salomeTool! + if options.sat: + d_files_to_add.update({"salomeTools" : (runner.cfg.VARS.salometoolsway, "")}) + + + if options.project: + d_files_to_add.update(project_package(options.project, tmp_working_dir)) + + if not(d_files_to_add): + msg = _("Error: Empty dictionnary to build the archive!\n") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Add the README file in the package + local_readme_tmp_path = add_readme(runner.cfg, + options, + tmp_working_dir) + d_files_to_add["README"] = (local_readme_tmp_path, "README") + + # Add the additional files of option add_files + if options.add_files: + for file_path in options.add_files: + if not os.path.exists(file_path): + msg = _("WARNING: the file %s is not accessible.\n") % file_path + continue + file_name = os.path.basename(file_path) + d_files_to_add[file_name] = (file_path, file_name) + + logger.write("\n", 2) + + logger.write(src.printcolors.printcLabel(_("Actually do the package")), 2) + logger.write("\n", 2) + + try: + # Creating the object tarfile + tar = tarfile.open(path_targz, mode='w:gz') + + # get the filtering function if needed + filter_function = exclude_VCS_and_extensions + + # Add the files to the tarfile object + res = add_files(tar, archive_name, d_files_to_add, logger, f_exclude=filter_function) + tar.close() + except KeyboardInterrupt: + logger.write(src.printcolors.printcError("\nERROR: forced interruption\n"), 1) + logger.write(_("Removing the temporary working directory ... "), 1) + # remove the working directory + shutil.rmtree(tmp_working_dir) + logger.write(_("OK"), 1) + logger.write(_("\n"), 1) + return 1 + + # remove the working directory + shutil.rmtree(tmp_working_dir) + + # Print again the path of the package + logger.write("\n", 2) + src.printcolors.print_value(logger, "Package path", path_targz, 2) + + return res def add_files(tar, name_archive, d_content, logger, f_exclude=None): @@ -875,7 +1144,7 @@ def find_product_scripts_and_pyconf(p_name, # read the pyconf of the product product_pyconf_path = src.find_file_in_lpath(p_name + ".pyconf", config.PATHS.PRODUCTPATH) - product_pyconf_cfg = src.pyconf.Config(product_pyconf_path) + product_pyconf_cfg = PYCONF.Config(product_pyconf_path) # find the compilation script if any if src.product.product_has_script(p_info): @@ -891,7 +1160,7 @@ def find_product_scripts_and_pyconf(p_name, p_info.environ.env_script) # find the patches if any if src.product.product_has_patches(p_info): - patches = src.pyconf.Sequence() + patches = PYCONF.Sequence() for patch_path in p_info.patches: p_path = src.Path(patch_path) p_path.copy(patches_tmp_dir) @@ -912,7 +1181,7 @@ def find_product_scripts_and_pyconf(p_name, product_pyconf_cfg[p_info.section].get_source = "archive" if not "archive_info" in product_pyconf_cfg[p_info.section]: product_pyconf_cfg[p_info.section].addMapping("archive_info", - src.pyconf.Mapping(product_pyconf_cfg), + PYCONF.Mapping(product_pyconf_cfg), "") product_pyconf_cfg[p_info.section ].archive_info.archive_name = p_info.name + ".tgz" @@ -938,12 +1207,12 @@ def find_application_pyconf(config, application_tmp_dir): application_pyconf_path = src.find_file_in_lpath( application_name + ".pyconf", config.PATHS.APPLICATIONPATH) - application_pyconf_cfg = src.pyconf.Config(application_pyconf_path) + application_pyconf_cfg = PYCONF.Config(application_pyconf_path) # Change the workdir - application_pyconf_cfg.APPLICATION.workdir = src.pyconf.Reference( + application_pyconf_cfg.APPLICATION.workdir = PYCONF.Reference( application_pyconf_cfg, - src.pyconf.DOLLAR, + PYCONF.DOLLAR, 'VARS.salometoolsway + $VARS.sep + ".."') # Prevent from compilation in base @@ -972,7 +1241,7 @@ def project_package(project_file_path, tmp_working_dir): ''' d_project = {} # Read the project file and get the directories to add to the package - project_pyconf_cfg = src.pyconf.Config(project_file_path) + project_pyconf_cfg = PYCONF.Config(project_file_path) paths = {"ARCHIVEPATH" : "archives", "APPLICATIONPATH" : "applications", "PRODUCTPATH" : "products", @@ -985,18 +1254,18 @@ def project_package(project_file_path, tmp_working_dir): # Add the directory to the files to add in the package d_project[path] = (project_pyconf_cfg[path], paths[path]) # Modify the value of the path in the package - project_pyconf_cfg[path] = src.pyconf.Reference( + project_pyconf_cfg[path] = PYCONF.Reference( project_pyconf_cfg, - src.pyconf.DOLLAR, + PYCONF.DOLLAR, 'project_path + "/' + paths[path] + '"') # Modify some values if "project_path" not in project_pyconf_cfg: project_pyconf_cfg.addMapping("project_path", - src.pyconf.Mapping(project_pyconf_cfg), + PYCONF.Mapping(project_pyconf_cfg), "") - project_pyconf_cfg.project_path = src.pyconf.Reference(project_pyconf_cfg, - src.pyconf.DOLLAR, + project_pyconf_cfg.project_path = PYCONF.Reference(project_pyconf_cfg, + PYCONF.DOLLAR, 'PWD') # Write the project pyconf file @@ -1115,248 +1384,3 @@ def update_config(config, prop, value): l_product_to_remove.append(product_name) for product_name in l_product_to_remove: config.APPLICATION.products.__delitem__(product_name) - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the package command description. - :rtype: str - ''' - return _("""\ -The package command creates an archive. -There are 4 kinds of archive, which can be mixed: - 1- The binary archive. It contains all the product installation directories and a launcher. - 2- The sources archive. It contains the products archives, - a project corresponding to the application and salomeTools. - 3- The project archive. It contains a project (give the project file path as argument). - 4- The salomeTools archive. It contains salomeTools. - -example: ->> sat package SALOME-master --bineries --sources""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with package parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # Check that a type of package is called, and only one - all_option_types = (options.binaries, - options.sources, - options.project not in ["", None], - options.sat) - - # Check if no option for package type - if all_option_types.count(True) == 0: - msg = _("ERROR: needs a type for the package\n" - " Use one of the following options:\n" - " --binaries, --sources, --project or --salometools") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # The repository where to put the package if not Binary or Source - package_default_path = runner.cfg.LOCAL.workdir - - # if the package contains binaries or sources: - if options.binaries or options.sources: - # Check that the command has been called with an application - src.check_config_has_application(runner.cfg) - - # Display information - logger.write(_("Packaging application %s\n") % \ - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - # Get the default directory where to put the packages - package_default_path = os.path.join(runner.cfg.APPLICATION.workdir, "PACKAGE") - src.ensure_path_exists(package_default_path) - - # if the package contains a project: - if options.project: - # check that the project is visible by SAT - if options.project not in runner.cfg.PROJECTS.project_file_paths: - local_path = os.path.join(runner.cfg.VARS.salometoolsway, - "data", - "local.pyconf") - msg = _("ERROR: the project %(proj)s is not visible by salomeTools." - "\nPlease add it in the %(local)s file.") % \ - {"proj" : options.project, "local" : local_path} - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # Remove the products that are filtered by the --without_property option - if options.without_property: - [prop, value] = options.without_property.split(":") - update_config(runner.cfg, prop, value) - - # get the name of the archive or build it - if options.name: - if os.path.basename(options.name) == options.name: - # only a name (not a path) - archive_name = options.name - dir_name = package_default_path - else: - archive_name = os.path.basename(options.name) - dir_name = os.path.dirname(options.name) - - # suppress extension - if archive_name[-len(".tgz"):] == ".tgz": - archive_name = archive_name[:-len(".tgz")] - if archive_name[-len(".tar.gz"):] == ".tar.gz": - archive_name = archive_name[:-len(".tar.gz")] - - else: - archive_name="" - dir_name = package_default_path - if options.binaries or options.sources: - archive_name = runner.cfg.APPLICATION.name - - if options.binaries: - archive_name += "-"+runner.cfg.VARS.dist - - if options.sources: - archive_name += "-SRC" - if options.with_vcs: - archive_name += "-VCS" - - if options.project: - project_name, __ = os.path.splitext( - os.path.basename(options.project)) - archive_name += ("PROJECT-" + project_name) - - if options.sat: - archive_name += ("salomeTools_" + runner.cfg.INTERNAL.sat_version) - if len(archive_name)==0: # no option worked - msg = _("Error: Cannot name the archive\n" - " check if at least one of the following options was " - "selected: --binaries, --sources, --project or" - " --salometools") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - path_targz = os.path.join(dir_name, archive_name + ".tgz") - - src.printcolors.print_value(logger, "Package path", path_targz, 2) - - # Create a working directory for all files that are produced during the - # package creation and that will be removed at the end of the command - tmp_working_dir = os.path.join(runner.cfg.VARS.tmp_root, - runner.cfg.VARS.datehour) - src.ensure_path_exists(tmp_working_dir) - logger.write("\n", 5) - logger.write(_("The temporary working directory: %s\n") % tmp_working_dir, 5) - - logger.write("\n", 3) - - msg = _("Preparation of files to add to the archive") - logger.write(src.printcolors.printcLabel(msg), 2) - logger.write("\n", 2) - - d_files_to_add={} # content of the archive - - # a dict to hold paths that will need to be substitute for users recompilations - d_paths_to_substitute={} - - if options.binaries: - d_bin_files_to_add = binary_package(runner.cfg, - logger, - options, - tmp_working_dir) - # for all binaries dir, store the substitution that will be required - # for extra compilations - for key in d_bin_files_to_add: - if key.endswith("(bin)"): - source_dir = d_bin_files_to_add[key][0] - path_in_archive = d_bin_files_to_add[key][1].replace("BINARIES-" + runner.cfg.VARS.dist,"INSTALL") - if os.path.basename(source_dir)==os.path.basename(path_in_archive): - # if basename is the same we will just substitute the dirname - d_paths_to_substitute[os.path.dirname(source_dir)]=\ - os.path.dirname(path_in_archive) - else: - d_paths_to_substitute[source_dir]=path_in_archive - - d_files_to_add.update(d_bin_files_to_add) - - if options.sources: - d_files_to_add.update(source_package(runner, - runner.cfg, - logger, - options, - tmp_working_dir)) - if options.binaries: - # for archives with bin and sources we provide a shell script able to - # install binaries for compilation - file_install_bin=produce_install_bin_file(runner.cfg,logger, - tmp_working_dir, - d_paths_to_substitute, - "install_bin.sh") - d_files_to_add.update({"install_bin" : (file_install_bin, "install_bin.sh")}) - logger.write("substitutions that need to be done later : \n", 5) - logger.write(str(d_paths_to_substitute), 5) - logger.write("\n", 5) - else: - # --salomeTool option is not considered when --sources is selected, as this option - # already brings salomeTool! - if options.sat: - d_files_to_add.update({"salomeTools" : (runner.cfg.VARS.salometoolsway, "")}) - - - if options.project: - d_files_to_add.update(project_package(options.project, tmp_working_dir)) - - if not(d_files_to_add): - msg = _("Error: Empty dictionnary to build the archive!\n") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # Add the README file in the package - local_readme_tmp_path = add_readme(runner.cfg, - options, - tmp_working_dir) - d_files_to_add["README"] = (local_readme_tmp_path, "README") - - # Add the additional files of option add_files - if options.add_files: - for file_path in options.add_files: - if not os.path.exists(file_path): - msg = _("WARNING: the file %s is not accessible.\n") % file_path - continue - file_name = os.path.basename(file_path) - d_files_to_add[file_name] = (file_path, file_name) - - logger.write("\n", 2) - - logger.write(src.printcolors.printcLabel(_("Actually do the package")), 2) - logger.write("\n", 2) - - try: - # Creating the object tarfile - tar = tarfile.open(path_targz, mode='w:gz') - - # get the filtering function if needed - filter_function = exclude_VCS_and_extensions - - # Add the files to the tarfile object - res = add_files(tar, archive_name, d_files_to_add, logger, f_exclude=filter_function) - tar.close() - except KeyboardInterrupt: - logger.write(src.printcolors.printcError("\nERROR: forced interruption\n"), 1) - logger.write(_("Removing the temporary working directory ... "), 1) - # remove the working directory - shutil.rmtree(tmp_working_dir) - logger.write(_("OK"), 1) - logger.write(_("\n"), 1) - return 1 - - # remove the working directory - shutil.rmtree(tmp_working_dir) - - # Print again the path of the package - logger.write("\n", 2) - src.printcolors.print_value(logger, "Package path", path_targz, 2) - - return res diff --git a/commands/patch.py b/commands/patch.py index f3c1600..0fd935d 100644 --- a/commands/patch.py +++ b/commands/patch.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -19,14 +20,102 @@ import os import subprocess -import src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand import commands.prepare -# Define all possible option for patch command : sat patch -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to get the sources. This option can be' - ' passed several time to get the sources of several products.')) +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The patch command apply the patches on the sources of the application products + if there is any. + + examples: + >> sat patch SALOME --products qt,boost + """ + + name = "patch" + + def getParser(self): + """Define all options for command 'sat patch '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products to get the sources. This option can be' + ' passed several time to get the sources of several products.')) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat patch '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) + + # Print some informations + logger.write('Patching sources of the application %s\n' % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + + src.printcolors.print_value(logger, 'workdir', + runner.cfg.APPLICATION.workdir, 2) + logger.write("\n", 2, False) + + # Get the products list with products informations regarding the options + products_infos = commands.prepare.get_products_list(options, runner.cfg, logger) + + # Get the maximum name length in order to format the terminal display + max_product_name_len = 1 + if len(products_infos) > 0: + max_product_name_len = max(map(lambda l: len(l), products_infos[0])) + 4 + + # The loop on all the products on which to apply the patches + good_result = 0 + for __, product_info in products_infos: + # Apply the patch + return_code, patch_res = apply_patch(runner.cfg, + product_info, + max_product_name_len, + logger) + logger.write(patch_res, 1, False) + if return_code: + good_result += 1 + + # Display the results (how much passed, how much failed, etc...) + + logger.write("\n", 2, False) + if good_result == len(products_infos): + status = src.OK_STATUS + res_count = "%d / %d" % (good_result, good_result) + else: + status = src.KO_STATUS + res_count = "%d / %d" % (good_result, len(products_infos)) + + # write results + logger.write("Patching sources of the application:", 1) + logger.write(" " + src.printcolors.printc(status), 1, False) + logger.write(" (%s)\n" % res_count, 1, False) + + return len(products_infos) - good_result + def apply_patch(config, product_info, max_product_name_len, logger): '''The method called to apply patches on a product @@ -119,70 +208,3 @@ def apply_patch(config, product_info, max_product_name_len, logger): res = not (False in res) return res, "\n".join(retcode) + "\n" - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the patch command description. - :rtype: str - ''' - return _("""\ -The patch command apply the patches on the sources of the application products -if there is any. - -example: ->> sat patch SALOME-master --products qt,boost""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with patch parameter. - ''' - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Print some informations - logger.write('Patching sources of the application %s\n' % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - - src.printcolors.print_value(logger, 'workdir', - runner.cfg.APPLICATION.workdir, 2) - logger.write("\n", 2, False) - - # Get the products list with products informations regarding the options - products_infos = commands.prepare.get_products_list(options, runner.cfg, logger) - - # Get the maximum name length in order to format the terminal display - max_product_name_len = 1 - if len(products_infos) > 0: - max_product_name_len = max(map(lambda l: len(l), products_infos[0])) + 4 - - # The loop on all the products on which to apply the patches - good_result = 0 - for __, product_info in products_infos: - # Apply the patch - return_code, patch_res = apply_patch(runner.cfg, - product_info, - max_product_name_len, - logger) - logger.write(patch_res, 1, False) - if return_code: - good_result += 1 - - # Display the results (how much passed, how much failed, etc...) - - logger.write("\n", 2, False) - if good_result == len(products_infos): - status = src.OK_STATUS - res_count = "%d / %d" % (good_result, good_result) - else: - status = src.KO_STATUS - res_count = "%d / %d" % (good_result, len(products_infos)) - - # write results - logger.write("Patching sources of the application:", 1) - logger.write(" " + src.printcolors.printc(status), 1, False) - logger.write(" (%s)\n" % res_count, 1, False) - - return len(products_infos) - good_result diff --git a/commands/prepare.py b/commands/prepare.py index 8e0f36e..503d196 100644 --- a/commands/prepare.py +++ b/commands/prepare.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,14 +17,143 @@ # 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 re import os +import re -import src import src.debug as DBG import src.returnCode as RCO from src.salomeTools import _BaseCommand +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The prepare command gets the sources of the application products + and apply the patches if there is any. + + examples: + >> sat prepare SALOME --products KERNEL,GUI + """ + + name = "prepare" + + def getParser(self): + """Define all options for command 'sat prepare '""" + parser = self.getParserWithHelp() + parser.add_option( + 'p', 'products', 'list2', 'products', + _('Optional: products to prepare. This option can be' + ' passed several time to prepare several products.')) + parser.add_option( + 'f', 'force', 'boolean', 'force', + _("Optional: force to prepare the products in development mode.")) + parser.add_option( + '', 'force_patch', 'boolean', 'force_patch', + _("Optional: force to apply patch to the products in development mode.")) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat prepare '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( config ) + + products_infos = self.get_products_list(options, config, logger) + + # Construct the arguments to pass to the clean, source and patch commands + args_appli = config.VARS.application + ' ' + args_product_opt = '--products ' + if options.products: + for p_name in options.products: + args_product_opt += ',' + p_name + else: + for p_name, __ in products_infos: + args_product_opt += ',' + p_name + + ldev_products = [p for p in products_infos if src.product.product_is_dev(p[1])] + args_product_opt_clean = args_product_opt + if not options.force and len(ldev_products) > 0: + l_products_not_getted = find_products_already_getted(ldev_products) + if len(l_products_not_getted) > 0: + msg = _("Do not get the source of the following products in development mode\n" + " Use the --force option to overwrite it.\n") + logger.write(src.printcolors.printcWarning(msg), 1) + args_product_opt_clean = remove_products(args_product_opt_clean, + l_products_not_getted, + logger) + logger.write("\n", 1) + + + args_product_opt_patch = args_product_opt + if not options.force_patch and len(ldev_products) > 0: + l_products_with_patchs = find_products_with_patchs(ldev_products) + if len(l_products_with_patchs) > 0: + msg = _("do not patch the following products in development mode\n" + " Use the --force_patch option to overwrite it.\n") + logger.write(src.printcolors.printcWarning(msg), 1) + args_product_opt_patch = remove_products(args_product_opt_patch, + l_products_with_patchs, + logger) + logger.write("\n", 1) + + # Construct the final commands arguments + args_clean = args_appli + args_product_opt_clean + " --sources" + args_source = args_appli + args_product_opt + args_patch = args_appli + args_product_opt_patch + + # If there is no more any product in the command arguments, + # do not call the concerned command + oExpr = re.compile("^--products *$") + do_clean = not(oExpr.search(args_product_opt_clean)) + do_source = not(oExpr.search(args_product_opt)) + do_patch = not(oExpr.search(args_product_opt_patch)) + + + # Initialize the results to Ok but nothing done status + res_clean = RCO.ReturnCode("OK", "nothing done") + res_source = RCO.ReturnCode("OK", "nothing done") + res_patch = RCO.ReturnCode("OK", "nothing done") + + # return res_clean + res_source + res_patch + + # Call the commands using the API + if do_clean: + msg = _("Clean the source directories ...") + logger.write(msg, 3) + logger.flush() + DBG.tofix("args_clean and TODO remove returns", args_clean, True) + res_clean = runner.getCommand("clean").run(args_clean) + return res_clean + res_source + res_patch + if do_source: + msg = _("Get the sources of the products ...") + logger.write(msg, 5) + res_source = runner.getCommand("source").run(args_source) + if do_patch: + msg = _("Patch the product sources (if any) ...") + logger.write(msg, 5) + res_patch = runner.getCommand("patch").run(args_patch) + + return res_clean + res_source + res_patch + def remove_products(arguments, l_products_info, logger): '''function that removes the products in l_products_info from arguments list. @@ -74,130 +204,3 @@ def find_products_with_patchs(l_products): if len(l_patchs)>0: l_res.append(p_name_p_cfg) return l_res - -######################################################################## -# Command class for command 'sat config etc.' -######################################################################## -class Command(_BaseCommand): - - def getParser(self): - # Define all possible option for prepare command : sat prepare - parser = src.options.Options() - parser.add_option( - 'p', 'products', 'list2', 'products', - _('Optional: products to prepare. This option can be' - ' passed several time to prepare several products.')) - parser.add_option( - 'f', 'force', 'boolean', 'force', - _("Optional: force to prepare the products in development mode.")) - parser.add_option( - '', 'force_patch', 'boolean', 'force_patch', - _("Optional: force to apply patch to the products in development mode.")) - return parser - - def description(self): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the config command description. - :rtype: str - ''' - return _("""\ -The prepare command gets the sources of the application products -and apply the patches if there is any. - -example: ->> sat prepare SALOME-master --products KERNEL,GUI""") - - - def run(self, args): - '''method that is called when salomeTools is called with prepare parameter. - ''' - - # Parse the options - parser = self.getParser() - runner = self.getRunner() - config = self.getConfig() - logger = self.getLogger() - - (options, args) = parser.parse_args(args) - DBG.tofix("options %s" % self.name, options, True) - - # check that the command has been called with an application - src.check_config_has_application( config ) - - products_infos = self.get_products_list(options, config, logger) - - # Construct the arguments to pass to the clean, source and patch commands - args_appli = config.VARS.application + ' ' - args_product_opt = '--products ' - if options.products: - for p_name in options.products: - args_product_opt += ',' + p_name - else: - for p_name, __ in products_infos: - args_product_opt += ',' + p_name - - ldev_products = [p for p in products_infos if src.product.product_is_dev(p[1])] - args_product_opt_clean = args_product_opt - if not options.force and len(ldev_products) > 0: - l_products_not_getted = find_products_already_getted(ldev_products) - if len(l_products_not_getted) > 0: - msg = _("Do not get the source of the following products in development mode\n" - " Use the --force option to overwrite it.\n") - logger.write(src.printcolors.printcWarning(msg), 1) - args_product_opt_clean = remove_products(args_product_opt_clean, - l_products_not_getted, - logger) - logger.write("\n", 1) - - - args_product_opt_patch = args_product_opt - if not options.force_patch and len(ldev_products) > 0: - l_products_with_patchs = find_products_with_patchs(ldev_products) - if len(l_products_with_patchs) > 0: - msg = _("do not patch the following products in development mode\n" - " Use the --force_patch option to overwrite it.\n") - logger.write(src.printcolors.printcWarning(msg), 1) - args_product_opt_patch = remove_products(args_product_opt_patch, - l_products_with_patchs, - logger) - logger.write("\n", 1) - - # Construct the final commands arguments - args_clean = args_appli + args_product_opt_clean + " --sources" - args_source = args_appli + args_product_opt - args_patch = args_appli + args_product_opt_patch - - # If there is no more any product in the command arguments, - # do not call the concerned command - oExpr = re.compile("^--products *$") - do_clean = not(oExpr.search(args_product_opt_clean)) - do_source = not(oExpr.search(args_product_opt)) - do_patch = not(oExpr.search(args_product_opt_patch)) - - - # Initialize the results to Ok but nothing done status - res_clean = RCO.ReturnCode("OK", "nothing done") - res_source = RCO.ReturnCode("OK", "nothing done") - res_patch = RCO.ReturnCode("OK", "nothing done") - - # return res_clean + res_source + res_patch - - # Call the commands using the API - if do_clean: - msg = _("Clean the source directories ...") - logger.write(msg, 3) - logger.flush() - DBG.tofix("args_clean and TODO remove returns", args_clean, True) - res_clean = runner.getCommand("clean").run(args_clean) - return res_clean + res_source + res_patch - if do_source: - msg = _("Get the sources of the products ...") - logger.write(msg, 5) - res_source = runner.getCommand("source").run(args_source) - if do_patch: - msg = _("Patch the product sources (if any) ...") - logger.write(msg, 5) - res_patch = runner.getCommand("patch").run(args_patch) - - return res_clean + res_source + res_patch diff --git a/commands/profile.py b/commands/profile.py index 7f888f1..020aaf4 100644 --- a/commands/profile.py +++ b/commands/profile.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,85 +17,127 @@ # 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 shutil import subprocess -import src - -parser = src.options.Options() - -parser.add_option( - 'p', 'prefix', 'string', 'prefix', - _("Where the profile's sources will be generated.") ) -parser.add_option( - 'n', 'name', 'string', 'name', - _("Name of the profile's sources. [Default: '${config.PRODUCT.name}_PROFILE]") ) -parser.add_option( - 'f', 'force', 'boolean', 'force', - _("Overwrites existing sources.") ) -parser.add_option( - 'u', 'no_update', 'boolean', 'no_update', - _("Does not update pyconf file.") ) -parser.add_option( - 'v', 'version', 'string', 'version', - _("Version of the application. [Default: 1.0]"), '1.0' ) -parser.add_option( - 's', 'slogan', 'string', 'slogan', - _("Slogan of the application.") ) - -################################################## +import src.debug as DBG +import src.returnCode as RCO +import src.pyconf as PYCONF +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The profile command creates default profile. + + examples: + >> sat profile [PRODUCT] + [-p | --prefix (string)] + [-n | --name (string)] + [-f | --force] + [-v | --version (string)] + [-s | --slogan (string)] + """ + + name = "profile" + + def getParser(self): + """Define all options for command 'sat profile '""" + parser = self.getParserWithHelp() + parser.add_option( + 'p', 'prefix', 'string', 'prefix', + _("Where the profile's sources will be generated.") ) + parser.add_option( + 'n', 'name', 'string', 'name', + _("Name of the profile's sources. [Default: '${config.PRODUCT.name}_PROFILE]") ) + parser.add_option( + 'f', 'force', 'boolean', 'force', + _("Overwrites existing sources.") ) + parser.add_option( + 'u', 'no_update', 'boolean', 'no_update', + _("Does not update pyconf file.") ) + parser.add_option( + 'v', 'version', 'string', 'version', + _("Version of the application. [Default: 1.0]"), '1.0' ) + parser.add_option( + 's', 'slogan', 'string', 'slogan', + _("Slogan of the application.") ) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat profile '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + src.check_config_has_application(runner.cfg) + + if options.prefix is None: + msg = _("The --%s argument is required\n") % "prefix" + logger.write(src.printcolors.printcWarning(msg), 1) + return 1 + + retcode = generate_profile_sources( runner.cfg, options, logger ) + + if not options.no_update : + update_pyconf( runner.cfg, options ) + + return retcode + -## # Class that overrides common.Reference # in order to manipulate fields starting with '@' -class profileReference( src.pyconf.Reference ) : +class profileReference( PYCONF.Reference ): def __str__(self): s = self.elements[0] for tt, tv in self.elements[1:]: - if tt == src.pyconf.DOT: + if tt == PYCONF.DOT: s += '.%s' % tv else: s += '[%r]' % tv - if self.type == src.pyconf.BACKTICK: - return src.pyconf.BACKTICK + s + src.pyconf.BACKTICK - elif self.type == src.pyconf.AT: - return src.pyconf.AT + s + if self.type == PYCONF.BACKTICK: + return PYCONF.BACKTICK + s + PYCONF.BACKTICK + elif self.type == PYCONF.AT: + return PYCONF.AT + s else: - return src.pyconf.DOLLAR + s + return PYCONF.DOLLAR + s ## # Class that overrides how fields starting with '@' are read. -class profileConfigReader( src.pyconf.ConfigReader ) : +class profileConfigReader( PYCONF.ConfigReader ) : def parseMapping(self, parent, suffix): - if self.token[0] == src.pyconf.LCURLY: - self.match(src.pyconf.LCURLY) - rv = src.pyconf.Mapping(parent) + if self.token[0] == PYCONF.LCURLY: + self.match(PYCONF.LCURLY) + rv = PYCONF.Mapping(parent) rv.setPath( - src.pyconf.makePath(object.__getattribute__(parent, 'path'), + PYCONF.makePath(object.__getattribute__(parent, 'path'), suffix)) self.parseMappingBody(rv) - self.match(src.pyconf.RCURLY) + self.match(PYCONF.RCURLY) else: - self.match(src.pyconf.AT) + self.match(PYCONF.AT) __, fn = self.match('"') - rv = profileReference(self, src.pyconf.AT, fn) + rv = profileReference(self, PYCONF.AT, fn) return rv -################################################## -## -# Describes the command -def description(): - return _("""\ -The profile command creates default profile. -usage: ->> sat profile [PRODUCT] - [-p | --prefix (string)] - [-n | --name (string)] - [-f | --force] - [-v | --version (string)] - [-s | --slogan (string)]""") ## # Gets the profile name @@ -178,9 +221,9 @@ def update_pyconf( config, options, logger ): os.path.join( path, pyconfBackup ) ) #Load config - cfg = src.pyconf.Config( ) + cfg = PYCONF.Config( ) object.__setattr__( cfg, 'reader', profileConfigReader( cfg ) ) - cfg.load( src.pyconf.defaultStreamOpener( os.path.join( path, pyconf ) ) ) + cfg.load( PYCONF.defaultStreamOpener( os.path.join( path, pyconf ) ) ) #Check if profile is in APPLICATION.products profile = get_profile_name ( options, config ) @@ -189,64 +232,42 @@ def update_pyconf( config, options, logger ): #Check if profile is in APPLICATION if not 'profile' in cfg.APPLICATION: - cfg.APPLICATION.addMapping( 'profile', src.pyconf.Mapping(), None ) + cfg.APPLICATION.addMapping( 'profile', PYCONF.Mapping(), None ) cfg.APPLICATION.profile.addMapping( 'module', profile, None ) cfg.APPLICATION.profile.addMapping( 'launcher_name', config.VARS.product.lower(), None ) #Check if profile info is in PRODUCTS if not 'PRODUCTS' in cfg: - cfg.addMapping( 'PRODUCTS', src.pyconf.Mapping(), None ) + cfg.addMapping( 'PRODUCTS', PYCONF.Mapping(), None ) if not profile in cfg.PRODUCTS: - cfg.PRODUCTS.addMapping( profile, src.pyconf.Mapping(), None ) - cfg.PRODUCTS[profile].addMapping( 'default', src.pyconf.Mapping(), + cfg.PRODUCTS.addMapping( profile, PYCONF.Mapping(), None ) + cfg.PRODUCTS[profile].addMapping( 'default', PYCONF.Mapping(), None ) prf = cfg.TOOLS.common.module_info[profile].default prf.addMapping( 'name', profile, None ) prf.addMapping( 'get_source', 'archive', None ) prf.addMapping( 'build_source', 'cmake', None ) - prf.addMapping( 'archive_info', src.pyconf.Mapping(), None ) + prf.addMapping( 'archive_info', PYCONF.Mapping(), None ) prf.archive_info.addMapping( 'name', os.path.join(os.path.abspath(options.prefix), profile), None ) tmp = "APPLICATION.workdir + $VARS.sep + 'SOURCES' + $VARS.sep + $name" prf.addMapping( 'source_dir', - src.pyconf.Reference(cfg, src.pyconf.DOLLAR, tmp ), + PYCONF.Reference(cfg, PYCONF.DOLLAR, tmp ), None ) tmp = "APPLICATION.workdir + $VARS.sep + 'BUILD' + $VARS.sep + $name" prf.addMapping( 'build_dir', - src.pyconf.Reference(cfg, src.pyconf.DOLLAR, tmp ), + PYCONF.Reference(cfg, PYCONF.DOLLAR, tmp ), None ) - prf.addMapping( 'depend', src.pyconf.Sequence(), None ) + prf.addMapping( 'depend', PYCONF.Sequence(), None ) prf.depend.append( 'KERNEL', None ) prf.depend.append( 'GUI', None ) prf.depend.append( 'Python', None ) prf.depend.append( 'Sphinx', None ) prf.depend.append( 'qt', None ) - prf.addMapping( 'opt_depend', src.pyconf.Sequence(), None ) + prf.addMapping( 'opt_depend', PYCONF.Sequence(), None ) #Save config f = file( os.path.join( path, pyconf ) , 'w') cfg.__save__(f) - - -## -# Runs the command. -def run(args, runner, logger): - '''method that is called when salomeTools is called with profile parameter. - ''' - (options, args) = parser.parse_args(args) - - src.check_config_has_application(runner.cfg) - - if options.prefix is None: - msg = _("The --%s argument is required\n") % "prefix" - logger.write(src.printcolors.printcWarning(msg), 1) - return 1 - - retcode = generate_profile_sources( runner.cfg, options, logger ) - - if not options.no_update : - update_pyconf( runner.cfg, options ) - - return retcode diff --git a/commands/run.py b/commands/run.py index f671344..9e3c062 100644 --- a/commands/run.py +++ b/commands/run.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -19,25 +20,48 @@ import os import subprocess -import src - -parser = src.options.Options() # no options yet +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the run command description. - :rtype: str - ''' - return _("""\ -This command runs the application launcher with the given arguments. +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The run command runs the application launcher with the given arguments. + + examples: + >> sat run SALOME + """ + + name = "run" + + def getParser(self): + """Define all options for command 'sat run '""" + parser = self.getParserWithHelp() # no options yet + return parser -example: ->> sat run SALOME-master""") + def run(self, cmd_arguments): + """method called for command 'sat run '""" + argList = self.assumeAsList(cmd_arguments) -def run(args, runner, logger): - '''method that is called when salomeTools is called with run parameter. - ''' + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() # check for product src.check_config_has_application(runner.cfg) diff --git a/commands/script.py b/commands/script.py index 199c0a5..1348b9e 100644 --- a/commands/script.py +++ b/commands/script.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,20 +17,97 @@ # 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 src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand + +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The script command executes the script(s) of the the given products in the build directory. + This is done only for the products that are constructed using a script (build_source : 'script'). + Otherwise, nothing is done. + + examples: + >> sat script SALOME --products Python,numpy + """ + + name = "script" + + def getParser(self): + """Define all options for the command 'sat script '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products to configure. This option can be' + ' passed several time to configure several products.')) + parser.add_option('', 'nb_proc', 'int', 'nb_proc', + _('Optional: The number of processors to use in the script if the make ' + 'command is used in it.\n\tWarning: the script has to be correctly written ' + 'if you want this option to work.\n\tThe $MAKE_OPTIONS has to be ' + 'used.'), 0) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat script '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( runner.cfg ) -# Define all possible option for the script command : sat script -parser = src.options.Options() -parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products to configure. This option can be' - ' passed several time to configure several products.')) -parser.add_option('', 'nb_proc', 'int', 'nb_proc', - _('Optional: The number of processors to use in the script if the make ' - 'command is used in it.\n\tWarning: the script has to be correctly written ' - 'if you want this option to work.\n\tThe $MAKE_OPTIONS has to be ' - 'used.'), 0) + # Get the list of products to treat + products_infos = get_products_list(options, runner.cfg, logger) + + # Print some informations + msg = ('Executing the script in the build directories of the application %s\n') % \ + src.printcolors.printcLabel(runner.cfg.VARS.application) + logger.write(msg, 1) + + info = [(_("BUILD directory"), os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] + src.print_info(logger, info) + + # Call the function that will loop over all the products and execute + # the right command(s) + if options.nb_proc is None: + options.nb_proc = 0 + res = run_script_all_products(runner.cfg, + products_infos, + options.nb_proc, + logger) + + # Print the final state + nb_products = len(products_infos) + if res == 0: + final_status = "OK" + else: + final_status = "KO" + + logger.write(_("\nScript: %(status)s (%(1)d/%(2)d)\n") % \ + { 'status': src.printcolors.printc(final_status), + '1': nb_products - res, + '2': nb_products }, 1) + + return res + def get_products_list(options, cfg, logger): '''method that gives the product list with their informations from @@ -169,62 +247,3 @@ def run_script_of_product(p_name_info, nb_proc, config, logger): logger.write("\n", 3, False) return res - -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the script command description. - :rtype: str - ''' - return _("""\ -The script command executes the script(s) of the the given products in the build directory. - This is done only for the products that are constructed using a script (build_source : 'script'). - Otherwise, nothing is done. - - example: - >> sat script SALOME-master --products Python,numpy -""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with make parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( runner.cfg ) - - # Get the list of products to treat - products_infos = get_products_list(options, runner.cfg, logger) - - # Print some informations - msg = ('Executing the script in the build directories of the application %s\n') % \ - src.printcolors.printcLabel(runner.cfg.VARS.application) - logger.write(msg, 1) - - info = [(_("BUILD directory"), os.path.join(runner.cfg.APPLICATION.workdir, 'BUILD'))] - src.print_info(logger, info) - - # Call the function that will loop over all the products and execute - # the right command(s) - if options.nb_proc is None: - options.nb_proc = 0 - res = run_script_all_products(runner.cfg, - products_infos, - options.nb_proc, - logger) - - # Print the final state - nb_products = len(products_infos) - if res == 0: - final_status = "OK" - else: - final_status = "KO" - - logger.write(_("\nScript: %(status)s (%(1)d/%(2)d)\n") % \ - { 'status': src.printcolors.printc(final_status), - '1': nb_products - res, - '2': nb_products }, 1) - - return res diff --git a/commands/shell.py b/commands/shell.py index fcbbc90..47abbec 100644 --- a/commands/shell.py +++ b/commands/shell.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -16,33 +17,54 @@ # 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 subprocess -import src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand -# Define all possible option for the shell command : sat shell -parser = src.options.Options() -parser.add_option('c', 'command', 'string', 'command', - _('Mandatory: The shell command to execute.'), "") +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The shell command executes the shell command passed as argument. -def description(): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the shell command description. - :rtype: str - ''' - return _("""\ -Executes the shell command passed as argument. -example: ->> sat shell --command 'ls -l /tmp'""") + examples: + >> sat shell --command 'ls -lt /tmp' + """ -def run(args, runner, logger): - '''method that is called when salomeTools is called with shell parameter. - ''' - - # Parse the options - (options, args) = parser.parse_args(args) + name = "shell" + + def getParser(self): + """Define all options for the command 'sat shell '""" + parser = self.getParserWithHelp() + parser.add_option('c', 'command', 'string', 'command', + _('Mandatory: The shell command to execute.'), "") + return parser + def run(self, cmd_arguments): + """method called for command 'sat shell '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + # Make sure the command option has been called if not options.command: message = _("The option --command is required\n") @@ -58,7 +80,7 @@ def run(args, runner, logger): shell=True, stdout=logger.logTxtFile, stderr=subprocess.STDOUT) - + # Format the result to be 0 (success) or 1 (fail) if res != 0: res = 1 diff --git a/commands/source.py b/commands/source.py index 57875f8..b93ab45 100644 --- a/commands/source.py +++ b/commands/source.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -19,11 +20,100 @@ import os import shutil -import src import src.debug as DBG import src.returnCode as RCO from src.salomeTools import _BaseCommand +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The source command gets the sources of the application products + from cvs, git or an archive. + + examples: + >> sat source SALOME --products KERNEL,GUI + """ + + name = "sourcre" + + def getParser(self): + """Define all options for command 'sat source '""" + parser = self.getParserWithHelp() + parser.add_option('p', 'products', 'list2', 'products', + _('Optional: products from which to get the sources. This option can be' + ' passed several time to get the sources of several products.')) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat source '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + # check that the command has been called with an application + src.check_config_has_application( config ) + + # Print some informations + logger.write(_('Getting sources of the application %s\n') % \ + src.printcolors.printcLabel(config.VARS.application), 1) + src.printcolors.print_value(logger, 'workdir', + config.APPLICATION.workdir, 2) + logger.write("\n", 2, False) + + # Get the products list with products informations regarding the options + products_infos = self.get_products_list(options, config, logger) + + # Call to the function that gets all the sources + good_result, results = get_all_product_sources(config, + products_infos, + logger) + + # Display the results (how much passed, how much failed, etc...) + details = [] + + logger.write("\n", 2, False) + if good_result == len(products_infos): + res_count = "%d / %d" % (good_result, good_result) + returnCode = RCO.ReturnCode("OK", "source "+res_count) + else: + res_count = "%d / %d" % (good_result, len(products_infos)) + returnCode = RCO.ReturnCode("KO", "source "+res_count) + for product in results: + if results[product] == 0 or results[product] is None: + details.append(product) + + result = len(products_infos) - good_result + + # write results + logger.write(_("Getting sources of the application:"), 1) + logger.write(" " + src.printcolors.printc(status), 1, False) + logger.write(" (%s)\n" % res_count, 1, False) + + if len(details) > 0: + logger.write(_("Following sources haven't been get:\n"), 2) + logger.write(" ".join(details), 2) + logger.write("\n", 2, False) + + return returnCode + + def get_source_for_dev(config, product_info, source_dir, logger, pad): '''The method called if the product is in development mode @@ -471,82 +561,3 @@ def check_sources(product_info, logger): return False, path_to_test logger.write(src.printcolors.printcSuccess(" OK\n"), 5) return True, "" - -######################################################################## -# Command class for command 'sat config etc.' -######################################################################## -class Command(_BaseCommand): - - def getParser(self): - # Define all possible option for patch command : sat patch - parser = src.options.Options() - parser.add_option('p', 'products', 'list2', 'products', - _('Optional: products from which to get the sources. This option can be' - ' passed several time to get the sources of several products.')) - return parser - - def description(self): - '''method that is called when salomeTools is called with --help option. - - :return: The text to display for the source command description. - :rtype: str - ''' - return _("The source command gets the sources of the application products " - "from cvs, git or an archive.\n\nexample:" - "\nsat source SALOME-master --products KERNEL,GUI") - - def run(self, args): - '''method that is called when salomeTools is called with source parameter. - ''' - runner = self.getRunner() - config = self.getConfig() - logger = self.getLogger() - - # Parse the options - (options, argsc) = self.parse_args(args) - - # check that the command has been called with an application - src.check_config_has_application( config ) - - # Print some informations - logger.write(_('Getting sources of the application %s\n') % \ - src.printcolors.printcLabel(config.VARS.application), 1) - src.printcolors.print_value(logger, 'workdir', - config.APPLICATION.workdir, 2) - logger.write("\n", 2, False) - - # Get the products list with products informations regarding the options - products_infos = self.get_products_list(options, config, logger) - - # Call to the function that gets all the sources - good_result, results = get_all_product_sources(config, - products_infos, - logger) - - # Display the results (how much passed, how much failed, etc...) - details = [] - - logger.write("\n", 2, False) - if good_result == len(products_infos): - res_count = "%d / %d" % (good_result, good_result) - returnCode = RCO.ReturnCode("OK", "source "+res_count) - else: - res_count = "%d / %d" % (good_result, len(products_infos)) - returnCode = RCO.ReturnCode("KO", "source "+res_count) - for product in results: - if results[product] == 0 or results[product] is None: - details.append(product) - - result = len(products_infos) - good_result - - # write results - logger.write(_("Getting sources of the application:"), 1) - logger.write(" " + src.printcolors.printc(status), 1, False) - logger.write(" (%s)\n" % res_count, 1, False) - - if len(details) > 0: - logger.write(_("Following sources haven't been get:\n"), 2) - logger.write(" ".join(details), 2) - logger.write("\n", 2, False) - - return returnCode diff --git a/commands/template.py b/commands/template.py index a5c8ceb..a6a617d 100644 --- a/commands/template.py +++ b/commands/template.py @@ -1,6 +1,7 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- -# Copyright (C) 2010-2013 CEA/DEN + +# Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -23,7 +24,9 @@ import subprocess import fnmatch import re -import src +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand # Compatibility python 2/3 for input function # input stays input for python 3 and input = raw_input for python 2 @@ -32,24 +35,161 @@ try: except NameError: pass -parser = src.options.Options() -parser.add_option('n', 'name', 'string', 'name', - _("""\ +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The template command creates the sources for a SALOME module from a template. + + examples: + >> sat template --name my_product_name --template PythonComponent --target /tmp + """ + + name = "template" + + def getParser(self): + """Define all options for command 'sat template '""" + parser = self.getParserWithHelp() + parser.add_option('n', 'name', 'string', 'name', + _("""\ REQUIRED: the name of the module to create. The name must be a single word in upper case with only alphanumeric characters. When generating a c++ component the module's name must be suffixed with 'CPP'.""")) -parser.add_option('t', 'template', 'string', 'template', - _('REQUIRED: the template to use.')) -parser.add_option('', 'target', 'string', 'target', - _('REQUIRED: where to create the module.')) -parser.add_option('', 'param', 'string', 'param', - _("""\ + parser.add_option('t', 'template', 'string', 'template', + _('REQUIRED: the template to use.')) + parser.add_option('', 'target', 'string', 'target', + _('REQUIRED: where to create the module.')) + parser.add_option('', 'param', 'string', 'param', + _("""\ Optional: dictionary to generate the configuration for salomeTools. Format is: --param param1=value1,param2=value2... (without spaces). Note that when using this option you must supply all the values, otherwise an error will be raised.""") ) -parser.add_option('', 'info', 'boolean', 'info', - _('Optional: Get information on the template.'), False) + parser.add_option('', 'info', 'boolean', 'info', + _('Optional: Get information on the template.'), False) + return parser + + def run(self, cmd_arguments): + """method called for command 'sat template '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + if options.template is None: + msg = _("Error: the --%s argument is required\n") % "template" + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + if options.target is None and options.info is None: + msg = _("Error: the --%s argument is required\n") % "target" + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + if "APPLICATION" in runner.cfg: + msg = _("Error: this command does not use a product.") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + if options.info: + return get_template_info(runner.cfg, options.template, logger) + + if options.name is None: + msg = _("Error: the --%s argument is required\n") % "name" + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + if not options.name.replace('_', '').isalnum(): + msg = _("Error: component name must contains only alphanumeric " + "characters and no spaces\n") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # CNC inutile + # Ask user confirmation if a module of the same name already exists + #if options.name in runner.cfg.PRODUCTS and not runner.options.batch: + # logger.write(src.printcolors.printcWarning( + # _("A module named '%s' already exists." % options.name)), 1) + # logger.write("\n", 1) + # rep = input(_("Are you sure you want to continue? [Yes/No] ")) + # if rep.upper() != _("YES"): + # return 1 + + if options.target is None: + msg = _("Error: the --%s argument is required\n") % "target" + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + target_dir = os.path.join(options.target, options.name) + if os.path.exists(target_dir): + msg = _("Error: the target already exists: %s") % target_dir + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # CNC inutile + #if options.template == "Application": + # if "_APPLI" not in options.name and not runner.options.batch: + # msg = _("An Application module named '..._APPLI' " + # "is usually recommended.") + # logger.write(src.printcolors.printcWarning(msg), 1) + # logger.write("\n", 1) + # rep = input(_("Are you sure you want to continue? [Yes/No] ")) + # if rep.upper() != _("YES"): + # return 1 + + logger.write(_('Create sources from template\n'), 1) + src.printcolors.print_value(logger, 'destination', target_dir, 2) + src.printcolors.print_value(logger, 'name', options.name, 2) + src.printcolors.print_value(logger, 'template', options.template, 2) + logger.write("\n", 3, False) + + conf_values = None + if options.param is not None: + conf_values = {} + for elt in options.param.split(","): + param_def = elt.strip().split('=') + if len(param_def) != 2: + msg = _("Error: bad parameter definition") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + conf_values[param_def[0].strip()] = param_def[1].strip() + + retcode = prepare_from_template(runner.cfg, options.name, options.template, + target_dir, conf_values, logger) + + if retcode == 0: + logger.write(_( + "The sources were created in %s") % src.printcolors.printcInfo( + target_dir), 3) + logger.write(src.printcolors.printcWarning(_("\nDo not forget to put " + "them in your version control system.")), 3) + + logger.write("\n", 3) + + return retcode class TParam: def __init__(self, param_def, compo_name, dico=None): @@ -427,117 +567,3 @@ def get_template_info(config, template_name, logger): shutil.rmtree(tmpdir) return retcode - -## -# Describes the command -def description(): - return _("""\ -The template command creates the sources for a SALOME module from a template. - -example: ->> sat template --name my_product_name --template PythonComponent --target /tmp""") - -def run(args, runner, logger): - '''method that is called when salomeTools is called with template parameter. - ''' - (options, args) = parser.parse_args(args) - - if options.template is None: - msg = _("Error: the --%s argument is required\n") % "template" - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - if options.target is None and options.info is None: - msg = _("Error: the --%s argument is required\n") % "target" - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - if "APPLICATION" in runner.cfg: - msg = _("Error: this command does not use a product.") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - if options.info: - return get_template_info(runner.cfg, options.template, logger) - - if options.name is None: - msg = _("Error: the --%s argument is required\n") % "name" - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - if not options.name.replace('_', '').isalnum(): - msg = _("Error: component name must contains only alphanumeric " - "characters and no spaces\n") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # CNC inutile - # Ask user confirmation if a module of the same name already exists - #if options.name in runner.cfg.PRODUCTS and not runner.options.batch: - # logger.write(src.printcolors.printcWarning( - # _("A module named '%s' already exists." % options.name)), 1) - # logger.write("\n", 1) - # rep = input(_("Are you sure you want to continue? [Yes/No] ")) - # if rep.upper() != _("YES"): - # return 1 - - if options.target is None: - msg = _("Error: the --%s argument is required\n") % "target" - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - target_dir = os.path.join(options.target, options.name) - if os.path.exists(target_dir): - msg = _("Error: the target already exists: %s") % target_dir - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - - # CNC inutile - #if options.template == "Application": - # if "_APPLI" not in options.name and not runner.options.batch: - # msg = _("An Application module named '..._APPLI' " - # "is usually recommended.") - # logger.write(src.printcolors.printcWarning(msg), 1) - # logger.write("\n", 1) - # rep = input(_("Are you sure you want to continue? [Yes/No] ")) - # if rep.upper() != _("YES"): - # return 1 - - logger.write(_('Create sources from template\n'), 1) - src.printcolors.print_value(logger, 'destination', target_dir, 2) - src.printcolors.print_value(logger, 'name', options.name, 2) - src.printcolors.print_value(logger, 'template', options.template, 2) - logger.write("\n", 3, False) - - conf_values = None - if options.param is not None: - conf_values = {} - for elt in options.param.split(","): - param_def = elt.strip().split('=') - if len(param_def) != 2: - msg = _("Error: bad parameter definition") - logger.write(src.printcolors.printcError(msg), 1) - logger.write("\n", 1) - return 1 - conf_values[param_def[0].strip()] = param_def[1].strip() - - retcode = prepare_from_template(runner.cfg, options.name, options.template, - target_dir, conf_values, logger) - - if retcode == 0: - logger.write(_( - "The sources were created in %s") % src.printcolors.printcInfo( - target_dir), 3) - logger.write(src.printcolors.printcWarning(_("\nDo not forget to put " - "them in your version control system.")), 3) - - logger.write("\n", 3) - - return retcode diff --git a/commands/test.py b/commands/test.py index 522db49..5ded493 100644 --- a/commands/test.py +++ b/commands/test.py @@ -1,5 +1,6 @@ #!/usr/bin/env python #-*- coding:utf-8 -*- + # Copyright (C) 2010-2012 CEA/DEN # # This library is free software; you can redistribute it and/or @@ -23,55 +24,58 @@ import subprocess import datetime import gzip +import src.debug as DBG +import src.returnCode as RCO +from src.salomeTools import _BaseCommand +import src.ElementTree as etree +from src.xmlManager import add_simple_node + try: from hashlib import sha1 except ImportError: from sha import sha as sha1 -import src -import src.ElementTree as etree -from src.xmlManager import add_simple_node -# Define all possible option for the test command : sat test -parser = src.options.Options() -parser.add_option('b', 'base', 'string', 'base', - _("""\ +######################################################################## +# Command class +######################################################################## +class Command(_BaseCommand): + """\ + The test command runs a test base on a SALOME installation. + + examples: + >> sat test SALOME --grid GEOM --session light + """ + + name = "test" + + def getParser(self): + """Define all options for command 'sat test '""" + parser = self.getParserWithHelp() + parser.add_option('b', 'base', 'string', 'base', + _("""\ Optional: Indicate the name of the test base to use. This name has to be registered in your application and in a project. A path to a test base can also be used.""")) -parser.add_option('l', 'launcher', 'string', 'launcher', - _("Optional: Use this option to specify the path to a SALOME launcher to " - "use to launch the test scripts of the test base.")) -parser.add_option('g', 'grid', 'list', 'grids', - _('Optional: Indicate which grid(s) to test (subdirectory of the test base).')) -parser.add_option('s', 'session', 'list', 'sessions', - _('Optional: indicate which session(s) to test (subdirectory of the grid).')) -parser.add_option('', 'display', 'string', 'display', - _("""\ + parser.add_option('l', 'launcher', 'string', 'launcher', + _("Optional: Use this option to specify the path to a SALOME launcher to " + "use to launch the test scripts of the test base.")) + parser.add_option('g', 'grid', 'list', 'grids', + _('Optional: Indicate which grid(s) to test (subdirectory of the test base).')) + parser.add_option('s', 'session', 'list', 'sessions', + _('Optional: indicate which session(s) to test (subdirectory of the grid).')) + parser.add_option('', 'display', 'string', 'display', + _("""\ Optional: set the display where to launch SALOME. If value is NO then option --show-desktop=0 will be used to launch SALOME.""")) + return parser -def description(): - '''method that is called when salomeTools is called with --help option. + def check_option(self, options): + """Check the options - :return: The text to display for the test command description. - :rtype: str - ''' - return _("""\ -The test command runs a test base on a SALOME installation. -example: ->> sat test SALOME-master --grid GEOM --session light""") - -def parse_option(args, config): - """ Parse the options and do some verifications about it - - :param args List: The list of arguments of the command - :param config Config: The global configuration - :return: the options of the current command launch and the full arguments - :rtype: Tuple (options, args) + :param options: The options + :return: None """ - (options, args) = parser.parse_args(args) - if not options.launcher: options.launcher = "" elif not os.path.isabs(options.launcher): @@ -83,8 +87,209 @@ def parse_option(args, config): if not os.path.exists(options.launcher): raise src.SatException( _("Launcher not found: %s") % options.launcher ) + return + + def run(self, cmd_arguments): + """method called for command 'sat test '""" + argList = self.assumeAsList(cmd_arguments) + + # print general help and returns + if len(argList) == 0: + self.print_help() + return RCO.ReturnCode("OK", "No arguments, as 'sat %s --help'" % self.name) + + self._options, remaindersArgs = self.parseArguments(argList) + + if self._options.help: + self.print_help() + return RCO.ReturnCode("OK", "Done 'sat %s --help'" % self.name) + + # shortcuts + runner = self.getRunner() + config = self.getConfig() + logger = self.getLogger() + options = self.getOptions() + + self.check_option(options) + + # the test base is specified either by the application, or by the --base option + with_application = False + if runner.cfg.VARS.application != 'None': + logger.write( + _('Running tests on application %s\n') % + src.printcolors.printcLabel(runner.cfg.VARS.application), 1) + with_application = True + elif not options.base: + raise src.SatException( + _('A test base is required. Use the --base option') ) + + # the launcher is specified either by the application, or by the --launcher option + if with_application: + # check if environment is loaded + if 'KERNEL_ROOT_DIR' in os.environ: + logger.write( src.printcolors.printcWarning( + _("WARNING: SALOME environment already sourced")) + "\n", 1 ) + + + elif options.launcher: + logger.write(src.printcolors.printcWarning( + _("Running SALOME application.")) + "\n\n", 1) + else: + msg = _("Impossible to find any launcher.\n" + "Please specify an application or a launcher") + logger.write(src.printcolors.printcError(msg)) + logger.write("\n") + return 1 + + # set the display + show_desktop = (options.display and options.display.upper() == "NO") + if options.display and options.display != "NO": + remote_name = options.display.split(':')[0] + if remote_name != "": + check_remote_machine(remote_name, logger) + # if explicitly set use user choice + os.environ['DISPLAY'] = options.display + elif 'DISPLAY' not in os.environ: + # if no display set + if ('test' in runner.cfg.LOCAL and + 'display' in runner.cfg.LOCAL.test and + len(runner.cfg.LOCAL.test.display) > 0): + # use default value for test tool + os.environ['DISPLAY'] = runner.cfg.LOCAL.test.display + else: + os.environ['DISPLAY'] = "localhost:0.0" + + # initialization + ################# + if with_application: + tmp_dir = os.path.join(runner.cfg.VARS.tmp_root, + runner.cfg.APPLICATION.name, + "test") + else: + tmp_dir = os.path.join(runner.cfg.VARS.tmp_root, + "test") + + # remove previous tmp dir + if os.access(tmp_dir, os.F_OK): + try: + shutil.rmtree(tmp_dir) + except: + logger.error( + _("error removing TT_TMP_RESULT %s\n") % tmp_dir) + + lines = [] + lines.append("date = '%s'" % runner.cfg.VARS.date) + lines.append("hour = '%s'" % runner.cfg.VARS.hour) + lines.append("node = '%s'" % runner.cfg.VARS.node) + lines.append("arch = '%s'" % runner.cfg.VARS.dist) + + if 'APPLICATION' in runner.cfg: + lines.append("application_info = {}") + lines.append("application_info['name'] = '%s'" % + runner.cfg.APPLICATION.name) + lines.append("application_info['tag'] = '%s'" % + runner.cfg.APPLICATION.tag) + lines.append("application_info['products'] = %s" % + str(runner.cfg.APPLICATION.products)) + + content = "\n".join(lines) - return (options, args) + # create hash from context information + dirname = sha1(content.encode()).hexdigest() + base_dir = os.path.join(tmp_dir, dirname) + os.makedirs(base_dir) + os.environ['TT_TMP_RESULT'] = base_dir + + # create env_info file + f = open(os.path.join(base_dir, 'env_info.py'), "w") + f.write(content) + f.close() + + # create working dir and bases dir + working_dir = os.path.join(base_dir, 'WORK') + os.makedirs(working_dir) + os.makedirs(os.path.join(base_dir, 'BASES')) + os.chdir(working_dir) + + if 'PYTHONPATH' not in os.environ: + os.environ['PYTHONPATH'] = '' + else: + for var in os.environ['PYTHONPATH'].split(':'): + if var not in sys.path: + sys.path.append(var) + + # launch of the tests + ##################### + test_base = "" + if options.base: + test_base = options.base + elif with_application and "test_base" in runner.cfg.APPLICATION: + test_base = runner.cfg.APPLICATION.test_base.name + + src.printcolors.print_value(logger, _('Display'), os.environ['DISPLAY'], 2) + src.printcolors.print_value(logger, _('Timeout'), + src.test_module.DEFAULT_TIMEOUT, 2) + src.printcolors.print_value(logger, _("Working dir"), base_dir, 3) + + # create the test object + test_runner = src.test_module.Test(runner.cfg, + logger, + base_dir, + testbase=test_base, + grids=options.grids, + sessions=options.sessions, + launcher=options.launcher, + show_desktop=show_desktop) + + if not test_runner.test_base_found: + # Fail + return 1 + + # run the test + logger.allowPrintLevel = False + retcode = test_runner.run_all_tests() + logger.allowPrintLevel = True + + logger.write(_("Tests finished"), 1) + logger.write("\n", 2, False) + + logger.write(_("\nGenerate the specific test log\n"), 5) + log_dir = src.get_log_path(runner.cfg) + out_dir = os.path.join(log_dir, "TEST") + src.ensure_path_exists(out_dir) + name_xml_board = logger.logFileName.split(".")[0] + "board" + ".xml" + historic_xml_path = generate_history_xml_path(runner.cfg, test_base) + + create_test_report(runner.cfg, + historic_xml_path, + out_dir, + retcode, + xmlname = name_xml_board) + xml_board_path = os.path.join(out_dir, name_xml_board) + + # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb + # de remontee de log des tests + print "TRACES OP - test.py/run() : historic_xml_path = '#%s#'" %historic_xml_path + print "TRACES OP - test.py/run() : log_dir = '#%s#'" %log_dir + print "TRACES OP - test.py/run() : name_xml_board = '#%s#'" %name_xml_board + + logger.l_logFiles.append(xml_board_path) + logger.add_link(os.path.join("TEST", name_xml_board), + "board", + retcode, + "Click on the link to get the detailed test results") + + # Add the historic files into the log files list of the command + logger.l_logFiles.append(historic_xml_path) + + logger.write( + _("Removing the temporary directory: %s\n" % + test_runner.tmp_working_dir), 5 ) + if os.path.exists(test_runner.tmp_working_dir): + shutil.rmtree(test_runner.tmp_working_dir) + + return retcode + def ask_a_path(): """ @@ -499,7 +704,7 @@ def create_test_report(config, gn.attrib['not_run'] = str(nb_not_run) # Remove the res attribute of all tests that were not launched - # this time + # this time for mn in gn.findall("grid"): if mn.attrib["executed_last_time"] == "no": for tyn in mn.findall("session"): @@ -543,187 +748,3 @@ def generate_history_xml_path(config, test_base): history_xml_name += ".xml" log_dir = src.get_log_path(config) return os.path.join(log_dir, "TEST", history_xml_name) - -def run(args, runner, logger): - '''method that is called when salomeTools is called with test parameter. - ''' - (options, args) = parse_option(args, runner.cfg) - - # the test base is specified either by the application, or by the --base option - with_application = False - if runner.cfg.VARS.application != 'None': - logger.write( - _('Running tests on application %s\n') % - src.printcolors.printcLabel(runner.cfg.VARS.application), 1) - with_application = True - elif not options.base: - raise src.SatException( - _('A test base is required. Use the --base option') ) - - # the launcher is specified either by the application, or by the --launcher option - if with_application: - # check if environment is loaded - if 'KERNEL_ROOT_DIR' in os.environ: - logger.write( src.printcolors.printcWarning( - _("WARNING: SALOME environment already sourced")) + "\n", 1 ) - - - elif options.launcher: - logger.write(src.printcolors.printcWarning( - _("Running SALOME application.")) + "\n\n", 1) - else: - msg = _("Impossible to find any launcher.\n" - "Please specify an application or a launcher") - logger.write(src.printcolors.printcError(msg)) - logger.write("\n") - return 1 - - # set the display - show_desktop = (options.display and options.display.upper() == "NO") - if options.display and options.display != "NO": - remote_name = options.display.split(':')[0] - if remote_name != "": - check_remote_machine(remote_name, logger) - # if explicitly set use user choice - os.environ['DISPLAY'] = options.display - elif 'DISPLAY' not in os.environ: - # if no display set - if ('test' in runner.cfg.LOCAL and - 'display' in runner.cfg.LOCAL.test and - len(runner.cfg.LOCAL.test.display) > 0): - # use default value for test tool - os.environ['DISPLAY'] = runner.cfg.LOCAL.test.display - else: - os.environ['DISPLAY'] = "localhost:0.0" - - # initialization - ################# - if with_application: - tmp_dir = os.path.join(runner.cfg.VARS.tmp_root, - runner.cfg.APPLICATION.name, - "test") - else: - tmp_dir = os.path.join(runner.cfg.VARS.tmp_root, - "test") - - # remove previous tmp dir - if os.access(tmp_dir, os.F_OK): - try: - shutil.rmtree(tmp_dir) - except: - logger.error( - _("error removing TT_TMP_RESULT %s\n") % tmp_dir) - - lines = [] - lines.append("date = '%s'" % runner.cfg.VARS.date) - lines.append("hour = '%s'" % runner.cfg.VARS.hour) - lines.append("node = '%s'" % runner.cfg.VARS.node) - lines.append("arch = '%s'" % runner.cfg.VARS.dist) - - if 'APPLICATION' in runner.cfg: - lines.append("application_info = {}") - lines.append("application_info['name'] = '%s'" % - runner.cfg.APPLICATION.name) - lines.append("application_info['tag'] = '%s'" % - runner.cfg.APPLICATION.tag) - lines.append("application_info['products'] = %s" % - str(runner.cfg.APPLICATION.products)) - - content = "\n".join(lines) - - # create hash from context information - dirname = sha1(content.encode()).hexdigest() - base_dir = os.path.join(tmp_dir, dirname) - os.makedirs(base_dir) - os.environ['TT_TMP_RESULT'] = base_dir - - # create env_info file - f = open(os.path.join(base_dir, 'env_info.py'), "w") - f.write(content) - f.close() - - # create working dir and bases dir - working_dir = os.path.join(base_dir, 'WORK') - os.makedirs(working_dir) - os.makedirs(os.path.join(base_dir, 'BASES')) - os.chdir(working_dir) - - if 'PYTHONPATH' not in os.environ: - os.environ['PYTHONPATH'] = '' - else: - for var in os.environ['PYTHONPATH'].split(':'): - if var not in sys.path: - sys.path.append(var) - - # launch of the tests - ##################### - test_base = "" - if options.base: - test_base = options.base - elif with_application and "test_base" in runner.cfg.APPLICATION: - test_base = runner.cfg.APPLICATION.test_base.name - - src.printcolors.print_value(logger, _('Display'), os.environ['DISPLAY'], 2) - src.printcolors.print_value(logger, _('Timeout'), - src.test_module.DEFAULT_TIMEOUT, 2) - src.printcolors.print_value(logger, _("Working dir"), base_dir, 3) - - # create the test object - test_runner = src.test_module.Test(runner.cfg, - logger, - base_dir, - testbase=test_base, - grids=options.grids, - sessions=options.sessions, - launcher=options.launcher, - show_desktop=show_desktop) - - if not test_runner.test_base_found: - # Fail - return 1 - - # run the test - logger.allowPrintLevel = False - retcode = test_runner.run_all_tests() - logger.allowPrintLevel = True - - logger.write(_("Tests finished"), 1) - logger.write("\n", 2, False) - - logger.write(_("\nGenerate the specific test log\n"), 5) - log_dir = src.get_log_path(runner.cfg) - out_dir = os.path.join(log_dir, "TEST") - src.ensure_path_exists(out_dir) - name_xml_board = logger.logFileName.split(".")[0] + "board" + ".xml" - historic_xml_path = generate_history_xml_path(runner.cfg, test_base) - - create_test_report(runner.cfg, - historic_xml_path, - out_dir, - retcode, - xmlname = name_xml_board) - xml_board_path = os.path.join(out_dir, name_xml_board) - - # OP 14/11/2017 Ajout de traces pour essayer de decouvrir le pb - # de remontee de log des tests - print "TRACES OP - test.py/run() : historic_xml_path = '#%s#'" %historic_xml_path - print "TRACES OP - test.py/run() : log_dir = '#%s#'" %log_dir - print "TRACES OP - test.py/run() : name_xml_board = '#%s#'" %name_xml_board - - logger.l_logFiles.append(xml_board_path) - logger.add_link(os.path.join("TEST", name_xml_board), - "board", - retcode, - "Click on the link to get the detailed test results") - - # Add the historic files into the log files list of the command - logger.l_logFiles.append(historic_xml_path) - - logger.write( - _("Removing the temporary directory: %s\n" % - test_runner.tmp_working_dir), 5 ) - if os.path.exists(test_runner.tmp_working_dir): - shutil.rmtree(test_runner.tmp_working_dir) - - return retcode - diff --git a/src/compilation.py b/src/compilation.py index 1091acd..732080c 100644 --- a/src/compilation.py +++ b/src/compilation.py @@ -21,7 +21,8 @@ import subprocess import sys import shutil -import src +from src.options import OptResult + C_COMPILE_ENV_LIST = ["CC", "CXX", @@ -38,7 +39,7 @@ class Builder: config, logger, product_info, - options = src.options.OptResult(), + options = OptResult(), check_src=True): self.config = config self.logger = logger diff --git a/src/configManager.py b/src/configManager.py index e05eed5..fae58d9 100644 --- a/src/configManager.py +++ b/src/configManager.py @@ -27,7 +27,7 @@ import src.loggingSat as LOG import src.returnCode as RCO import src.architecture as ARCH import src.utilsSat as UTS - +import src.pyconf as PYCONF class ConfigOpener: '''Class that helps to find an application pyconf @@ -42,9 +42,9 @@ class ConfigOpener: def __call__(self, name): if os.path.isabs(name): - return src.pyconf.ConfigInputStream(open(name, 'rb')) + return PYCONF.ConfigInputStream(open(name, 'rb')) else: - return src.pyconf.ConfigInputStream( + return PYCONF.ConfigInputStream( open(os.path.join( self.get_path(name), name ), 'rb') ) raise IOError(_("Configuration file '%s' not found") % name) @@ -113,7 +113,7 @@ class ConfigManager: UTS.ensure_path_exists(var['personal_machines_dir']) # read linux distributions dictionary - distrib_cfg = src.pyconf.Config(os.path.join(var['srcDir'], + distrib_cfg = PYCONF.Config(os.path.join(var['srcDir'], 'internal_config', 'distrib.pyconf')) @@ -182,21 +182,21 @@ class ConfigManager: :param datadir str: The repository that contain external data for salomeTools. :return: The final config. - :rtype: class 'src.pyconf.Config' + :rtype: class 'PYCONF.Config' ''' # create a ConfigMerger to handle merge - merger = src.pyconf.ConfigMerger() #MergeHandler()) + merger = PYCONF.ConfigMerger() #MergeHandler()) # create the configuration instance - cfg = src.pyconf.Config() + cfg = PYCONF.Config() # ===================================================================== # create VARS section var = self._create_vars(application=application, command=command, datadir=datadir) # add VARS to config - cfg.VARS = src.pyconf.Mapping(cfg) + cfg.VARS = PYCONF.Mapping(cfg) for variable in var: cfg.VARS[variable] = var[variable] @@ -207,12 +207,12 @@ class ConfigManager: # ===================================================================== # Load INTERNAL config # read src/internal_config/salomeTools.pyconf - src.pyconf.streamOpener = ConfigOpener([ + PYCONF.streamOpener = ConfigOpener([ os.path.join(cfg.VARS.srcDir, 'internal_config')]) try: - internal_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.srcDir, + internal_cfg = PYCONF.Config(open(os.path.join(cfg.VARS.srcDir, 'internal_config', 'salomeTools.pyconf'))) - except src.pyconf.ConfigError as e: + except PYCONF.ConfigError as e: raise src.SatException(_("Error in configuration file:" " salomeTools.pyconf\n %(error)s") % \ {'error': str(e) }) @@ -226,12 +226,12 @@ class ConfigManager: # ===================================================================== # Load LOCAL config file # search only in the data directory - src.pyconf.streamOpener = ConfigOpener([cfg.VARS.datadir]) + PYCONF.streamOpener = ConfigOpener([cfg.VARS.datadir]) try: - local_cfg = src.pyconf.Config(open(os.path.join(cfg.VARS.datadir, + local_cfg = PYCONF.Config(open(os.path.join(cfg.VARS.datadir, 'local.pyconf')), PWD = ('LOCAL', cfg.VARS.datadir) ) - except src.pyconf.ConfigError as e: + except PYCONF.ConfigError as e: raise src.SatException(_("Error in configuration file: " "local.pyconf\n %(error)s") % \ {'error': str(e) }) @@ -268,12 +268,12 @@ class ConfigManager: # ===================================================================== # Load the PROJECTS - projects_cfg = src.pyconf.Config() + projects_cfg = PYCONF.Config() projects_cfg.addMapping("PROJECTS", - src.pyconf.Mapping(projects_cfg), + PYCONF.Mapping(projects_cfg), "The projects\n") projects_cfg.PROJECTS.addMapping("projects", - src.pyconf.Mapping(cfg.PROJECTS), + PYCONF.Mapping(cfg.PROJECTS), "The projects definition\n") for project_pyconf_path in cfg.PROJECTS.project_file_paths: @@ -284,7 +284,7 @@ class ConfigManager: project_name = os.path.basename(project_pyconf_path)[:-len(".pyconf")] try: project_pyconf_dir = os.path.dirname(project_pyconf_path) - project_cfg = src.pyconf.Config(open(project_pyconf_path), + project_cfg = PYCONF.Config(open(project_pyconf_path), PWD=("", project_pyconf_dir)) except Exception as e: msg = _("ERROR: Error in configuration file: %(file_path)s\n %(error)s\n") % \ @@ -292,7 +292,7 @@ class ConfigManager: sys.stdout.write(msg) continue projects_cfg.PROJECTS.projects.addMapping(project_name, - src.pyconf.Mapping(projects_cfg.PROJECTS.projects), + PYCONF.Mapping(projects_cfg.PROJECTS.projects), "The %s project\n" % project_name) projects_cfg.PROJECTS.projects[project_name]=project_cfg projects_cfg.PROJECTS.projects[project_name]["file_path"] = \ @@ -308,17 +308,17 @@ class ConfigManager: # Create the paths where to search the application configurations, # the product configurations, the products archives, # the jobs configurations and the machines configurations - cfg.addMapping("PATHS", src.pyconf.Mapping(cfg), "The paths\n") - cfg.PATHS["APPLICATIONPATH"] = src.pyconf.Sequence(cfg.PATHS) + cfg.addMapping("PATHS", PYCONF.Mapping(cfg), "The paths\n") + cfg.PATHS["APPLICATIONPATH"] = PYCONF.Sequence(cfg.PATHS) cfg.PATHS.APPLICATIONPATH.append(cfg.VARS.personal_applications_dir, "") - cfg.PATHS["PRODUCTPATH"] = src.pyconf.Sequence(cfg.PATHS) + cfg.PATHS["PRODUCTPATH"] = PYCONF.Sequence(cfg.PATHS) cfg.PATHS.PRODUCTPATH.append(cfg.VARS.personal_products_dir, "") - cfg.PATHS["ARCHIVEPATH"] = src.pyconf.Sequence(cfg.PATHS) + cfg.PATHS["ARCHIVEPATH"] = PYCONF.Sequence(cfg.PATHS) cfg.PATHS.ARCHIVEPATH.append(cfg.VARS.personal_archives_dir, "") - cfg.PATHS["JOBPATH"] = src.pyconf.Sequence(cfg.PATHS) + cfg.PATHS["JOBPATH"] = PYCONF.Sequence(cfg.PATHS) cfg.PATHS.JOBPATH.append(cfg.VARS.personal_jobs_dir, "") - cfg.PATHS["MACHINEPATH"] = src.pyconf.Sequence(cfg.PATHS) + cfg.PATHS["MACHINEPATH"] = PYCONF.Sequence(cfg.PATHS) cfg.PATHS.MACHINEPATH.append(cfg.VARS.personal_machines_dir, "") # initialise the path with local directory @@ -344,14 +344,14 @@ class ConfigManager: if application is not None: # search APPLICATION file in all directories in configPath cp = cfg.PATHS.APPLICATIONPATH - src.pyconf.streamOpener = ConfigOpener(cp) + PYCONF.streamOpener = ConfigOpener(cp) do_merge = True try: - application_cfg = src.pyconf.Config(application + '.pyconf') + application_cfg = PYCONF.Config(application + '.pyconf') except IOError as e: raise src.SatException(_("%s, use 'config --list' to get the" " list of available applications.") % e) - except src.pyconf.ConfigError as e: + except PYCONF.ConfigError as e: if (not ('-e' in parser.parse_args()[1]) or ('--edit' in parser.parse_args()[1]) and command == 'config'): @@ -382,12 +382,12 @@ class ConfigManager: # ===================================================================== # Load product config files in PRODUCTS section - products_cfg = src.pyconf.Config() + products_cfg = PYCONF.Config() products_cfg.addMapping("PRODUCTS", - src.pyconf.Mapping(products_cfg), + PYCONF.Mapping(products_cfg), "The products\n") if application is not None: - src.pyconf.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH) + PYCONF.streamOpener = ConfigOpener(cfg.PATHS.PRODUCTPATH) for product_name in application_cfg.APPLICATION.products.keys(): # Loop on all files that are in softsDir directory # and read their config @@ -396,7 +396,7 @@ class ConfigManager: if product_file_path: products_dir = os.path.dirname(product_file_path) try: - prod_cfg = src.pyconf.Config(open(product_file_path), + prod_cfg = PYCONF.Config(open(product_file_path), PWD=("", products_dir)) prod_cfg.from_file = product_file_path products_cfg.PRODUCTS[product_name] = prod_cfg @@ -430,7 +430,7 @@ class ConfigManager: # load USER config self.set_user_config_file(cfg) user_cfg_file = self.get_user_config_file() - user_cfg = src.pyconf.Config(open(user_cfg_file)) + user_cfg = PYCONF.Config(open(user_cfg_file)) merger.merge(cfg, user_cfg) # apply overwrite from command line if needed @@ -443,7 +443,7 @@ class ConfigManager: '''Set the user config file name and path. If necessary, build it from another one or create it from scratch. - :param config class 'src.pyconf.Config': The global config + :param config class 'PYCONF.Config': The global config (containing all pyconf). ''' # get the expected name and path of the file @@ -459,16 +459,16 @@ class ConfigManager: '''This method is called when there are no user config file. It build it from scratch. - :param config class 'src.pyconf.Config': The global config. + :param config class 'PYCONF.Config': The global config. :return: the config corresponding to the file created. - :rtype: config class 'src.pyconf.Config' + :rtype: config class 'PYCONF.Config' ''' cfg_name = self.get_user_config_file() - user_cfg = src.pyconf.Config() + user_cfg = PYCONF.Config() # - user_cfg.addMapping('USER', src.pyconf.Mapping(user_cfg), "") + user_cfg.addMapping('USER', PYCONF.Mapping(user_cfg), "") user_cfg.USER.addMapping('cvs_user', config.VARS.user, "This is the user name used to access salome cvs base.\n") @@ -496,9 +496,9 @@ class ConfigManager: "to read pdf documentation\n") # CNC 25/10/17 : plus nécessaire a priori # user_cfg.USER.addMapping("base", -# src.pyconf.Reference( +# PYCONF.Reference( # user_cfg, -# src.pyconf.DOLLAR, +# PYCONF.DOLLAR, # 'workdir + $VARS.sep + "BASE"'), # "The products installation base (could be " # "ignored if this key exists in the local.pyconf" @@ -703,7 +703,7 @@ def getConfigColored(config, path, stream, show_label=False, level=0, show_full_ get a colored representation value from a config pyconf instance. used recursively from the initial path. - :param config class 'src.pyconf.Config': The configuration + :param config class 'PYCONF.Config': The configuration from which the value is displayed. :param path str : the path in the configuration of the value to print. :param show_label boolean: if True, do a basic display. @@ -745,7 +745,7 @@ def getConfigColored(config, path, stream, show_label=False, level=0, show_full_ if show_label: strean.write("\n") for v in sorted(val.keys()): print_value(config, path + '.' + v, stream, show_label, level + 1) - elif val.__class__ == src.pyconf.Sequence or isinstance(val, list): + elif val.__class__ == PYCONF.Sequence or isinstance(val, list): # in this case, value is a list (or a Sequence) if show_label: stream.write("\n") index = 0 diff --git a/src/environment.py b/src/environment.py index d926432..3d79f3e 100644 --- a/src/environment.py +++ b/src/environment.py @@ -21,7 +21,7 @@ import subprocess import string import sys -import src +import src.pyconf as PYCONF class Environ: '''Class to manage the environment context @@ -475,11 +475,11 @@ class SalomeEnviron: continue # if it is a dict, do not do anything - if isinstance(val, src.pyconf.Mapping): + if isinstance(val, PYCONF.Mapping): continue # if it is a list, loop on its values - if isinstance(val, src.pyconf.Sequence): + if isinstance(val, PYCONF.Sequence): # transform into list of strings l_val = [] for item in val: diff --git a/src/product.py b/src/product.py index ea886a0..9cf8a78 100644 --- a/src/product.py +++ b/src/product.py @@ -22,7 +22,7 @@ import os import re -import src +import src.pyconf as PYCONF AVAILABLE_VCS = ['git', 'svn', 'cvs'] config_expression = "^config-\d+$" @@ -53,7 +53,7 @@ def get_product_config(config, product_name, with_install_dir=True): dev = 'no' base = 'maybe' section = None - if isinstance(version, src.pyconf.Mapping): + if isinstance(version, PYCONF.Mapping): dic_version = version # Get the version/tag if not 'tag' in dic_version: @@ -126,17 +126,17 @@ def get_product_config(config, product_name, with_install_dir=True): # If there is no definition but the product is declared as native, # construct a new definition containing only the get_source key if prod_info is None and version == "native": - prod_info = src.pyconf.Config() + prod_info = PYCONF.Config() prod_info.name = product_name prod_info.get_source = "native" # If there is no definition but the product is fixed, # construct a new definition containing only the product name if prod_info is None and os.path.isdir(version): - prod_info = src.pyconf.Config() + prod_info = PYCONF.Config() prod_info.name = product_name prod_info.get_source = "fixed" - prod_info.addMapping("environ", src.pyconf.Mapping(prod_info), "") + prod_info.addMapping("environ", PYCONF.Mapping(prod_info), "") # If prod_info is still None, it means that there is no product definition @@ -167,7 +167,7 @@ Please add a section in it.""") % {"1" : vv, "2" : prod_pyconf_path} if prod_info.get_source == "archive": if not "archive_info" in prod_info: prod_info.addMapping("archive_info", - src.pyconf.Mapping(prod_info), + PYCONF.Mapping(prod_info), "") if "archive_name" not in prod_info.archive_info: arch_name = product_name + "-" + version + ".tar.gz" @@ -431,7 +431,7 @@ def check_config_exists(config, prod_dir, prod_info): # If there is no dependency, it is the right path if len(prod_info.depend)==0: - compile_cfg = src.pyconf.Config(config_file) + compile_cfg = PYCONF.Config(config_file) if len(compile_cfg) == 0: return True, os.path.join(prod_dir, dir_or_file) continue @@ -439,7 +439,7 @@ def check_config_exists(config, prod_dir, prod_info): # check if there is the config described in the file corresponds the # dependencies of the product config_corresponds = True - compile_cfg = src.pyconf.Config(config_file) + compile_cfg = PYCONF.Config(config_file) for prod_dep in prod_info.depend: # if the dependency is not in the config, # the config does not correspond diff --git a/src/salomeTools.py b/src/salomeTools.py index 12e5101..0bd70da 100755 --- a/src/salomeTools.py +++ b/src/salomeTools.py @@ -42,6 +42,7 @@ import pprint as PP import src # for __version__ import src.debug as DBG # Easy print stderr (for DEBUG only) import src.returnCode as RCO # Easy (ok/ko, why) return methods code +from src.options import Options # get path to src rootdir = os.path.realpath( os.path.join(os.path.dirname(__file__), "..") ) @@ -163,7 +164,7 @@ class _BaseCommand(object): res = "%s(\n %s)\n" % (self.getClassName(), tmp[1:-1]) return res - def run(self, args): + def run(self, cmd_arguments): """ virtual example method for Command instance have to return RCO.ReturnCode() @@ -188,6 +189,12 @@ class _BaseCommand(object): raise Exception("%s instance needs self._option not None, fix it." % self.getClassName()) else: return self._options + + def getParserWithHelp(self): + """returns elementary parser with help option set""" + parser = Options() + parser.add_option('h', 'help', 'boolean', 'help', _("shows help on command.")) + return parser def getRunner(self): if self._runner is None: @@ -330,8 +337,7 @@ class Sat(object): Define all possible for salomeTools/sat command: 'sat ' (internal use only) """ - import src.options - parser = src.options.Options() + parser = Options() parser.add_option('h', 'help', 'boolean', 'help', _("shows global help or help on a specific command.")) parser.add_option('o', 'overwrite', 'list', "overwrite", diff --git a/src/test_module.py b/src/test_module.py index 57a15fd..d1648e9 100755 --- a/src/test_module.py +++ b/src/test_module.py @@ -35,7 +35,7 @@ import string import imp import subprocess -import src +import src.pyconf as PYCONF # directories not considered as test grids C_IGNORE_GRIDS = ['.git', '.svn', 'RESSOURCES'] @@ -80,7 +80,7 @@ class Test: self.known_errors = None # create section for results - self.config.TESTS = src.pyconf.Sequence(self.config) + self.config.TESTS = PYCONF.Sequence(self.config) self.nb_run = 0 self.nb_succeed = 0 @@ -615,18 +615,18 @@ class Test: self.logger.write("status = %s, elapsed = %s\n" % (status, elapsed), 5) # create the test result to add in the config object - test_info = src.pyconf.Mapping(self.config) + test_info = PYCONF.Mapping(self.config) test_info.testbase = self.currentTestBase test_info.grid = self.currentgrid test_info.session = self.currentsession - test_info.script = src.pyconf.Sequence(self.config) + test_info.script = PYCONF.Sequence(self.config) script_results = self.read_results(listTest, elapsed == time_out) for sr in sorted(script_results.keys()): self.nb_run += 1 # create script result - script_info = src.pyconf.Mapping(self.config) + script_info = PYCONF.Mapping(self.config) script_info.name = sr script_info.res = script_results[sr][0] script_info.time = script_results[sr][1] @@ -640,7 +640,7 @@ class Test: kfres = script_results[sr][3] if len(kfres) > 0: - script_info.known_error = src.pyconf.Mapping(self.config) + script_info.known_error = PYCONF.Mapping(self.config) script_info.known_error.date = kfres[0] script_info.known_error.expected = kfres[1] script_info.known_error.comment = kfres[2] diff --git a/test/test_100_satHelp.py b/test/test_100_satHelp.py index 0ffef0e..315c58b 100755 --- a/test/test_100_satHelp.py +++ b/test/test_100_satHelp.py @@ -101,7 +101,8 @@ class TestCase(unittest.TestCase): cmd = "sat %s --help" % c stdout, stderr = SAT.launchSat(cmd) self.assertEqual(stderr, "") - self.assertTrue(c in stdout) + DBG.write("test_050 %s stdout" % c, stdout) + self.assertTrue("The %s command" % c in stdout) self.assertTrue("Available options" in stdout) def test_051(self): @@ -112,7 +113,8 @@ class TestCase(unittest.TestCase): returnCode = s.execute_cli(cmd) self.assertTrue(returnCode.isOk()) logs = self.logger.getLogsAndClear() - DBG.write(cmd, logs, True) + DBG.write(cmd, logs) + self.assertTrue("The %s command" % c in logs) self.assertTrue("Available options" in logs) if __name__ == '__main__': -- 2.39.2