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