3 # Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
5 # Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Lesser General Public
10 # License as published by the Free Software Foundation; either
11 # version 2.1 of the License, or (at your option) any later version.
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 # See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
25 # File : extension_utilities.py
26 # Author : Konstantin Leontev, Open Cascade
28 # @package SalomeOnDemandTK
29 # @brief Set of utility functions those help to build SALOME python extensions.
32 Utilities and constants those help deal with salome extension files.
38 from traceback import format_exc
40 # Setup logger's output
41 FORMAT = '%(funcName)s():%(lineno)s: %(message)s'
42 logging.basicConfig(format=FORMAT, level=logging.DEBUG)
43 logger = logging.getLogger()
45 SALOME_EXTDIR = '__SALOME_EXT__'
46 ARCFILE_EXT = 'salomex'
47 BFILE_EXT = 'salomexb'
48 CFILE_EXT = 'salomexc'
49 DFILE_EXT = 'salomexd'
51 ENVPYFILE_SUF = '_env.py'
54 EXTDESCR_KEY = 'descr'
55 EXTDEPENDSON_KEY = 'depends_on'
56 EXTAUTHOR_KEY = 'author'
57 EXTCOMPONENT_KEY = 'components'
60 def create_salomexd(name, descr='', depends_on=None, author='', components=None):
62 Create a basic salomexd file from provided args.
63 Current version is a json file with function args as the keys.
66 name - the name of the corresponding salome extension.
67 depends_on - list of the modules that current extension depends on.
68 author - an author of the extension.
69 components - the names of the modules those current extension was built from.
72 Raises OSError exception.
78 logger.debug('Create salomexd file...')
80 if depends_on is None:
83 if components is None:
86 json_string = json.dumps(
90 EXTDEPENDSON_KEY: depends_on,
91 EXTAUTHOR_KEY: author,
92 EXTCOMPONENT_KEY: components
98 with open(name + '.' + DFILE_EXT, "w", encoding="utf-8") as file:
99 file.write(json_string)
102 logger.error(format_exc())
105 def read_salomexd(file_path):
107 Reads a content of a salomexd file. Current version is a json file.
108 There's no check if the file_path is a valid salomexd file name.
109 It's expected that user call isvalid_filename() in advance.
112 file_path - the path to the salomexd file.
115 Raises OSError exception.
118 A dictionary that represents the content of the salomexd file.
121 logger.debug('Read salomexd file %s', file_path)
124 with open(file_path, 'r', encoding='UTF-8') as file:
125 return json.load(file)
128 logger.error(format_exc())
132 def create_salomexb(name, included):
134 Create a salomexb file from a list of included file names.
141 name - the name of the corresponding salome extension.
142 included - list of the directories those must be included inside a salomex.
145 Raises OSError exception.
151 logger.debug('Create salomexb file...')
154 with open(name + '.' + BFILE_EXT, "w", encoding="utf-8") as file:
155 file.write('\n'.join(included[0:]))
158 logger.error(format_exc())
161 def read_salomexb(file_path):
163 Returns a content af a salomexb file as a list of strings.
164 There's no check if the file_path is a valid salomexb file name.
165 It's expected that user call isvalid_filename() in advance.
168 file_path - the path to the salomexb file.
171 Raises OSError exception.
174 List of strings - paths to the directories those must be included in
175 corresponding salomex archive file.
178 logger.debug('Read salomexb file %s', file_path)
181 with open(file_path, 'r', encoding='UTF-8') as file:
182 return [line.rstrip() for line in file]
185 logger.error(format_exc())
189 def list_files(dir_path):
191 Returns the recursive list of relative paths to files as strings
192 in the dir_path root directory and all subdirectories.
195 dir_path - the path to the directory where you search for files.
198 Raises OSError exception.
201 A list of relative paths to files inside the given directory.
205 for root, _, files in os.walk(dir_path):
207 files_list += os.path.relpath(os.path.join(root, file), dir_path)
212 def list_files_filter(dir_path, filter_patterns):
214 Returns the recursive list of relative paths to files as strings
215 in the dir_path root directory and all subdirectories.
218 dir_path - the path to the directory where you search for files.
219 filter_patterns - list of expressions for matching file names.
222 files_abs - a list of absolute paths to selected files.
223 files_rel - a list of relative paths to selected files.
226 logger.debug('Get list of files to add into archive...')
231 for root, _, files in os.walk(dir_path):
233 for pattern in filter_patterns:
234 filename_abs = os.path.join(root, file)
235 filename_rel = os.path.relpath(filename_abs, dir_path)
237 if filename_rel.startswith(pattern):
238 logger.debug('File name %s matches pattern %s', filename_rel, pattern)
239 files_abs.append(filename_abs)
240 files_rel.append(filename_rel)
242 return files_abs, files_rel
245 def list_files_ext(dir_path, ext):
247 Returns a list of abs paths to files with a given extension
248 in the dir_path directory.
251 dir_path - the path to the directory where you search for files.
252 ext - a given extension.
255 A list of absolute paths to selected files.
258 logger.debug('Get list of files with extension %s...', ext)
261 return [os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(dot_ext)]
264 def list_tonewline_str(str_list):
266 Converts the given list of strings to a newline separated string.
269 dir_path - the path to the directory where you search for files.
272 A newline separated string.
274 return '\n'.join(file for file in str_list)
277 def isvalid_filename(filename, extension):
279 Checks if a given filename is valid in a sense that it exists and have a given extension.
282 filename - the name of the file to check.
283 extension - expected file name extension.
286 True if the given filename is valid for given extension.
289 logger.debug('Check if the filename %s exists and has an extension %s', filename, extension)
291 # First do we even have something to check here
292 if filename == '' or extension == '':
293 logger.error('A filename and extension cannot be empty! Args: filename=%s, extension=%s',
297 # Check if the filename matchs the provided extension
298 _, ext = os.path.splitext(filename)
299 ext = ext.lstrip('.')
301 logger.error('The filename %s doesnt have a valid extension! \
302 The valid extension must be: %s, but get: %s',
303 filename, extension, ext)
306 # Check if the file base name is not empty
307 base_name = os.path.basename(filename)
309 logger.error('The file name %s has an empty base name!', filename)
312 # Check if a file with given filename exists
313 if not os.path.isfile(filename):
314 logger.error('The filename %s is not an existing regular file!', filename)
317 logger.debug('Filename %s exists and has an extension %s', filename, extension)
321 def isvalid_dirname(dirname):
323 Checks if a given directory name exists.
326 dirname - the name of the directory to check.
329 True if the given dirname is valid.
332 logger.debug('Check if the dirname %s exists', dirname)
334 # First do we even have something to check here
336 logger.error('A dirname argument cannot be empty! dirname=%s', dirname)
339 # Check if a file with given filename exists
340 if not os.path.isdir(dirname):
341 logger.error('The dirname %s is not an existing regular file!', dirname)
344 logger.debug('Directory %s exists', dirname)
348 def list_dependants(install_dir, salomex_name):
350 Checks if we have installed extensions those depend on a given extension.
353 install_dir - path to SALOME install root directory.
354 salomex_name - a name of salome extension to check.
357 True if the given extension has dependants.
360 logger.debug('Check if there are other extensions that depends on %s...', salomex_name)
362 salomexd_files = list_files_ext(install_dir, DFILE_EXT)
364 for salomexd_file in salomexd_files:
365 logger.debug('Check dependencies for %s...', salomexd_file)
366 salomexd_content = read_salomexd(salomexd_file)
368 if EXTDEPENDSON_KEY in salomexd_content and salomexd_content[EXTDEPENDSON_KEY]:
369 depends_on = salomexd_content[EXTDEPENDSON_KEY]
370 logger.debug('List of dependencies: %s', depends_on)
372 if salomex_name in depends_on:
373 dependant_name = None
374 if EXTNAME_KEY in salomexd_content and salomexd_content[EXTNAME_KEY]:
375 dependant_name = salomexd_content[EXTNAME_KEY]
377 logger.warning('%s file doesn\'t have %s key! '
378 'Get an extension name from the filename.',
379 salomexd_file, EXTNAME_KEY)
380 dependant_name, _ = os.path.splitext(os.path.basename(salomexd_file))
382 dependants.append(dependant_name)
384 if len(dependants) > 0:
385 logger.debug('An extension %s has followed extensions those depend on it: %s',
386 salomex_name, dependants)
391 def is_empty_dir(directory):
393 Checks if the given directory is empty.
396 directory - path to directory to check.
399 True if the given directory is empty.
402 return not next(os.scandir(directory), None)