]> SALOME platform Git repositories - tools/sat.git/blob - src/environment.py
Salome HOME
33623c2e29b7984e39e096c00b3a46b67d7fad72
[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         all_products_infos = src.product.get_products_infos(
233                                  self.cfg.APPLICATION.products,
234                                  self.cfg)
235         
236         from compile import get_dependencies_graph,depth_first_topo_graph
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         self.all_products_graph=all_products_graph
249
250
251     def append(self, key, value, sep=os.pathsep):
252         """\
253         append value to key using sep
254         
255         :param key str: the environment variable to append
256         :param value str: the value to append to key
257         :param sep str: the separator string
258         """
259         return self.environ.append(key, value, sep)
260
261     def prepend(self, key, value, sep=os.pathsep):
262         """\
263         prepend value to key using sep
264         
265         :param key str: the environment variable to prepend
266         :param value str: the value to prepend to key
267         :param sep str: the separator string
268         """
269         return self.environ.prepend(key, value, sep)
270
271     def is_defined(self, key):
272         """\
273         Check if the key exists in the environment
274         
275         :param key str: the environment variable to check
276         """
277         return self.environ.is_defined(key)
278
279     def get(self, key):
280         """\
281         Get the value of the environment variable "key"
282         
283         :param key str: the environment variable
284         """
285         return self.environ.get(key)
286
287     def get_value(self, key):
288         """\
289         Get the real value of the environment variable "key"
290         This method is added for API compatibility with FileEnviron class
291         
292         :param key str: the environment variable
293         """
294         if key in self.environ:
295             return self.environ[key]
296         else:
297             return ""
298
299     def set(self, key, value):
300         """\
301         Set the environment variable "key" to value "value"
302         
303         :param key str: the environment variable to set
304         :param value str: the value
305         """
306         # check if value needs to be evaluated
307         if value is not None and value.startswith("`") and value.endswith("`"):
308             res = subprocess.Popen("echo %s" % value,
309                                    shell=True,
310                                    stdout=subprocess.PIPE).communicate()
311             value = res[0].strip()
312
313         return self.environ.set(key, value)
314
315     def dump(self, out):
316         """\
317         Write the environment to out
318         
319         :param out file: the stream where to write the environment
320         """
321         for k in self.environ.environ.keys():
322             try:
323                 value = self.get(k)
324             except:
325                 value = "?"
326             out.write("%s=%s\n" % (k, value))
327
328     def add_line(self, nb_line):
329         """\
330         Add empty lines to the out stream (in case of file generation)
331         
332         :param nb_line int: the number of empty lines to add
333         """
334         if 'add_line' in dir(self.environ):
335             self.environ.add_line(nb_line)
336
337     def add_comment(self, comment):
338         """\
339         Add a commentary to the out stream (in case of file generation)
340         
341         :param comment str: the commentary to add
342         """
343         if 'add_comment' in dir(self.environ):
344             self.environ.add_comment(comment)
345
346     def add_warning(self, warning):
347         """\
348         Add a warning to the out stream (in case of file generation)
349         
350         :param warning str: the warning to add
351         """
352         if 'add_warning' in dir(self.environ):
353             self.environ.add_warning(warning)
354
355     def finish(self):
356         """\
357         Add a final instruction in the out file (in case of file generation)
358         
359         :param required bool: Do nothing if required is False
360         """
361         if 'finish' in dir(self.environ):
362             self.environ.add_line(1)
363             # what for ?
364             # self.environ.add_comment("clean all the path")
365             self.environ.finish()
366
367     def set_python_libdirs(self):
368         """Set some generic variables for python library paths"""
369         ver = self.get('PYTHON_VERSION')
370         self.set('PYTHON_LIBDIR', os.path.join('lib',
371                                                 'python' + ver,
372                                                 'site-packages'))
373         self.python_lib = self.get('PYTHON_LIBDIR')
374         self.has_python = True
375
376     def set_application_env(self, logger):
377         """\
378         Sets the environment defined in the APPLICATION file.
379         
380         :param logger Logger: The logger instance to display messages
381         """
382         
383         if self.for_package:
384            if src.architecture.is_windows():
385               self.set("PRODUCT_ROOT_DIR", "%out_dir_Path%")
386            else:
387               self.set("PRODUCT_ROOT_DIR", "out_dir_Path")
388
389         else:
390            self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR = src.pyconf.Reference(self.cfg, src.pyconf.DOLLAR, "workdir")
391
392
393         # Set the variables defined in the "environ" section
394         if 'environ' in self.cfg.APPLICATION:
395             # we write PRODUCT environment it in order to conform to 
396             # parseConfigFile.py
397             self.add_comment("PRODUCT environment") 
398             self.load_cfg_environment(self.cfg.APPLICATION.environ)
399             if self.forBuild and "build" in self.cfg.APPLICATION.environ:
400                 self.load_cfg_environment(self.cfg.APPLICATION.environ.build)
401             if not self.forBuild and "launch" in self.cfg.APPLICATION.environ:
402                 self.load_cfg_environment(self.cfg.APPLICATION.environ.launch)
403             self.add_line(1)
404
405
406     def set_salome_minimal_product_env(self, product_info, logger):
407         """\
408         Sets the minimal environment for a SALOME product.
409         xxx_ROOT_DIR and xxx_SRC_DIR
410         
411         :param product_info Config: The product description
412         :param logger Logger: The logger instance to display messages        
413         """
414         DBG.write("set_salome_minimal_product_env", product_info)
415
416         # set root dir
417         root_dir = product_info.name + "_ROOT_DIR"
418         
419         if src.product.product_is_configuration(product_info):
420             # configuration modules are not installed, root_dir points at source dir
421             if not self.for_package:
422                 self.set(root_dir, product_info.source_dir)
423             else:
424                 self.set(root_dir, os.path.join("out_dir_Path",
425                          "SOURCES",
426                          os.path.basename(product_info.source_dir)))
427         elif 'install_dir' in product_info and product_info.install_dir:
428             self.set(root_dir, product_info.install_dir)
429         elif not self.silent:
430             logger.write("  " + _("No install_dir for product %s\n") %
431                           product_info.name, 5)
432     
433         source_in_package = src.get_property_in_product_cfg(product_info,
434                                                            "sources_in_package")
435         if not self.for_package or source_in_package == "yes":
436             # set source dir, unless no source dir
437             if not src.product.product_is_fixed(product_info):
438                 src_dir = product_info.name + "_SRC_DIR"
439                 if not self.for_package:
440                     self.set(src_dir, product_info.source_dir)
441                 else:
442                     self.set(src_dir, os.path.join("out_dir_Path",
443                              "SOURCES",
444                              os.path.basename(product_info.source_dir)))
445
446     def expand_salome_modules(self, pi):
447         if 'component_name' in pi:
448             compo_name = pi.component_name
449         else:
450             compo_name = pi.name
451         self.append('SALOME_MODULES', compo_name, ',')
452         
453         
454     def set_salome_generic_product_env(self, pi):
455         """\
456         Sets the generic environment for a SALOME product.
457         
458         :param pi Config: The product description
459         """
460         if src.product.product_is_configuration(pi):
461             # configuration modules are not installed and should not be set like others
462             return
463
464         # Construct XXX_ROOT_DIR
465         env_root_dir = self.get(pi.name + "_ROOT_DIR")
466         l_binpath_libpath = []
467         # create additional ROOT_DIR for CPP components
468         if 'component_name' in pi:
469             compo_name = pi.component_name
470             if compo_name + "CPP" == pi.name:
471                 compo_root_dir = compo_name + "_ROOT_DIR"
472                 envcompo_root_dir = os.path.join(
473                             self.cfg.TOOLS.common.install_root, compo_name )
474                 self.set(compo_root_dir ,  envcompo_root_dir)
475                 bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome')
476                 lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome')
477                 l_binpath_libpath.append( (bin_path, lib_path) )
478
479
480         if src.get_property_in_product_cfg(pi, "fhs"):
481             lib_path = os.path.join(env_root_dir, 'lib')
482             bin_path = os.path.join(env_root_dir, 'bin')
483             if self.has_python:
484             # if the application doesn't include python, we don't need these two lines
485                 pylib_path = os.path.join(env_root_dir, self.python_lib)
486         else:
487             lib_path = os.path.join(env_root_dir, 'lib', 'salome')
488             bin_path = os.path.join(env_root_dir, 'bin', 'salome')
489             if self.has_python:
490             # if the application doesn't include python, we don't need these two lines
491                 pylib_path = os.path.join(env_root_dir, self.python_lib, 'salome')
492
493         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
494         # PYTHONPATH
495         l_binpath_libpath.append( (bin_path, lib_path) )
496
497         for bin_path, lib_path in l_binpath_libpath:
498             if not self.forBuild:
499                 self.prepend('PATH', bin_path)
500                 if src.architecture.is_windows():
501                     self.prepend('PATH', lib_path)
502                 else :
503                     self.prepend('LD_LIBRARY_PATH', lib_path)
504
505             l = [ bin_path, lib_path ]
506             if not src.product.product_is_wheel(pi):
507                 if self.has_python:
508                     l.append(pylib_path)
509                 self.prepend('PYTHONPATH', l)
510
511     def set_cpp_env(self, product_info):
512         """\
513         Sets the generic environment for a SALOME cpp product.
514         
515         :param product_info Config: The product description
516         """
517         # Construct XXX_ROOT_DIR
518         env_root_dir = self.get(product_info.name + "_ROOT_DIR")
519         l_binpath_libpath = []
520
521         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
522         # PYTHONPATH
523         bin_path = os.path.join(env_root_dir, 'bin')
524         lib_path = os.path.join(env_root_dir, 'lib')
525         l_binpath_libpath.append( (bin_path, lib_path) )
526
527         for bin_path, lib_path in l_binpath_libpath:
528             if not self.forBuild:
529                 self.prepend('PATH', bin_path)
530                 if src.architecture.is_windows():
531                     self.prepend('PATH', lib_path)
532                 else :
533                     self.prepend('LD_LIBRARY_PATH', lib_path)
534
535             l = [ bin_path, lib_path ]
536             if self.has_python:
537                 l.append(os.path.join(env_root_dir, self.python_lib))
538             self.prepend('PYTHONPATH', l)
539
540     def load_cfg_environment(self, cfg_env):
541         """\
542         Loads environment defined in cfg_env 
543         
544         :param cfg_env Config: A config containing an environment    
545         """
546         # Loop on cfg_env values
547         for env_def in cfg_env:
548             val = cfg_env[env_def]
549             
550             # if it is env_script, do not do anything (reserved keyword)
551             if env_def == "env_script":
552                 continue
553             
554             # if it is a dict, do not do anything
555             if isinstance(val, src.pyconf.Mapping):
556                 continue
557
558             # if it is a list, loop on its values
559             if isinstance(val, src.pyconf.Sequence):
560                 # transform into list of strings
561                 l_val = []
562                 for item in val:
563                     l_val.append(item)
564                 val = l_val
565
566             # "_" means that the value must be prepended
567             if env_def.startswith("_"):
568                 # separator exception for PV_PLUGIN_PATH
569                 if env_def[1:] == 'PV_PLUGIN_PATH':
570                     self.prepend(env_def[1:], val, ';')
571                 else:
572                     self.prepend(env_def[1:], val)
573             elif env_def.endswith("_"):
574                 # separator exception for PV_PLUGIN_PATH
575                 if env_def[:-1] == 'PV_PLUGIN_PATH':
576                     self.append(env_def[:-1], val, ';')
577                 else:
578                     self.append(env_def[:-1], val)
579             else:
580                 self.set(env_def, val)
581
582     def set_a_product(self, product, logger):
583         """\
584         Sets the environment of a product. 
585         
586         :param product str: The product name
587         :param logger Logger: The logger instance to display messages
588         """
589
590         # Get the informations corresponding to the product
591         pi = src.product.get_product_config(self.cfg, product)
592         # skip compile time products at run time 
593         if not self.forBuild:
594             if src.product.product_is_compile_time(pi):
595                 return
596         else:
597             if src.product.product_is_native(pi) :
598                 self.set("SAT_%s_IS_NATIVE"%pi.name, "1")
599                 
600
601         # skip pip products when pip is activated and installation is done in python 
602         #if (src.appli_test_property(self.cfg,"pip", "yes") and 
603         #    src.product.product_test_property(pi,"pip", "yes") and
604         #    src.appli_test_property(self.cfg,"pip_install_dir", "python") ):
605         #        return
606
607         # skip product if git server misses non opensource products
608         is_not_prod_opensource       = src.product.product_is_not_opensource(pi)
609         git_server= src.get_git_server(self.cfg, logger)
610         has_git_server_non_opensource = src.check_git_server_has_non_opensource( self.cfg, git_server)
611         if has_git_server_non_opensource and is_not_prod_opensource:
612             logger.warning("%s is a closed-source software and is not available on %s" % (pi.name, git_server))
613             return
614
615         # skip mesa products (if any) at run time, 
616         # unless use_mesa property was activated
617         if not self.forBuild:
618             if not ("APPLICATION" in self.cfg  and
619                     "properties" in self.cfg.APPLICATION  and
620                     "use_mesa" in self.cfg.APPLICATION.properties  and
621                     self.cfg.APPLICATION.properties.use_mesa == "yes") :
622                 if ("properties" in pi and
623                     "is_mesa" in pi.properties  and
624                     pi.properties.is_mesa == "yes") :
625                     logger.write(_("Skip mesa product %s\n") % pi.name, 4)
626                     return
627                
628         
629         if self.for_package:
630             prod_base_name=os.path.basename(pi.install_dir)
631             if prod_base_name.startswith("config"):
632                 # case of a products installed in base. We remove "config-i"
633                 prod_base_name=os.path.basename(os.path.dirname(pi.install_dir))
634             pi.install_dir = os.path.join(
635                                  "out_dir_Path",
636                                  self.for_package,
637                                  prod_base_name)
638
639         if not self.silent:
640             logger.write(_("Setting environment for %s\n") % product, 4)
641
642         self.add_line(1)
643         self.add_comment('setting environ for ' + product)
644             
645         # Do not define environment if the product is native
646         if src.product.product_is_native(pi):
647             if src.product.product_has_env_script(pi):
648                 self.run_env_script(pi, native=True)
649             return
650                
651         # Set an additional environment for SALOME products
652         if src.product.product_is_salome(pi):
653             # set environment using definition of the product
654             self.set_salome_minimal_product_env(pi, logger)
655             self.set_salome_generic_product_env(pi)
656            
657         
658         # Expand SALOME_MODULES variable for products which have a salome gui
659         if src.product.product_has_salome_gui(pi):
660             self.expand_salome_modules(pi)
661
662         # use variable LICENCE_FILE to communicate the licence file name to the environment script
663         licence_file_name = src.product.product_has_licence(pi, self.cfg.PATHS.LICENCEPATH)
664         if licence_file_name:
665             logger.write("licence file found for product %s : %s\n" % (pi.name, licence_file_name), 5) 
666             self.set("LICENCE_FILE", licence_file_name)
667
668         if src.product.product_is_cpp(pi):
669             # set a specific environment for cpp modules
670             self.set_salome_minimal_product_env(pi, logger)
671             self.set_cpp_env(pi)
672             
673             if src.product.product_is_generated(pi):
674                 if "component_name" in pi:
675                     # hack the source and install directories in order to point  
676                     # on the generated product source install directories
677                     install_dir_save = pi.install_dir
678                     source_dir_save = pi.source_dir
679                     name_save = pi.name
680                     pi.install_dir = os.path.join(self.cfg.APPLICATION.workdir,
681                                                   self.cfg.INTERNAL.config.install_dir,
682                                                   pi.component_name)
683                     if self.for_package:
684                         pi.install_dir = os.path.join("out_dir_Path",
685                                                       self.for_package,
686                                                       pi.component_name)
687                     pi.source_dir = os.path.join(self.cfg.APPLICATION.workdir,
688                                                   "GENERATED",
689                                                   pi.component_name)
690                     pi.name = pi.component_name
691                     self.set_salome_minimal_product_env(pi, logger)
692                     self.set_salome_generic_product_env(pi)
693                     
694                     # Put original values
695                     pi.install_dir = install_dir_save
696                     pi.source_dir = source_dir_save
697                     pi.name = name_save
698         
699         # Put the environment define in the configuration of the product
700         if "environ" in pi:
701             self.load_cfg_environment(pi.environ)
702             if self.forBuild and "build" in pi.environ:
703                 self.load_cfg_environment(pi.environ.build)
704             if not self.forBuild and "launch" in pi.environ:
705                 self.load_cfg_environment(pi.environ.launch)
706             # if product_info defines a env_scripts, load it
707             if 'env_script' in pi.environ:
708                 self.run_env_script(pi, logger)
709
710         
711             
712
713     def run_env_script(self, product_info, logger=None, native=False):
714         """\
715         Runs an environment script. 
716         
717         :param product_info Config: The product description
718         :param logger Logger: The logger instance to display messages
719         :param native Boolean: if True load set_native_env instead of set_env
720         """
721         env_script = product_info.environ.env_script
722         # Check that the script exists
723         if not os.path.exists(env_script):
724             raise src.SatException(_("Environment script not found: %s") % 
725                                    env_script)
726
727         if not self.silent and logger is not None:
728             logger.write("  ** load %s\n" % env_script, 4)
729
730         # import the script and run the set_env function
731         try:
732             import imp
733             pyproduct = imp.load_source(product_info.name + "_env_script",
734                                         env_script)
735             if not native:
736                 if self.forBuild and "set_env_build" in dir(pyproduct):
737                     pyproduct.set_env_build(self,
738                                             product_info.install_dir,
739                                             product_info.version)
740                 elif (not self.forBuild) and "set_env_launch" in dir(pyproduct):
741                     pyproduct.set_env_launch(self,
742                                             product_info.install_dir,
743                                             product_info.version)
744                 else:
745                     # at least this one is mandatory,
746                     # if set_env_build and set_env_build are not defined
747                     pyproduct.set_env(self,
748                                       product_info.install_dir,
749                                       product_info.version)
750             else:
751                 # not mandatory, if set_nativ_env not defined, we do nothing
752                 if "set_nativ_env" in dir(pyproduct):
753                     pyproduct.set_nativ_env(self)
754         except:
755             __, exceptionValue, exceptionTraceback = sys.exc_info()
756             print(exceptionValue)
757             import traceback
758             traceback.print_tb(exceptionTraceback)
759             traceback.print_exc()
760
761     def set_products(self, logger, src_root=None):
762         """\
763         Sets the environment for all the products. 
764         
765         :param logger Logger: The logger instance to display messages
766         :param src_root src: the application working directory
767         """
768         self.add_line(1)
769         self.add_comment('setting environ for all products')
770
771         # Make sure that the python lib dirs are set after python
772         if "Python" in self.sorted_product_list:
773             self.set_a_product("Python", logger)
774             self.set_python_libdirs()
775
776         # The loop on the products
777         for product in self.sorted_product_list:
778             if product == "Python":
779                 continue
780             self.set_a_product(product, logger)
781  
782     def set_full_environ(self, logger, env_info):
783         """\
784         Sets the full environment for products, with their dependencies 
785         specified in env_info dictionary. 
786         
787         :param logger Logger: The logger instance to display messages
788         :param env_info list: the list of products
789         """
790         DBG.write("set_full_environ for", env_info)
791         # DBG.write("set_full_environ config", self.cfg.APPLICATION.environ, True)
792         # set product environ
793         self.set_application_env(logger)
794
795         # use the sorted list of all products to sort the list of products 
796         # we have to set
797         visited=[]
798         from compile import depth_search_graph # to get the dependencies
799         for p_name in env_info:
800             visited=depth_search_graph(self.all_products_graph, p_name, visited)
801         sorted_product_list=[]
802         for n in self.sorted_product_list:
803             if n in visited:
804                 sorted_product_list.append(n)
805
806         if "Python" in sorted_product_list:
807             self.set_a_product("Python", logger)
808             self.set_python_libdirs()
809
810         # set products
811         for product in sorted_product_list:
812             if product == "Python":
813                 continue
814             self.set_a_product(product, logger)
815
816 class FileEnvWriter:
817     """\
818     Class to dump the environment to a file.
819     """
820     def __init__(self, config, logger, out_dir, src_root, env_info=None):
821         """\
822         Initialization.
823
824         :param cfg Config: the global config
825         :param logger Logger: The logger instance to display messages
826         :param out_dir str: The directory path where t put the output files
827         :param src_root str: The application working directory
828         :param env_info str: The list of products to add in the files.
829         """
830         self.config = config
831         self.logger = logger
832         self.out_dir = out_dir
833         self.src_root= src_root
834         self.silent = True
835         self.env_info = env_info
836
837     def write_tcl_files(self,
838                         forBuild, 
839                         shell, 
840                         for_package = None,
841                         no_path_init=False,
842                         additional_env = {}):
843         """\
844         Create tcl environment files for environment module.
845         
846         :param forBuild bool: if true, the build environment
847         :param shell str: the type of file wanted (.sh, .bat)
848         :param for_package bool: if true do specific stuff for required for packages
849         :param no_path_init bool: if true generate a environ file that do not reinitialise paths
850         :param additional_env dict: contains sat_ prefixed variables to help the génération, 
851                                     and also variables to add in the environment.
852         :return: The path to the generated file
853         :rtype: str
854         """
855
856         # get the products informations
857         all_products=self.config.APPLICATION.products
858         products_infos = src.product.get_products_infos(all_products, self.config) 
859
860         # set a global environment (we need it to resolve variable references
861         # between dependent products
862         global_environ = src.environment.SalomeEnviron(self.config,
863                                   src.environment.Environ(additional_env),
864                                   False)
865         global_environ.set_products(self.logger)
866         
867         # The loop on the products
868         for product in all_products:
869             # create one file per product
870             pi = src.product.get_product_config(self.config, product)
871             if "base" not in pi:  # we write tcl files only for products in base
872                 continue
873
874             # get the global environment, and complete it with sat_ prefixed 
875             # prefixed variables which are used to transfer info to 
876             # TclFileEnviron class  
877             product_env = copy.deepcopy(global_environ.environ)
878             product_env.environ["sat_product_name"] = pi.name
879             product_env.environ["sat_product_version"] = pi.version
880             product_env.environ["sat_product_base_path"] = src.get_base_path(self.config)
881             product_env.environ["sat_product_base_name"] = pi.base
882    
883             # store infos in sat_product_load_depend to set dependencies in tcl file
884             sat_product_load_depend=""
885             for p_name,p_info in products_infos:
886                 if p_name in pi.depend:
887                     sat_product_load_depend+="module load %s/%s/%s;" % (pi.base, 
888                                                                         p_info.name, 
889                                                                         p_info.version)
890             if len(sat_product_load_depend)>0:
891                 # if there are dependencies, store the module to load (get rid of trailing ;)
892                 product_env.environ["sat_product_load_depend"]=sat_product_load_depend[0:-1]
893
894
895             env_file_name = os.path.join(product_env.environ["sat_product_base_path"], 
896                                          "modulefiles", 
897                                          product_env.environ["sat_product_base_name"],
898                                          product_env.environ["sat_product_name"], 
899                                          product_env.environ["sat_product_version"])
900             prod_dir_name=os.path.dirname(env_file_name)
901             if not os.path.isdir(prod_dir_name):
902                 os.makedirs(prod_dir_name)
903
904             env_file = open(env_file_name, "w")
905             file_environ = src.fileEnviron.get_file_environ(env_file,
906                                            "tcl", product_env)
907             env = SalomeEnviron(self.config, 
908                                 file_environ, 
909                                 False, 
910                                 for_package=for_package)
911             if "Python" in pi.depend:
912                 # short cut, env.python_lib is required by set_a_product for salome modules
913                 env.has_python="True"
914                 env.python_lib=global_environ.get("PYTHON_LIBDIR")
915             env.set_a_product(product, self.logger)
916             env_file.close()
917             if not self.silent:
918                 self.logger.write(_("    Create tcl module environment file %s\n") % 
919                                   src.printcolors.printcLabel(env_file_name), 3)
920
921
922     def write_env_file(self,
923                        filename,
924                        forBuild, 
925                        shell, 
926                        for_package = None,
927                        no_path_init=False,
928                        additional_env = {}):
929         """\
930         Create an environment file.
931         
932         :param filename str: the file path
933         :param forBuild bool: if true, the build environment
934         :param shell str: the type of file wanted (.sh, .bat)
935         :param for_package bool: if true do specific stuff for required for packages
936         :param no_path_init bool: if true generate a environ file that do not reinitialise paths
937         :param additional_env dict: contains sat_ prefixed variables to help the génération, 
938                                     and also variables to add in the environment.
939         :return: The path to the generated file
940         :rtype: str
941         """
942         additional_env["sat_dist"]=self.config.VARS.dist
943         if not self.silent:
944             self.logger.write(_("Create environment file %s\n") % 
945                               src.printcolors.printcLabel(filename), 3)
946         # create then env object
947         env_file = open(os.path.join(self.out_dir, filename), "w")
948
949         # we duplicate additional_env, and transmit it to fileEnviron, which will use its sat_ prefixed variables.
950         # the other variables of additional_env are added to the environement file at the end of this function.
951         salome_env = copy.deepcopy(additional_env)
952         file_environ = src.fileEnviron.get_file_environ(env_file,
953                                                shell,
954                                                src.environment.Environ(salome_env))
955         if no_path_init:
956             # specify we don't want to reinitialise paths
957             # path will keep the inherited value, which will be appended with new values.
958             file_environ.set_no_init_path()
959
960         env = SalomeEnviron(self.config, 
961                             file_environ, 
962                             forBuild, 
963                             for_package=for_package)
964
965         env.silent = self.silent
966
967         # Set the environment
968         if self.env_info is not None:
969             env.set_full_environ(self.logger, self.env_info)
970         else:
971             # set env from the APPLICATION
972             env.set_application_env(self.logger)
973             # set the products
974             env.set_products(self.logger,
975                             src_root=self.src_root)
976         # Add the additional environment if it is not empty
977         if len(additional_env) != 0:
978             env.add_line(1)
979             env.add_comment("[APPLI variables]")
980             for variable in additional_env:
981                 if not variable.startswith("sat_"):
982                     # by convention variables starting with sat_ are used to transfer information, 
983                     # not to be written in env
984                     env.set(variable, additional_env[variable])
985
986         # finalise the writing and close the file
987         env.finish()
988         env_file.close()
989
990         return env_file.name
991    
992
993 class Shell:
994     """\
995     Definition of a Shell.
996     """
997     def __init__(self, name, extension):
998         """\
999         Initialization.
1000
1001         :param name str: the shell name
1002         :param extension str: the shell extension
1003         """
1004         self.name = name
1005         self.extension = extension
1006
1007 def load_environment(config, build, logger):
1008     """\
1009     Loads the environment (used to run the tests, for example).
1010     
1011     :param config Config: the global config
1012     :param build bool: build environement if True
1013     :param logger Logger: The logger instance to display messages
1014     """
1015     environ = SalomeEnviron(config, Environ(os.environ), build)
1016     environ.set_application_env(logger)
1017     environ.set_products(logger)