X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2Fenvironment.py;h=0699a3d1ece9cf32b450ac025f0a9093ef4217b9;hb=c76437f0fb9f7f66bfca0eb10674fbdd3d22ba6c;hp=0634ec5a40b5d4159a74ea1a08b9267739b21546;hpb=35294cf67057a8c57d5d0ab6b076f94bd97653fa;p=tools%2Fsat.git diff --git a/src/environment.py b/src/environment.py index 0634ec5..0699a3d 100644 --- a/src/environment.py +++ b/src/environment.py @@ -20,55 +20,71 @@ import os import subprocess import string import sys +import copy import src +import src.debug as DBG +import pprint as PP + class Environ: - '''Class to manage the environment context - ''' + """\ + Class to manage the environment context + """ def __init__(self, environ=None): - '''Initialization. If the environ argument is passed, the environment + """Initialization. If the environ argument is passed, the environment will be add to it, else it is the external environment. :param environ dict: - ''' + """ if environ is not None: self.environ = environ else: self.environ = os.environ def __repr__(self): - """easy non exhaustive quick resume for debug print - """ - res={} - res["environ"]=self.environ - return self.__class__.__name__ + str(res)[0:-1] + " ...etc...}" + """easy non exhaustive quick resume for debug print""" + return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(self.environ)) def _expandvars(self, value): - '''replace some $VARIABLE into its actual value in the environment + """\ + replace some $VARIABLE into its actual value in the environment :param value str: the string to be replaced :return: the replaced variable :rtype: str - ''' - if "$" in value: + """ + if src.architecture.is_windows(): + delim = "%" + else: + delim = "$" + if delim in value: # The string.Template class is a string class # for supporting $-substitutions zt = string.Template(value) + zt.delimiter = delim try: value = zt.substitute(self.environ) except KeyError as exc: - raise src.SatException(_("Missing definition " - "in environment: %s") % str(exc)) + pass + #raise src.SatException(_("Missing definition " + # "in environment: %s") % str(exc)) return value def append_value(self, key, value, sep=os.pathsep): - '''append value to key using sep - + """\ + append value to key using sep, + if value contains ":" or ";" then raise error + :param key str: the environment variable to append :param value str: the value to append to key :param sep str: the separator string - ''' + """ + # check that value so no contain the system separator + separator=os.pathsep + if separator in value: + raise Exception("Environ append key '%s' value '%s' contains forbidden character '%s'" % (key, value, separator)) + # check if the key is already in the environment if key in self.environ: value_list = self.environ[key].split(sep) @@ -82,12 +98,13 @@ class Environ: self.set(key, value) def append(self, key, value, sep=os.pathsep): - '''Same as append_value but the value argument can be a list + """\ + Same as append_value but the value argument can be a list :param key str: the environment variable to append :param value str or list: the value(s) to append to key :param sep str: the separator string - ''' + """ if isinstance(value, list): for v in value: self.append_value(key, v, sep) @@ -95,12 +112,20 @@ class Environ: self.append_value(key, value, sep) def prepend_value(self, key, value, sep=os.pathsep): - '''prepend value to key using sep + """\ + prepend value to key using sep, + if value contains ":" or ";" then raise error :param key str: the environment variable to prepend :param value str: the value to prepend to key :param sep str: the separator string - ''' + """ + # check that value so no contain the system separator + separator=os.pathsep + if separator in value: + raise Exception("Environ append key '%s' value '%s' contains forbidden character '%s'" % (key, value, separator)) + + # check if the key is already in the environment if key in self.environ: value_list = self.environ[key].split(sep) if not value in value_list: @@ -112,68 +137,70 @@ class Environ: self.set(key, value) def prepend(self, key, value, sep=os.pathsep): - '''Same as prepend_value but the value argument can be a list + """\ + Same as prepend_value but the value argument can be a list :param key str: the environment variable to prepend :param value str or list: the value(s) to prepend to key :param sep str: the separator string - ''' + """ if isinstance(value, list): - for v in value: + for v in reversed(value): # prepend list, first item at last to stay first self.prepend_value(key, v, sep) else: self.prepend_value(key, value, sep) def is_defined(self, key): - '''Check if the key exists in the environment + """\ + Check if the key exists in the environment :param key str: the environment variable to check - ''' + """ return key in self.environ.keys() def set(self, key, value): - '''Set the environment variable "key" to value "value" + """\ + Set the environment variable "key" to value "value" :param key str: the environment variable to set :param value str: the value - ''' + """ self.environ[key] = self._expandvars(value) def get(self, key): - '''Get the value of the environment variable "key" + """\ + Get the value of the environment variable "key" :param key str: the environment variable - ''' + """ if key in self.environ: return self.environ[key] else: return "" - def command_value(self, key, command): - '''Get the value given by the system command "command" - and put it in the environment variable key + def get_value(self, key): + """\ + Get the value of the environment variable "key" + This method is added for API compatibility with FileEnviron class :param key str: the environment variable - :param command str: the command to execute - ''' - value = subprocess.Popen(command, - shell=True, - stdout=subprocess.PIPE, - env=self.environ).communicate()[0] - self.environ[key] = value + """ + return self.get(key) + class SalomeEnviron: - """Class to manage the environment of SALOME. + """\ + Class to manage the environment of SALOME. """ - def __init__(self, cfg, environ, forBuild=False, for_package=None, enable_simple_env_script = True): - '''Initialization. + """\ + Initialization. :param cfg Config: the global config :param environ Environ: the Environ instance where @@ -182,59 +209,100 @@ class SalomeEnviron: else a build one :param for_package str: If not None, produce a relative environment designed for a package. - ''' + """ self.environ = environ self.cfg = cfg self.forBuild = forBuild self.for_package = for_package self.enable_simple_env_script = enable_simple_env_script self.silent = False + self.has_python = False + self.__set_sorted_products_list() 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...}" + """easy almost exhaustive quick resume for debug print""" + res = { + "environ" : self.environ, + "forBuild" : self.forBuild, + "for_package" : self.for_package, + } + return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(res)) + + def __set_sorted_products_list(self): + all_products_infos = src.product.get_products_infos( + self.cfg.APPLICATION.products, + self.cfg) + + from compile import get_dependencies_graph,depth_first_topo_graph + all_products_graph=get_dependencies_graph(all_products_infos, self.forBuild) + visited_nodes=[] + sorted_nodes=[] + for n in all_products_graph: + if n not in visited_nodes: + visited_nodes,sorted_nodes=depth_first_topo_graph( + all_products_graph, + n, + visited_nodes, + sorted_nodes) + self.sorted_product_list=sorted_nodes + self.all_products_graph=all_products_graph + def append(self, key, value, sep=os.pathsep): - '''append value to key using sep + """\ + append value to key using sep :param key str: the environment variable to append :param value str: the value to append to key :param sep str: the separator string - ''' + """ return self.environ.append(key, value, sep) def prepend(self, key, value, sep=os.pathsep): - '''prepend value to key using sep + """\ + prepend value to key using sep :param key str: the environment variable to prepend :param value str: the value to prepend to key :param sep str: the separator string - ''' + """ return self.environ.prepend(key, value, sep) def is_defined(self, key): - '''Check if the key exists in the environment + """\ + Check if the key exists in the environment :param key str: the environment variable to check - ''' + """ return self.environ.is_defined(key) def get(self, key): - '''Get the value of the environment variable "key" + """\ + Get the value of the environment variable "key" :param key str: the environment variable - ''' + """ return self.environ.get(key) + def get_value(self, key): + """\ + Get the real value of the environment variable "key" + This method is added for API compatibility with FileEnviron class + + :param key str: the environment variable + """ + if key in self.environ: + return self.environ[key] + else: + return "" + def set(self, key, value): - '''Set the environment variable "key" to value "value" + """\ + Set the environment variable "key" to value "value" :param key str: the environment variable to set :param value str: the 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, @@ -245,7 +313,8 @@ class SalomeEnviron: return self.environ.set(key, value) def dump(self, out): - """Write the environment to out + """\ + Write the environment to out :param out file: the stream where to write the environment """ @@ -257,7 +326,8 @@ class SalomeEnviron: out.write("%s=%s\n" % (k, value)) def add_line(self, nb_line): - """Add empty lines to the out stream (in case of file generation) + """\ + Add empty lines to the out stream (in case of file generation) :param nb_line int: the number of empty lines to add """ @@ -265,7 +335,8 @@ class SalomeEnviron: self.environ.add_line(nb_line) def add_comment(self, comment): - """Add a commentary to the out stream (in case of file generation) + """\ + Add a commentary to the out stream (in case of file generation) :param comment str: the commentary to add """ @@ -273,146 +344,112 @@ class SalomeEnviron: self.environ.add_comment(comment) def add_warning(self, warning): - """Add a warning to the out stream (in case of file generation) + """\ + Add a warning to the out stream (in case of file generation) :param warning str: the warning to add """ if 'add_warning' in dir(self.environ): self.environ.add_warning(warning) - def finish(self, required): - """Add a final instruction in the out file (in case of file generation) + def finish(self): + """\ + Add a final instruction in the out file (in case of file generation) :param required bool: Do nothing if required is False """ if 'finish' in dir(self.environ): self.environ.add_line(1) - self.environ.add_comment("clean all the path") - self.environ.finish(required) + # what for ? + # self.environ.add_comment("clean all the path") + self.environ.finish() def set_python_libdirs(self): - """Set some generic variables for python library paths - """ + """Set some generic variables for python library paths""" ver = self.get('PYTHON_VERSION') - self.set('PYTHON_LIBDIR0', os.path.join('lib', + self.set('PYTHON_LIBDIR', 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') - - def get_names(self, lProducts): - """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 the product has the property has_salome_hui = "yes" - - :param lProducts list: List of products to potentially add - """ - lProdHasGui = [p for p in lProducts if 'properties' in - src.product.get_product_config(self.cfg, p) and - 'has_salome_gui' in - src.product.get_product_config(self.cfg, p).properties and - src.product.get_product_config(self.cfg, - p).properties.has_salome_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 + self.python_lib = self.get('PYTHON_LIBDIR') + self.has_python = True def set_application_env(self, logger): - """Sets the environment defined in the APPLICATION file. + """\ + Sets the environment defined in the APPLICATION file. :param logger Logger: The logger instance to display messages """ + if self.for_package: + if src.architecture.is_windows(): + self.set("PRODUCT_ROOT_DIR", "%out_dir_Path%") + else: + self.set("PRODUCT_ROOT_DIR", "out_dir_Path") + + else: + self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR = src.pyconf.Reference(self.cfg, src.pyconf.DOLLAR, "workdir") + + # Set the variables defined in the "environ" section if 'environ' in self.cfg.APPLICATION: - self.add_comment("APPLICATION environment") - for p in self.cfg.APPLICATION.environ: - val = self.cfg.APPLICATION.environ[p] - # "_" means that the value must be prepended - if p.startswith("_"): - # separator exception for PV_PLUGIN_PATH - if p[1:] == 'PV_PLUGIN_PATH': - self.prepend(p[1:], val, ';') - else: - self.prepend(p[1:], val) - elif p.endswith("_"): - # separator exception for PV_PLUGIN_PATH - if p[:-1] == 'PV_PLUGIN_PATH': - self.append(p[:-1], val, ';') - else: - self.append(p[:-1], val) - else: - self.set(p, val) + # we write PRODUCT environment it in order to conform to + # parseConfigFile.py + self.add_comment("PRODUCT environment") + self.load_cfg_environment(self.cfg.APPLICATION.environ) + if self.forBuild and "build" in self.cfg.APPLICATION.environ: + self.load_cfg_environment(self.cfg.APPLICATION.environ.build) + if not self.forBuild and "launch" in self.cfg.APPLICATION.environ: + self.load_cfg_environment(self.cfg.APPLICATION.environ.launch) self.add_line(1) - # If there is an "environ_script" section, load the scripts - 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 there is profile (SALOME), then define additional variables - if ('profile' in self.cfg.APPLICATION and - "product" in self.cfg.APPLICATION.profile): - 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() ) ) - def set_salome_minimal_product_env(self, product_info, logger): - """Sets the minimal environment for a SALOME product. - xxx_ROOT_DIR and xxx_SRC_DIR + """\ + Sets the minimal environment for a SALOME product. + xxx_ROOT_DIR and xxx_SRC_DIR :param product_info Config: The product description :param logger Logger: The logger instance to display messages """ # set root dir + DBG.write("set_salome_minimal_product_env", product_info) root_dir = product_info.name + "_ROOT_DIR" - if not self.is_defined(root_dir): - if '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) - - if not self.for_package: + if '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) + + source_in_package = src.get_property_in_product_cfg(product_info, + "sources_in_package") + if not self.for_package or source_in_package == "yes": # set source dir, unless no source dir if not src.product.product_is_fixed(product_info): src_dir = product_info.name + "_SRC_DIR" - if not self.is_defined(src_dir): + if not self.for_package: self.set(src_dir, product_info.source_dir) + else: + self.set(src_dir, os.path.join("out_dir_Path", + "SOURCES", + os.path.basename(product_info.source_dir))) + def expand_salome_modules(self, pi): + if 'component_name' in pi: + compo_name = pi.component_name + else: + compo_name = pi.name + self.append('SALOME_MODULES', compo_name, ',') + + def set_salome_generic_product_env(self, pi): - """Sets the generic environment for a SALOME product. + """\ + Sets the generic environment for a SALOME product. :param pi Config: The product description """ # Construct XXX_ROOT_DIR 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 @@ -425,15 +462,22 @@ class SalomeEnviron: 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 = '' + + if src.get_property_in_product_cfg(pi, "fhs"): + lib_path = os.path.join(env_root_dir, 'lib') + bin_path = os.path.join(env_root_dir, 'bin') + if self.has_python: + # if the application doesn't include python, we don't need these two lines + pylib_path = os.path.join(env_root_dir, self.python_lib) + else: + lib_path = os.path.join(env_root_dir, 'lib', 'salome') + bin_path = os.path.join(env_root_dir, 'bin', 'salome') + if self.has_python: + # if the application doesn't include python, we don't need these two lines + pylib_path = os.path.join(env_root_dir, self.python_lib, 'salome') # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and # PYTHONPATH - 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: @@ -444,14 +488,15 @@ class SalomeEnviron: 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) + l = [ bin_path, lib_path ] + if not src.product.product_is_wheel(pi): + if self.has_python: + l.append(pylib_path) + self.prepend('PYTHONPATH', l) def set_cpp_env(self, product_info): - """Sets the generic environment for a SALOME cpp product. + """\ + Sets the generic environment for a SALOME cpp product. :param product_info Config: The product description """ @@ -473,14 +518,14 @@ class SalomeEnviron: else : self.prepend('LD_LIBRARY_PATH', lib_path) - l = [ bin_path, lib_path, - os.path.join(env_root_dir, self.python_lib0), - os.path.join(env_root_dir, self.python_lib1) - ] + l = [ bin_path, lib_path ] + if self.has_python: + l.append(os.path.join(env_root_dir, self.python_lib)) self.prepend('PYTHONPATH', l) def load_cfg_environment(self, cfg_env): - """Loads environment defined in cfg_env + """\ + Loads environment defined in cfg_env :param cfg_env Config: A config containing an environment """ @@ -521,7 +566,8 @@ class SalomeEnviron: self.set(env_def, val) def set_a_product(self, product, logger): - """Sets the environment of a product. + """\ + Sets the environment of a product. :param product str: The product name :param logger Logger: The logger instance to display messages @@ -529,11 +575,40 @@ class SalomeEnviron: # Get the informations corresponding to the product pi = src.product.get_product_config(self.cfg, product) + # skip compile time products at run time + if not self.forBuild: + if src.product.product_is_compile_time(pi): + return + + # skip pip products when pip is activated and installation is done in python + #if (src.appli_test_property(self.cfg,"pip", "yes") and + # src.product.product_test_property(pi,"pip", "yes") and + # src.appli_test_property(self.cfg,"pip_install_dir", "python") ): + # return + + # skip mesa products (if any) at run time, + # unless use_mesa property was activated + if not self.forBuild: + if not ("APPLICATION" in self.cfg and + "properties" in self.cfg.APPLICATION and + "use_mesa" in self.cfg.APPLICATION.properties and + self.cfg.APPLICATION.properties.use_mesa == "yes") : + if ("properties" in pi and + "is_mesa" in pi.properties and + pi.properties.is_mesa == "yes") : + logger.write(_("Skip mesa product %s\n") % pi.name, 4) + return + if self.for_package: - pi.install_dir = os.path.join("out_dir_Path", - self.for_package, - pi.name) + prod_base_name=os.path.basename(pi.install_dir) + if prod_base_name.startswith("config"): + # case of a products installed in base. We remove "config-i" + prod_base_name=os.path.basename(os.path.dirname(pi.install_dir)) + pi.install_dir = os.path.join( + "out_dir_Path", + self.for_package, + prod_base_name) if not self.silent: logger.write(_("Setting environment for %s\n") % product, 4) @@ -552,7 +627,24 @@ class SalomeEnviron: # set environment using definition of the product self.set_salome_minimal_product_env(pi, logger) self.set_salome_generic_product_env(pi) + + # Expand SALOME_MODULES variable for products which have a salome gui + if src.product.product_has_salome_gui(pi): + self.expand_salome_modules(pi) + + # use variable LICENCE_FILE to communicate the licence file name to the environment script + licence_file_name = src.product.product_has_licence(pi, self.cfg.PATHS.LICENCEPATH) + if licence_file_name: + logger.write("licence file found for product %s : %s\n" % (pi.name, licence_file_name), 5) + self.set("LICENCE_FILE", licence_file_name) + + # these infos may be needed for the environment of some products + if "debug" in pi and pi.debug == "yes": + self.set("SAT_DEBUG", "1") + if "verbose" in pi and pi.verbose == "yes": + self.set("SAT_VERBOSE", "1") + if src.product.product_is_cpp(pi): # set a specific environment for cpp modules self.set_salome_minimal_product_env(pi, logger) @@ -566,8 +658,12 @@ class SalomeEnviron: source_dir_save = pi.source_dir name_save = pi.name pi.install_dir = os.path.join(self.cfg.APPLICATION.workdir, - "INSTALL", + self.cfg.INTERNAL.config.install_dir, pi.component_name) + if self.for_package: + pi.install_dir = os.path.join("out_dir_Path", + self.for_package, + pi.component_name) pi.source_dir = os.path.join(self.cfg.APPLICATION.workdir, "GENERATED", pi.component_name) @@ -595,7 +691,8 @@ class SalomeEnviron: def run_env_script(self, product_info, logger=None, native=False): - """Runs an environment script. + """\ + Runs an environment script. :param product_info Config: The product description :param logger Logger: The logger instance to display messages @@ -616,10 +713,22 @@ class SalomeEnviron: pyproduct = imp.load_source(product_info.name + "_env_script", env_script) if not native: - pyproduct.set_env(self, - product_info.install_dir, - product_info.version) + if self.forBuild and "set_env_build" in dir(pyproduct): + pyproduct.set_env_build(self, + product_info.install_dir, + product_info.version) + elif (not self.forBuild) and "set_env_launch" in dir(pyproduct): + pyproduct.set_env_launch(self, + product_info.install_dir, + product_info.version) + else: + # at least this one is mandatory, + # if set_env_build and set_env_build are not defined + pyproduct.set_env(self, + product_info.install_dir, + product_info.version) else: + # not mandatory, if set_nativ_env not defined, we do nothing if "set_nativ_env" in dir(pyproduct): pyproduct.set_nativ_env(self) except: @@ -629,42 +738,9 @@ class SalomeEnviron: traceback.print_tb(exceptionTraceback) traceback.print_exc() - def run_simple_env_script(self, script_path, logger=None): - """Runs an environment script. Same as run_env_script, but with a - script path as parameter. - - :param script_path str: a path to an environment script - :param logger Logger: The logger instance to display messages - """ - if not self.enable_simple_env_script: - return - # Check that the script exists - if not os.path.exists(script_path): - raise src.SatException(_("Environment script not found: %s") % - script_path) - - if not self.silent and logger is not None: - logger.write(" ** load %s\n" % script_path, 4) - - script_basename = os.path.basename(script_path) - if script_basename.endswith(".py"): - script_basename = script_basename[:-len(".py")] - - # import the script and run the set_env function - try: - import imp - pyproduct = imp.load_source(script_basename + "_env_script", - script_path) - pyproduct.load_env(self) - except: - __, exceptionValue, exceptionTraceback = sys.exc_info() - print(exceptionValue) - import traceback - traceback.print_tb(exceptionTraceback) - traceback.print_exc() - def set_products(self, logger, src_root=None): - """Sets the environment for all the products. + """\ + Sets the environment for all the products. :param logger Logger: The logger instance to display messages :param src_root src: the application working directory @@ -672,58 +748,65 @@ class SalomeEnviron: self.add_line(1) self.add_comment('setting environ for all products') - # Set the application working directory - if src_root is None: - src_root = self.cfg.APPLICATION.workdir - self.set('SRC_ROOT', src_root) - - # SALOME variables - 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)) - # Make sure that the python lib dirs are set after python - if "Python" in self.cfg.APPLICATION.products: + if "Python" in self.sorted_product_list: self.set_a_product("Python", logger) self.set_python_libdirs() # The loop on the products - for product in self.cfg.APPLICATION.products.keys(): + for product in self.sorted_product_list: if product == "Python": continue self.set_a_product(product, logger) - self.finish(False) def set_full_environ(self, logger, env_info): - """Sets the full environment for products - specified in env_info dictionary. + """\ + Sets the full environment for products, with their dependencies + specified in env_info dictionary. :param logger Logger: The logger instance to display messages :param env_info list: the list of products """ + DBG.write("set_full_environ for", env_info) + # DBG.write("set_full_environ config", self.cfg.APPLICATION.environ, True) # set product environ self.set_application_env(logger) - self.set_python_libdirs() + # use the sorted list of all products to sort the list of products + # we have to set + visited=[] + from compile import depth_search_graph # to get the dependencies + for p_name in env_info: + visited=depth_search_graph(self.all_products_graph, p_name, visited) + sorted_product_list=[] + for n in self.sorted_product_list: + if n in visited: + sorted_product_list.append(n) + + if "Python" in sorted_product_list: + self.set_a_product("Python", logger) + self.set_python_libdirs() - # set products - for product in env_info: + # set products + for product in sorted_product_list: + if product == "Python": + continue self.set_a_product(product, logger) class FileEnvWriter: - """Class to dump the environment to a file. + """\ + Class to dump the environment to a file. """ def __init__(self, config, logger, out_dir, src_root, env_info=None): - '''Initialization. + """\ + Initialization. :param cfg Config: the global config :param logger Logger: The logger instance to display messages :param out_dir str: The directory path where t put the output files :param src_root str: The application working directory :param env_info str: The list of products to add in the files. - ''' + """ self.config = config self.logger = logger self.out_dir = out_dir @@ -731,25 +814,133 @@ class FileEnvWriter: self.silent = True self.env_info = env_info - def write_env_file(self, filename, forBuild, shell, for_package = None): - """Create an environment file. + def write_tcl_files(self, + forBuild, + shell, + for_package = None, + no_path_init=False, + additional_env = {}): + """\ + Create tcl environment files for environment module. + + :param forBuild bool: if true, the build environment + :param shell str: the type of file wanted (.sh, .bat) + :param for_package bool: if true do specific stuff for required for packages + :param no_path_init bool: if true generate a environ file that do not reinitialise paths + :param additional_env dict: contains sat_ prefixed variables to help the génération, + and also variables to add in the environment. + :return: The path to the generated file + :rtype: str + """ + + # get the products informations + all_products=self.config.APPLICATION.products + products_infos = src.product.get_products_infos(all_products, self.config) + + # set a global environment (we need it to resolve variable references + # between dependent products + global_environ = src.environment.SalomeEnviron(self.config, + src.environment.Environ(additional_env), + False) + global_environ.set_products(self.logger) + + # The loop on the products + for product in all_products: + # create one file per product + pi = src.product.get_product_config(self.config, product) + if "base" not in pi: # we write tcl files only for products in base + continue + + # get the global environment, and complete it with sat_ prefixed + # prefixed variables which are used to transfer info to + # TclFileEnviron class + product_env = copy.deepcopy(global_environ.environ) + product_env.environ["sat_product_name"] = pi.name + product_env.environ["sat_product_version"] = pi.version + product_env.environ["sat_product_base_path"] = src.get_base_path(self.config) + product_env.environ["sat_product_base_name"] = pi.base + + # store infos in sat_product_load_depend to set dependencies in tcl file + sat_product_load_depend="" + for p_name,p_info in products_infos: + if p_name in pi.depend: + sat_product_load_depend+="module load %s/%s/%s;" % (pi.base, + p_info.name, + p_info.version) + if len(sat_product_load_depend)>0: + # if there are dependencies, store the module to load (get rid of trailing ;) + product_env.environ["sat_product_load_depend"]=sat_product_load_depend[0:-1] + + + env_file_name = os.path.join(product_env.environ["sat_product_base_path"], + "modulefiles", + product_env.environ["sat_product_base_name"], + product_env.environ["sat_product_name"], + product_env.environ["sat_product_version"]) + prod_dir_name=os.path.dirname(env_file_name) + if not os.path.isdir(prod_dir_name): + os.makedirs(prod_dir_name) + + env_file = open(env_file_name, "w") + file_environ = src.fileEnviron.get_file_environ(env_file, + "tcl", product_env) + env = SalomeEnviron(self.config, + file_environ, + False, + for_package=for_package) + if "Python" in pi.depend: + # short cut, env.python_lib is required by set_a_product for salome modules + env.has_python="True" + env.python_lib=global_environ.get("PYTHON_LIBDIR") + env.set_a_product(product, self.logger) + env_file.close() + if not self.silent: + self.logger.write(_(" Create tcl module environment file %s\n") % + src.printcolors.printcLabel(env_file_name), 3) + + + def write_env_file(self, + filename, + forBuild, + shell, + for_package = None, + no_path_init=False, + additional_env = {}): + """\ + Create an environment file. :param filename str: the file path :param forBuild bool: if true, the build environment :param shell str: the type of file wanted (.sh, .bat) + :param for_package bool: if true do specific stuff for required for packages + :param no_path_init bool: if true generate a environ file that do not reinitialise paths + :param additional_env dict: contains sat_ prefixed variables to help the génération, + and also variables to add in the environment. :return: The path to the generated file :rtype: str """ 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, + + # we duplicate additional_env, and transmit it to fileEnviron, which will use its sat_ prefixed variables. + # the other variables of additional_env are added to the environement file at the end of this function. + salome_env = copy.deepcopy(additional_env) + file_environ = src.fileEnviron.get_file_environ(env_file, shell, - {}) - env = SalomeEnviron(self.config, tmp, forBuild, for_package=for_package) + src.environment.Environ(salome_env)) + if no_path_init: + # specify we don't want to reinitialise paths + # path will keep the inherited value, which will be appended with new values. + file_environ.set_no_init_path() + + env = SalomeEnviron(self.config, + file_environ, + forBuild, + for_package=for_package) + env.silent = self.silent # Set the environment @@ -758,87 +949,43 @@ class FileEnvWriter: else: # set env from the APPLICATION env.set_application_env(self.logger) - - # The list of products to launch - lProductsName = env.get_names(self.config.APPLICATION.products.keys()) - env.set( "SALOME_MODULES", ','.join(lProductsName)) - # set the products env.set_products(self.logger, src_root=self.src_root) + # Add the additional environment if it is not empty + if len(additional_env) != 0: + env.add_line(1) + env.add_comment("[APPLI variables]") + for variable in additional_env: + if not variable.startswith("sat_"): + # by convention variables starting with sat_ are used to transfer information, + # not to be written in env + env.set(variable, additional_env[variable]) - # add cleanup and close - env.finish(True) + # finalise the writing and close the file + env.finish() env_file.close() return env_file.name - def write_cfgForPy_file(self, - filename, - additional_env = {}, - for_package = None, - with_commercial = True): - """Append to current opened aFile a cfgForPy - environment (SALOME python launcher). - - :param filename str: the file path - :param additional_env dict: a dictionary of additional variables - to add to the environment - :param for_package str: If not None, produce a relative environment - designed for a package. - """ - if not self.silent: - self.logger.write(_("Create configuration file %s\n") % - src.printcolors.printcLabel(filename.name), 3) - - # create then env object - tmp = src.fileEnviron.get_file_environ(filename, - "cfgForPy", - {}) - # environment for launch - env = SalomeEnviron(self.config, - tmp, - forBuild=False, - for_package=for_package, - enable_simple_env_script = with_commercial) - 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) - - # The list of products to launch - lProductsName = env.get_names(self.config.APPLICATION.products.keys()) - env.set( "SALOME_MODULES", ','.join(lProductsName)) - - # set the products - env.set_products(self.logger, - src_root=self.src_root) - - # Add the additional environment if it is not empty - if len(additional_env) != 0: - for variable in additional_env: - env.set(variable, additional_env[variable]) - - # add cleanup and close - env.finish(True) class Shell: - """Definition of a Shell. + """\ + Definition of a Shell. """ def __init__(self, name, extension): - '''Initialization. + """\ + Initialization. :param name str: the shell name :param extension str: the shell extension - ''' + """ self.name = name self.extension = extension def load_environment(config, build, logger): - """Loads the environment (used to run the tests, for example). + """\ + Loads the environment (used to run the tests, for example). :param config Config: the global config :param build bool: build environement if True @@ -847,4 +994,3 @@ 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)