From 6c55499bee9cc4aa143c11da9eb12abc8cdc6816 Mon Sep 17 00:00:00 2001 From: Serge Rehbinder Date: Mon, 25 Apr 2016 15:34:29 +0200 Subject: [PATCH] Add Builder class --- commands/environ.py | 465 +------------------ data/products/PRODUCT_ARCHIVE.pyconf | 14 +- data/products/PRODUCT_GIT.pyconf | 2 +- src/__init__.py | 1 + src/compilation.py | 657 +++++++++++++++++++++++++++ src/environment.py | 458 +++++++++++++++++++ src/fileEnviron.py | 3 +- src/product.py | 25 +- 8 files changed, 1154 insertions(+), 471 deletions(-) create mode 100644 src/compilation.py diff --git a/commands/environ.py b/commands/environ.py index 981e69c..6ea7395 100644 --- a/commands/environ.py +++ b/commands/environ.py @@ -17,8 +17,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA import os -import sys -import subprocess import src @@ -36,465 +34,6 @@ parser.add_option('t', 'target', 'string', 'out_dir', C_SHELLS = { "bash": "sh", "batch": "bat" } C_ALL_SHELL = [ "bash", "batch" ] -class SalomeEnviron: - """Class to manage the environment of SALOME. - """ - - def __init__(self, cfg, environ, forBuild=False): - self.environ = environ - self.cfg = cfg - self.forBuild = forBuild - self.silent = False - - def __repr__(self): - """easy non exhaustive quick resume for debug print""" - res={} - res["environ"]=str(self.environ) - res["forBuild"]=self.forBuild - return self.__class__.__name__ + str(res)[0:-1] + " ...etc...}" - - def append(self, key, value, sep=os.pathsep): - return self.environ.append(key, value, sep) - - def prepend(self, key, value, sep=os.pathsep): - return self.environ.prepend(key, value, sep) - - def is_defined(self, key): - return self.environ.is_defined(key) - - def get(self, key): - return self.environ.get(key) - - def set(self, key, value): - # check if value needs to be evaluated - if value is not None and value.startswith("`") and value.endswith("`"): - res = subprocess.Popen("echo %s" % value, shell=True, stdout=subprocess.PIPE).communicate() - value = res[0].strip() - - return self.environ.set(key, value) - - def dump(self, out): - """Write the environment to out""" - for k in self.environ.environ.keys(): - try: - value = self.get(k) - except: - value = "?" - out.write("%s=%s\n" % (k, value)) - - def add_line(self, nb_line): - if 'add_line' in dir(self.environ): - self.environ.add_line(nb_line) - - def add_comment(self, comment): - if 'add_comment' in dir(self.environ): - self.environ.add_comment(comment) - - def add_warning(self, warning): - if 'add_warning' in dir(self.environ): - self.environ.add_warning(warning) - - def finish(self, required): - if 'finish' in dir(self.environ): - self.environ.add_line(1) - self.environ.add_comment("clean all the path") - self.environ.finish(required) - - def list_version_4_prereq(self, prerequisite, logger): - alist = [] - for path in self.cfg.TOOLS.environ.prereq_install_dir: - if not os.path.exists(path): - continue - prereqlist = os.listdir(path) - for prereq in prereqlist: - if prereq.split("-")[0] == prerequisite: - #logger.error(str(prereq) + "\n") - alist.append(str(prereq)) - - if len(alist) > 0: - logger.write(_("Available prerequisites are:") + "\n\t%s\n" % '\n\t'.join(alist), 2) - - def set_python_libdirs(self): - if src.architecture.is_windows(): - # sysconfig.get_python_lib() does not return appropriate path on Windows - # clearly decide here once for windows - ver = self.get('PYTHON_VERSION') - self.set('PYTHON_LIBDIR0', os.path.join('lib', 'python' + ver, 'site-packages')) - self.set('PYTHON_LIBDIR1', os.path.join('lib64', 'python' + ver, 'site-packages')) - - else: - """obsolete: too hazardous for WHEN we have to interpret that throught new python script salomeContext - #less "' is clearer and safer for Popen etc... - cmd = 'python -c "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.get_python_lib(plat_specific=%s, standard_lib=False, prefix=str()))"' - #False==0 ; True==1 - self.environ.command_value('PYTHON_LIBDIR0', cmd % "False") - self.environ.command_value('PYTHON_LIBDIR1', cmd % "True") - """ - #cleary decide here once for linux - ver = self.get('PYTHON_VERSION') - self.set('PYTHON_LIBDIR0', os.path.join('lib', 'python' + ver, 'site-packages')) - self.set('PYTHON_LIBDIR1', os.path.join('lib64', 'python' + ver, 'site-packages')) - - self.python_lib0 = self.get('PYTHON_LIBDIR0') - self.python_lib1 = self.get('PYTHON_LIBDIR1') - - ## - # Get the products name to add in SALOME_MODULES environment variable - # It is the name of the product, except in the case where the is a component name. - # And it has to be in SALOME_MODULES variable only if has_gui = "yes" - def getNames(self, lProducts): - lProdHasGui = [p for p in lProducts if 'has_gui' in src.product.get_product_config(self.cfg, p) and src.product.get_product_config(self.cfg, p).has_gui=='yes'] - lProdName = [] - for ProdName in lProdHasGui: - pi = src.product.get_product_config(self.cfg, ProdName) - if 'component_name' in pi: - lProdName.append(pi.component_name) - else: - lProdName.append(ProdName) - return lProdName - - ## - # Sets the environment defined in the PRODUCT file. - def set_application_env(self, logger): - if 'environ' in self.cfg.APPLICATION: - self.add_comment("APPLICATION environment") - for p in self.cfg.APPLICATION.environ: - self.set(p, self.cfg.APPLICATION.environ[p]) - self.add_line(1) - - if 'environ_script' in self.cfg.APPLICATION: - for pscript in self.cfg.APPLICATION.environ_script: - self.add_comment("script %s" % pscript) - sname = pscript.replace(" ", "_") - self.run_env_script("APPLICATION_%s" % sname, self.cfg.APPLICATION.environ_script[pscript], logger) - self.add_line(1) - - if 'profile' in self.cfg.APPLICATION: - profile_product = self.cfg.APPLICATION.profile.product - product_info_profile = src.product.get_product_config(self.cfg, profile_product) - profile_share_salome = os.path.join( product_info_profile.install_dir, "share", "salome" ) - self.set( "SUITRoot", profile_share_salome ) - self.set( "SalomeAppConfig", os.path.join( profile_share_salome, "resources", profile_product.lower() ) ) - - # The list of products to launch - lProductsName = self.getNames(self.cfg.APPLICATION.products.keys()) - - self.set( "SALOME_MODULES", ','.join(lProductsName)) - - ## - # Set xxx_ROOT_DIR and xxx_SRC_DIR. - def set_salome_minimal_product_env(self, product_info, logger, single_dir, cfgdic=None): - # set root dir - root_dir = product_info.name + "_ROOT_DIR" - indic = cfgdic is not None and root_dir in cfgdic - if not self.is_defined(root_dir) and not indic: - if single_dir: - self.set(root_dir, os.path.join(self.get('INSTALL_ROOT'), 'SALOME')) - elif 'install_dir' in product_info and product_info.install_dir: - self.set(root_dir, product_info.install_dir) - elif not self.silent: - logger.write(" " + _("No install_dir for product %s\n") % product_info.name, 5) - - # set source dir, unless the product is fixed (no source dir) - if not src.product.product_is_fixed(product_info): - src_dir = product_info.name + "_SRC_DIR" - indic = cfgdic is not None and src_dir in cfgdic - if not self.is_defined(src_dir) and not indic: - self.set(src_dir, product_info.source_dir) - - def set_salome_generic_product_env(self, product): - pi = src.product.get_product_config(self.cfg, product) - env_root_dir = self.get(pi.name + "_ROOT_DIR") - l_binpath_libpath = [] - - # create additional ROOT_DIR for CPP components - if 'component_name' in pi: - compo_name = pi.component_name - if compo_name + "CPP" == product: - compo_root_dir = compo_name + "_ROOT_DIR" - envcompo_root_dir = os.path.join( self.cfg.TOOLS.common.install_root, compo_name ) - self.set(compo_root_dir , envcompo_root_dir) - bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome') - lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome') - l_binpath_libpath.append( (bin_path, lib_path) ) - - appliname = 'salome' - if src.get_cfg_param(pi, 'product_type', 'SALOME').upper() not in [ "SALOME", "SMESH_PLUGIN", "SAMPLE" ]: - appliname = '' - - bin_path = os.path.join(env_root_dir, 'bin', appliname) - lib_path = os.path.join(env_root_dir, 'lib', appliname) - l_binpath_libpath.append( (bin_path, lib_path) ) - - for bin_path, lib_path in l_binpath_libpath: - if not self.forBuild: - self.prepend('PATH', bin_path) - if src.architecture.is_windows(): - self.prepend('PATH', lib_path) - else : - self.prepend('LD_LIBRARY_PATH', lib_path) - - l = [ bin_path, lib_path, - os.path.join(env_root_dir, self.python_lib0, appliname), - os.path.join(env_root_dir, self.python_lib1, appliname) - ] - self.prepend('PYTHONPATH', l) - - ## - # Loads environment define in the configuration. - def load_cfg_environment(self, cfg_env): - for env_def in cfg_env: - val = cfg_env[env_def] - if isinstance(val, src.pyconf.Mapping): - continue - - if isinstance(val, src.pyconf.Sequence): - # transform into list of strings - val = map(lambda l: l, val) - - if env_def.startswith("_"): - # separator exception for PV_PLUGIN_PATH - if env_def[1:] == 'PV_PLUGIN_PATH': - self.prepend(env_def[1:], val, ';') - else: - self.prepend(env_def[1:], val) - elif env_def.endswith("_"): - # separator exception for PV_PLUGIN_PATH - if env_def[:-1] == 'PV_PLUGIN_PATH': - self.prepend(env_def[:-1], val, ';') - else: - self.prepend(env_def[:-1], val) - else: - self.set(env_def, val) - - ## - # Sets the environment of a product. - def set_a_product(self, product, logger, single_dir): - - if not self.silent: - logger.write(_("Setting environment for %s\n") % product, 4) - - self.add_line(1) - self.add_comment('setting environ for ' + product) - - pi = src.product.get_product_config(self.cfg, product) - - # Do not define environment if the product is native or fixed - if src.product.product_is_native(pi): - return - - if "environ" in pi: - # set environment using definition of the product - self.set_salome_minimal_product_env(pi, logger, single_dir, pi.environ) - self.set_salome_generic_product_env(product) - self.load_cfg_environment(pi.environ) - if self.forBuild and "build" in pi.environ: - self.load_cfg_environment(pi.environ.build) - if not self.forBuild and "launch" in pi.environ: - self.load_cfg_environment(pi.environ.launch) - else: - # no environment defined in config - self.set_salome_minimal_product_env(pi, logger, single_dir) - if 'install_dir' in pi : - self.set_salome_generic_product_env(product) - - # if product_info defines a env_scripts load it - if 'env_script' in pi: - self.run_env_script(product, pi.env_script, logger) - - - ## - # Runs an environment script. - def run_env_script(self, product, env_script, logger=None): - if not os.path.exists(env_script): - raise src.SatException(_("Environment script not found: %s") % env_script) - - if not self.silent and logger is not None: - logger.write(" ** load %s\n" % env_script, 4) - - try: - import imp - pyproduct = imp.load_source(product + "_env_script", env_script) - pyproduct.load_env(self) - except: - __, exceptionValue, exceptionTraceback = sys.exc_info() - print(exceptionValue) - import traceback - traceback.print_tb(exceptionTraceback) - traceback.print_exc() - - ## - # Sets the environment for all the products. - def set_products(self, logger, src_root=None, single_dir=False): - self.add_line(1) - self.add_comment('setting environ for all products') - - self.set_python_libdirs() - - if src_root is None: - src_root = self.cfg.APPLICATION.workdir - self.set('SRC_ROOT', src_root) - - appli_name = "APPLI" - if "APPLI" in self.cfg and "application_name" in self.cfg.APPLI: - appli_name = self.cfg.APPLI.application_name - self.set("SALOME_APPLI_ROOT", os.path.join(self.cfg.APPLICATION.workdir, appli_name)) - - if not single_dir: - single_dir = src.get_cfg_param(self.cfg.APPLICATION, "compil_in_single_dir", "no") == 'yes' - - for product in src.get_cfg_param(self.cfg.APPLICATION, "imported_products", []): - self.set_a_product(product, logger, single_dir=single_dir) - self.finish(False) - - for product in self.cfg.APPLICATION.products.keys(): - self.set_a_product(product, logger, single_dir=single_dir) - self.finish(False) - - - ## - # Sets the full environment for prerequisites and products specified in env_info dictionary. - def set_full_environ(self, logger, env_info): - # set product environ - self.set_application_env(logger) - - # set products - self.set('INSTALL_ROOT', self.cfg.TOOLS.common.install_root) - self.set('SRC_ROOT', self.cfg.TOOLS.common.source_root) - self.set_python_libdirs() - - single_dir = src.get_cfg_param(self.cfg.PRODUCT, "compil_in_single_dir", "no") == 'yes' - for product in env_info['products']: - self.set_a_product(product, logger, single_dir=single_dir) - -## -# Class to dump the environment to a file. -class FileEnvWriter: - def __init__(self, config, logger, out_dir, src_root, single_dir, env_info=None): - self.config = config - self.logger = logger - self.out_dir = out_dir - self.src_root= src_root - self.single_dir = single_dir - self.silent = True - self.env_info = env_info - - def write_env_file(self, filename, forBuild, shell): - """Create an environment file.""" - if not self.silent: - self.logger.write(_("Create environment file %s\n") % src.printcolors.printcLabel(filename), 3) - - # create then env object - env_file = open(os.path.join(self.out_dir, filename), "w") - tmp = src.fileEnviron.get_file_environ(env_file, shell, {}, self.config ) - env = SalomeEnviron(self.config, tmp, forBuild) - env.silent = self.silent - - if self.env_info is not None: - env.set_full_environ(self.logger, self.env_info) - else: - # set env from PRODUCT - env.set_application_env(self.logger) - # set the products - env.set_products(self.logger, - src_root=self.src_root, single_dir=self.single_dir) - - # add cleanup and close - env.finish(True) - env_file.close() - - return env_file.name - - def write_product_file(self, filename, shell): - """Create a product file.""" - if not self.silent: - self.logger.write(_("Create product file %s\n") % src.printcolors.printcLabel(filename), 3) - - prod_file = open(os.path.join(self.out_dir, filename), "w") - if shell == "bash": - content = _bash_content % self.out_dir - elif shell == "batch": - content = _batch_content % self.out_dir - else: - raise src.SatException(_("Unknown shell: %s") % shell) - - prod_file.write(content) - prod_file.close() - - return prod_file.name - - def write_cfgForPy_file(self, aFile, additional_env = {}): - """append to current opened aFile a cfgForPy environment (python syntax).""" - if not self.silent: - self.logger.write(_("Create configuration file %s\n") % src.printcolors.printcLabel(aFile.name), 3) - - # create then env object - tmp = src.fileEnviron.get_file_environ(aFile, "cfgForPy", {}, self.config) - forBuild = True - forLaunch = False - env = SalomeEnviron(self.config, tmp, forLaunch) - env.silent = self.silent - - if self.env_info is not None: - env.set_full_environ(self.logger, self.env_info) - else: - # set env from PRODUCT - env.set_application_env(self.logger) - # set the prerequisites - env.set_prerequisites(self.logger) - # set the products - env.set_products(self.logger, - src_root=self.src_root, single_dir=self.single_dir) - - if len(additional_env) != 0: - for variable in additional_env: - env.set(variable, additional_env[variable]) - - # add cleanup and close - env.finish(True) - - -# create bash product file -_bash_content = """PRODUCT_DIR=%s -if [[ "${ENV_FOR_LAUNCH}x" == "x" ]] -then - export ENV_FOR_LAUNCH=1 -fi - -if [[ "${ENV_FOR_LAUNCH}" == "1" ]] -then - source $PRODUCT_DIR/env_launch.sh -else - source $PRODUCT_DIR/env_build.sh -fi -""" - -# create batch product file -_batch_content = """set PRODUCT_DIR=%s -IF NOT DEFINED ENV_FOR_LAUNCH set ENV_FOR_LAUNCH=1 - -if "%%ENV_FOR_LAUNCH%%"=="1" ( - %%PRODUCT_DIR%%\\env_launch.bat -) else ( - %%PRODUCT_DIR%%\\env_build.bat -) -""" - -## -# Definition of a Shell. -class Shell: - def __init__(self, name, extension): - self.name = name - self.extension = extension - -## -# Loads the environment (used to run the tests). -def load_environment(config, build, logger): - environ = SalomeEnviron(config, src.environment.Environ(os.environ), build) - environ.set_application_env(logger) - environ.set_prerequisites(logger) - environ.set_products(logger) - environ.finish(True) ## # Writes all the environment files @@ -522,9 +61,9 @@ def write_all_source_files(config, logger, out_dir=None, src_root=None, if shell not in C_SHELLS: logger.write(_("Unknown shell: %s\n") % shell, 2) else: - shells_list.append(Shell(shell, C_SHELLS[shell])) + shells_list.append(src.environment.Shell(shell, C_SHELLS[shell])) - writer = FileEnvWriter(config, logger, out_dir, src_root, single_dir, env_info) + writer = src.environment.FileEnvWriter(config, logger, out_dir, src_root, single_dir, env_info) writer.silent = silent files = [] for_build = True diff --git a/data/products/PRODUCT_ARCHIVE.pyconf b/data/products/PRODUCT_ARCHIVE.pyconf index bbda9f1..cb3ff80 100644 --- a/data/products/PRODUCT_ARCHIVE.pyconf +++ b/data/products/PRODUCT_ARCHIVE.pyconf @@ -33,17 +33,21 @@ PRODUCT_ARCHIVE_4_4_2 : } environ : { - "_LD_LIBRARY_PATH" : "${SOFT_ROOT_DIR}" + $VARS.sep + "lib" - "_PYTHONPATH" : ["${SOFT_ROOT_DIR}" + $VARS.sep + "lib" - "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR0}" - "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR1}"] + build: + { + "_LD_LIBRARY_PATH" : "COUCOU" + "_PYTHONPATH" : ["${SOFT_ROOT_DIR}" + $VARS.sep + "lib" + "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR0}" + "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR1}"] + } } + env_script : "/home/sr755891/SAT-ETENDU/00-DEV/RESOURCES/env_scripts/pytz.py" present_files : { source : ['my_test_file.txt', 'my_test_file.txt~'] install : ['', '', ''] } - depend : [] + depend : ['PRODUCT_NATIVE', 'PRODUCT_CVS'] opt_depend : [] type : "sample" source_dir : $APPLICATION.workdir + $VARS.sep + 'SOURCES' + $VARS.sep + $name diff --git a/data/products/PRODUCT_GIT.pyconf b/data/products/PRODUCT_GIT.pyconf index 34dbdc2..7613791 100644 --- a/data/products/PRODUCT_GIT.pyconf +++ b/data/products/PRODUCT_GIT.pyconf @@ -15,7 +15,7 @@ PRODUCT_GIT : "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR0}" "${SOFT_ROOT_DIR}" + $VARS.sep + "${PYTHON_LIBDIR1}"] } - depend : [] + depend : [PRODUCT_ARCHIVE, PRODUCT_NATIVE] opt_depend : [] type : "sample" source_dir : $APPLICATION.workdir + $VARS.sep + 'SOURCES' + $VARS.sep + $name diff --git a/src/__init__.py b/src/__init__.py index 04a0928..0b61594 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -31,6 +31,7 @@ from . import logger from . import product from . import environment from . import fileEnviron +from . import compilation OK_STATUS = "OK" KO_STATUS = "KO" diff --git a/src/compilation.py b/src/compilation.py new file mode 100644 index 0000000..f774861 --- /dev/null +++ b/src/compilation.py @@ -0,0 +1,657 @@ +#!/usr/bin/env python +#-*- coding:utf-8 -*- +# Copyright (C) 2010-2013 CEA/DEN +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import os +import subprocess +import sys + +import src + +C_COMPILE_ENV_LIST = ["CC", + "CXX", + "F77", + "CFLAGS", + "CXXFLAGS", + "LIBS", + "LDFLAGS"] + +class CompilationResult: + def __init__(self): + self.prepare = False + self.buildconfigure = False + self.configure = False + self.cmake = False + self.make = False + self.install = False + self.check = False + self.check_tried = False + self.ignored = False + self.reason = "" + + def isOK(self): + if self.ignored: + return False + + return self.prepare \ + and self.buildconfigure \ + and self.configure \ + and self.cmake \ + and self.make \ + and self.install \ + and self.check + + def setAllFail(self): + self.prepare = False + self.buildconfigure = False + self.configure = False + self.cmake = False + self.make = False + self.install = False + self.check = False + + def setIgnored(self, reason=None): + self.ignored = True + if reason: + self.reason = reason + else: + self.reason = _("ignored") + + def getErrorText(self): + if self.ignored or len(self.reason): + return self.reason + + if not self.prepare: return "PREPARE BUILD" + if not self.buildconfigure: return "BUILD CONFIGURE" + if not self.configure: return "CONFIGURE" + if not self.cmake: return "CMAKE" + if not self.make: return "MAKE" + if not self.install: return "INSTALL" + if not self.check: return "CHECK" + + return "" + +class Builder: + """Class to handle all construction steps, like cmake, configure, make, ... + """ + def __init__(self, config, logger, options, product_info, debug_mode=False, check_src=True): + self.config = config + self.logger = logger + self.options = options + self.product_info = product_info + self.build_dir = src.Path(self.product_info.build_dir) + self.source_dir = src.Path(self.product_info.source_dir) + self.source_dir = src.Path(self.product_info.install_dir) + self.header = "" + self.debug_mode = debug_mode + + if not self.source_dir.exists() and check_src: + raise src.SatException(_("No sources found for product %(product)s in %(source_dir)s" % \ + { "product": self.product, "source_dir": self.source_dir } )) + + # check that required modules exist + for dep in self.product_info.depend: + assert dep in self.config.TOOLS.src.product_info, "UNDEFINED product: %s" % dep + dep_info = self.config.TOOLS.src.product_info[dep] + if 'install_dir' in dep_info and not os.path.exists(dep_info.install_dir): + raise src.SatException(_("Module %s is required") % dep) + + self.results = CompilationResult() + + ## + # Shortcut method to log in both log files. + def log(self, text, level, showInfo=True): + self.logger.write(text, level, showInfo) + self.logger.logTxtFile.write(src.printcolors.cleancolor(text)) + + ## + # Shortcut method to log a command. + def log_command(self, command): + self.log("> %s\n" % command, 5) + + def log_result(self, res): + if res == 0: + self.logger.write("%s\n" % src.printcolors.printc(src.OK_STATUS), 5) + else: + self.logger.write("%s, code = %s\n" % (src.printcolors.printc(src.KO_STATUS), res), 5) + + ## + # Logs a compilation step (configure, make ...) + def log_step(self, step): + if self.config.USER.output_level == 3: + self.logger.write("\r%s%s" % (self.header, " " * 20), 3) + self.logger.write("\r%s%s" % (self.header, step), 3) + self.log("==== %s \n" % src.printcolors.printcInfo(step), 4) + self.logger.flush() + + ## + # Prepares the environment for windows. + # Build two environment: one for building and one for testing (launch). + def wprepare(self): + self.log_step('PREPARE BUILD') + + if not self.build_dir.exists(): + # create build dir + self.build_dir.make() + elif self.options.clean_all: + self.log(' %s\n' % src.printcolors.printcWarning("CLEAN ALL"), 4) + # clean build dir if clean_all option given + self.log(' clean previous build = %s\n' % str(self.build_dir), 4) + self.build_dir.rm() + self.build_dir.make() + + if self.options.clean_all or self.options.clean_install: + if os.path.exists(str(self.install_dir)) and not self.single_dir: + self.log(' clean previous install = %s\n' % str(self.install_dir), 4) + self.install_dir.rm() + + self.log(' build_dir = %s\n' % str(self.build_dir), 4) + self.log(' install_dir = %s\n' % str(self.install_dir), 4) + self.log('\n', 4) + + environ_info = {} + + # add products in depend and opt_depend list recursively + environ_info['products'] = src.product.get_product_dependencies(self.config, self.product_info) + + # create build environment + self.build_environ = src.environment.SalomeEnviron(self.config, src.environment.Environ(dict(os.environ)), True) + self.build_environ.silent = (self.config.USER.output_level < 5) + self.build_environ.set_full_environ(self.logger, environ_info) + + # create runtime environment + self.launch_environ = src.environment.SalomeEnviron(self.config, src.environment.Environ(dict(os.environ)), False) + self.launch_environ.silent = True # no need to show here + self.launch_environ.set_full_environ(self.logger, environ_info) + + for ee in C_COMPILE_ENV_LIST: + vv = self.build_environ.get(ee) + if len(vv) > 0: + self.log(" %s = %s\n" % (ee, vv), 4, False) + + self.results.prepare = True + self.log_result(0) + return self.results.prepare + + ## + # Prepares the environment. + # Build two environment: one for building and one for testing (launch). + def prepare(self): + self.log_step('PREPARE BUILD') + + if not self.build_dir.exists(): + # create build dir + self.build_dir.make() + elif self.options.clean_all: + self.log(' %s\n' % src.printcolors.printcWarning("CLEAN ALL"), 4) + # clean build dir if clean_all option given + self.log(' clean previous build = %s\n' % str(self.build_dir), 4) + self.build_dir.rm() + self.build_dir.make() + + if self.options.clean_all or self.options.clean_install: + if os.path.exists(str(self.install_dir)) and not self.single_dir: + self.log(' clean previous install = %s\n' % str(self.install_dir), 4) + self.install_dir.rm() + + self.log(' build_dir = %s\n' % str(self.build_dir), 4) + self.log(' install_dir = %s\n' % str(self.install_dir), 4) + self.log('\n', 4) + + # set the environment + environ_info = {} + + # add products in depend and opt_depend list recursively + environ_info['products'] = src.product.get_product_dependencies(self.config, self.product_info) + + # create build environment + self.build_environ = src.environment.SalomeEnviron(self.config, src.environment.Environ(dict(os.environ)), True) + self.build_environ.silent = (self.config.USER.output_level < 5) + self.build_environ.set_full_environ(self.logger, environ_info) + + # create runtime environment + self.launch_environ = src.environment.SalomeEnviron(self.config, src.environment.Environ(dict(os.environ)), False) + self.launch_environ.silent = True # no need to show here + self.launch_environ.set_full_environ(self.logger, environ_info) + + for ee in C_COMPILE_ENV_LIST: + vv = self.build_environ.get(ee) + if len(vv) > 0: + self.log(" %s = %s\n" % (ee, vv), 4, False) + + self.results.prepare = True + self.log_result(0) + return self.results.prepare + + ## + # Runs cmake with the given options. + def cmake(self, options=""): + self.log_step('CMAKE') + + # cmake so no (build)configure + self.results.configure = True + + cmake_option = options + cmake_option +=' -DCMAKE_VERBOSE_MAKEFILE=ON -DSALOME_CMAKE_DEBUG=ON' + if 'cmake_options' in self.product_info: + cmake_option += " %s " % " ".join(self.product_info.cmake_options.split()) + + # add debug option + if self.debug_mode: + cmake_option += " -DCMAKE_BUILD_TYPE=Debug" + else : + cmake_option += " -DCMAKE_BUILD_TYPE=Release" + + # In case CMAKE_GENERATOR is defined in environment, use it in spite of automatically detect it + if 'cmake_generator' in self.config.APPLICATION: + cmake_option += ' -DCMAKE_GENERATOR=%s' % self.config.PRODUCT.cmake_generator + + command = "cmake %s -DCMAKE_INSTALL_PREFIX=%s %s" %(cmake_option, self.install_dir, self.source_dir) + + self.log_command(command) + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.results.cmake = (res == 0) + self.log_result(res) + return self.results.cmake + + ## + # Runs build_configure with the given options. + def build_configure(self, options=""): + skip = src.get_cfg_param(self.product_info, "build_configure", False) + if skip: + self.results.buildconfigure = True + res = 0 + else: + self.log_step('BUILD CONFIGURE') + + self.results.buildconfigure = False + + if 'buildconfigure_options' in self.product_info: + options += " %s " % self.product_info.buildconfigure_options + + command = str('./build_configure') + command = command + " " + options + self.log_command(command) + + res = subprocess.call(command, + shell=True, + cwd=str(self.source_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + self.results.buildconfigure = (res == 0) + + self.log_result(res) + return self.results.buildconfigure + + ## + # Runs configure with the given options. + def configure(self, options=""): + self.log_step('CONFIGURE') + + # configure so no cmake + self.results.cmake = True + + if 'configure_options' in self.product_info: + options += " %s " % self.product_info.configure_options + + command = "%s/configure --prefix=%s" % (self.source_dir, str(self.install_dir)) + + command = command + " " + options + self.log_command(command) + + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.log_result(res) + self.results.configure = (res == 0) + return self.results.configure + + def hack_libtool(self): + if not os.path.exists(str(self.build_dir + 'libtool')): + return + + lf = open(os.path.join(str(self.build_dir), "libtool"), 'r') + for line in lf.readlines(): + if 'hack_libtool' in line: + return + + # fix libtool by replacing CC="" with hack_libtool function + hack_command='''sed -i "s%^CC=\\"\(.*\)\\"%hack_libtool() { \\n\\ +if test \\"\$(echo \$@ | grep -E '\\\\\\-L/usr/lib(/../lib)?(64)? ')\\" == \\\"\\\" \\n\\ + then\\n\\ + cmd=\\"\\1 \$@\\"\\n\\ + else\\n\\ + cmd=\\"\\1 \\"\`echo \$@ | sed -r -e 's|(.*)-L/usr/lib(/../lib)?(64)? (.*)|\\\\\\1\\\\\\4 -L/usr/lib\\\\\\3|g'\`\\n\\ + fi\\n\\ + \$cmd\\n\\ +}\\n\\ +CC=\\"hack_libtool\\"%g" libtool''' + + self.log_command(hack_command) + subprocess.call(hack_command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + def get_nb_proc(self): + nbproc = -1 + if "nb_proc" in self.product_info: + # nb proc is specified in module definition + nbproc = self.product_info.nb_proc + if self.options.nb_proc and self.options.nb_proc < self.product_info.nb_proc: + # use command line value only if it is lower than module definition + nbproc = self.options.nb_proc + else: + # nb proc is not specified in module definition + if self.options.nb_proc: + nbproc = self.options.nb_proc + else: + nbproc = self.config.VARS.nb_proc + + assert nbproc > 0 + return nbproc + + ## + # Runs make to build the module. + def make(self): + nbproc = self.get_nb_proc() + + hh = 'MAKE -j%s' % str(nbproc) + if self.debug_mode: + hh += " " + src.printcolors.printcWarning("DEBUG") + self.log_step(hh) + + # make + command = 'make' + if self.options.makeflags: + command = command + " " + self.options.makeflags + command = command + " -j" + str(nbproc) + + self.log_command(command) + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.results.make = (res == 0) + self.log_result(res) + return self.results.make + + ## + # Runs msbuild to build the module. + def wmake(self): + nbproc = self.get_nb_proc() + + hh = 'MSBUILD /m:%s' % str(nbproc) + if self.debug_mode: + hh += " " + src.printcolors.printcWarning("DEBUG") + self.log_step(hh) + + # make + command = 'msbuild' + if self.options.makeflags: + command = command + " " + self.options.makeflags + command = command + " /maxcpucount:" + str(nbproc) + if self.debug_mode: + command = command + " /p:Configuration=Debug" + else: + command = command + " /p:Configuration=Release" + command = command + " ALL_BUILD.vcxproj" + + self.log_command(command) + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.results.make = (res == 0) + self.log_result(res) + return self.results.make + + ## + # Runs 'make install'. + def install(self): + self.log_step('INSTALL') + if self.config.VARS.dist_name=="Win": + command = 'msbuild INSTALL.vcxproj' + if self.debug_mode: + command = command + " /p:Configuration=Debug" + else: + command = command + " /p:Configuration=Release" + else : + command = 'make install' + + self.log_command(command) + + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.build_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.results.install = (res == 0) + self.log_result(res) + return self.results.install + + ## + # Runs 'make_check'. + def check(self): + self.log_step('CHECK') + if src.architecture.is_windows(): + command = 'msbuild RUN_TESTS.vcxproj' + else : + if self.use_autotools : + command = 'make check' + else : + command = 'make test' + + self.log_command(command) + + self.results.check_tried = True + res = subprocess.call(command, + shell=True, + cwd=str(self.build_dir), + env=self.launch_environ.environ.environ, + stdout=self.logger.logTxtFile, + stderr=subprocess.STDOUT) + + self.results.check = (res == 0) + self.log_result(res) + return self.results.check + + ## + # Cleans the build. + def clean(self): + self.log_step('CLEAN') + + if src.get_cfg_param(self.config.PRODUCT, 'clean_build_dir', 'no') == "yes": + if self.results.buildconfigure and self.results.configure \ + and self.results.make and self.results.install and self.results.check: + self.log(_('Clean BUILD directory\n'), 4) + self.build_dir.rm() + else: + self.log(_('No clean: some error during compilation\n'), 5) + else: + self.log(_('No clean: not specified in the config\n'), 5) + + def get_result(self): + return self.results + + ## + # Performs a default build for this module. + def do_default_build(self, build_conf_options="", configure_options="", show_warning=True): + use_autotools = False + if 'use_autotools' in self.product_info: + uc = self.product_info.use_autotools + if uc in ['always', 'yes']: + use_autotools = True + elif uc == 'option': + use_autotools = self.options.autotools + + + self.use_autotools = use_autotools + + use_ctest = False + if 'use_ctest' in self.product_info: + uc = self.product_info.use_ctest + if uc in ['always', 'yes']: + use_ctest = True + elif uc == 'option': + use_ctest = self.options.ctest + + self.use_ctest = use_ctest + + if show_warning: + cmd = "" + if use_autotools: cmd = "(autotools)" + if use_ctest: cmd = "(ctest)" + + self.log("\n", 4, False) + self.log("%(module)s: Run default compilation method %(cmd)s\n" % \ + { "module": self.module, "cmd": cmd }, 4) + + if use_autotools: + if not self.prepare(): return self.get_result() + if not self.build_configure(build_conf_options): return self.get_result() + if not self.configure(configure_options): return self.get_result() + if not self.make(): return self.get_result() + if not self.install(): return self.get_result() + self.results.check = True + if not self.clean(): return self.get_result() + + else: # CMake + if self.config.VARS.dist_name=='Win': + if not self.wprepare(): return self.get_result() + self.results.buildconfigure = True + if not self.cmake(): return self.get_result() + self.results.ctest = True + if not self.wmake(): return self.get_result() + if not self.install(): return self.get_result() + self.results.check = True + if not self.clean(): return self.get_result() + else : + if not self.prepare(): return self.get_result() + self.results.buildconfigure = True + if not self.cmake(): return self.get_result() + self.results.ctest = True + if not self.make(): return self.get_result() + if not self.install(): return self.get_result() + self.results.check = True + if not self.clean(): return self.get_result() + + return self.get_result() + + ## + # Performs a build with a script. + def do_script_build(self, script): + retcode = CompilationResult() + retcode.setAllFail() + # script found + self.logger.write(_("Compile %(module)s using script %(script)s\n") % \ + { 'module': self.module, 'script': src.printcolors.printcLabel(script) }, 4) + try: + import imp + pymodule = imp.load_source(self.module + "_compile_script", script) + retcode = pymodule.compil(self.config, self, self.logger) + except: + __, exceptionValue, exceptionTraceback = sys.exc_info() + print(exceptionValue) + import traceback + traceback.print_tb(exceptionTraceback) + traceback.print_exc() + + return retcode + + ## + # Builds the module. + # If a script is specified used it, else use 'default' method. + def run_compile(self, no_compile=False): + retcode = CompilationResult() + retcode.setAllFail() + + if no_compile: + if os.path.exists(str(self.install_dir)): + retcode.setIgnored(_("already installed")) + else: + retcode.setIgnored(src.printcolors.printcError(_("NOT INSTALLED"))) + + self.log_file.close() + os.remove(os.path.realpath(self.log_file.name)) + return retcode + + # check if the module is already installed + if not self.single_dir and os.path.exists(str(self.install_dir)) \ + and not self.options.clean_all and not self.options.clean_install: + + retcode.setIgnored(_("already installed")) + self.log_file.close() + os.remove(os.path.realpath(self.log_file.name)) + return retcode + + if 'compile_method' in self.product_info: + if self.product_info.compile_method == "copy": + self.prepare() + retcode.prepare = self.results.prepare + retcode.buildconfigure = True + retcode.configure = True + retcode.make = True + retcode.cmake = True + retcode.ctest = True + + if not self.source_dir.smartcopy(self.install_dir): + raise src.SatException(_("Error when copying %s sources to install dir") % self.module) + retcode.install = True + retcode.check = True + + elif self.product_info.compile_method == "default": + retcode = self.do_default_build(show_warning=False) + + + elif os.path.isfile(self.product_info.compile_method): + retcode = self.do_script_build(self.product_info.compile_method) + + else: + raise src.SatException(_("Unknown compile_method: %s") % self.product_info.compile_method) + + else: + script = os.path.join(self.config.VARS.dataDir, 'compil_scripts', 'modules', self.module + '.py') + + if not os.path.exists(script): + # no script use default method + retcode = self.do_default_build(show_warning=False) + else: + retcode = self.do_script_build(script) + + return retcode diff --git a/src/environment.py b/src/environment.py index 95f7b3c..935f957 100644 --- a/src/environment.py +++ b/src/environment.py @@ -19,9 +19,36 @@ import os import subprocess import string +import sys import src +# create bash product file +_bash_content = """PRODUCT_DIR=%s +if [[ "${ENV_FOR_LAUNCH}x" == "x" ]] +then + export ENV_FOR_LAUNCH=1 +fi + +if [[ "${ENV_FOR_LAUNCH}" == "1" ]] +then + source $PRODUCT_DIR/env_launch.sh +else + source $PRODUCT_DIR/env_build.sh +fi +""" + +# create batch product file +_batch_content = """set PRODUCT_DIR=%s +IF NOT DEFINED ENV_FOR_LAUNCH set ENV_FOR_LAUNCH=1 + +if "%%ENV_FOR_LAUNCH%%"=="1" ( + %%PRODUCT_DIR%%\\env_launch.bat +) else ( + %%PRODUCT_DIR%%\\env_build.bat +) +""" + class Environ: '''Class to manage the environment context ''' @@ -160,3 +187,434 @@ class Environ: stdout=subprocess.PIPE, env=self.environ).communicate()[0] self.environ[key] = value + + +class SalomeEnviron: + """Class to manage the environment of SALOME. + """ + + def __init__(self, cfg, environ, forBuild=False): + self.environ = environ + self.cfg = cfg + self.forBuild = forBuild + self.silent = False + + def __repr__(self): + """easy non exhaustive quick resume for debug print""" + res={} + res["environ"]=str(self.environ) + res["forBuild"]=self.forBuild + return self.__class__.__name__ + str(res)[0:-1] + " ...etc...}" + + def append(self, key, value, sep=os.pathsep): + return self.environ.append(key, value, sep) + + def prepend(self, key, value, sep=os.pathsep): + return self.environ.prepend(key, value, sep) + + def is_defined(self, key): + return self.environ.is_defined(key) + + def get(self, key): + return self.environ.get(key) + + def set(self, key, value): + # check if value needs to be evaluated + if value is not None and value.startswith("`") and value.endswith("`"): + res = subprocess.Popen("echo %s" % value, shell=True, stdout=subprocess.PIPE).communicate() + value = res[0].strip() + + return self.environ.set(key, value) + + def dump(self, out): + """Write the environment to out""" + for k in self.environ.environ.keys(): + try: + value = self.get(k) + except: + value = "?" + out.write("%s=%s\n" % (k, value)) + + def add_line(self, nb_line): + if 'add_line' in dir(self.environ): + self.environ.add_line(nb_line) + + def add_comment(self, comment): + if 'add_comment' in dir(self.environ): + self.environ.add_comment(comment) + + def add_warning(self, warning): + if 'add_warning' in dir(self.environ): + self.environ.add_warning(warning) + + def finish(self, required): + if 'finish' in dir(self.environ): + self.environ.add_line(1) + self.environ.add_comment("clean all the path") + self.environ.finish(required) + + def list_version_4_prereq(self, prerequisite, logger): + alist = [] + for path in self.cfg.TOOLS.environ.prereq_install_dir: + if not os.path.exists(path): + continue + prereqlist = os.listdir(path) + for prereq in prereqlist: + if prereq.split("-")[0] == prerequisite: + #logger.error(str(prereq) + "\n") + alist.append(str(prereq)) + + if len(alist) > 0: + logger.write(_("Available prerequisites are:") + "\n\t%s\n" % '\n\t'.join(alist), 2) + + def set_python_libdirs(self): + if src.architecture.is_windows(): + # sysconfig.get_python_lib() does not return appropriate path on Windows + # clearly decide here once for windows + ver = self.get('PYTHON_VERSION') + self.set('PYTHON_LIBDIR0', os.path.join('lib', 'python' + ver, 'site-packages')) + self.set('PYTHON_LIBDIR1', os.path.join('lib64', 'python' + ver, 'site-packages')) + + else: + ver = self.get('PYTHON_VERSION') + self.set('PYTHON_LIBDIR0', os.path.join('lib', 'python' + ver, 'site-packages')) + self.set('PYTHON_LIBDIR1', os.path.join('lib64', 'python' + ver, 'site-packages')) + + self.python_lib0 = self.get('PYTHON_LIBDIR0') + self.python_lib1 = self.get('PYTHON_LIBDIR1') + + ## + # Get the products name to add in SALOME_MODULES environment variable + # It is the name of the product, except in the case where the is a component name. + # And it has to be in SALOME_MODULES variable only if has_gui = "yes" + def getNames(self, lProducts): + lProdHasGui = [p for p in lProducts if 'has_gui' in src.product.get_product_config(self.cfg, p) and src.product.get_product_config(self.cfg, p).has_gui=='yes'] + lProdName = [] + for ProdName in lProdHasGui: + pi = src.product.get_product_config(self.cfg, ProdName) + if 'component_name' in pi: + lProdName.append(pi.component_name) + else: + lProdName.append(ProdName) + return lProdName + + ## + # Sets the environment defined in the PRODUCT file. + def set_application_env(self, logger): + if 'environ' in self.cfg.APPLICATION: + self.add_comment("APPLICATION environment") + for p in self.cfg.APPLICATION.environ: + self.set(p, self.cfg.APPLICATION.environ[p]) + self.add_line(1) + + if 'environ_script' in self.cfg.APPLICATION: + for pscript in self.cfg.APPLICATION.environ_script: + self.add_comment("script %s" % pscript) + sname = pscript.replace(" ", "_") + self.run_env_script("APPLICATION_%s" % sname, self.cfg.APPLICATION.environ_script[pscript], logger) + self.add_line(1) + + if 'profile' in self.cfg.APPLICATION: + profile_product = self.cfg.APPLICATION.profile.product + product_info_profile = src.product.get_product_config(self.cfg, profile_product) + profile_share_salome = os.path.join( product_info_profile.install_dir, "share", "salome" ) + self.set( "SUITRoot", profile_share_salome ) + self.set( "SalomeAppConfig", os.path.join( profile_share_salome, "resources", profile_product.lower() ) ) + + # The list of products to launch + lProductsName = self.getNames(self.cfg.APPLICATION.products.keys()) + + self.set( "SALOME_MODULES", ','.join(lProductsName)) + + ## + # Set xxx_ROOT_DIR and xxx_SRC_DIR. + def set_salome_minimal_product_env(self, product_info, logger, single_dir, cfgdic=None): + # set root dir + root_dir = product_info.name + "_ROOT_DIR" + indic = cfgdic is not None and root_dir in cfgdic + if not self.is_defined(root_dir) and not indic: + if single_dir: + self.set(root_dir, os.path.join(self.get('INSTALL_ROOT'), 'SALOME')) + elif 'install_dir' in product_info and product_info.install_dir: + self.set(root_dir, product_info.install_dir) + elif not self.silent: + logger.write(" " + _("No install_dir for product %s\n") % product_info.name, 5) + + # set source dir, unless the product is fixed (no source dir) + if not src.product.product_is_fixed(product_info): + src_dir = product_info.name + "_SRC_DIR" + indic = cfgdic is not None and src_dir in cfgdic + if not self.is_defined(src_dir) and not indic: + self.set(src_dir, product_info.source_dir) + + def set_salome_generic_product_env(self, product): + pi = src.product.get_product_config(self.cfg, product) + env_root_dir = self.get(pi.name + "_ROOT_DIR") + l_binpath_libpath = [] + + # create additional ROOT_DIR for CPP components + if 'component_name' in pi: + compo_name = pi.component_name + if compo_name + "CPP" == product: + compo_root_dir = compo_name + "_ROOT_DIR" + envcompo_root_dir = os.path.join( self.cfg.TOOLS.common.install_root, compo_name ) + self.set(compo_root_dir , envcompo_root_dir) + bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome') + lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome') + l_binpath_libpath.append( (bin_path, lib_path) ) + + appliname = 'salome' + if src.get_cfg_param(pi, 'product_type', 'SALOME').upper() not in [ "SALOME", "SMESH_PLUGIN", "SAMPLE" ]: + appliname = '' + + bin_path = os.path.join(env_root_dir, 'bin', appliname) + lib_path = os.path.join(env_root_dir, 'lib', appliname) + l_binpath_libpath.append( (bin_path, lib_path) ) + + for bin_path, lib_path in l_binpath_libpath: + if not self.forBuild: + self.prepend('PATH', bin_path) + if src.architecture.is_windows(): + self.prepend('PATH', lib_path) + else : + self.prepend('LD_LIBRARY_PATH', lib_path) + + l = [ bin_path, lib_path, + os.path.join(env_root_dir, self.python_lib0, appliname), + os.path.join(env_root_dir, self.python_lib1, appliname) + ] + self.prepend('PYTHONPATH', l) + + ## + # Loads environment define in the configuration. + def load_cfg_environment(self, cfg_env): + for env_def in cfg_env: + val = cfg_env[env_def] + if isinstance(val, src.pyconf.Mapping): + continue + + if isinstance(val, src.pyconf.Sequence): + # transform into list of strings + l_val = [] + for item in val: + l_val.append(item) + val = l_val + + if env_def.startswith("_"): + # separator exception for PV_PLUGIN_PATH + if env_def[1:] == 'PV_PLUGIN_PATH': + self.prepend(env_def[1:], val, ';') + else: + self.prepend(env_def[1:], val) + elif env_def.endswith("_"): + # separator exception for PV_PLUGIN_PATH + if env_def[:-1] == 'PV_PLUGIN_PATH': + self.prepend(env_def[:-1], val, ';') + else: + self.prepend(env_def[:-1], val) + else: + self.set(env_def, val) + + ## + # Sets the environment of a product. + def set_a_product(self, product, logger, single_dir): + + if not self.silent: + logger.write(_("Setting environment for %s\n") % product, 4) + + self.add_line(1) + self.add_comment('setting environ for ' + product) + + pi = src.product.get_product_config(self.cfg, product) + + # Do not define environment if the product is native or fixed + if src.product.product_is_native(pi): + return + + if "environ" in pi: + # set environment using definition of the product + self.set_salome_minimal_product_env(pi, logger, single_dir, pi.environ) + self.set_salome_generic_product_env(product) + self.load_cfg_environment(pi.environ) + if self.forBuild and "build" in pi.environ: + self.load_cfg_environment(pi.environ.build) + if not self.forBuild and "launch" in pi.environ: + self.load_cfg_environment(pi.environ.launch) + else: + # no environment defined in config + self.set_salome_minimal_product_env(pi, logger, single_dir) + if 'install_dir' in pi : + self.set_salome_generic_product_env(product) + + # if product_info defines a env_scripts load it + if 'env_script' in pi: + self.run_env_script(pi, logger) + + + ## + # Runs an environment script. + def run_env_script(self, product_info, logger=None): + env_script = product_info.env_script + if not os.path.exists(product_info.env_script): + raise src.SatException(_("Environment script not found: %s") % env_script) + + if not self.silent and logger is not None: + logger.write(" ** load %s\n" % product_info.env_script, 4) + + try: + import imp + pyproduct = imp.load_source(product_info.name + "_env_script", env_script) + pyproduct.set_env(self, product_info.install_dir, product_info.version) + except: + __, exceptionValue, exceptionTraceback = sys.exc_info() + print(exceptionValue) + import traceback + traceback.print_tb(exceptionTraceback) + traceback.print_exc() + + ## + # Sets the environment for all the products. + def set_products(self, logger, src_root=None, single_dir=False): + self.add_line(1) + self.add_comment('setting environ for all products') + + self.set_python_libdirs() + + if src_root is None: + src_root = self.cfg.APPLICATION.workdir + self.set('SRC_ROOT', src_root) + + appli_name = "APPLI" + if "APPLI" in self.cfg and "application_name" in self.cfg.APPLI: + appli_name = self.cfg.APPLI.application_name + self.set("SALOME_APPLI_ROOT", os.path.join(self.cfg.APPLICATION.workdir, appli_name)) + + if not single_dir: + single_dir = src.get_cfg_param(self.cfg.APPLICATION, "compil_in_single_dir", "no") == 'yes' + + for product in src.get_cfg_param(self.cfg.APPLICATION, "imported_products", []): + self.set_a_product(product, logger, single_dir=single_dir) + self.finish(False) + + for product in self.cfg.APPLICATION.products.keys(): + self.set_a_product(product, logger, single_dir=single_dir) + self.finish(False) + + + ## + # Sets the full environment for prerequisites and products specified in env_info dictionary. + def set_full_environ(self, logger, env_info): + # set product environ + self.set_application_env(logger) + + # set products + install_root = os.path.join(self.cfg.APPLICATION.workdir, "INSTALL") + source_root = os.path.join(self.cfg.APPLICATION.workdir, "SOURCES") + self.set('INSTALL_ROOT', install_root) + self.set('SRC_ROOT', source_root) + self.set_python_libdirs() + + single_dir = src.get_cfg_param(self.cfg.APPLICATION, "compil_in_single_dir", "no") == 'yes' + for product in env_info['products']: + self.set_a_product(product, logger, single_dir=single_dir) + +## +# Class to dump the environment to a file. +class FileEnvWriter: + def __init__(self, config, logger, out_dir, src_root, single_dir, env_info=None): + self.config = config + self.logger = logger + self.out_dir = out_dir + self.src_root= src_root + self.single_dir = single_dir + self.silent = True + self.env_info = env_info + + def write_env_file(self, filename, forBuild, shell): + """Create an environment file.""" + if not self.silent: + self.logger.write(_("Create environment file %s\n") % src.printcolors.printcLabel(filename), 3) + + # create then env object + env_file = open(os.path.join(self.out_dir, filename), "w") + tmp = src.fileEnviron.get_file_environ(env_file, shell, {}, self.config ) + env = SalomeEnviron(self.config, tmp, forBuild) + env.silent = self.silent + + if self.env_info is not None: + env.set_full_environ(self.logger, self.env_info) + else: + # set env from PRODUCT + env.set_application_env(self.logger) + # set the products + env.set_products(self.logger, + src_root=self.src_root, single_dir=self.single_dir) + + # add cleanup and close + env.finish(True) + env_file.close() + + return env_file.name + + def write_product_file(self, filename, shell): + """Create a product file.""" + if not self.silent: + self.logger.write(_("Create product file %s\n") % src.printcolors.printcLabel(filename), 3) + + prod_file = open(os.path.join(self.out_dir, filename), "w") + if shell == "bash": + content = _bash_content % self.out_dir + elif shell == "batch": + content = _batch_content % self.out_dir + else: + raise src.SatException(_("Unknown shell: %s") % shell) + + prod_file.write(content) + prod_file.close() + + return prod_file.name + + def write_cfgForPy_file(self, aFile, additional_env = {}): + """append to current opened aFile a cfgForPy environment (python syntax).""" + if not self.silent: + self.logger.write(_("Create configuration file %s\n") % src.printcolors.printcLabel(aFile.name), 3) + + # create then env object + tmp = src.fileEnviron.get_file_environ(aFile, "cfgForPy", {}, self.config) + forBuild = True + forLaunch = False + env = SalomeEnviron(self.config, tmp, forLaunch) + env.silent = self.silent + + if self.env_info is not None: + env.set_full_environ(self.logger, self.env_info) + else: + # set env from PRODUCT + env.set_application_env(self.logger) + # set the prerequisites + env.set_prerequisites(self.logger) + # set the products + env.set_products(self.logger, + src_root=self.src_root, single_dir=self.single_dir) + + if len(additional_env) != 0: + for variable in additional_env: + env.set(variable, additional_env[variable]) + + # add cleanup and close + env.finish(True) + +## +# Definition of a Shell. +class Shell: + def __init__(self, name, extension): + self.name = name + self.extension = extension + +## +# Loads the environment (used to run the tests). +def load_environment(config, build, logger): + environ = SalomeEnviron(config, Environ(os.environ), build) + environ.set_application_env(logger) + environ.set_products(logger) + environ.finish(True) \ No newline at end of file diff --git a/src/fileEnviron.py b/src/fileEnviron.py index 389fc3b..e23d2a3 100644 --- a/src/fileEnviron.py +++ b/src/fileEnviron.py @@ -140,7 +140,8 @@ class FileEnviron: self.prepend_value(key, value, sep) def is_defined(self, key): - return self.environ.has_key(key) + return (key in self.environ) + def set(self, key, value): raise NotImplementedError("set is not implement for this shell!") diff --git a/src/product.py b/src/product.py index de0e1d3..8ef4125 100644 --- a/src/product.py +++ b/src/product.py @@ -117,10 +117,11 @@ def get_product_config(config, product_name): prod_info.name = product_name prod_info.get_source = "native" - # Set the debug and dev keys + # Set the debug, dev and version keys if prod_info is not None: prod_info.debug = debug prod_info.dev = dev + prod_info.version = version # Set the install_dir key if "install_dir" not in prod_info: @@ -158,6 +159,28 @@ def get_products_infos(lproducts, config): raise src.SatException(msg) return products_infos +def get_product_dependencies(config, product_info): + '''Get recursively the list of products that are + in the product_info dependencies + + :param config Config: The global configuration + :param product_info Config: The configuration specific to + the product + :return: the list of products in dependence + :rtype: list + ''' + if "depend" not in product_info or product_info.depend == []: + return [] + res = [] + for prod in product_info.depend: + if prod not in res: + res.append(prod) + prod_info = get_product_config(config, prod) + dep_prod = get_product_dependencies(config, prod_info) + for prod_in_dep in dep_prod: + if prod_in_dep not in res: + res.append(prod_in_dep) + return res def product_is_sample(product_info): '''Know if a product has the sample type -- 2.30.2