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