From 4bf2d3ee60a8f515aa0d319c1093062e25b04f36 Mon Sep 17 00:00:00 2001 From: Serge Rehbinder Date: Fri, 2 Sep 2016 11:20:27 +0200 Subject: [PATCH] Add the package commande --- commands/compile.py | 5 +- commands/config.py | 2 +- commands/package.py | 843 ++++++++++++++++++++++++++++++++++ data/site.pyconf | 2 +- src/product.py | 12 +- src/xsl/jobs_board_report.xsl | 2 +- 6 files changed, 861 insertions(+), 5 deletions(-) create mode 100644 commands/package.py diff --git a/commands/compile.py b/commands/compile.py index 3a2dcf4..78530a8 100644 --- a/commands/compile.py +++ b/commands/compile.py @@ -453,7 +453,10 @@ def add_compile_config_file(p_info, config): # Create the compile config compile_cfg = src.pyconf.Config() for prod_name in p_info.depend: - compile_cfg.addMapping(prod_name, src.pyconf.Mapping(compile_cfg), "") + if prod_name not in compile_cfg: + compile_cfg.addMapping(prod_name, + src.pyconf.Mapping(compile_cfg), + "") prod_dep_info = src.product.get_product_config(config, prod_name, False) compile_cfg[prod_name] = prod_dep_info.version # Write it in the install directory of the product diff --git a/commands/config.py b/commands/config.py index ef7b2a5..02d0cc5 100644 --- a/commands/config.py +++ b/commands/config.py @@ -490,7 +490,7 @@ class ConfigManager: user_cfg, src.pyconf.DOLLAR, 'workdir + $VARS.sep + "LOGS"'), - "The log reposotory\n") + "The log repository\n") # src.ensure_path_exists(config.VARS.personalDir) diff --git a/commands/package.py b/commands/package.py new file mode 100644 index 0000000..a040162 --- /dev/null +++ b/commands/package.py @@ -0,0 +1,843 @@ +#!/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 stat +import shutil +import tarfile + +import src + +BINARY = "binary" +SOURCE = "Source" +PROJECT = "Project" +SAT = "Sat" + +ARCHIVE_DIR = "ARCHIVES" +PROJECT_DIR = "PROJECT" + +PROJECT_TEMPLATE = """#!/usr/bin/env python +#-*- coding:utf-8 -*- + +# The path to the archive root directory +root_path : "" +# path to the PROJECT +project_path : $root_path + "PROJECT/" + +# Where to search the archives of the products +ARCHIVEPATH : $root_path + "ARCHIVES" +# Where to search the pyconf of the applications +APPLICATIONPATH : $project_path + "applications/" +# Where to search the pyconf of the products +PRODUCTPATH : $project_path + "products/" +# Where to search the pyconf of the jobs of the project +JOBPATH : $project_path + "jobs/" +# Where to search the pyconf of the machines of the project +MACHINEPATH : $project_path + "machines/" +""" + +SITE_TEMPLATE = ("""#!/usr/bin/env python +#-*- coding:utf-8 -*- + +SITE : +{ + log : + { + log_dir : $USER.workdir + "/LOGS" + } + test :{ + tmp_dir_with_application : '/tmp' + $VARS.sep + $VARS.user + """ +"""$VARS.sep + $APPLICATION.name + $VARS.sep + 'test' + tmp_dir : '/tmp' + $VARS.sep + $VARS.user + $VARS.sep + 'test' + timeout : 150 + } +} + +PROJECTS : +{ +project_file_paths : [$VARS.salometoolsway + $VARS.sep + \"..\" + $VARS.sep""" +""" + \"""" + PROJECT_DIR + """\" + $VARS.sep + "project.pyconf"] +} +""") + +# Define all possible option for the package command : sat package +parser = src.options.Options() +parser.add_option('b', 'binaries', 'boolean', 'binaries', + _('Produce a binary package.'), False) +parser.add_option('f', 'force_creation', 'boolean', 'force_creation', + _('Create the archive even if there are missing products.'), False) +parser.add_option('s', 'sources', 'boolean', 'sources', + _('Produce a compilable archive of the sources of the application.'), False) +parser.add_option('p', 'project', 'string', 'project', + _('Produce an archive that contains a project.'), "") +parser.add_option('', 'sat', 'boolean', 'sat', + _('Produce an archive that contains salomeTools.'), False) +parser.add_option('n', 'name', 'string', 'name', + _('The name or full path of the archive.'), None) +parser.add_option('', 'with_vcs', 'boolean', 'with_vcs', + _('Only source package: do not make archive of vcs products.'), False) + +def add_files(tar, name_archive, d_content, logger): + '''Create an archive containing all directories and files that are given in + the d_content argument. + + :param tar tarfile: The tarfile instance used to make the archive. + :param name_archive str: The name of the archive to make. + :param d_content dict: The dictionary that contain all directories and files + to add in the archive. + d_content[label] = + (path_on_local_machine, path_in_archive) + :param logger Logger: the logging instance + :return: 0 if success, 1 if not. + :rtype: int + ''' + # get the max length of the messages in order to make the display + max_len = len(max(d_content.keys(), key=len)) + + success = 0 + # loop over each directory or file stored in the d_content dictionary + for name in d_content.keys(): + # display information + len_points = max_len - len(name) + logger.write(name + " " + len_points * "." + " ", 3) + # Get the local path and the path in archive + # of the directory or file to add + local_path, archive_path = d_content[name] + in_archive = os.path.join(name_archive, archive_path) + # Add it in the archive + try: + tar.add(local_path, arcname=in_archive) + logger.write(src.printcolors.printcSuccess(_("OK")), 3) + except Exception as e: + logger.write(src.printcolors.printcError(_("KO ")), 3) + logger.write(e, 3) + success = 1 + logger.write("\n", 3) + return success + +def produce_relative_launcher(config, + logger, + file_dir, + file_name, + binaries_dir_name): + '''Create a specific SALOME launcher for the binary package. This launcher + uses relative paths. + + :param config Config: The global configuration. + :param logger Logger: the logging instance + :param file_dir str: the directory where to put the launcher + :param file_name str: The launcher name + :param binaries_dir_name str: the name of the repository where the binaries + are, in the archive. + :return: the path of the produced launcher + :rtype: str + ''' + + # Get the launcher template + profile_install_dir = os.path.join(binaries_dir_name, + config.APPLICATION.profile.product) + withProfile = src.fileEnviron.withProfile.replace( "PROFILE_INSTALL_DIR", + profile_install_dir ) + + before, after = withProfile.split( + "# here your local standalone environment\n") + + # create an environment file writer + writer = src.environment.FileEnvWriter(config, + logger, + file_dir, + src_root=None) + + filepath = os.path.join(file_dir, file_name) + # open the file and write into it + launch_file = open(filepath, "w") + launch_file.write(before) + # Write + writer.write_cfgForPy_file(launch_file, for_package = binaries_dir_name) + launch_file.write(after) + launch_file.close() + + # change the rights in order to make the file executable for everybody + os.chmod(filepath, + stat.S_IRUSR | + stat.S_IRGRP | + stat.S_IROTH | + stat.S_IWUSR | + stat.S_IXUSR | + stat.S_IXGRP | + stat.S_IXOTH) + + return filepath + +def binary_package(config, logger, options, tmp_working_dir): + '''Prepare a dictionary that stores all the needed directories and files to + add in a binary package. + + :param config Config: The global configuration. + :param logger Logger: the logging instance + :param options OptResult: the options of the launched command + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + binary package + :return: the dictionary that stores all the needed directories and files to + add in a binary package. + {label : (path_on_local_machine, path_in_archive)} + :rtype: dict + ''' + + # Get the list of product installation to add to the archive + l_products_name = config.APPLICATION.products.keys() + l_product_info = src.product.get_products_infos(l_products_name, + config) + l_install_dir = [] + l_not_installed = [] + for prod_name, prod_info in l_product_info: + # ignore the native and fixed products + if (src.product.product_is_native(prod_info) + or src.product.product_is_fixed(prod_info)): + continue + if src.product.check_installation(prod_info): + l_install_dir.append((prod_name, prod_info.install_dir)) + else: + l_not_installed.append(prod_name) + + # Print warning or error if there are some missing products + if len(l_not_installed) > 0: + text_missing_prods = "" + for p_name in l_not_installed: + text_missing_prods += "-" + p_name + "\n" + if not options.force_creation: + msg = _("ERROR: there are missing products installations:") + logger.write("%s\n%s" % (src.printcolors.printcError(msg), + text_missing_prods), + 1) + return None + else: + msg = _("WARNING: there are missing products installations:") + logger.write("%s\n%s" % (src.printcolors.printcWarning(msg), + text_missing_prods), + 1) + + # construct the name of the directory that will contain the binaries + binaries_dir_name = "BINARIES-" + config.VARS.dist + + # construct the correlation table between the product names, there + # actual install directories and there install directory in archive + d_products = {} + for prod_name, install_dir in l_install_dir: + path_in_archive = os.path.join(binaries_dir_name, prod_name) + d_products[prod_name] = (install_dir, path_in_archive) + + # create the relative launcher and add it to the files to add + launcher_name = config.APPLICATION.profile.launcher_name + launcher_package = produce_relative_launcher(config, + logger, + tmp_working_dir, + launcher_name, + binaries_dir_name) + + d_products["launcher"] = (launcher_package, launcher_name) + + return d_products + +def source_package(sat, config, logger, options, tmp_working_dir): + '''Prepare a dictionary that stores all the needed directories and files to + add in a source package. + + :param config Config: The global configuration. + :param logger Logger: the logging instance + :param options OptResult: the options of the launched command + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + binary package + :return: the dictionary that stores all the needed directories and files to + add in a source package. + {label : (path_on_local_machine, path_in_archive)} + :rtype: dict + ''' + + # Get all the products that are prepared using an archive + logger.write("Find archive products ... ") + d_archives, l_pinfo_vcs = get_archives(config, logger) + logger.write("Done\n") + d_archives_vcs = {} + if not options.with_vcs: + # Make archives with the products that are not prepared using an archive + # (git, cvs, svn, etc) + logger.write("Construct archives for vcs products ... ") + d_archives_vcs = get_archives_vcs(l_pinfo_vcs, + sat, + config, + logger, + tmp_working_dir) + logger.write("Done\n") + + # Create a project + logger.write("Create the project ... ") + d_project = create_project_for_src_package(config, + tmp_working_dir, + options.with_vcs) + logger.write("Done\n") + + # Add salomeTools + tmp_sat = add_salomeTools(config, tmp_working_dir) + d_sat = {"salomeTools" : (tmp_sat, "salomeTools")} + + # Add a sat symbolic link + tmp_satlink_path = os.path.join(tmp_working_dir, 'sat') + t = os.getcwd() + os.chdir(tmp_working_dir) + if os.path.lexists(tmp_satlink_path): + os.remove(tmp_satlink_path) + os.symlink(os.path.join('salomeTools', 'sat'), 'sat') + os.chdir(t) + + d_sat["sat link"] = (tmp_satlink_path, "sat") + + return src.merge_dicts(d_archives, d_archives_vcs, d_project, d_sat) + +def get_archives(config, logger): + '''Find all the products that are get using an archive and all the products + that are get using a vcs (git, cvs, svn) repository. + + :param config Config: The global configuration. + :param logger Logger: the logging instance + :return: the dictionary {name_product : + (local path of its archive, path in the package of its archive )} + and the list of specific configuration corresponding to the vcs + products + :rtype: (Dict, List) + ''' + # Get the list of product informations + l_products_name = config.APPLICATION.products.keys() + l_product_info = src.product.get_products_infos(l_products_name, + config) + d_archives = {} + l_pinfo_vcs = [] + for p_name, p_info in l_product_info: + # ignore the native and fixed products + if (src.product.product_is_native(p_info) + or src.product.product_is_fixed(p_info)): + continue + if p_info.get_source == "archive": + archive_path = p_info.archive_info.archive_name + archive_name = os.path.basename(archive_path) + else: + l_pinfo_vcs.append((p_name, p_info)) + + d_archives[p_name] = (archive_path, + os.path.join(ARCHIVE_DIR, archive_name)) + return d_archives, l_pinfo_vcs + +def add_salomeTools(config, tmp_working_dir): + '''Prepare a version of salomeTools that has a specific site.pyconf file + configured for a source package. + + :param config Config: The global configuration. + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + source package + :return: The path to the local salomeTools directory to add in the package + :rtype: str + ''' + # Copy sat in the temporary working directory + sat_tmp_path = src.Path(os.path.join(tmp_working_dir, "salomeTools")) + sat_running_path = src.Path(config.VARS.salometoolsway) + sat_running_path.copy(sat_tmp_path) + + # Update the site.pyconf file that contains the path to the project + site_pyconf_name = "site.pyconf" + site_pyconf_dir = os.path.join(tmp_working_dir, "salomeTools", "data") + site_pyconf_file = os.path.join(site_pyconf_dir, site_pyconf_name) + ff = open(site_pyconf_file, "w") + ff.write(SITE_TEMPLATE) + ff.close() + + return sat_tmp_path.path + +def get_archives_vcs(l_pinfo_vcs, sat, config, logger, tmp_working_dir): + '''For sources package that require that all products are get using an + archive, one has to create some archive for the vcs products. + So this method calls the clean and source command of sat and then create + the archives. + + :param l_pinfo_vcs List: The list of specific configuration corresponding to + each vcs product + :param sat Sat: The Sat instance that can be called to clean and source the + products + :param config Config: The global configuration. + :param logger Logger: the logging instance + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + source package + :return: the dictionary that stores all the archives to add in the source + package. {label : (path_on_local_machine, path_in_archive)} + :rtype: dict + ''' + # clean the source directory of all the vcs products, then use the source + # command and thus construct an archive that will not contain the patches + l_prod_names = [pn for pn, __ in l_pinfo_vcs] + # clean + logger.write(_("clean sources\n")) + args_clean = config.VARS.application + args_clean += " --sources --products " + args_clean += ",".join(l_prod_names) + sat.clean(args_clean, batch=True, verbose=0, logger_add_link = logger) + # source + logger.write(_("get sources")) + args_source = config.VARS.application + args_source += " --products " + args_source += ",".join(l_prod_names) + sat.source(args_source, batch=True, verbose=0, logger_add_link = logger) + + # make the new archives + d_archives_vcs = {} + for pn, pinfo in l_pinfo_vcs: + path_archive = make_archive(pn, pinfo, tmp_working_dir) + d_archives_vcs[pn] = (path_archive, + os.path.join(ARCHIVE_DIR, pn + ".tgz")) + return d_archives_vcs + +def make_archive(prod_name, prod_info, where): + '''Create an archive of a product by searching its source directory. + + :param prod_name str: The name of the product. + :param prod_info Config: The specific configuration corresponding to the + product + :param where str: The path of the repository where to put the resulting + archive + :return: The path of the resulting archive + :rtype: str + ''' + path_targz_prod = os.path.join(where, prod_name + ".tgz") + tar_prod = tarfile.open(path_targz_prod, mode='w:gz') + local_path = prod_info.source_dir + tar_prod.add(local_path, arcname=prod_name) + tar_prod.close() + return path_targz_prod + +def create_project_for_src_package(config, tmp_working_dir, with_vcs): + '''Create a specific project for a source package. + + :param config Config: The global configuration. + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + source package + :param with_vcs boolean: True if the package is with vcs products (not + transformed into archive products) + :return: The dictionary + {"project" : (produced project, project path in the archive)} + :rtype: Dict + ''' + + # Create in the working temporary directory the full project tree + project_tmp_dir = os.path.join(tmp_working_dir, PROJECT_DIR) + products_pyconf_tmp_dir = os.path.join(project_tmp_dir, + "products") + compil_scripts_tmp_dir = os.path.join(project_tmp_dir, + "products", + "compil_scripts") + env_scripts_tmp_dir = os.path.join(project_tmp_dir, + "products", + "env_scripts") + patches_tmp_dir = os.path.join(project_tmp_dir, + "products", + "patches") + application_tmp_dir = os.path.join(project_tmp_dir, + "applications") + for directory in [project_tmp_dir, + compil_scripts_tmp_dir, + env_scripts_tmp_dir, + patches_tmp_dir, + application_tmp_dir]: + src.ensure_path_exists(directory) + + # Create the pyconf that contains the information of the project + project_pyconf_name = "project.pyconf" + project_pyconf_file = os.path.join(project_tmp_dir, project_pyconf_name) + ff = open(project_pyconf_file, "w") + ff.write(PROJECT_TEMPLATE) + ff.close() + + # Loop over the products to get there pyconf and all the scripts + # (compilation, environment, patches) + # and create the pyconf file to add to the project + lproducts_name = config.APPLICATION.products.keys() + l_products = src.product.get_products_infos(lproducts_name, config) + for p_name, p_info in l_products: + # ignore native and fixed products + if (src.product.product_is_native(p_info) or + src.product.product_is_fixed(p_info)): + continue + find_product_scripts_and_pyconf(p_name, + p_info, + config, + with_vcs, + compil_scripts_tmp_dir, + env_scripts_tmp_dir, + patches_tmp_dir, + products_pyconf_tmp_dir) + + find_application_pyconf(config, application_tmp_dir) + + d_project = {"project" : (project_tmp_dir, PROJECT_DIR )} + return d_project + +def find_product_scripts_and_pyconf(p_name, + p_info, + config, + with_vcs, + compil_scripts_tmp_dir, + env_scripts_tmp_dir, + patches_tmp_dir, + products_pyconf_tmp_dir): + '''Create a specific pyconf file for a given product. Get its environment + script, its compilation script and patches and put it in the temporary + working directory. This method is used in the source package in order to + construct the specific project. + + :param p_name str: The name of the product. + :param p_info Config: The specific configuration corresponding to the + product + :param config Config: The global configuration. + :param with_vcs boolean: True if the package is with vcs products (not + transformed into archive products) + :param compil_scripts_tmp_dir str: The path to the temporary compilation + scripts directory of the project. + :param env_scripts_tmp_dir str: The path to the temporary environment script + directory of the project. + :param patches_tmp_dir str: The path to the temporary patch scripts + directory of the project. + :param products_pyconf_tmp_dir str: The path to the temporary product + scripts directory of the project. + ''' + + # 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) + + # find the compilation script if any + if src.product.product_has_script(p_info): + compil_script_path = src.Path(p_info.compil_script) + compil_script_path.copy(compil_scripts_tmp_dir) + product_pyconf_cfg[p_info.section].compil_script = os.path.basename( + p_info.compil_script) + # find the environment script if any + if src.product.product_has_env_script(p_info): + env_script_path = src.Path(p_info.environ.env_script) + env_script_path.copy(env_scripts_tmp_dir) + product_pyconf_cfg[p_info.section].environ.env_script = os.path.basename( + p_info.environ.env_script) + # find the patches if any + if src.product.product_has_patches(p_info): + patches = src.pyconf.Sequence() + for patch_path in p_info.patches: + p_path = src.Path(patch_path) + p_path.copy(patches_tmp_dir) + patches.append(os.path.basename(patch_path), "") + + product_pyconf_cfg[p_info.section].patches = patches + + if with_vcs: + # put in the pyconf file the resolved values + for info in ["git_info", "cvs_info", "svn_info"]: + if info in p_info: + for key in p_info[info]: + product_pyconf_cfg[p_info.section][info][key] = p_info[ + info][key] + else: + # if the product is not archive, then make it become archive. + if src.product.product_is_vcs(p_info): + 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), + "") + product_pyconf_cfg[p_info.section + ].archive_info.archive_name = p_info.name + ".tgz" + + # write the pyconf file to the temporary project location + product_tmp_pyconf_path = os.path.join(products_pyconf_tmp_dir, + p_name + ".pyconf") + ff = open(product_tmp_pyconf_path, 'w') + ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n") + product_pyconf_cfg.__save__(ff, 1) + ff.close() + +def find_application_pyconf(config, application_tmp_dir): + '''Find the application pyconf file and put it in the specific temporary + directory containing the specific project of a source package. + + :param config Config: The global configuration. + :param application_tmp_dir str: The path to the temporary application + scripts directory of the project. + ''' + # read the pyconf of the application + application_name = config.VARS.application + application_pyconf_path = src.find_file_in_lpath( + application_name + ".pyconf", + config.PATHS.APPLICATIONPATH) + application_pyconf_cfg = src.pyconf.Config(application_pyconf_path) + + # Change the workdir + application_pyconf_cfg.APPLICATION.workdir = src.pyconf.Reference( + application_pyconf_cfg, + src.pyconf.DOLLAR, + 'VARS.salometoolsway + $VARS.sep + ".."') + + # Prevent from compilation in base + application_pyconf_cfg.APPLICATION.no_base = "yes" + + # write the pyconf file to the temporary application location + application_tmp_pyconf_path = os.path.join(application_tmp_dir, + application_name + ".pyconf") + ff = open(application_tmp_pyconf_path, 'w') + ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n") + application_pyconf_cfg.__save__(ff, 1) + ff.close() + +def project_package(project_file_path, tmp_working_dir): + '''Prepare a dictionary that stores all the needed directories and files to + add in a project package. + + :param project_file_path str: The path to the local project. + :param tmp_working_dir str: The temporary local directory containing some + specific directories or files needed in the + project package + :return: the dictionary that stores all the needed directories and files to + add in a project package. + {label : (path_on_local_machine, path_in_archive)} + :rtype: dict + ''' + d_project = {} + # Read the project file and get the directories to add to the package + project_pyconf_cfg = src.pyconf.Config(project_file_path) + paths = {"ARCHIVEPATH" : "archives", + "APPLICATIONPATH" : "applications", + "PRODUCTPATH" : "products", + "JOBPATH" : "jobs", + "MACHINEPATH" : "machines"} + # Loop over the project paths and add it + for path in paths: + if path not in project_pyconf_cfg: + continue + # 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, + src.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), + "") + project_pyconf_cfg.project_path = "" + + # Write the project pyconf file + project_file_name = os.path.basename(project_file_path) + project_pyconf_tmp_path = os.path.join(tmp_working_dir, project_file_name) + ff = open(project_pyconf_tmp_path, 'w') + ff.write("#!/usr/bin/env python\n#-*- coding:utf-8 -*-\n\n") + project_pyconf_cfg.__save__(ff, 1) + ff.close() + d_project["Project hat file"] = (project_pyconf_tmp_path, project_file_name) + + return d_project + +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 of the application.") + +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 != "", + options.sat) + + # Check if no option for package type + if all_option_types.count(True) == 0: + msg = _("Error: Precise a type for the package\nUse one of the " + "following options: --binaries, --sources, --project or --sat") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Check for only one option for package type + if all_option_types.count(True) > 1: + msg = _("Error: You can use only one type for the package\nUse only one" + " of the following options: --binaries, --sources, --project or" + " --sat") + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Get the package type + if options.binaries: + package_type = BINARY + if options.sources: + package_type = SOURCE + if options.project: + package_type = PROJECT + if options.sat: + package_type = SAT + + # The repository where to put the package if not Binary or Source + package_default_path = runner.cfg.USER.workdir + + if package_type in [BINARY, SOURCE]: + # 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) + + elif package_type == PROJECT: + # check that the project is visible by SAT + if options.project not in runner.cfg.PROJECTS.project_file_paths: + site_path = os.path.join(runner.cfg.VARS.salometoolsway, + "data", + "site.pyconf") + msg = _("ERROR: the project %(proj)s is not visible by salomeTools." + "\nPlease add it in the %(site)s file." % { + "proj" : options.project, "site" : site_path}) + logger.write(src.printcolors.printcError(msg), 1) + logger.write("\n", 1) + return 1 + + # Print + src.printcolors.print_value(logger, "Package type", package_type, 2) + + # get the name of the archive or construct 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: + dir_name = package_default_path + if package_type == BINARY: + archive_name = (runner.cfg.APPLICATION.name + + "-" + + runner.cfg.VARS.dist) + + if package_type == SOURCE: + archive_name = (runner.cfg.APPLICATION.name + + "-" + + "SRC") + + if package_type == PROJECT: + project_name, __ = os.path.splitext( + os.path.basename(options.project)) + archive_name = ("PROJECT" + + "-" + + project_name) + + if package_type == SAT: + archive_name = ("salomeTools" + + "-" + + runner.cfg.INTERNAL.sat_version) + + path_targz = os.path.join(dir_name, archive_name + ".tgz") + + # Print the path of the package + 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", 3) + + msg = _("Preparation of files to add to the archive") + logger.write(src.printcolors.printcLabel(msg), 2) + logger.write("\n", 2) + + if package_type == BINARY: + d_files_to_add = binary_package(runner.cfg, + logger, + options, + tmp_working_dir) + if not(d_files_to_add): + return 1 + + if package_type == SOURCE: + d_files_to_add = source_package(runner, + runner.cfg, + logger, + options, + tmp_working_dir) + + if package_type == PROJECT: + d_files_to_add = project_package(options.project, tmp_working_dir) + + if package_type == SAT: + d_files_to_add = {"salomeTools" : (runner.cfg.VARS.salometoolsway, "")} + + logger.write("\n", 2) + + logger.write(src.printcolors.printcLabel(_("Actually do the package")), 2) + logger.write("\n", 2) + + # Creating the object tarfile + tar = tarfile.open(path_targz, mode='w:gz') + + # Add the files to the tarfile object + res = add_files(tar, archive_name, d_files_to_add, logger) + tar.close() + + # 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 \ No newline at end of file diff --git a/data/site.pyconf b/data/site.pyconf index d721713..221ccc3 100644 --- a/data/site.pyconf +++ b/data/site.pyconf @@ -13,5 +13,5 @@ SITE : PROJECTS : { -project_file_paths : ["/home/salome/SPN_PRIVATE/SAT5/SALOME-PROJECT/salome.pyconf"] +project_file_paths : ["/home/salome/SPN_PRIVATE/SAT5/SALOME-PROJECT/salome.pyconf", "/tmp/test.pyconf"] } diff --git a/src/product.py b/src/product.py index d68c883..6a674de 100644 --- a/src/product.py +++ b/src/product.py @@ -276,7 +276,7 @@ def get_install_dir(config, base, version, prod_info): if in_base: install_dir = get_base_install_dir(config, prod_info, version) else: - if "install_dir" not in prod_info: + if "install_dir" not in prod_info or prod_info.install_dir == "base": # Set it to the default value (in application directory) install_dir = os.path.join(config.APPLICATION.workdir, "INSTALL", @@ -533,6 +533,16 @@ def product_is_cmake(product_info): build_src = product_info.build_source return build_src.lower() == 'cmake' +def product_is_vcs(product_info): + '''Know if a product is download using git, svn or cvs (not archive) + + :param product_info Config: The configuration specific to + the product + :return: True if the product is vcs, else False + :rtype: boolean + ''' + return product_info.get_source in AVAILABLE_VCS + def product_has_script(product_info): '''Know if a product has a compilation script diff --git a/src/xsl/jobs_board_report.xsl b/src/xsl/jobs_board_report.xsl index 6577c5e..f0bdf30 100644 --- a/src/xsl/jobs_board_report.xsl +++ b/src/xsl/jobs_board_report.xsl @@ -132,7 +132,7 @@ - + -- 2.39.2