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