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