Salome HOME
updated copyright message
[modules/kernel.git] / bin / SalomeOnDemandTK / extension_remover.py
1 #!/usr/bin/env python3
2 # -*- coding:utf-8 -*-
3 # Copyright (C) 2007-2023  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
6 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
7 #
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.
12 #
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.
17 #
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
21 #
22 # See https://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #
24
25 #  File   : extension_remover.py
26 #  Author : Konstantin Leontev, Open Cascade
27 #
28 #  @package SalomeOnDemandTK
29 #  @brief Set of utility to remove SALOME python extensions.
30
31 """Set of utility to remove SALOME python extensions.
32 """
33
34 import os
35 import sys
36 import shutil
37 from traceback import format_exc
38
39 from .extension_utilities import logger, \
40     SALOME_EXTDIR, EXTCOMPONENT_KEY, \
41     isvalid_dirname, list_dependants, is_empty_dir, \
42     find_envpy, value_from_salomexd, check_if_installed
43
44
45 def remove_if_empty(top_dir, directory):
46     """
47     Recursively remove empty directories from the given one to the top.
48
49     Args:
50         top_dir - top parent directory that can be removed as well
51         directory - the given directory
52
53     Returns:
54         None.
55     """
56
57     #logger.debug('Check if %s is empty...', directory)
58     if not is_empty_dir(directory):
59         return
60
61     logger.debug('Directory %s is empty. Remove it.', directory)
62     os.rmdir(directory)
63
64     # Don't go up than top root
65     if top_dir == directory:
66         return
67
68     # Remove the parent dir as well
69     parent_dir = os.path.abspath(os.path.join(directory, os.pardir))
70     remove_if_empty(top_dir, parent_dir)
71
72
73 def remove_bylist(root_dir, salomexc):
74     """
75     Remove files and directories listed in the given salomexc file.
76
77     Args:
78         root_dir - a root dir for listed files
79         salomexc - file that contents a list of files to remove.
80
81     Returns:
82         True if all the files were deleted without critical errors.
83     """
84
85     logger.debug('Remove files from %s dir listed in %s...',
86         root_dir, salomexc)
87
88     try:
89         with open(salomexc, 'r', encoding='UTF-8') as file:
90             for line in file:
91                 path_to_remove = os.path.join(root_dir, line.strip())
92                 logger.debug('Remove file %s...', path_to_remove)
93
94                 if os.path.isfile(path_to_remove):
95                     os.remove(path_to_remove)
96
97                     # Remove the parent folder if empty
98                     parent_dir = os.path.dirname(path_to_remove)
99                     remove_if_empty(root_dir, parent_dir)
100
101                 elif os.path.islink(path_to_remove):
102                     os.unlink(path_to_remove)
103
104                     # Remove the parent folder if empty
105                     parent_dir = os.path.dirname(path_to_remove)
106                     remove_if_empty(root_dir, parent_dir)
107
108                 elif os.path.isdir(path_to_remove):
109                     logger.warning('Directories are not expected to be listed in %s file! '
110                         'Remove %s anyway.',
111                         salomexc, path_to_remove)
112                     # Use instead of rmdir here, because dir can be not empty
113                     shutil.rmtree(path_to_remove)
114
115                 else:
116                     logger.warning('Unexpected path %s!'
117                         'It is not a file or directory. Skip.',
118                         path_to_remove)
119
120     except OSError:
121         logger.error(format_exc())
122         return False
123
124     return True
125
126 def remove_salomex(install_dir, salomex_name):
127     """
128     Remove a salome extension from SALOME install root.
129
130     Args:
131         salome_root - path to SALOME install root directory.
132         salomex_name - a name of salome extension to remove.
133
134     Returns:
135         List of deleted components or None if the functions fails.
136     """
137
138     logger.debug('Starting remove a salome extension %s', salomex_name)
139
140     # Return value
141     components = None
142
143     # Check if provided dirname is valid
144     if not isvalid_dirname(install_dir):
145         return components
146
147     # Check if the given extension is installed
148     salomexd, salomexc = check_if_installed(install_dir, salomex_name)
149     if not salomexc:
150         logger.debug('Going to exit from extension removing process.')
151         return components
152
153     # Check if we cannot remove an extension because of dependencies
154     dependants = list_dependants(install_dir, salomex_name)
155     if len(dependants) > 0:
156         logger.error('Cannot remove an extension %s because followed extensions depend on it: %s! '
157             'Going to exit from extension removing process.',
158             salomex_name, dependants)
159         return components
160
161     # Try to remove all the files listed in the control file
162     if not remove_bylist(os.path.join(install_dir, SALOME_EXTDIR), salomexc):
163         return components
164
165     # Remove control file
166     os.remove(salomexc)
167
168     # Remove env file
169     env_py = find_envpy(install_dir, salomex_name)
170     if env_py:
171         os.remove(env_py)
172     else:
173         logger.warning('Cannot find and remove %s file! ', env_py)
174
175     # Remove description file
176     if salomexd:
177         # Get components to deactivate in UI if the case
178         components = value_from_salomexd(salomexd, EXTCOMPONENT_KEY)
179         os.remove(salomexd)
180
181     logger.debug('An extension %s was removed from %s',
182         salomex_name, install_dir)
183
184     return components if components else []
185
186
187 if __name__ == '__main__':
188     if len(sys.argv) == 3:
189         arg_1, arg_2 = sys.argv[1:] # pylint: disable=unbalanced-tuple-unpacking
190         remove_salomex(arg_1, arg_2)
191     else:
192         logger.error('You must provide all the arguments!')
193         logger.info(remove_salomex.__doc__)