Salome HOME
Be able to produce a relative environment for a package launcher
[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 import os
20 import shutil
21 import errno
22 import stat
23
24 from . import pyconf
25 from . import architecture
26 from . import printcolors
27 from . import options
28 from . import system
29 from . import ElementTree
30 from . import logger
31 from . import product
32 from . import environment
33 from . import fileEnviron
34 from . import compilation
35 from . import test_module
36
37 OK_STATUS = "OK"
38 KO_STATUS = "KO"
39 NA_STATUS = "NA"
40 KNOWNFAILURE_STATUS = "KF"
41 TIMEOUT_STATUS = "TIMEOUT"
42
43 class SatException(Exception):
44     '''rename Exception Class
45     '''
46     pass
47
48 def ensure_path_exists(p):
49     '''Create a path if not existing
50     
51     :param p str: The path.
52     '''
53     if not os.path.exists(p):
54         os.makedirs(p)
55         
56 def check_config_has_application( config, details = None ):
57     '''check that the config has the key APPLICATION. Else raise an exception.
58     
59     :param config class 'common.pyconf.Config': The config.
60     '''
61     if 'APPLICATION' not in config:
62         message = _("An APPLICATION is required. Use 'config --list' to get"
63                     " the list of available applications.\n")
64         if details :
65             details.append(message)
66         raise SatException( message )
67
68 def check_config_has_profile( config, details = None ):
69     '''check that the config has the key APPLICATION.profile.
70        Else, raise an exception.
71     
72     :param config class 'common.pyconf.Config': The config.
73     '''
74     check_config_has_application(config)
75     if 'profile' not in config.APPLICATION:
76         message = _("A profile section is required in your application.\n")
77         if details :
78             details.append(message)
79         raise SatException( message )
80
81 def config_has_application( config ):
82     return 'APPLICATION' in config
83
84 def get_cfg_param(config, param_name, default):
85     '''Search for param_name value in config.
86        If param_name is not in config, then return default,
87        else, return the found value
88        
89     :param config class 'common.pyconf.Config': The config.
90     :param param_name str: the name of the parameter to get the value
91     :param default str: The value to return if param_name is not in config
92     :return: see initial description of the function
93     :rtype: str
94     '''
95     if param_name in config:
96         return config[param_name]
97     return default
98
99 def print_info(logger, info):
100     '''Prints the tuples that are in info variable in a formatted way.
101     
102     :param logger Logger: The logging instance to use for the prints.
103     :param info list: The list of tuples to display
104     '''
105     # find the maximum length of the first value of the tuples in info
106     smax = max(map(lambda l: len(l[0]), info))
107     # Print each item of info with good indentation
108     for i in info:
109         sp = " " * (smax - len(i[0]))
110         printcolors.print_value(logger, sp + i[0], i[1], 2)
111     logger.write("\n", 2)
112
113 def get_base_path(config):
114     '''Returns the path of the product base.
115     
116     :param config Config: The global Config instance.
117     :return: The path of the product base.
118     :rtype: str
119     '''
120     if "base" in config.SITE:
121         base_path = config.SITE.base
122     else:
123         # default base
124         base_path = config.USER.base
125     return base_path
126
127 def get_salome_version(config):
128     if hasattr(config.APPLICATION, 'version_salome'):
129         Version = config.APPLICATION.version_salome
130     else:
131         KERNEL_info = product.get_product_config(config, "KERNEL")
132         VERSION = os.path.join(
133                             KERNEL_info.install_dir,
134                             "bin",
135                             "salome",
136                             "VERSION")
137         if not os.path.isfile(VERSION):
138             return None
139             
140         fVERSION = open(VERSION)
141         Version = fVERSION.readline()
142         fVERSION.close()
143         
144     VersionSalome = int(only_numbers(Version))    
145     return VersionSalome
146
147 def only_numbers(str_num):
148     return ''.join([nb for nb in str_num if nb in '0123456789'] or '0')
149
150 def read_config_from_a_file(filePath):
151         try:
152             cfg_file = pyconf.Config(filePath)
153         except pyconf.ConfigError as e:
154             raise SatException(_("Error in configuration file: %(file)s\n  %(error)s") % \
155                 { 'file': filePath, 'error': str(e) })
156         return cfg_file
157
158 def get_tmp_filename(cfg, name):
159     if not os.path.exists(cfg.VARS.tmp_root):
160         os.makedirs(cfg.VARS.tmp_root)
161
162     return os.path.join(cfg.VARS.tmp_root, name)
163
164 ##
165 # Utils class to simplify path manipulations.
166 class Path:
167     def __init__(self, path):
168         self.path = str(path)
169
170     def __add__(self, other):
171         return Path(os.path.join(self.path, str(other)))
172
173     def __abs__(self):
174         return Path(os.path.abspath(self.path))
175
176     def __str__(self):
177         return self.path
178
179     def __eq__(self, other):
180         return self.path == other.path
181
182     def exists(self):
183         return self.islink() or os.path.exists(self.path)
184
185     def islink(self):
186         return os.path.islink(self.path)
187
188     def isdir(self):
189         return os.path.isdir(self.path)
190
191     def list(self):
192         return [Path(p) for p in os.listdir(self.path)]
193
194     def dir(self):
195         return Path(os.path.dirname(self.path))
196
197     def base(self):
198         return Path(os.path.basename(self.path))
199
200     def make(self, mode=None):
201         os.makedirs(self.path)        
202         if mode:
203             os.chmod(self.path, mode)
204         
205     def chmod(self, mode):
206         os.chmod(self.path, mode)
207
208     def rm(self):    
209         if self.islink():
210             os.remove(self.path)
211         else:
212             shutil.rmtree( self.path, onerror = handleRemoveReadonly )
213
214     def copy(self, path, smart=False):
215         if not isinstance(path, Path):
216             path = Path(path)
217
218         if os.path.islink(self.path):
219             return self.copylink(path)
220         elif os.path.isdir(self.path):
221             return self.copydir(path, smart)
222         else:
223             return self.copyfile(path)
224
225     def smartcopy(self, path):
226         return self.copy(path, True)
227
228     def readlink(self):
229         if self.islink():
230             return os.readlink(self.path)
231         else:
232             return False
233
234     def symlink(self, path):
235         try:
236             os.symlink(str(path), self.path)
237             return True
238         except:
239             return False
240
241     def copylink(self, path):
242         try:
243             os.symlink(os.readlink(self.path), str(path))
244             return True
245         except:
246             return False
247
248     def copydir(self, dst, smart=False):
249         try:
250             names = self.list()
251
252             if not dst.exists():
253                 dst.make()
254
255             for name in names:
256                 if name == dst:
257                     continue
258                 if smart and (str(name) in [".git", "CVS", ".svn"]):
259                     continue
260                 srcname = self + name
261                 dstname = dst + name
262                 srcname.copy(dstname, smart)
263             return True
264         except:
265             return False
266
267     def copyfile(self, path):
268         try:
269             shutil.copy2(self.path, str(path))
270             return True
271         except:
272             return False
273
274 def find_file_in_lpath(file_name, lpath, additional_dir = ""):
275     """Find in all the directories in lpath list the file that has the same name
276        as file_name. If it is found, return the full path of the file, else,
277        return False. 
278        The additional_dir (optional) is the name of the directory to add to all 
279        paths in lpath.
280     
281     :param file_name str: The file name to search
282     :param lpath List: The list of directories where to search
283     :param additional_dir str: The name of the additional directory
284     :return: the full path of the file or False if not found
285     :rtype: str
286     """
287     for directory in lpath:
288         dir_complete = os.path.join(directory, additional_dir)
289         if not os.path.isdir(directory) or not os.path.isdir(dir_complete):
290             continue
291         l_files = os.listdir(dir_complete)
292         for file_n in l_files:
293             if file_n == file_name:
294                 return os.path.join(dir_complete, file_name)
295     return False
296
297 def handleRemoveReadonly(func, path, exc):
298     excvalue = exc[1]
299     if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
300         os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777
301         func(path)
302     else:
303         raise
304
305 def deepcopy_list(input_list):
306     """ Do a deep copy of a list
307     
308     :param input_list List: The list to copy
309     :return: The copy of the list
310     :rtype: List
311     """
312     res = []
313     for elem in input_list:
314         res.append(elem)
315     return res
316
317 def parse_date(date):
318     """Transform YYYYMMDD_hhmmss into YYYY-MM-DD hh:mm:ss.
319     
320     :param date str: The date to transform
321     :return: The date in the new format
322     :rtype: str
323     """
324     if len(date) != 15:
325         return date
326     res = "%s-%s-%s %s:%s:%s" % (date[0:4],
327                                  date[4:6],
328                                  date[6:8],
329                                  date[9:11],
330                                  date[11:13],
331                                  date[13:])
332     return res
333
334 def merge_dicts(*dict_args):
335     '''
336     Given any number of dicts, shallow copy and merge into a new dict,
337     precedence goes to key value pairs in latter dicts.
338     '''
339     result = {}
340     for dictionary in dict_args:
341         result.update(dictionary)
342     return result