--- /dev/null
+#!/usr/bin/env python3
+# -*- coding:utf-8 -*-
+# Copyright (C) 2007-2022 CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+# File : extension_remover.py
+# Author : Konstantin Leontev, Open Cascade
+#
+# @package SalomeOnDemandTK
+# @brief Set of utility to unpack SALOME python extensions.
+
+"""Set of utility to remove SALOME python extensions.
+"""
+
+import os
+import sys
+import shutil
+from traceback import format_exc
+
+from .extension_utilities import logger, \
+ DFILE_EXT, CFILE_EXT, SALOME_EXTDIR, ENVPYFILE_SUF, \
+ isvalid_dirname, list_dependants, is_empty_dir
+
+
+def remove_if_empty(top_dir, directory):
+ """
+ Recursively remove empty directories from the given one to the top.
+
+ Args:
+ top_dir - top parent directory that can be removed as well
+ directory - the given directory
+
+ Returns:
+ None.
+ """
+
+ #logger.debug('Check if %s is empty...', directory)
+ if not is_empty_dir(directory):
+ return
+
+ logger.debug('Directory %s is empty. Remove it.', directory)
+ os.rmdir(directory)
+
+ # Don't go up than top root
+ if top_dir == directory:
+ return
+
+ # Remove the parent dir as well
+ parent_dir = os.path.abspath(os.path.join(directory, os.pardir))
+ remove_if_empty(top_dir, parent_dir)
+
+
+def remove_bylist(root_dir, salomexc):
+ """
+ Remove files and directories listed in the given salomexc file.
+
+ Args:
+ root_dir - a root dir for listed files
+ salomexc - file that contents a list of files to remove.
+
+ Returns:
+ True if all the files were deleted without critical errors.
+ """
+
+ logger.debug('Remove files from %s dir listed in %s...',
+ root_dir, salomexc)
+
+ try:
+ with open(salomexc, 'r', encoding='UTF-8') as file:
+ for line in file:
+ path_to_remove = os.path.join(root_dir, line.strip())
+ logger.debug('Remove file %s...', path_to_remove)
+
+ if os.path.isfile(path_to_remove):
+ os.remove(path_to_remove)
+
+ # Remove the parent folder if empty
+ parent_dir = os.path.dirname(path_to_remove)
+ remove_if_empty(root_dir, parent_dir)
+
+ elif os.path.islink(path_to_remove):
+ os.unlink(path_to_remove)
+
+ # Remove the parent folder if empty
+ parent_dir = os.path.dirname(path_to_remove)
+ remove_if_empty(root_dir, parent_dir)
+
+ elif os.path.isdir(path_to_remove):
+ logger.warning('Directories are not expected to be listed in %s file! '
+ 'Remove %s anyway.',
+ salomexc, path_to_remove)
+ # Use instead of rmdir here, because dir can be not empty
+ shutil.rmtree(path_to_remove)
+
+ else:
+ logger.error('Unexpected path %s!'
+ 'It is not a file or directory. Skip.',
+ path_to_remove)
+
+ except OSError:
+ logger.error(format_exc())
+ return False
+
+ return True
+
+def remove_salomex(install_dir, salomex_name):
+ """
+ Remove a salome extension from SALOME install root.
+
+ Args:
+ salome_root - path to SALOME install root directory.
+ salomex_name - a name of salome extension to remove.
+
+ Returns:
+ None.
+ """
+
+ logger.debug('Starting remove a salome extension %s', salomex_name)
+
+ # Check if provided dirname is valid
+ if not isvalid_dirname(install_dir):
+ return
+
+ # Check if the given extension is installed
+ logger.debug('Check if an extension %s is installed:', salomex_name)
+
+ logger.debug('Try to find %s file...', DFILE_EXT)
+ salomexd = os.path.join(install_dir, salomex_name + '.' + DFILE_EXT)
+ has_salomexd = os.path.isfile(salomexd)
+ if not has_salomexd:
+ logger.debug('Cannot find a description file %s for extension %s! '
+ 'Extension has been already removed or %s file was deleted by mistake. '
+ 'In the former case we can use %s file to clean up.',
+ salomexd, salomex_name, DFILE_EXT, CFILE_EXT)
+
+ logger.debug('Try to find %s file...', CFILE_EXT)
+ salomexc = os.path.join(install_dir, salomex_name + '.' + CFILE_EXT)
+ if not os.path.isfile(salomexc):
+ logger.debug('Cannot find %s for extension %s! '
+ 'Going to exit from extension removing process.',
+ salomexc, salomex_name)
+ return
+
+ # Check if we cannot remove an extension because of dependencies
+ dependants = list_dependants(install_dir, salomex_name)
+ if len(dependants) > 0:
+ logger.error('Cannot remove an extension %s because followed extensions depend on it: %s! '
+ 'Going to exit from extension removing process.',
+ salomex_name, dependants)
+ return
+
+ # Try to remove all the files listed in the control file
+ if not remove_bylist(os.path.join(install_dir, SALOME_EXTDIR), salomexc):
+ return
+
+ # Remove control file
+ os.remove(salomexc)
+
+ # Remove env file
+ env_py = os.path.join(install_dir, salomex_name + ENVPYFILE_SUF)
+ if os.path.isfile(env_py):
+ os.remove(env_py)
+ else:
+ logger.error('Cannot find and remove %s file! ', env_py)
+
+ # Remove description file
+ if has_salomexd:
+ os.remove(salomexd)
+
+ logger.debug('An extension %s was removed from %s',
+ salomex_name, install_dir)
+
+
+if __name__ == '__main__':
+ if len(sys.argv) == 3:
+ arg_1, arg_2 = sys.argv[1:] # pylint: disable=unbalanced-tuple-unpacking
+ remove_salomex(arg_1, arg_2)
+ else:
+ logger.error('You must provide all the arguments!')
+ logger.info(remove_salomex.__doc__)
CFILE_EXT = 'salomexc'
DFILE_EXT = 'salomexd'
PYFILE_EXT = 'py'
+ENVPYFILE_SUF = '_env.py'
EXTNAME_KEY = 'name'
EXTDESCR_KEY = 'descr'
return files_abs, files_rel
+def list_files_ext(dir_path, ext):
+ """
+ Returns a list of abs paths to files with a given extension
+ in the dir_path directory.
+
+ Args:
+ dir_path - the path to the directory where you search for files.
+ ext - a given extension.
+
+ Returns:
+ A list of absolute paths to selected files.
+ """
+
+ logger.debug('Get list of files with extension %s...', ext)
+
+ dot_ext = '.' + ext
+ return [os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(dot_ext)]
+
+
def list_tonewline_str(str_list):
"""
Converts the given list of strings to a newline separated string.
logger.debug('Directory %s exists', dirname)
return True
+
+
+def list_dependants(install_dir, salomex_name):
+ """
+ Checks if we have installed extensions those depend on a given extension.
+
+ Args:
+ install_dir - path to SALOME install root directory.
+ salomex_name - a name of salome extension to check.
+
+ Returns:
+ True if the given extension has dependants.
+ """
+
+ logger.debug('Check if there are other extensions that depends on %s...', salomex_name)
+ dependants = []
+ salomexd_files = list_files_ext(install_dir, DFILE_EXT)
+
+ for salomexd_file in salomexd_files:
+ logger.debug('Check dependencies for %s...', salomexd_file)
+ salomexd_content = read_salomexd(salomexd_file)
+
+ if EXTDEPENDSON_KEY in salomexd_content and salomexd_content[EXTDEPENDSON_KEY]:
+ depends_on = salomexd_content[EXTDEPENDSON_KEY]
+ logger.debug('List of dependencies: %s', depends_on)
+
+ if salomex_name in depends_on:
+ dependant_name = None
+ if EXTNAME_KEY in salomexd_content and salomexd_content[EXTNAME_KEY]:
+ dependant_name = salomexd_content[EXTNAME_KEY]
+ else:
+ logger.warning('%s file doesn\'t have %s key! '
+ 'Get an extension name from the filename.',
+ salomexd_file, EXTNAME_KEY)
+ dependant_name, _ = os.path.splitext(os.path.basename(salomexd_file))
+
+ dependants.append(dependant_name)
+
+ if len(dependants) > 0:
+ logger.debug('An extension %s has followed extensions those depend on it: %s',
+ salomex_name, dependants)
+
+ return dependants
+
+
+def is_empty_dir(directory):
+ """
+ Checks if the given directory is empty.
+
+ Args:
+ directory - path to directory to check.
+
+ Returns:
+ True if the given directory is empty.
+ """
+
+ return not next(os.scandir(directory), None)