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