3 # Copyright (C) 2010-2013 CEA/DEN
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 import src.debug as DBG
29 '''Class to manage the environment context
31 def __init__(self, environ=None):
32 '''Initialization. If the environ argument is passed, the environment
33 will be add to it, else it is the external environment.
37 if environ is not None:
38 self.environ = environ
40 self.environ = os.environ
43 """easy non exhaustive quick resume for debug print
45 return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(self.environ))
47 def _expandvars(self, value):
48 '''replace some $VARIABLE into its actual value in the environment
50 :param value str: the string to be replaced
51 :return: the replaced variable
55 # The string.Template class is a string class
56 # for supporting $-substitutions
57 zt = string.Template(value)
59 value = zt.substitute(self.environ)
60 except KeyError as exc:
61 raise src.SatException(_("Missing definition "
62 "in environment: %s") % str(exc))
65 def append_value(self, key, value, sep=os.pathsep):
66 '''append value to key using sep
68 :param key str: the environment variable to append
69 :param value str: the value to append to key
70 :param sep str: the separator string
72 # check if the key is already in the environment
73 if key in self.environ:
74 value_list = self.environ[key].split(sep)
75 # Check if the value is already in the key value or not
76 if not value in value_list:
77 value_list.append(value)
79 value_list.append(value_list.pop(value_list.index(value)))
80 self.set(key, sep.join(value_list))
84 def append(self, key, value, sep=os.pathsep):
85 '''Same as append_value but the value argument can be a list
87 :param key str: the environment variable to append
88 :param value str or list: the value(s) to append to key
89 :param sep str: the separator string
91 if isinstance(value, list):
93 self.append_value(key, v, sep)
95 self.append_value(key, value, sep)
97 def prepend_value(self, key, value, sep=os.pathsep):
98 '''prepend value to key using sep
100 :param key str: the environment variable to prepend
101 :param value str: the value to prepend to key
102 :param sep str: the separator string
104 if key in self.environ:
105 value_list = self.environ[key].split(sep)
106 if not value in value_list:
107 value_list.insert(0, value)
109 value_list.insert(0, value_list.pop(value_list.index(value)))
110 self.set(key, sep.join(value_list))
114 def prepend(self, key, value, sep=os.pathsep):
115 '''Same as prepend_value but the value argument can be a list
117 :param key str: the environment variable to prepend
118 :param value str or list: the value(s) to prepend to key
119 :param sep str: the separator string
121 if isinstance(value, list):
123 self.prepend_value(key, v, sep)
125 self.prepend_value(key, value, sep)
127 def is_defined(self, key):
128 '''Check if the key exists in the environment
130 :param key str: the environment variable to check
132 return key in self.environ.keys()
134 def set(self, key, value):
135 '''Set the environment variable "key" to value "value"
137 :param key str: the environment variable to set
138 :param value str: the value
140 self.environ[key] = self._expandvars(value)
143 '''Get the value of the environment variable "key"
145 :param key str: the environment variable
147 if key in self.environ:
148 return self.environ[key]
152 def command_value(self, key, command):
153 '''Get the value given by the system command "command"
154 and put it in the environment variable key
156 :param key str: the environment variable
157 :param command str: the command to execute
159 value = subprocess.Popen(command,
161 stdout=subprocess.PIPE,
162 env=self.environ).communicate()[0]
163 self.environ[key] = value
167 """Class to manage the environment of SALOME.
175 enable_simple_env_script = True):
178 :param cfg Config: the global config
179 :param environ Environ: the Environ instance where
180 to store the environment variables
181 :param forBuild bool: If true, it is a launch environment,
183 :param for_package str: If not None, produce a relative environment
184 designed for a package.
186 self.environ = environ
188 self.forBuild = forBuild
189 self.for_package = for_package
190 self.enable_simple_env_script = enable_simple_env_script
194 """easy almost exhaustive quick resume for debug print"""
196 "environ" : self.environ,
197 "forBuild" : self.forBuild,
198 "for_package" : self.for_package,
200 return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(res))
202 def append(self, key, value, sep=os.pathsep):
203 '''append value to key using sep
205 :param key str: the environment variable to append
206 :param value str: the value to append to key
207 :param sep str: the separator string
209 return self.environ.append(key, value, sep)
211 def prepend(self, key, value, sep=os.pathsep):
212 '''prepend value to key using sep
214 :param key str: the environment variable to prepend
215 :param value str: the value to prepend to key
216 :param sep str: the separator string
218 return self.environ.prepend(key, value, sep)
220 def is_defined(self, key):
221 '''Check if the key exists in the environment
223 :param key str: the environment variable to check
225 return self.environ.is_defined(key)
228 '''Get the value of the environment variable "key"
230 :param key str: the environment variable
232 return self.environ.get(key)
234 def set(self, key, value):
235 '''Set the environment variable "key" to value "value"
237 :param key str: the environment variable to set
238 :param value str: the value
240 # check if value needs to be evaluated
241 if value is not None and value.startswith("`") and value.endswith("`"):
242 res = subprocess.Popen("echo %s" % value,
244 stdout=subprocess.PIPE).communicate()
245 value = res[0].strip()
247 return self.environ.set(key, value)
250 """Write the environment to out
252 :param out file: the stream where to write the environment
254 for k in self.environ.environ.keys():
259 out.write("%s=%s\n" % (k, value))
261 def add_line(self, nb_line):
262 """Add empty lines to the out stream (in case of file generation)
264 :param nb_line int: the number of empty lines to add
266 if 'add_line' in dir(self.environ):
267 self.environ.add_line(nb_line)
269 def add_comment(self, comment):
270 """Add a commentary to the out stream (in case of file generation)
272 :param comment str: the commentary to add
274 if 'add_comment' in dir(self.environ):
275 self.environ.add_comment(comment)
277 def add_warning(self, warning):
278 """Add a warning to the out stream (in case of file generation)
280 :param warning str: the warning to add
282 if 'add_warning' in dir(self.environ):
283 self.environ.add_warning(warning)
285 def finish(self, required):
286 """Add a final instruction in the out file (in case of file generation)
288 :param required bool: Do nothing if required is False
290 if 'finish' in dir(self.environ):
291 self.environ.add_line(1)
292 self.environ.add_comment("clean all the path")
293 self.environ.finish(required)
295 def set_python_libdirs(self):
296 """Set some generic variables for python library paths
298 ver = self.get('PYTHON_VERSION')
299 self.set('PYTHON_LIBDIR0', os.path.join('lib',
302 self.set('PYTHON_LIBDIR1', os.path.join('lib64',
306 self.python_lib0 = self.get('PYTHON_LIBDIR0')
307 self.python_lib1 = self.get('PYTHON_LIBDIR1')
309 def get_names(self, lProducts):
310 """Get the products name to add in SALOME_MODULES environment variable
311 It is the name of the product, except in the case where the is a
312 component name. And it has to be in SALOME_MODULES variable only
313 if the product has the property has_salome_hui = "yes"
315 :param lProducts list: List of products to potentially add
317 lProdHasGui = [p for p in lProducts if 'properties' in
318 src.product.get_product_config(self.cfg, p) and
320 src.product.get_product_config(self.cfg, p).properties and
321 src.product.get_product_config(self.cfg,
322 p).properties.has_salome_gui=='yes']
324 for ProdName in lProdHasGui:
325 pi = src.product.get_product_config(self.cfg, ProdName)
326 if 'component_name' in pi:
327 lProdName.append(pi.component_name)
329 lProdName.append(ProdName)
332 def set_application_env(self, logger):
333 """Sets the environment defined in the APPLICATION file.
335 :param logger Logger: The logger instance to display messages
338 # add variable PRODUCT_ROOT_DIR as $workdir in APPLICATION.environ section if not present
340 tmp = self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR
342 self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR = src.pyconf.Reference(self.cfg, src.pyconf.DOLLAR, "workdir")
343 DBG.write("set_application_env add default Config.APPLICATION.environ.PRODUCT_ROOT_DIR", self.cfg.APPLICATION.environ)
345 # Set the variables defined in the "environ" section
346 if 'environ' in self.cfg.APPLICATION:
347 # we write PRODUCT environment it in order to conform to
349 self.add_comment("PRODUCT environment")
350 self.load_cfg_environment(self.cfg.APPLICATION.environ)
351 if self.forBuild and "build" in self.cfg.APPLICATION.environ:
352 self.load_cfg_environment(self.cfg.APPLICATION.environ.build)
353 if not self.forBuild and "launch" in self.cfg.APPLICATION.environ:
354 self.load_cfg_environment(self.cfg.APPLICATION.environ.launch)
357 # If there is an "environ_script" section, load the scripts
358 if 'environ_script' in self.cfg.APPLICATION:
359 for pscript in self.cfg.APPLICATION.environ_script:
360 self.add_comment("script %s" % pscript)
361 sname = pscript.replace(" ", "_")
362 self.run_env_script("APPLICATION_%s" % sname,
363 self.cfg.APPLICATION.environ_script[pscript],
367 def set_salome_minimal_product_env(self, product_info, logger):
368 """Sets the minimal environment for a SALOME product.
369 xxx_ROOT_DIR and xxx_SRC_DIR
371 :param product_info Config: The product description
372 :param logger Logger: The logger instance to display messages
375 DBG.write("set_salome_minimal_product_env", product_info)
376 root_dir = product_info.name + "_ROOT_DIR"
377 if not self.is_defined(root_dir):
378 if 'install_dir' in product_info and product_info.install_dir:
379 self.set(root_dir, product_info.install_dir)
380 elif not self.silent:
381 logger.write(" " + _("No install_dir for product %s\n") %
382 product_info.name, 5)
384 source_in_package = src.get_property_in_product_cfg(product_info,
385 "sources_in_package")
386 if not self.for_package or source_in_package == "yes":
387 # set source dir, unless no source dir
388 if not src.product.product_is_fixed(product_info):
389 src_dir = product_info.name + "_SRC_DIR"
390 if not self.is_defined(src_dir):
391 if not self.for_package:
392 self.set(src_dir, product_info.source_dir)
394 self.set(src_dir, os.path.join("out_dir_Path",
398 def set_salome_generic_product_env(self, pi):
399 """Sets the generic environment for a SALOME product.
401 :param pi Config: The product description
403 # Construct XXX_ROOT_DIR
404 env_root_dir = self.get(pi.name + "_ROOT_DIR")
405 l_binpath_libpath = []
407 # create additional ROOT_DIR for CPP components
408 if 'component_name' in pi:
409 compo_name = pi.component_name
410 if compo_name + "CPP" == pi.name:
411 compo_root_dir = compo_name + "_ROOT_DIR"
412 envcompo_root_dir = os.path.join(
413 self.cfg.TOOLS.common.install_root, compo_name )
414 self.set(compo_root_dir , envcompo_root_dir)
415 bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome')
416 lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome')
417 l_binpath_libpath.append( (bin_path, lib_path) )
419 if src.get_property_in_product_cfg(pi, "fhs"):
420 lib_path = os.path.join(env_root_dir, 'lib')
421 pylib1_path = os.path.join(env_root_dir, self.python_lib0)
422 pylib2_path = os.path.join(env_root_dir, self.python_lib1)
423 bin_path = os.path.join(env_root_dir, 'bin')
425 lib_path = os.path.join(env_root_dir, 'lib', 'salome')
426 pylib1_path = os.path.join(env_root_dir, self.python_lib0, 'salome')
427 pylib2_path = os.path.join(env_root_dir, self.python_lib1, 'salome')
428 bin_path = os.path.join(env_root_dir, 'bin', 'salome')
430 # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and
432 l_binpath_libpath.append( (bin_path, lib_path) )
434 for bin_path, lib_path in l_binpath_libpath:
435 if not self.forBuild:
436 self.prepend('PATH', bin_path)
437 if src.architecture.is_windows():
438 self.prepend('PATH', lib_path)
440 self.prepend('LD_LIBRARY_PATH', lib_path)
442 l = [ bin_path, lib_path, pylib1_path, pylib2_path ]
443 self.prepend('PYTHONPATH', l)
445 def set_cpp_env(self, product_info):
446 """Sets the generic environment for a SALOME cpp product.
448 :param product_info Config: The product description
450 # Construct XXX_ROOT_DIR
451 env_root_dir = self.get(product_info.name + "_ROOT_DIR")
452 l_binpath_libpath = []
454 # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and
456 bin_path = os.path.join(env_root_dir, 'bin')
457 lib_path = os.path.join(env_root_dir, 'lib')
458 l_binpath_libpath.append( (bin_path, lib_path) )
460 for bin_path, lib_path in l_binpath_libpath:
461 if not self.forBuild:
462 self.prepend('PATH', bin_path)
463 if src.architecture.is_windows():
464 self.prepend('PATH', lib_path)
466 self.prepend('LD_LIBRARY_PATH', lib_path)
468 l = [ bin_path, lib_path,
469 os.path.join(env_root_dir, self.python_lib0),
470 os.path.join(env_root_dir, self.python_lib1)
472 self.prepend('PYTHONPATH', l)
474 def load_cfg_environment(self, cfg_env):
475 """Loads environment defined in cfg_env
477 :param cfg_env Config: A config containing an environment
479 # Loop on cfg_env values
480 for env_def in cfg_env:
481 val = cfg_env[env_def]
483 # if it is env_script, do not do anything (reserved keyword)
484 if env_def == "env_script":
487 # if it is a dict, do not do anything
488 if isinstance(val, src.pyconf.Mapping):
491 # if it is a list, loop on its values
492 if isinstance(val, src.pyconf.Sequence):
493 # transform into list of strings
499 # "_" means that the value must be prepended
500 if env_def.startswith("_"):
501 # separator exception for PV_PLUGIN_PATH
502 if env_def[1:] == 'PV_PLUGIN_PATH':
503 self.prepend(env_def[1:], val, ';')
505 self.prepend(env_def[1:], val)
506 elif env_def.endswith("_"):
507 # separator exception for PV_PLUGIN_PATH
508 if env_def[:-1] == 'PV_PLUGIN_PATH':
509 self.append(env_def[:-1], val, ';')
511 self.append(env_def[:-1], val)
513 self.set(env_def, val)
515 def set_a_product(self, product, logger):
516 """Sets the environment of a product.
518 :param product str: The product name
519 :param logger Logger: The logger instance to display messages
522 # Get the informations corresponding to the product
523 pi = src.product.get_product_config(self.cfg, product)
526 pi.install_dir = os.path.join("out_dir_Path",
531 logger.write(_("Setting environment for %s\n") % product, 4)
534 self.add_comment('setting environ for ' + product)
536 # Do not define environment if the product is native
537 if src.product.product_is_native(pi):
538 if src.product.product_has_env_script(pi):
539 self.run_env_script(pi, native=True)
542 # Set an additional environment for SALOME products
543 if src.product.product_is_salome(pi):
544 # set environment using definition of the product
545 self.set_salome_minimal_product_env(pi, logger)
546 self.set_salome_generic_product_env(pi)
548 if src.product.product_is_cpp(pi):
549 # set a specific environment for cpp modules
550 self.set_salome_minimal_product_env(pi, logger)
553 if src.product.product_is_generated(pi):
554 if "component_name" in pi:
555 # hack the source and install directories in order to point
556 # on the generated product source install directories
557 install_dir_save = pi.install_dir
558 source_dir_save = pi.source_dir
560 pi.install_dir = os.path.join(self.cfg.APPLICATION.workdir,
564 pi.install_dir = os.path.join("out_dir_Path",
567 pi.source_dir = os.path.join(self.cfg.APPLICATION.workdir,
570 pi.name = pi.component_name
571 self.set_salome_minimal_product_env(pi, logger)
572 self.set_salome_generic_product_env(pi)
574 # Put original values
575 pi.install_dir = install_dir_save
576 pi.source_dir = source_dir_save
579 # Put the environment define in the configuration of the product
581 self.load_cfg_environment(pi.environ)
582 if self.forBuild and "build" in pi.environ:
583 self.load_cfg_environment(pi.environ.build)
584 if not self.forBuild and "launch" in pi.environ:
585 self.load_cfg_environment(pi.environ.launch)
586 # if product_info defines a env_scripts, load it
587 if 'env_script' in pi.environ:
588 self.run_env_script(pi, logger)
593 def run_env_script(self, product_info, logger=None, native=False):
594 """Runs an environment script.
596 :param product_info Config: The product description
597 :param logger Logger: The logger instance to display messages
598 :param native Boolean: if True load set_native_env instead of set_env
600 env_script = product_info.environ.env_script
601 # Check that the script exists
602 if not os.path.exists(env_script):
603 raise src.SatException(_("Environment script not found: %s") %
606 if not self.silent and logger is not None:
607 logger.write(" ** load %s\n" % env_script, 4)
609 # import the script and run the set_env function
612 pyproduct = imp.load_source(product_info.name + "_env_script",
615 pyproduct.set_env(self,
616 product_info.install_dir,
617 product_info.version)
619 if "set_nativ_env" in dir(pyproduct):
620 pyproduct.set_nativ_env(self)
622 __, exceptionValue, exceptionTraceback = sys.exc_info()
623 print(exceptionValue)
625 traceback.print_tb(exceptionTraceback)
626 traceback.print_exc()
628 def run_simple_env_script(self, script_path, logger=None):
629 """Runs an environment script. Same as run_env_script, but with a
630 script path as parameter.
632 :param script_path str: a path to an environment script
633 :param logger Logger: The logger instance to display messages
635 if not self.enable_simple_env_script:
637 # Check that the script exists
638 if not os.path.exists(script_path):
639 raise src.SatException(_("Environment script not found: %s") %
642 if not self.silent and logger is not None:
643 logger.write(" ** load %s\n" % script_path, 4)
645 script_basename = os.path.basename(script_path)
646 if script_basename.endswith(".py"):
647 script_basename = script_basename[:-len(".py")]
649 # import the script and run the set_env function
652 pyproduct = imp.load_source(script_basename + "_env_script",
654 pyproduct.load_env(self)
656 __, exceptionValue, exceptionTraceback = sys.exc_info()
657 print(exceptionValue)
659 traceback.print_tb(exceptionTraceback)
660 traceback.print_exc()
662 def set_products(self, logger, src_root=None):
663 """Sets the environment for all the products.
665 :param logger Logger: The logger instance to display messages
666 :param src_root src: the application working directory
669 self.add_comment('setting environ for all products')
671 # Make sure that the python lib dirs are set after python
672 if "Python" in self.cfg.APPLICATION.products:
673 self.set_a_product("Python", logger)
674 self.set_python_libdirs()
676 # The loop on the products
677 for product in self.cfg.APPLICATION.products.keys():
678 if product == "Python":
680 self.set_a_product(product, logger)
683 def set_full_environ(self, logger, env_info):
684 """Sets the full environment for products
685 specified in env_info dictionary.
687 :param logger Logger: The logger instance to display messages
688 :param env_info list: the list of products
690 DBG.write("set_full_environ for", env_info)
691 # DBG.write("set_full_environ config", self.cfg.APPLICATION.environ, True)
692 # set product environ
693 self.set_application_env(logger)
695 self.set_python_libdirs()
698 for product in env_info:
699 self.set_a_product(product, logger)
702 """Class to dump the environment to a file.
704 def __init__(self, config, logger, out_dir, src_root, env_info=None):
707 :param cfg Config: the global config
708 :param logger Logger: The logger instance to display messages
709 :param out_dir str: The directory path where t put the output files
710 :param src_root str: The application working directory
711 :param env_info str: The list of products to add in the files.
715 self.out_dir = out_dir
716 self.src_root= src_root
718 self.env_info = env_info
720 def write_env_file(self, filename, forBuild, shell, for_package = None):
721 """Create an environment file.
723 :param filename str: the file path
724 :param forBuild bool: if true, the build environment
725 :param shell str: the type of file wanted (.sh, .bat)
726 :return: The path to the generated file
730 self.logger.write(_("Create environment file %s\n") %
731 src.printcolors.printcLabel(filename), 3)
733 # create then env object
734 env_file = open(os.path.join(self.out_dir, filename), "w")
735 tmp = src.fileEnviron.get_file_environ(env_file,
738 env = SalomeEnviron(self.config, tmp, forBuild, for_package=for_package)
739 env.silent = self.silent
741 # Set the environment
742 if self.env_info is not None:
743 env.set_full_environ(self.logger, self.env_info)
745 # set env from the APPLICATION
746 env.set_application_env(self.logger)
748 # The list of products to launch
749 lProductsName = env.get_names(self.config.APPLICATION.products.keys())
750 env.set( "SALOME_MODULES", ','.join(lProductsName))
753 env.set_products(self.logger,
754 src_root=self.src_root)
756 # add cleanup and close
762 def write_cfgForPy_file(self,
766 with_commercial = True):
767 """Append to current opened aFile a cfgForPy
768 environment (SALOME python launcher).
770 :param filename str: the file path
771 :param additional_env dict: a dictionary of additional variables
772 to add to the environment
773 :param for_package str: If not None, produce a relative environment
774 designed for a package.
777 self.logger.write(_("Create configuration file %s\n") %
778 src.printcolors.printcLabel(filename.name), 3)
780 # create then env object
781 tmp = src.fileEnviron.get_file_environ(filename,
784 # environment for launch
785 env = SalomeEnviron(self.config,
788 for_package=for_package,
789 enable_simple_env_script = with_commercial)
790 env.silent = self.silent
792 if self.env_info is not None:
793 env.set_full_environ(self.logger, self.env_info)
795 # set env from PRODUCT
796 env.set_application_env(self.logger)
798 # The list of products to launch
799 lProductsName = env.get_names(self.config.APPLICATION.products.keys())
800 env.set( "SALOME_MODULES", ','.join(lProductsName))
803 env.set_products(self.logger,
804 src_root=self.src_root)
806 # Add the additional environment if it is not empty
807 if len(additional_env) != 0:
808 for variable in additional_env:
809 env.set(variable, additional_env[variable])
811 # add cleanup and close
815 """Definition of a Shell.
817 def __init__(self, name, extension):
820 :param name str: the shell name
821 :param extension str: the shell extension
824 self.extension = extension
826 def load_environment(config, build, logger):
827 """Loads the environment (used to run the tests, for example).
829 :param config Config: the global config
830 :param build bool: build environement if True
831 :param logger Logger: The logger instance to display messages
833 environ = SalomeEnviron(config, Environ(os.environ), build)
834 environ.set_application_env(logger)
835 environ.set_products(logger)