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