Salome HOME
fix #12327 Mauvaise exception après un sat -h prepare
[tools/sat.git] / src / __init__.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
20 """\
21 initial imports and utilities methods for salomeTools
22 """
23
24 import os
25 import shutil
26 import errno
27 import stat
28
29 from . import pyconf
30 from . import architecture
31 from . import printcolors
32 from . import options
33 from . import system
34 from . import ElementTree
35 from . import logger
36 from . import product
37 from . import environment
38 from . import fileEnviron
39 from . import compilation
40 from . import test_module
41 from . import template
42
43 import platform
44 if platform.system() == "Windows" :
45     import colorama
46     colorama.init()
47
48 OK_STATUS = "OK"
49 KO_STATUS = "KO"
50 NA_STATUS = "NA"
51 KNOWNFAILURE_STATUS = "KF"
52 TIMEOUT_STATUS = "TIMEOUT"
53
54 CONFIG_FILENAME = "sat-config.pyconf"
55
56 class SatException(Exception):
57     """rename Exception Class"""
58     pass
59
60 def ensure_path_exists(p):
61     """Create a path if not existing
62     
63     :param p str: The path.
64     """
65     if not os.path.exists(p):
66         os.makedirs(p)
67         
68 def check_config_has_application( config, details = None ):
69     """check that the config has the key APPLICATION. Else raise an exception.
70     
71     :param config class 'common.pyconf.Config': The config.
72     """
73     if 'APPLICATION' not in config:
74         message = _("An APPLICATION is required. Use 'config --list' to get the list of available applications.\n")
75         if details :
76             details.append(message)
77         raise SatException( message )
78
79 def check_config_has_profile( config, details = None ):
80     """\
81     check that the config has the key APPLICATION.profile.
82     else, raise an exception.
83     
84     :param config class 'common.pyconf.Config': The config.
85     """
86     check_config_has_application(config)
87     if 'profile' not in config.APPLICATION:
88         message = _("A profile section is required in your application.\n")
89         if details :
90             details.append(message)
91         raise SatException( message )
92
93 def config_has_application( config ):
94     return 'APPLICATION' in config
95
96 def get_cfg_param(config, param_name, default):
97     """\
98     eearch for param_name value in config.
99     if param_name is not in config 
100     then return default,
101     else return the found value
102        
103     :param config class 'common.pyconf.Config': The config.
104     :param param_name str: the name of the parameter to get the value
105     :param default str: The value to return if param_name is not in config
106     :return: see initial description of the function
107     :rtype: str
108     """
109     if param_name in config:
110         return config[param_name]
111     return default
112
113 def print_info(logger, info):
114     """\
115     Prints the tuples that are in info variable in a formatted way.
116     
117     :param logger Logger: The logging instance to use for the prints.
118     :param info list: The list of tuples to display
119     """
120     # find the maximum length of the first value of the tuples in info
121     smax = max(map(lambda l: len(l[0]), info))
122     # Print each item of info with good indentation
123     for i in info:
124         sp = " " * (smax - len(i[0]))
125         printcolors.print_value(logger, sp + i[0], i[1], 2)
126     logger.write("\n", 2)
127
128 def get_base_path(config):
129     """\
130     Returns the path of the products base.
131     
132     :param config Config: The global Config instance.
133     :return: The path of the products base.
134     :rtype: str
135     """
136     if "base" not in config.LOCAL:
137         local_file_path = os.path.join(config.VARS.salometoolsway,
138                                       "data",
139                                       "local.pyconf")
140         msg = _("Please define a base path in the file %s" % local_file_path)
141         raise SatException(msg)
142         
143     base_path = os.path.abspath(config.LOCAL.base)
144     
145     return base_path
146
147 def get_launcher_name(config):
148     """\
149     Returns the name of salome launcher.
150     
151     :param config Config: The global Config instance.
152     :return: The name of salome launcher.
153     :rtype: str
154     """
155     check_config_has_application(config)
156     if 'profile' in config.APPLICATION and 'launcher_name' in config.APPLICATION.profile:
157         launcher_name = config.APPLICATION.profile.launcher_name
158     else:
159         launcher_name = 'salome'
160
161     return launcher_name
162
163 def get_log_path(config):
164     """\
165     Returns the path of the logs.
166     
167     :param config Config: The global Config instance.
168     :return: The path of the logs.
169     :rtype: str
170     """
171     if "log_dir" not in config.LOCAL:
172         local_file_path = os.path.join(config.VARS.salometoolsway,
173                                       "data",
174                                       "local.pyconf")
175         msg = _("Please define a log_dir in the file %s" % local_file_path)
176         raise SatException(msg)
177       
178     log_dir_path = os.path.abspath(config.LOCAL.log_dir)
179     
180     return log_dir_path
181
182 def get_salome_version(config):
183     if hasattr(config.APPLICATION, 'version_salome'):
184         Version = config.APPLICATION.version_salome
185     else:
186         KERNEL_info = product.get_product_config(config, "KERNEL")
187         VERSION = os.path.join(
188                             KERNEL_info.install_dir,
189                             "bin",
190                             "salome",
191                             "VERSION")
192         if not os.path.isfile(VERSION):
193             return None
194             
195         fVERSION = open(VERSION)
196         Version = fVERSION.readline()
197         fVERSION.close()
198         
199     VersionSalome = int(only_numbers(Version))    
200     return VersionSalome
201
202 def only_numbers(str_num):
203     return ''.join([nb for nb in str_num if nb in '0123456789'] or '0')
204
205 def read_config_from_a_file(filePath):
206         try:
207             cfg_file = pyconf.Config(filePath)
208         except pyconf.ConfigError as e:
209             raise SatException(_("Error in configuration file: %(file)s\n  %(error)s") % \
210                 { 'file': filePath, 'error': str(e) })
211         return cfg_file
212
213 def get_tmp_filename(cfg, name):
214     if not os.path.exists(cfg.VARS.tmp_root):
215         os.makedirs(cfg.VARS.tmp_root)
216
217     return os.path.join(cfg.VARS.tmp_root, name)
218
219 ##
220 # Utils class to simplify path manipulations.
221 class Path:
222     def __init__(self, path):
223         self.path = str(path)
224
225     def __add__(self, other):
226         return Path(os.path.join(self.path, str(other)))
227
228     def __abs__(self):
229         return Path(os.path.abspath(self.path))
230
231     def __str__(self):
232         return self.path
233
234     def __eq__(self, other):
235         return self.path == other.path
236
237     def exists(self):
238         return self.islink() or os.path.exists(self.path)
239
240     def islink(self):
241         return os.path.islink(self.path)
242
243     def isdir(self):
244         return os.path.isdir(self.path)
245
246     def isfile(self):
247         return os.path.isfile(self.path)
248
249     def list(self):
250         return [Path(p) for p in os.listdir(self.path)]
251
252     def dir(self):
253         return Path(os.path.dirname(self.path))
254
255     def base(self):
256         return Path(os.path.basename(self.path))
257
258     def make(self, mode=None):
259         os.makedirs(self.path)        
260         if mode:
261             os.chmod(self.path, mode)
262         
263     def chmod(self, mode):
264         os.chmod(self.path, mode)
265
266     def rm(self):    
267         if self.islink():
268             os.remove(self.path)
269         else:
270             shutil.rmtree( self.path, onerror = handleRemoveReadonly )
271
272     def copy(self, path, smart=False):
273         if not isinstance(path, Path):
274             path = Path(path)
275
276         if os.path.islink(self.path):
277             return self.copylink(path)
278         elif os.path.isdir(self.path):
279             return self.copydir(path, smart)
280         else:
281             return self.copyfile(path)
282
283     def smartcopy(self, path):
284         return self.copy(path, True)
285
286     def readlink(self):
287         if self.islink():
288             return os.readlink(self.path)
289         else:
290             return False
291
292     def symlink(self, path):
293         try:
294             os.symlink(str(path), self.path)
295             return True
296         except:
297             return False
298
299     def copylink(self, path):
300         try:
301             os.symlink(os.readlink(self.path), str(path))
302             return True
303         except:
304             return False
305
306     def copydir(self, dst, smart=False):
307         try:
308             names = self.list()
309
310             if not dst.exists():
311                 dst.make()
312
313             for name in names:
314                 if name == dst:
315                     continue
316                 if smart and (str(name) in [".git", "CVS", ".svn"]):
317                     continue
318                 srcname = self + name
319                 dstname = dst + name
320                 srcname.copy(dstname, smart)
321             return True
322         except:
323             return False
324
325     def copyfile(self, path):
326         try:
327             shutil.copy2(self.path, str(path))
328             return True
329         except:
330             return False
331
332 def find_file_in_lpath(file_name, lpath, additional_dir = ""):
333     """\
334     Find in all the directories in lpath list the file that has the same name
335     as file_name. 
336     If it is found 
337     then return the full path of the file
338     else return False.
339  
340     The additional_dir (optional) is the name of the directory to add to all 
341     paths in lpath.
342     
343     :param file_name str: The file name to search
344     :param lpath List: The list of directories where to search
345     :param additional_dir str: The name of the additional directory
346     :return: the full path of the file or False if not found
347     :rtype: str
348     """
349     for directory in lpath:
350         dir_complete = os.path.join(directory, additional_dir)
351         if not os.path.isdir(directory) or not os.path.isdir(dir_complete):
352             continue
353         l_files = os.listdir(dir_complete)
354         for file_n in l_files:
355             if file_n == file_name:
356                 return os.path.join(dir_complete, file_name)
357     return False
358
359 def handleRemoveReadonly(func, path, exc):
360     excvalue = exc[1]
361     if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
362         os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
363         func(path)
364     else:
365         raise
366
367 def deepcopy_list(input_list):
368     """\
369     Do a deep copy of a list
370     
371     :param input_list List: The list to copy
372     :return: The copy of the list
373     :rtype: List
374     """
375     res = []
376     for elem in input_list:
377         res.append(elem)
378     return res
379
380 def remove_item_from_list(input_list, item):
381     """\
382     Remove all occurences of item from input_list
383     
384     :param input_list List: The list to modify
385     :return: The without any item
386     :rtype: List
387     """
388     res = []
389     for elem in input_list:
390         if elem == item:
391             continue
392         res.append(elem)
393     return res
394
395 def parse_date(date):
396     """\
397     Transform YYYYMMDD_hhmmss into YYYY-MM-DD hh:mm:ss.
398     
399     :param date str: The date to transform
400     :return: The date in the new format
401     :rtype: str
402     """
403     if len(date) != 15:
404         return date
405     res = "%s-%s-%s %s:%s:%s" % (date[0:4],
406                                  date[4:6],
407                                  date[6:8],
408                                  date[9:11],
409                                  date[11:13],
410                                  date[13:])
411     return res
412
413 def merge_dicts(*dict_args):
414     """\
415     Given any number of dicts, shallow copy and merge into a new dict,
416     precedence goes to key value pairs in latter dicts.
417     """
418     result = {}
419     for dictionary in dict_args:
420         result.update(dictionary)
421     return result
422
423 def replace_in_file(filein, strin, strout):
424     """Replace <strin> by <strout> in file <filein>"""
425     shutil.move(filein, filein + "_old")
426     fileout= filein
427     filein = filein + "_old"
428     fin = open(filein, "r")
429     fout = open(fileout, "w")
430     for line in fin:
431         fout.write(line.replace(strin, strout))
432
433 def get_property_in_product_cfg(product_cfg, pprty):
434     if not "properties" in product_cfg:
435         return None
436     if not pprty in product_cfg.properties:
437         return None
438     return product_cfg.properties[pprty]
439
440 def activate_mesa_property(config):
441     """Add mesa property into application properties
442     
443     :param config Config: The global configuration. It must have an application!
444     """
445     # Verify the existence of the file
446     if not 'properties' in config.APPLICATION:
447         config.APPLICATION.addMapping( 'properties', pyconf.Mapping(), None )
448     config.APPLICATION.properties.use_mesa="yes"
449