Salome HOME
correction du bug sat #8584
[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, no_PRODUCT_ROOT_DIR=False):
387         """\
388         Sets the environment defined in the APPLICATION file.
389         
390         :param logger Logger: The logger instance to display messages
391         """
392         
393         # add variable PRODUCT_ROOT_DIR as $workdir in APPLICATION.environ section if not present
394         # but if sat launcher or sat package do not duplicate line context.setVariable(r"PRODUCT_ROOT_DIR", ...
395         # no_PRODUCT_ROOT_DIR used only for write_cfgForPy_file
396         if not no_PRODUCT_ROOT_DIR: # do not duplicate context.setVariable(r"PRODUCT_ROOT_DIR"
397           try:
398             tmp = self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR
399           except:
400             self.cfg.APPLICATION.environ.PRODUCT_ROOT_DIR = src.pyconf.Reference(self.cfg, src.pyconf.DOLLAR, "workdir")
401             DBG.write("set_application_env: add APPLICATION.environ.PRODUCT_ROOT_DIR", self.cfg.APPLICATION.environ)
402           
403         # these sensitive variables are reset to avoid bad environment interactions
404         self.add_line(1)
405         self.add_comment("reset these sensitive variables to avoid bad environment interactions")
406         self.add_comment("comment these to lines if you wish a different behaviour")
407         self.set("LD_LIBRARY_PATH", "")
408         self.set("PYTHONPATH", "")
409         self.add_line(1)
410
411         # Set the variables defined in the "environ" section
412         if 'environ' in self.cfg.APPLICATION:
413             # we write PRODUCT environment it in order to conform to 
414             # parseConfigFile.py
415             self.add_comment("PRODUCT environment") 
416             self.load_cfg_environment(self.cfg.APPLICATION.environ)
417             if self.forBuild and "build" in self.cfg.APPLICATION.environ:
418                 self.load_cfg_environment(self.cfg.APPLICATION.environ.build)
419             if not self.forBuild and "launch" in self.cfg.APPLICATION.environ:
420                 self.load_cfg_environment(self.cfg.APPLICATION.environ.launch)
421             self.add_line(1)
422
423
424     def set_salome_minimal_product_env(self, product_info, logger):
425         """\
426         Sets the minimal environment for a SALOME product.
427         xxx_ROOT_DIR and xxx_SRC_DIR
428         
429         :param product_info Config: The product description
430         :param logger Logger: The logger instance to display messages        
431         """
432         # set root dir
433         DBG.write("set_salome_minimal_product_env", product_info)
434         root_dir = product_info.name + "_ROOT_DIR"
435         if not self.is_defined(root_dir):
436             if 'install_dir' in product_info and product_info.install_dir:
437                 self.set(root_dir, product_info.install_dir)
438             elif not self.silent:
439                 logger.write("  " + _("No install_dir for product %s\n") %
440                               product_info.name, 5)
441         
442         source_in_package = src.get_property_in_product_cfg(product_info,
443                                                            "sources_in_package")
444         if not self.for_package or source_in_package == "yes":
445             # set source dir, unless no source dir
446             if not src.product.product_is_fixed(product_info):
447                 src_dir = product_info.name + "_SRC_DIR"
448                 if not self.is_defined(src_dir):
449                     if not self.for_package:
450                         self.set(src_dir, product_info.source_dir)
451                     else:
452                         self.set(src_dir, os.path.join("out_dir_Path",
453                                                        "SOURCES",
454                                                        product_info.name))
455
456     def set_salome_generic_product_env(self, pi):
457         """\
458         Sets the generic environment for a SALOME product.
459         
460         :param pi Config: The product description
461         """
462         # Construct XXX_ROOT_DIR
463         env_root_dir = self.get(pi.name + "_ROOT_DIR")
464         l_binpath_libpath = []
465
466         # create additional ROOT_DIR for CPP components
467         if 'component_name' in pi:
468             compo_name = pi.component_name
469             if compo_name + "CPP" == pi.name:
470                 compo_root_dir = compo_name + "_ROOT_DIR"
471                 envcompo_root_dir = os.path.join(
472                             self.cfg.TOOLS.common.install_root, compo_name )
473                 self.set(compo_root_dir ,  envcompo_root_dir)
474                 bin_path = os.path.join(envcompo_root_dir, 'bin', 'salome')
475                 lib_path = os.path.join(envcompo_root_dir, 'lib', 'salome')
476                 l_binpath_libpath.append( (bin_path, lib_path) )
477
478
479         if src.get_property_in_product_cfg(pi, "fhs"):
480             lib_path = os.path.join(env_root_dir, 'lib')
481             bin_path = os.path.join(env_root_dir, 'bin')
482             if self.has_python:
483             # if the application doesn't include python, we don't need these two lines
484                 pylib1_path = os.path.join(env_root_dir, self.python_lib0)
485                 pylib2_path = os.path.join(env_root_dir, self.python_lib1)
486         else:
487             lib_path = os.path.join(env_root_dir, 'lib', 'salome')
488             bin_path = os.path.join(env_root_dir, 'bin', 'salome')
489             if self.has_python:
490             # if the application doesn't include python, we don't need these two lines
491                 pylib1_path = os.path.join(env_root_dir, self.python_lib0, 'salome')
492                 pylib2_path = os.path.join(env_root_dir, self.python_lib1, 'salome')
493
494         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
495         # PYTHONPATH
496         l_binpath_libpath.append( (bin_path, lib_path) )
497
498         for bin_path, lib_path in l_binpath_libpath:
499             if not self.forBuild:
500                 self.prepend('PATH', bin_path)
501                 if src.architecture.is_windows():
502                     self.prepend('PATH', lib_path)
503                 else :
504                     self.prepend('LD_LIBRARY_PATH', lib_path)
505
506             l = [ bin_path, lib_path ]
507             if self.has_python:
508                 l.append(pylib1_path)
509                 l.append(pylib2_path)
510
511             self.prepend('PYTHONPATH', l)
512
513     def set_cpp_env(self, product_info):
514         """\
515         Sets the generic environment for a SALOME cpp product.
516         
517         :param product_info Config: The product description
518         """
519         # Construct XXX_ROOT_DIR
520         env_root_dir = self.get(product_info.name + "_ROOT_DIR")
521         l_binpath_libpath = []
522
523         # Construct the paths to prepend to PATH and LD_LIBRARY_PATH and 
524         # PYTHONPATH
525         bin_path = os.path.join(env_root_dir, 'bin')
526         lib_path = os.path.join(env_root_dir, 'lib')
527         l_binpath_libpath.append( (bin_path, lib_path) )
528
529         for bin_path, lib_path in l_binpath_libpath:
530             if not self.forBuild:
531                 self.prepend('PATH', bin_path)
532                 if src.architecture.is_windows():
533                     self.prepend('PATH', lib_path)
534                 else :
535                     self.prepend('LD_LIBRARY_PATH', lib_path)
536
537             l = [ bin_path, lib_path ]
538             if self.has_python:
539                 l.append(os.path.join(env_root_dir, self.python_lib0))
540                 l.append(os.path.join(env_root_dir, self.python_lib1))
541             self.prepend('PYTHONPATH', l)
542
543     def load_cfg_environment(self, cfg_env):
544         """\
545         Loads environment defined in cfg_env 
546         
547         :param cfg_env Config: A config containing an environment    
548         """
549         # Loop on cfg_env values
550         for env_def in cfg_env:
551             val = cfg_env[env_def]
552             
553             # if it is env_script, do not do anything (reserved keyword)
554             if env_def == "env_script":
555                 continue
556             
557             # if it is a dict, do not do anything
558             if isinstance(val, src.pyconf.Mapping):
559                 continue
560
561             # if it is a list, loop on its values
562             if isinstance(val, src.pyconf.Sequence):
563                 # transform into list of strings
564                 l_val = []
565                 for item in val:
566                     l_val.append(item)
567                 val = l_val
568
569             # "_" means that the value must be prepended
570             if env_def.startswith("_"):
571                 # separator exception for PV_PLUGIN_PATH
572                 if env_def[1:] == 'PV_PLUGIN_PATH':
573                     self.prepend(env_def[1:], val, ';')
574                 else:
575                     self.prepend(env_def[1:], val)
576             elif env_def.endswith("_"):
577                 # separator exception for PV_PLUGIN_PATH
578                 if env_def[:-1] == 'PV_PLUGIN_PATH':
579                     self.append(env_def[:-1], val, ';')
580                 else:
581                     self.append(env_def[:-1], val)
582             else:
583                 self.set(env_def, val)
584
585     def set_a_product(self, product, logger):
586         """\
587         Sets the environment of a product. 
588         
589         :param product str: The product name
590         :param logger Logger: The logger instance to display messages
591         """
592
593         # Get the informations corresponding to the product
594         pi = src.product.get_product_config(self.cfg, product)
595
596         # skip mesa products (if any) at run time, 
597         # unless use_mesa property was activated
598         if not self.forBuild:
599             if not ("APPLICATION" in self.cfg  and
600                     "properties" in self.cfg.APPLICATION  and
601                     "use_mesa" in self.cfg.APPLICATION.properties  and
602                     self.cfg.APPLICATION.properties.use_mesa == "yes") :
603                 if ("properties" in pi and
604                     "is_mesa" in pi.properties  and
605                     pi.properties.is_mesa == "yes") :
606                     logger.write(_("Skip mesa product %s\n") % pi.name, 4)
607                     return
608                
609         
610         if self.for_package:
611             pi.install_dir = os.path.join("out_dir_Path",
612                                           self.for_package,
613                                           pi.name)
614
615         if not self.silent:
616             logger.write(_("Setting environment for %s\n") % product, 4)
617
618         self.add_line(1)
619         self.add_comment('setting environ for ' + product)
620             
621         # Do not define environment if the product is native
622         if src.product.product_is_native(pi):
623             if src.product.product_has_env_script(pi):
624                 self.run_env_script(pi, native=True)
625             return
626                
627         # Set an additional environment for SALOME products
628         if src.product.product_is_salome(pi):
629             # set environment using definition of the product
630             self.set_salome_minimal_product_env(pi, logger)
631             self.set_salome_generic_product_env(pi)
632         
633         # use variable LICENCE_FILE to communicate the licence file name to the environment script
634         licence_file_name = src.product.product_has_licence(pi, self.cfg.PATHS.LICENCEPATH)
635         if licence_file_name:
636             logger.write("licence file found for product %s : %s\n" % (pi.name, licence_file_name), 5) 
637             self.set("LICENCE_FILE", licence_file_name)
638
639         if src.product.product_is_cpp(pi):
640             # set a specific environment for cpp modules
641             self.set_salome_minimal_product_env(pi, logger)
642             self.set_cpp_env(pi)
643             
644             if src.product.product_is_generated(pi):
645                 if "component_name" in pi:
646                     # hack the source and install directories in order to point  
647                     # on the generated product source install directories
648                     install_dir_save = pi.install_dir
649                     source_dir_save = pi.source_dir
650                     name_save = pi.name
651                     pi.install_dir = os.path.join(self.cfg.APPLICATION.workdir,
652                                                   "INSTALL",
653                                                   pi.component_name)
654                     if self.for_package:
655                         pi.install_dir = os.path.join("out_dir_Path",
656                                                       self.for_package,
657                                                       pi.component_name)
658                     pi.source_dir = os.path.join(self.cfg.APPLICATION.workdir,
659                                                   "GENERATED",
660                                                   pi.component_name)
661                     pi.name = pi.component_name
662                     self.set_salome_minimal_product_env(pi, logger)
663                     self.set_salome_generic_product_env(pi)
664                     
665                     # Put original values
666                     pi.install_dir = install_dir_save
667                     pi.source_dir = source_dir_save
668                     pi.name = name_save
669         
670         # Put the environment define in the configuration of the product
671         if "environ" in pi:
672             self.load_cfg_environment(pi.environ)
673             if self.forBuild and "build" in pi.environ:
674                 self.load_cfg_environment(pi.environ.build)
675             if not self.forBuild and "launch" in pi.environ:
676                 self.load_cfg_environment(pi.environ.launch)
677             # if product_info defines a env_scripts, load it
678             if 'env_script' in pi.environ:
679                 self.run_env_script(pi, logger)
680
681         
682             
683
684     def run_env_script(self, product_info, logger=None, native=False):
685         """\
686         Runs an environment script. 
687         
688         :param product_info Config: The product description
689         :param logger Logger: The logger instance to display messages
690         :param native Boolean: if True load set_native_env instead of set_env
691         """
692         env_script = product_info.environ.env_script
693         # Check that the script exists
694         if not os.path.exists(env_script):
695             raise src.SatException(_("Environment script not found: %s") % 
696                                    env_script)
697
698         if not self.silent and logger is not None:
699             logger.write("  ** load %s\n" % env_script, 4)
700
701         # import the script and run the set_env function
702         try:
703             import imp
704             pyproduct = imp.load_source(product_info.name + "_env_script",
705                                         env_script)
706             if not native:
707                 if self.forBuild and "set_env_build" in dir(pyproduct):
708                     pyproduct.set_env_build(self,
709                                             product_info.install_dir,
710                                             product_info.version)
711                 elif (not self.forBuild) and "set_env_launch" in dir(pyproduct):
712                     pyproduct.set_env_launch(self,
713                                             product_info.install_dir,
714                                             product_info.version)
715                 else:
716                     # at least this one is mandatory,
717                     # if set_env_build and set_env_build are not defined
718                     pyproduct.set_env(self,
719                                       product_info.install_dir,
720                                       product_info.version)
721             else:
722                 # not mandatory, if set_nativ_env not defined, we do nothing
723                 if "set_nativ_env" in dir(pyproduct):
724                     pyproduct.set_nativ_env(self)
725         except:
726             __, exceptionValue, exceptionTraceback = sys.exc_info()
727             print(exceptionValue)
728             import traceback
729             traceback.print_tb(exceptionTraceback)
730             traceback.print_exc()
731
732     def run_simple_env_script(self, script_path, logger=None):
733         """\
734         Runs an environment script. Same as run_env_script, but with a 
735         script path as parameter.
736         
737         :param script_path str: a path to an environment script
738         :param logger Logger: The logger instance to display messages
739         """
740         if not self.enable_simple_env_script:
741             return
742         # Check that the script exists
743         if not os.path.exists(script_path):
744             raise src.SatException(_("Environment script not found: %s") % 
745                                    script_path)
746
747         if not self.silent and logger is not None:
748             logger.write("  ** load %s\n" % script_path, 4)
749
750         script_basename = os.path.basename(script_path)
751         if script_basename.endswith(".py"):
752             script_basename = script_basename[:-len(".py")]
753
754         # import the script and run the set_env function
755         try:
756             import imp
757             pyproduct = imp.load_source(script_basename + "_env_script",
758                                         script_path)
759             pyproduct.load_env(self)
760         except:
761             __, exceptionValue, exceptionTraceback = sys.exc_info()
762             print(exceptionValue)
763             import traceback
764             traceback.print_tb(exceptionTraceback)
765             traceback.print_exc()
766
767     def set_products(self, logger, src_root=None):
768         """\
769         Sets the environment for all the products. 
770         
771         :param logger Logger: The logger instance to display messages
772         :param src_root src: the application working directory
773         """
774         self.add_line(1)
775         self.add_comment('setting environ for all products')
776
777         # Make sure that the python lib dirs are set after python
778         if "Python" in self.cfg.APPLICATION.products:
779             self.set_a_product("Python", logger)
780             self.set_python_libdirs()
781
782         # The loop on the products
783         for product in self.cfg.APPLICATION.products.keys():
784             if product == "Python":
785                 continue
786             self.set_a_product(product, logger)
787             self.finish(False)
788  
789     def set_full_environ(self, logger, env_info):
790         """\
791         Sets the full environment for products 
792         specified in env_info dictionary. 
793         
794         :param logger Logger: The logger instance to display messages
795         :param env_info list: the list of products
796         """
797         DBG.write("set_full_environ for", env_info)
798         # DBG.write("set_full_environ config", self.cfg.APPLICATION.environ, True)
799
800         # set product environ
801         self.set_application_env(logger)
802
803         if "Python" in env_info:
804             self.set_a_product("Python", logger)
805             self.set_python_libdirs()
806
807         # set products
808         for product in env_info:
809             if product == "Python":
810                 continue
811             self.set_a_product(product, logger)
812
813 class FileEnvWriter:
814     """\
815     Class to dump the environment to a file.
816     """
817     def __init__(self, config, logger, out_dir, src_root, env_info=None):
818         """\
819         Initialization.
820
821         :param cfg Config: the global config
822         :param logger Logger: The logger instance to display messages
823         :param out_dir str: The directory path where t put the output files
824         :param src_root str: The application working directory
825         :param env_info str: The list of products to add in the files.
826         """
827         self.config = config
828         self.logger = logger
829         self.out_dir = out_dir
830         self.src_root= src_root
831         self.silent = True
832         self.env_info = env_info
833
834     def write_env_file(self, filename, forBuild, shell, for_package = None):
835         """\
836         Create an environment file.
837         
838         :param filename str: the file path
839         :param forBuild bool: if true, the build environment
840         :param shell str: the type of file wanted (.sh, .bat)
841         :return: The path to the generated file
842         :rtype: str
843         """
844         if not self.silent:
845             self.logger.write(_("Create environment file %s\n") % 
846                               src.printcolors.printcLabel(filename), 3)
847
848         # create then env object
849         env_file = open(os.path.join(self.out_dir, filename), "w")
850         tmp = src.fileEnviron.get_file_environ(env_file,
851                                                shell,
852                                                {})
853         env = SalomeEnviron(self.config, tmp, forBuild, for_package=for_package)
854         env.silent = self.silent
855
856         # Set the environment
857         if self.env_info is not None:
858             env.set_full_environ(self.logger, self.env_info)
859         else:
860             # set env from the APPLICATION
861             env.set_application_env(self.logger)
862             
863             # The list of products to launch
864             lProductsName = env.get_names(self.config.APPLICATION.products.keys())
865             env.set( "SALOME_MODULES",    ','.join(lProductsName))
866             
867             # set the products
868             env.set_products(self.logger,
869                             src_root=self.src_root)
870
871         # add cleanup and close
872         env.finish(True)
873         env_file.close()
874
875         return env_file.name
876    
877     def write_cfgForPy_file(self,
878                             filename,
879                             additional_env = {},
880                             for_package = None,
881                             with_commercial = True):
882         """\
883         Append to current opened aFile a cfgForPy 
884         environment (SALOME python launcher).
885            
886         :param filename str: the file path
887         :param additional_env dict: a dictionary of additional variables 
888                                     to add to the environment
889         :param for_package str: If not None, produce a relative environment 
890                                 designed for a package. 
891         """
892         if not self.silent:
893             self.logger.write(_("Create configuration file %s\n") % 
894                               src.printcolors.printcLabel(filename.name), 3)
895
896         # create then env object
897         tmp = src.fileEnviron.get_file_environ(filename, "cfgForPy", {})
898         # DBG.write("fileEnviron.get_file_environ %s" % filename, tmp, True)
899
900         # environment for launch
901         env = SalomeEnviron(self.config,
902                             tmp,
903                             forBuild=False,
904                             for_package=for_package,
905                             enable_simple_env_script = with_commercial)
906         env.silent = self.silent
907
908         DBG.write("write_cfgForPy_file", self.config.APPLICATION.environ)
909
910         if self.env_info is not None:
911             env.set_full_environ(self.logger, self.env_info)
912             DBG.write("set_full_environ", self.env_info)
913
914         else:
915             # set env from PRODUCT
916             env.set_application_env(self.logger, no_PRODUCT_ROOT_DIR=True)
917
918             # The list of products to launch
919             lProductsName = env.get_names(self.config.APPLICATION.products.keys())
920             env.set("SALOME_MODULES", ','.join(lProductsName))
921
922             # set the products
923             env.set_products(self.logger, src_root=self.src_root)
924             DBG.write("set_application_env without PRODUCT_ROOT_DIR", self.config.APPLICATION.environ)
925
926         # Add the additional environment if it is not empty
927         if len(additional_env) != 0:
928             for variable in additional_env:
929                 env.set(variable, additional_env[variable])
930
931         # add cleanup and close
932         env.finish(True)
933
934 class Shell:
935     """\
936     Definition of a Shell.
937     """
938     def __init__(self, name, extension):
939         """\
940         Initialization.
941
942         :param name str: the shell name
943         :param extension str: the shell extension
944         """
945         self.name = name
946         self.extension = extension
947
948 def load_environment(config, build, logger):
949     """\
950     Loads the environment (used to run the tests, for example).
951     
952     :param config Config: the global config
953     :param build bool: build environement if True
954     :param logger Logger: The logger instance to display messages
955     """
956     environ = SalomeEnviron(config, Environ(os.environ), build)
957     environ.set_application_env(logger)
958     environ.set_products(logger)
959     environ.finish(True)