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 Utilities and constants those help to deal with salome extension files.
32 Utilities and constants those help to 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.
75 logger.debug('Create salomexd file...')
77 if depends_on is None:
80 if components is None:
83 json_string = json.dumps(
87 EXTDEPENDSON_KEY: depends_on,
88 EXTAUTHOR_KEY: author,
89 EXTCOMPONENT_KEY: components
95 with open(name + '.' + DFILE_EXT, "w", encoding="utf-8") as file:
96 file.write(json_string)
99 logger.error(format_exc())
102 def read_salomexd(file_path):
104 Reads a content of a salomexd file. Current version is a json file.
105 There's no check if the file_path is a valid salomexd file name.
106 It's expected that user call isvalid_filename() in advance.
109 file_path - the path to the salomexd file.
112 A dictionary that represents the content of the salomexd file.
115 logger.debug('Read salomexd file %s', file_path)
118 with open(file_path, 'r', encoding='UTF-8') as file:
119 return json.load(file)
122 logger.error(format_exc())
126 def create_salomexb(name, included):
128 Create a salomexb file from a list of included file names.
135 name - the name of the corresponding salome extension.
136 included - list of the directories those must be included inside a salomex.
142 logger.debug('Create salomexb file...')
145 with open(name + '.' + BFILE_EXT, "w", encoding="utf-8") as file:
146 file.write('\n'.join(included[0:]))
149 logger.error(format_exc())
152 def read_salomexb(file_path):
154 Returns a content af a salomexb file as a list of strings.
155 There's no check if the file_path is a valid salomexb file name.
156 It's expected that user call isvalid_filename() in advance.
159 file_path - the path to the salomexb file.
162 List of strings - paths to the directories those must be included in
163 corresponding salomex archive file.
166 logger.debug('Read salomexb file %s', file_path)
169 with open(file_path, 'r', encoding='UTF-8') as file:
170 return [line.rstrip() for line in file]
173 logger.error(format_exc())
177 def list_files(dir_path):
179 Returns the recursive list of relative paths to files as strings
180 in the dir_path root directory and all subdirectories.
183 dir_path - the path to the directory where you search for files.
186 Raises OSError exception.
189 A list of relative paths to files inside the given directory.
193 for root, _, files in os.walk(dir_path):
195 files_list += os.path.relpath(os.path.join(root, file), dir_path)
200 def list_files_filter(dir_path, filter_patterns):
202 Returns the recursive list of relative paths to files as strings
203 in the dir_path root directory and all subdirectories.
206 dir_path - the path to the directory where you search for files.
207 filter_patterns - list of expressions for matching file names.
210 files_abs - a list of absolute paths to selected files.
211 files_rel - a list of relative paths to selected files.
214 logger.debug('Get list of files to add into archive...')
219 for root, _, files in os.walk(dir_path):
221 for pattern in filter_patterns:
222 filename_abs = os.path.join(root, file)
223 filename_rel = os.path.relpath(filename_abs, dir_path)
225 if filename_rel.startswith(pattern):
226 logger.debug('File name %s matches pattern %s', filename_rel, pattern)
227 files_abs.append(filename_abs)
228 files_rel.append(filename_rel)
230 return files_abs, files_rel
233 def list_files_ext(dir_path, ext):
235 Returns a list of abs paths to files with a given extension
236 in the dir_path directory.
239 dir_path - the path to the directory where you search for files.
240 ext - a given extension.
243 A list of absolute paths to selected files.
246 logger.debug('Get list of files with extension %s...', ext)
249 return [os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(dot_ext)]
252 def list_tonewline_str(str_list):
254 Converts the given list of strings to a newline separated string.
257 dir_path - the path to the directory where you search for files.
260 A newline separated string.
262 return '\n'.join(file for file in str_list)
265 def isvalid_filename(filename, extension):
267 Checks if a given filename is valid in a sense that it exists and have a given extension.
270 filename - the name of the file to check.
271 extension - expected file name extension.
274 True if the given filename is valid for given extension.
277 logger.debug('Check if the filename %s exists and has an extension %s', filename, extension)
279 # First do we even have something to check here
280 if filename == '' or extension == '':
281 logger.error('A filename and extension cannot be empty! Args: filename=%s, extension=%s',
285 # Check if the filename matchs the provided extension
286 _, ext = os.path.splitext(filename)
287 ext = ext.lstrip('.')
289 logger.error('The filename %s doesnt have a valid extension! \
290 The valid extension must be: %s, but get: %s',
291 filename, extension, ext)
294 # Check if the file base name is not empty
295 base_name = os.path.basename(filename)
297 logger.error('The file name %s has an empty base name!', filename)
300 # Check if a file with given filename exists
301 if not os.path.isfile(filename):
302 logger.error('The filename %s is not an existing regular file!', filename)
305 logger.debug('Filename %s exists and has an extension %s', filename, extension)
309 def isvalid_dirname(dirname):
311 Checks if a given directory name exists.
314 dirname - the name of the directory to check.
317 True if the given dirname is valid.
320 logger.debug('Check if the dirname %s exists', dirname)
322 # First do we even have something to check here
324 logger.error('A dirname argument cannot be empty! dirname=%s', dirname)
327 # Check if a file with given filename exists
328 if not os.path.isdir(dirname):
329 logger.error('The dirname %s is not an existing regular file!', dirname)
332 logger.debug('Directory %s exists', dirname)
336 def list_dependants(install_dir, salomex_name):
338 Checks if we have installed extensions those depend on a given extension.
341 install_dir - path to SALOME install root directory.
342 salomex_name - a name of salome extension to check.
345 True if the given extension has dependants.
348 logger.debug('Check if there are other extensions that depends on %s...', salomex_name)
350 salomexd_files = list_files_ext(install_dir, DFILE_EXT)
352 for salomexd_file in salomexd_files:
353 dependant_name, _ = os.path.splitext(os.path.basename(salomexd_file))
355 # Don't process <salomex_name> extension itself
356 if dependant_name == salomex_name:
359 logger.debug('Check dependencies for %s...', salomexd_file)
360 salomexd_content = read_salomexd(salomexd_file)
362 if EXTDEPENDSON_KEY in salomexd_content and salomexd_content[EXTDEPENDSON_KEY]:
363 depends_on = salomexd_content[EXTDEPENDSON_KEY]
364 logger.debug('List of dependencies: %s', depends_on)
366 if salomex_name in depends_on:
367 dependants.append(dependant_name)
369 if len(dependants) > 0:
370 logger.debug('Followed extensions %s depend on %s',
371 dependants, salomex_name)
376 def is_empty_dir(directory):
378 Checks if the given directory is empty.
381 directory - path to directory to check.
384 True if the given directory is empty.
387 return not next(os.scandir(directory), None)
390 def find_file(directory, file_name):
392 Finds a file in the given directory.
395 directory - path to directory to check.
396 file_name - given base filename with extension
399 Abs path if the file exist, otherwise None.
402 logger.debug('Try to find %s file in %s...', file_name, directory)
403 file = os.path.join(directory, file_name)
404 if os.path.isfile(file):
405 logger.debug('File %s exists.', file)
408 logger.debug('File %s doesnt\'t exist. Return None.', file)
412 def find_salomexd(install_dir, salomex_name):
414 Finds a salomexd file for the given extension.
417 install_dir - path to directory to check.
418 salomex_name - extension's name.
421 Abs path if the file exist, otherwise None.
424 return find_file(install_dir, salomex_name + '.' + DFILE_EXT)
427 def find_salomexc(install_dir, salomex_name):
429 Finds a salomexc file for the given extension.
432 install_dir - path to directory to check.
433 salomex_name - extension's name.
436 Abs path if the file exist, otherwise None.
439 return find_file(install_dir, salomex_name + '.' + CFILE_EXT)
442 def find_envpy(install_dir, salomex_name):
444 Finds a _env.py file for the given extension.
447 install_dir - path to directory to check.
448 salomex_name - extension's name.
451 Abs path if the file exist, otherwise None.
454 return find_file(install_dir, salomex_name + ENVPYFILE_SUF)