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