Salome HOME
option compile --update
[tools/sat.git] / src / environment.py
1 #!/usr/bin/env python
2 #-*- coding:utf-8 -*-
3 #  Copyright (C) 2010-2013  CEA/DEN
4 #
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.
9 #
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.
14 #
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
18
19 import os
20 import subprocess
21 import string
22 import sys
23 import copy
24
25 import src
26 import src.debug as DBG
27 import pprint as PP
28
29
30 class Environ:
31     """\
32     Class to manage the environment context
33     """
34     def __init__(self, environ=None):
35         """Initialization. If the environ argument is passed, the environment
36            will be add to it, else it is the external environment.
37            
38         :param environ dict:  
39         """
40         if environ is not None:
41             self.environ = environ
42         else:
43             self.environ = os.environ
44
45     def __repr__(self):
46         """easy non exhaustive quick resume for debug print"""
47         return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(self.environ))
48
49     def _expandvars(self, value):
50         """\
51         replace some $VARIABLE into its actual value in the environment
52         
53         :param value str: the string to be replaced
54         :return: the replaced variable
55         :rtype: str
56         """
57         if src.architecture.is_windows():
58             delim = "%"
59         else:
60             delim = "$"
61         if delim in value:
62             # The string.Template class is a string class 
63             # for supporting $-substitutions
64             zt = string.Template(value)
65             zt.delimiter = delim
66             try:
67                 value = zt.substitute(self.environ)
68             except KeyError as exc:
69                 pass
70                 #raise src.SatException(_("Missing definition "
71                 #                         "in environment: %s") % str(exc))
72         return value
73
74     def append_value(self, key, value, sep=os.pathsep):
75         """\
76         append value to key using sep,
77         if value contains ":" or ";" then raise error
78
79         :param key str: the environment variable to append
80         :param value str: the value to append to key
81         :param sep str: the separator string
82         """
83         # check that value so no contain the system separator
84         separator=os.pathsep
85         if separator in value:
86             raise Exception("Environ append key '%s' value '%s' contains forbidden character '%s'" % (key, value, separator))
87
88         # check if the key is already in the environment
89         if key in self.environ:
90             value_list = self.environ[key].split(sep)
91             # Check if the value is already in the key value or not
92             if not value in value_list:
93                 value_list.append(value)
94             else:
95                 value_list.append(value_list.pop(value_list.index(value)))
96             self.set(key, sep.join(value_list))
97         else:
98             self.set(key, value)
99
100     def append(self, key, value, sep=os.pathsep):
101         """\
102         Same as append_value but the value argument can be a list
103         
104         :param key str: the environment variable to append
105         :param value str or list: the value(s) to append to key
106         :param sep str: the separator string
107         """
108         if isinstance(value, list):
109             for v in value:
110                 self.append_value(key, v, sep)
111         else:
112             self.append_value(key, value, sep)
113
114     def prepend_value(self, key, value, sep=os.pathsep):
115         """\
116         prepend value to key using sep,
117         if value contains ":" or ";" then raise error
118         
119         :param key str: the environment variable to prepend
120         :param value str: the value to prepend to key
121         :param sep str: the separator string
122         """
123         # check that value so no contain the system separator
124         separator=os.pathsep
125         if separator in value:
126             raise Exception("Environ append key '%s' value '%s' contains forbidden character '%s'" % (key, value, separator))
127
128         # check if the key is already in the environment
129         if key in self.environ:
130             value_list = self.environ[key].split(sep)
131             if not value in value_list:
132                 value_list.insert(0, value)
133             else:
134                 value_list.insert(0, value_list.pop(value_list.index(value)))
135             self.set(key, sep.join(value_list))
136         else:
137             self.set(key, value)
138
139     def prepend(self, key, value, sep=os.pathsep):
140         """\
141         Same as prepend_value but the value argument can be a list
142         
143         :param key str: the environment variable to prepend
144         :param value str or list: the value(s) to prepend to key
145         :param sep str: the separator string
146         """
147         if isinstance(value, list):
148             for v in reversed(value): # prepend list, first item at last to stay first
149                 self.prepend_value(key, v, sep)
150         else:
151             self.prepend_value(key, value, sep)
152
153     def is_defined(self, key):
154         """\
155         Check if the key exists in the environment
156         
157         :param key str: the environment variable to check
158         """
159         return key in self.environ.keys()
160
161     def set(self, key, value):
162         """\
163         Set the environment variable "key" to value "value"
164         
165         :param key str: the environment variable to set
166         :param value str: the value
167         """
168         self.environ[key] = self._expandvars(value)
169
170     def get(self, key):
171         """\
172         Get the value of the environment variable "key"
173         
174         :param key str: the environment variable
175         """
176         if key in self.environ:
177             return self.environ[key]
178         else:
179             return ""
180
181     def get_value(self, key):
182         """\
183         Get the value of the environment variable "key"
184         This method is added for API compatibility with FileEnviron class
185         
186         :param key str: the environment variable
187         """
188         return self.get(key)
189
190
191
192 class SalomeEnviron:
193     """\
194     Class to manage the environment of SALOME.
195     """
196     def __init__(self,
197                  cfg,
198                  environ,
199                  forBuild=False,
200                  for_package=None,
201                  enable_simple_env_script = True):
202         """\
203         Initialization.
204
205         :param cfg Config: the global config
206         :param environ Environ: the Environ instance where 
207                                 to store the environment variables
208         :param forBuild bool: If true, it is a launch environment, 
209                               else a build one
210         :param for_package str: If not None, produce a relative environment 
211                                 designed for a package. 
212         """
213         self.environ = environ
214         self.cfg = cfg
215         self.forBuild = forBuild
216         self.for_package = for_package
217         self.enable_simple_env_script = enable_simple_env_script
218         self.silent = False
219         self.has_python = False
220         self.__set_sorted_products_list()
221
222     def __repr__(self):
223         """easy almost exhaustive quick resume for debug print"""
224         res = {
225           "environ" : self.environ,
226           "forBuild" : self.forBuild,
227           "for_package" : self.for_package,
228         }
229         return "%s(\n%s\n)" % (self.__class__.__name__, PP.pformat(res))
230
231     def __set_sorted_products_list(self):
232         from compile import get_dependencies_graph, depth_first_topo_graph
233         all_products_infos = src.product.get_products_infos(
234                                  self.cfg.APPLICATION.products,
235                                  self.cfg)
236         
237         all_products_graph=get_dependencies_graph(all_products_infos, self.forBuild)
238         visited_nodes=[]
239         sorted_nodes=[]
240         for n in all_products_graph:
241             if n not in visited_nodes:
242                 visited_nodes,sorted_nodes=depth_first_topo_graph(
243                                                all_products_graph, 
244                                                n, 
245                                                visited_nodes,
246                                                sorted_nodes)
247         self.sorted_product_list=sorted_nodes
248
249
250     def append(self, key, value, sep=os.pathsep):
251         """\
252         append value to key using sep
253         
254         :param key str: the environment variable to append
255         :param value str: the value to append to key
256         :param sep str: the separator string
257         """
258         return self.environ.append(key, value, sep)
259
260     def prepend(self, key, value, sep=os.pathsep):
261         """\
262         prepend value to key using sep
263         
264         :param key str: the environment variable to prepend
265         :param value str: the value to prepend to key
266         :param sep str: the separator string
267         """
268         return self.environ.prepend(key, value, sep)
269
270     def is_defined(self, key):
271         """\
272         Check if the key exists in the environment
273         
274         :param key str: the environment variable to check
275         """
276         return self.environ.is_defined(key)
277
278     def get(self, key):
279         """\
280         Get the value of the environment variable "key"
281         
282         :param key str: the environment variable
283         """
284         return self.environ.get(key)
285
286     def get_value(self, key):
287         """\
288         Get the real value of the environment variable "key"
289         This method is added for API compatibility with FileEnviron class
290         
291         :param key str: the environment variable
292         """
293         if key in self.environ:
294             return self.environ[key]
295         else:
296             return ""
297
298     def set(self, key, value):
299         """\
300         Set the environment variable "key" to value "value"
301         
302         :param key str: the environment variable to set
303         :param value str: the value
304         """
305         # check if value needs to be evaluated
306         if value is not None and value.startswith("`") and value.endswith("`"):
307             res = subprocess.Popen("echo %s" % value,
308                                    shell=True,
309                                    stdout=subprocess.PIPE).communicate()
310             value = res[0].strip()
311
312         return self.environ.set(key, value)
313
314     def dump(self, out):
315         """\
316         Write the environment to out
317         
318         :param out file: the stream where to write the environment
319         """
320         for k in self.environ.environ.keys():
321             try:
322                 value = self.get(k)
323             except:
324                 value = "?"
325             out.write("%s=%s\n" % (k, value))
326
327     def add_line(self, nb_line):
328         """\
329         Add empty lines to the out stream (in case of file generation)
330         
331         :param nb_line int: the number of empty lines to add
332         """
333         if 'add_line' in dir(self.environ):
334             self.environ.add_line(nb_line)
335
336     def add_comment(self, comment):
337         """\
338         Add a commentary to the out stream (in case of file generation)
339         
340         :param comment str: the commentary to add
341         """
342         if 'add_comment' in dir(self.environ):
343             self.environ.add_comment(comment)
344
345     def add_warning(self, warning):
346         """\
347         Add a warning to the out stream (in case of file generation)
348         
349         :param warning str: the warning to add
350         """
351         if 'add_warning' in dir(self.environ):
352             self.environ.add_warning(warning)
353
354     def finish(self):
355         """\
356         Add a final instruction in the out file (in case of file generation)
357         
358         :param required bool: Do nothing if required is False
359         """
360         if 'finish' in dir(self.environ):
361             self.environ.add_line(1)
362             # what for ?
363             # self.environ.add_comment("clean all the path")
364             self.environ.finish()
365
366     def set_python_libdirs(self):
367         """Set some generic variables for python library paths"""
368         ver = self.get('PYTHON_VERSION')
369         self.set('PYTHON_LIBDIR', os.path.join('lib',
370                                                 'python' + ver,
371                                                 'site-packages'))
372         self.python_lib = self.get('PYTHON_LIBDIR')
373         self.has_python = True
374
375     def set_application_env(self, logger):
376         """\
377         Sets the environment defined in the APPLICATION file.
378         
379         :param logger Logger: The logger instance to display messages
380         """
381         
382         if self.for_package:
383            if src.architecture.is_windows():
384               self.set("PRODUCT_ROOT_DIR", "%out_dir_Path%")
385            else:
386               self.set("PRODUCT_ROOT_DIR", "out_dir_Path")
387
388         else:
389            self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR = src.pyconf.Reference(self.cfg, src.pyconf.DOLLAR, "workdir")
390
391         # these sensitive variables are reset to avoid bad environment interactions
392         self.add_line(1)
393         self.add_comment("reset these sensitive variables to avoid bad environment interactions")
394         self.add_comment("comment these to lines if you wish a different behaviour")
395         if not src.architecture.is_windows():
396            self.set("LD_LIBRARY_PATH", "")
397         self.set("PYTHONPATH", "")
398         self.add_line(1)
399
400         # Set the variables defined in the "environ" section
401         if 'environ' in self.cfg.APPLICATION:
402             # we write PRODUCT environment it in order to conform to 
403             # parseConfigFile.py
404             self.add_comment("PRODUCT environment") 
405             self.load_cfg_environment(self.cfg.APPLICATION.environ)
406             if self.forBuild and "build" in self.cfg.APPLICATION.environ:
407                 self.load_cfg_environment(self.cfg.APPLICATION.environ.build)
408             if not self.forBuild and "launch" in self.cfg.APPLICATION.environ:
409                 self.load_cfg_environment(self.cfg.APPLICATION.environ.launch)
410             self.add_line(1)
411
412
413     def set_salome_minimal_product_env(self, product_info, logger):
414         """\
415         Sets the minimal environment for a SALOME product.
416         xxx_ROOT_DIR and xxx_SRC_DIR
417         
418         :param product_info Config: The product description
419         :param logger Logger: The logger instance to display messages        
420         """
421         # set root dir
422         DBG.write("set_salome_minimal_product_env", product_info)
423         root_dir = product_info.name + "_ROOT_DIR"
424         if 'install_dir' in product_info and product_info.install_dir:
425             self.set(root_dir, product_info.install_dir)
426         elif not self.silent:
427             logger.write("  " + _("No install_dir for product %s\n") %
428                           product_info.name, 5)
429     
430         source_in_package = src.get_property_in_product_cfg(product_info,
431                                                            "sources_in_package")
432         if not self.for_package or source_in_package == "yes":
433             # set source dir, unless no source dir
434             if not src.product.product_is_fixed(product_info):
435                 src_dir = product_info.name + "_SRC_DIR"
436                 if not self.for_package:
437                     self.set(src_dir, product_info.source_dir)
438                 else:
439                     self.set(src_dir, os.path.join("out_dir_Path",
440                              "SOURCES",
441                              os.path.basename(product_info.source_dir)))
442
443     def expand_salome_modules(self, pi):
444         if 'component_name' in pi:
445             compo_name = pi.component_name
446         else:
447             compo_name = pi.name
448         self.append('SALOME_MODULES', compo_name, ',')
449         
450         
451     def set_salome_generic_product_env(self, pi):
452         """\
453         Sets the generic environment for a SALOME product.
454         
455         :param pi Config: The product description
456         """
457         # Construct XXX_ROOT_DIR
458         env_root_dir = self.get(pi.name + "_ROOT_DIR")
459         l_binpath_libpath = []
460         # create additional ROOT_DIR for CPP components
461         if 'component_name' in pi:
462             compo_name = pi.component_name
463             if compo_name + "CPP" == pi.name:
464                 compo_root_dir = compo_name + "_ROOT_DIR"
465                 envcompo_root_dir = os.path.join(
466                             self.cfg.TOOLS.common.install_root, compo_name )
467                 self.set(compo_root_dir ,  envcompo_root_dir)
468                 bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome')
469                 lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome')
470                 l_binpath_libpath.append( (bin_path, lib_path) )
471
472
473         if src.get_property_in_product_cfg(pi, "fhs"):
474             lib_path = os.path.join(env_root_dir, 'lib')
475             bin_path = os.path.join(env_root_dir, 'bin')
476             if self.has_python:
477             # if the application doesn't include python, we don't need these two lines
478                 pylib_path = os.path.join(env_root_dir, self.python_lib)
479         else:
480             lib_path = os.path.join(env_root_dir, 'lib', 'salome')
481             bin_path = os.path.join(env_root_dir, 'bin', 'salome')
482             if self.has_python:
483             # if the application doesn't include python, we don't need these two lines
484                 pylib_path = os.path.join(env_root_dir, self.python_lib, 'salome')
485
486         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
487         # PYTHONPATH
488         l_binpath_libpath.append( (bin_path, lib_path) )
489
490         for bin_path, lib_path in l_binpath_libpath:
491             if not self.forBuild:
492                 self.prepend('PATH', bin_path)
493                 if src.architecture.is_windows():
494                     self.prepend('PATH', lib_path)
495                 else :
496                     self.prepend('LD_LIBRARY_PATH', lib_path)
497
498             l = [ bin_path, lib_path ]
499             if not src.product.product_is_wheel(pi):
500                 if self.has_python:
501                     l.append(pylib_path)
502                 self.prepend('PYTHONPATH', l)
503
504     def set_cpp_env(self, product_info):
505         """\
506         Sets the generic environment for a SALOME cpp product.
507         
508         :param product_info Config: The product description
509         """
510         # Construct XXX_ROOT_DIR
511         env_root_dir = self.get(product_info.name + "_ROOT_DIR")
512         l_binpath_libpath = []
513
514         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
515         # PYTHONPATH
516         bin_path = os.path.join(env_root_dir, 'bin')
517         lib_path = os.path.join(env_root_dir, 'lib')
518         l_binpath_libpath.append( (bin_path, lib_path) )
519
520         for bin_path, lib_path in l_binpath_libpath:
521             if not self.forBuild:
522                 self.prepend('PATH', bin_path)
523                 if src.architecture.is_windows():
524                     self.prepend('PATH', lib_path)
525                 else :
526                     self.prepend('LD_LIBRARY_PATH', lib_path)
527
528             l = [ bin_path, lib_path ]
529             if self.has_python:
530                 l.append(os.path.join(env_root_dir, self.python_lib))
531             self.prepend('PYTHONPATH', l)
532
533     def load_cfg_environment(self, cfg_env):
534         """\
535         Loads environment defined in cfg_env 
536         
537         :param cfg_env Config: A config containing an environment    
538         """
539         # Loop on cfg_env values
540         for env_def in cfg_env:
541             val = cfg_env[env_def]
542             
543             # if it is env_script, do not do anything (reserved keyword)
544             if env_def == "env_script":
545                 continue
546             
547             # if it is a dict, do not do anything
548             if isinstance(val, src.pyconf.Mapping):
549                 continue
550
551             # if it is a list, loop on its values
552             if isinstance(val, src.pyconf.Sequence):
553                 # transform into list of strings
554                 l_val = []
555                 for item in val:
556                     l_val.append(item)
557                 val = l_val
558
559             # "_" means that the value must be prepended
560             if env_def.startswith("_"):
561                 # separator exception for PV_PLUGIN_PATH
562                 if env_def[1:] == 'PV_PLUGIN_PATH':
563                     self.prepend(env_def[1:], val, ';')
564                 else:
565                     self.prepend(env_def[1:], val)
566             elif env_def.endswith("_"):
567                 # separator exception for PV_PLUGIN_PATH
568                 if env_def[:-1] == 'PV_PLUGIN_PATH':
569                     self.append(env_def[:-1], val, ';')
570                 else:
571                     self.append(env_def[:-1], val)
572             else:
573                 self.set(env_def, val)
574
575     def set_a_product(self, product, logger):
576         """\
577         Sets the environment of a product. 
578         
579         :param product str: The product name
580         :param logger Logger: The logger instance to display messages
581         """
582
583         # Get the informations corresponding to the product
584         pi = src.product.get_product_config(self.cfg, product)
585         # skip compile time products at run time 
586         if not self.forBuild:
587             if src.product.product_is_compile_time(pi):
588                 return
589
590         # skip pip products when pip is activated and installation is done in python 
591         #if (src.appli_test_property(self.cfg,"pip", "yes") and 
592         #    src.product.product_test_property(pi,"pip", "yes") and
593         #    src.appli_test_property(self.cfg,"pip_install_dir", "python") ):
594         #        return
595
596         # skip mesa products (if any) at run time, 
597         # unless use_mesa property was activated
598         if not self.forBuild:
599             if not ("APPLICATION" in self.cfg  and
600                     "properties" in self.cfg.APPLICATION  and
601                     "use_mesa" in self.cfg.APPLICATION.properties  and
602                     self.cfg.APPLICATION.properties.use_mesa == "yes") :
603                 if ("properties" in pi and
604                     "is_mesa" in pi.properties  and
605                     pi.properties.is_mesa == "yes") :
606                     logger.write(_("Skip mesa product %s\n") % pi.name, 4)
607                     return
608                
609         
610         if self.for_package:
611             prod_base_name=os.path.basename(pi.install_dir)
612             if prod_base_name.startswith("config"):
613                 # case of a products installed in base. We remove "config-i"
614                 prod_base_name=os.path.basename(os.path.dirname(pi.install_dir))
615             pi.install_dir = os.path.join(
616                                  "out_dir_Path",
617                                  self.for_package,
618                                  prod_base_name)
619
620         if not self.silent:
621             logger.write(_("Setting environment for %s\n") % product, 4)
622
623         self.add_line(1)
624         self.add_comment('setting environ for ' + product)
625             
626         # Do not define environment if the product is native
627         if src.product.product_is_native(pi):
628             if src.product.product_has_env_script(pi):
629                 self.run_env_script(pi, native=True)
630             return
631                
632         # Set an additional environment for SALOME products
633         if src.product.product_is_salome(pi):
634             # set environment using definition of the product
635             self.set_salome_minimal_product_env(pi, logger)
636             self.set_salome_generic_product_env(pi)
637            
638         
639         # Expand SALOME_MODULES variable for products which have a salome gui
640         if src.product.product_has_salome_gui(pi):
641             self.expand_salome_modules(pi)
642
643         # use variable LICENCE_FILE to communicate the licence file name to the environment script
644         licence_file_name = src.product.product_has_licence(pi, self.cfg.PATHS.LICENCEPATH)
645         if licence_file_name:
646             logger.write("licence file found for product %s : %s\n" % (pi.name, licence_file_name), 5) 
647             self.set("LICENCE_FILE", licence_file_name)
648
649         if src.product.product_is_cpp(pi):
650             # set a specific environment for cpp modules
651             self.set_salome_minimal_product_env(pi, logger)
652             self.set_cpp_env(pi)
653             
654             if src.product.product_is_generated(pi):
655                 if "component_name" in pi:
656                     # hack the source and install directories in order to point  
657                     # on the generated product source install directories
658                     install_dir_save = pi.install_dir
659                     source_dir_save = pi.source_dir
660                     name_save = pi.name
661                     pi.install_dir = os.path.join(self.cfg.APPLICATION.workdir,
662                                                   self.cfg.INTERNAL.config.install_dir,
663                                                   pi.component_name)
664                     if self.for_package:
665                         pi.install_dir = os.path.join("out_dir_Path",
666                                                       self.for_package,
667                                                       pi.component_name)
668                     pi.source_dir = os.path.join(self.cfg.APPLICATION.workdir,
669                                                   "GENERATED",
670                                                   pi.component_name)
671                     pi.name = pi.component_name
672                     self.set_salome_minimal_product_env(pi, logger)
673                     self.set_salome_generic_product_env(pi)
674                     
675                     # Put original values
676                     pi.install_dir = install_dir_save
677                     pi.source_dir = source_dir_save
678                     pi.name = name_save
679         
680         # Put the environment define in the configuration of the product
681         if "environ" in pi:
682             self.load_cfg_environment(pi.environ)
683             if self.forBuild and "build" in pi.environ:
684                 self.load_cfg_environment(pi.environ.build)
685             if not self.forBuild and "launch" in pi.environ:
686                 self.load_cfg_environment(pi.environ.launch)
687             # if product_info defines a env_scripts, load it
688             if 'env_script' in pi.environ:
689                 self.run_env_script(pi, logger)
690
691         
692             
693
694     def run_env_script(self, product_info, logger=None, native=False):
695         """\
696         Runs an environment script. 
697         
698         :param product_info Config: The product description
699         :param logger Logger: The logger instance to display messages
700         :param native Boolean: if True load set_native_env instead of set_env
701         """
702         env_script = product_info.environ.env_script
703         # Check that the script exists
704         if not os.path.exists(env_script):
705             raise src.SatException(_("Environment script not found: %s") % 
706                                    env_script)
707
708         if not self.silent and logger is not None:
709             logger.write("  ** load %s\n" % env_script, 4)
710
711         # import the script and run the set_env function
712         try:
713             import imp
714             pyproduct = imp.load_source(product_info.name + "_env_script",
715                                         env_script)
716             if not native:
717                 if self.forBuild and "set_env_build" in dir(pyproduct):
718                     pyproduct.set_env_build(self,
719                                             product_info.install_dir,
720                                             product_info.version)
721                 elif (not self.forBuild) and "set_env_launch" in dir(pyproduct):
722                     pyproduct.set_env_launch(self,
723                                             product_info.install_dir,
724                                             product_info.version)
725                 else:
726                     # at least this one is mandatory,
727                     # if set_env_build and set_env_build are not defined
728                     pyproduct.set_env(self,
729                                       product_info.install_dir,
730                                       product_info.version)
731             else:
732                 # not mandatory, if set_nativ_env not defined, we do nothing
733                 if "set_nativ_env" in dir(pyproduct):
734                     pyproduct.set_nativ_env(self)
735         except:
736             __, exceptionValue, exceptionTraceback = sys.exc_info()
737             print(exceptionValue)
738             import traceback
739             traceback.print_tb(exceptionTraceback)
740             traceback.print_exc()
741
742     def set_products(self, logger, src_root=None):
743         """\
744         Sets the environment for all the products. 
745         
746         :param logger Logger: The logger instance to display messages
747         :param src_root src: the application working directory
748         """
749         self.add_line(1)
750         self.add_comment('setting environ for all products')
751
752         # Make sure that the python lib dirs are set after python
753         if "Python" in self.sorted_product_list:
754             self.set_a_product("Python", logger)
755             self.set_python_libdirs()
756
757         # The loop on the products
758         for product in self.sorted_product_list:
759             if product == "Python":
760                 continue
761             self.set_a_product(product, logger)
762  
763     def set_full_environ(self, logger, env_info):
764         """\
765         Sets the full environment for products 
766         specified in env_info dictionary. 
767         
768         :param logger Logger: The logger instance to display messages
769         :param env_info list: the list of products
770         """
771         DBG.write("set_full_environ for", env_info)
772         # DBG.write("set_full_environ config", self.cfg.APPLICATION.environ, True)
773         # set product environ
774         self.set_application_env(logger)
775
776         # use the sorted list of all products to sort the list of products 
777         # we have to set
778         sorted_product_list=[]
779         for n in self.sorted_product_list:
780             if n in env_info:
781                 sorted_product_list.append(n)
782
783         if "Python" in sorted_product_list:
784             self.set_a_product("Python", logger)
785             self.set_python_libdirs()
786
787         # set products
788         for product in sorted_product_list:
789             if product == "Python":
790                 continue
791             self.set_a_product(product, logger)
792
793 class FileEnvWriter:
794     """\
795     Class to dump the environment to a file.
796     """
797     def __init__(self, config, logger, out_dir, src_root, env_info=None):
798         """\
799         Initialization.
800
801         :param cfg Config: the global config
802         :param logger Logger: The logger instance to display messages
803         :param out_dir str: The directory path where t put the output files
804         :param src_root str: The application working directory
805         :param env_info str: The list of products to add in the files.
806         """
807         self.config = config
808         self.logger = logger
809         self.out_dir = out_dir
810         self.src_root= src_root
811         self.silent = True
812         self.env_info = env_info
813
814     def write_tcl_files(self,
815                         forBuild, 
816                         shell, 
817                         for_package = None,
818                         no_path_init=False,
819                         additional_env = {}):
820         """\
821         Create tcl environment files for environment module.
822         
823         :param forBuild bool: if true, the build environment
824         :param shell str: the type of file wanted (.sh, .bat)
825         :param for_package bool: if true do specific stuff for required for packages
826         :param no_path_init bool: if true generate a environ file that do not reinitialise paths
827         :param additional_env dict: contains sat_ prefixed variables to help the génération, 
828                                     and also variables to add in the environment.
829         :return: The path to the generated file
830         :rtype: str
831         """
832
833         # get the products informations
834         all_products=self.config.APPLICATION.products
835         products_infos = src.product.get_products_infos(all_products, self.config) 
836
837         # set a global environment (we need it to resolve variable references
838         # between dependent products
839         global_environ = src.environment.SalomeEnviron(self.config,
840                                   src.environment.Environ(additional_env),
841                                   False)
842         global_environ.set_products(self.logger)
843         
844         # The loop on the products
845         for product in all_products:
846             # create one file per product
847             pi = src.product.get_product_config(self.config, product)
848             if "base" not in pi:  # we write tcl files only for products in base
849                 continue
850
851             # get the global environment, and complete it with sat_ prefixed 
852             # prefixed variables which are used to transfer info to 
853             # TclFileEnviron class  
854             product_env = copy.deepcopy(global_environ.environ)
855             product_env.environ["sat_product_name"] = pi.name
856             product_env.environ["sat_product_version"] = pi.version
857             product_env.environ["sat_product_base_path"] = src.get_base_path(self.config)
858             product_env.environ["sat_product_base_name"] = pi.base
859    
860             # store infos in sat_product_load_depend to set dependencies in tcl file
861             sat_product_load_depend=""
862             for p_name,p_info in products_infos:
863                 if p_name in pi.depend:
864                     sat_product_load_depend+="module load %s/%s/%s;" % (pi.base, 
865                                                                         p_info.name, 
866                                                                         p_info.version)
867             if len(sat_product_load_depend)>0:
868                 # if there are dependencies, store the module to load (get rid of trailing ;)
869                 product_env.environ["sat_product_load_depend"]=sat_product_load_depend[0:-1]
870
871
872             env_file_name = os.path.join(product_env.environ["sat_product_base_path"], 
873                                          "modulefiles", 
874                                          product_env.environ["sat_product_base_name"],
875                                          product_env.environ["sat_product_name"], 
876                                          product_env.environ["sat_product_version"])
877             prod_dir_name=os.path.dirname(env_file_name)
878             if not os.path.isdir(prod_dir_name):
879                 os.makedirs(prod_dir_name)
880
881             env_file = open(env_file_name, "w")
882             file_environ = src.fileEnviron.get_file_environ(env_file,
883                                            "tcl", product_env)
884             env = SalomeEnviron(self.config, 
885                                 file_environ, 
886                                 False, 
887                                 for_package=for_package)
888             if "Python" in pi.depend:
889                 # short cut, env.python_lib is required by set_a_product for salome modules
890                 env.has_python="True"
891                 env.python_lib=global_environ.get("PYTHON_LIBDIR")
892             env.set_a_product(product, self.logger)
893             env_file.close()
894             if not self.silent:
895                 self.logger.write(_("    Create tcl module environment file %s\n") % 
896                                   src.printcolors.printcLabel(env_file_name), 3)
897
898
899     def write_env_file(self,
900                        filename,
901                        forBuild, 
902                        shell, 
903                        for_package = None,
904                        no_path_init=False,
905                        additional_env = {}):
906         """\
907         Create an environment file.
908         
909         :param filename str: the file path
910         :param forBuild bool: if true, the build environment
911         :param shell str: the type of file wanted (.sh, .bat)
912         :param for_package bool: if true do specific stuff for required for packages
913         :param no_path_init bool: if true generate a environ file that do not reinitialise paths
914         :param additional_env dict: contains sat_ prefixed variables to help the génération, 
915                                     and also variables to add in the environment.
916         :return: The path to the generated file
917         :rtype: str
918         """
919         if not self.silent:
920             self.logger.write(_("Create environment file %s\n") % 
921                               src.printcolors.printcLabel(filename), 3)
922         # create then env object
923         env_file = open(os.path.join(self.out_dir, filename), "w")
924
925         # we duplicate additional_env, and transmit it to fileEnviron, which will use its sat_ prefixed variables.
926         # the other variables of additional_env are added to the environement file at the end of this function.
927         salome_env = copy.deepcopy(additional_env)
928         file_environ = src.fileEnviron.get_file_environ(env_file,
929                                                shell,
930                                                src.environment.Environ(salome_env))
931         if no_path_init:
932             # specify we don't want to reinitialise paths
933             # path will keep the inherited value, which will be appended with new values.
934             file_environ.set_no_init_path()
935
936         env = SalomeEnviron(self.config, 
937                             file_environ, 
938                             forBuild, 
939                             for_package=for_package)
940
941         env.silent = self.silent
942
943         # Set the environment
944         if self.env_info is not None:
945             env.set_full_environ(self.logger, self.env_info)
946         else:
947             # set env from the APPLICATION
948             env.set_application_env(self.logger)
949             # set the products
950             env.set_products(self.logger,
951                             src_root=self.src_root)
952         # Add the additional environment if it is not empty
953         if len(additional_env) != 0:
954             env.add_line(1)
955             env.add_comment("[APPLI variables]")
956             for variable in additional_env:
957                 if not variable.startswith("sat_"):
958                     # by convention variables starting with sat_ are used to transfer information, 
959                     # not to be written in env
960                     env.set(variable, additional_env[variable])
961
962         # finalise the writing and close the file
963         env.finish()
964         env_file.close()
965
966         return env_file.name
967    
968
969 class Shell:
970     """\
971     Definition of a Shell.
972     """
973     def __init__(self, name, extension):
974         """\
975         Initialization.
976
977         :param name str: the shell name
978         :param extension str: the shell extension
979         """
980         self.name = name
981         self.extension = extension
982
983 def load_environment(config, build, logger):
984     """\
985     Loads the environment (used to run the tests, for example).
986     
987     :param config Config: the global config
988     :param build bool: build environement if True
989     :param logger Logger: The logger instance to display messages
990     """
991     environ = SalomeEnviron(config, Environ(os.environ), build)
992     environ.set_application_env(logger)
993     environ.set_products(logger)