]> SALOME platform Git repositories - modules/kernel.git/blob - bin/SalomeOnDemandTK/extension_utilities.py
Salome HOME
[bos #32522][EDF] SALOME on Demand. Added extension_unpacker module. ExtensionBuilder...
[modules/kernel.git] / bin / SalomeOnDemandTK / extension_utilities.py
1 #!/usr/bin/env python3
2 # -*- coding:utf-8 -*-
3 # Copyright (C) 2007-2022  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_utilities.py
26 #  Author : Konstantin Leontev, Open Cascade
27 #
28 #  @package SalomeOnDemandTK
29 #  @brief Set of utility functions those help to build SALOME python extensions.
30
31 """
32 Utilities and constants those help deal with salome extension files.
33 """
34
35 import os
36 import logging
37 import json
38 from traceback import format_exc
39
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()
44
45 SALOME_EXTDIR = '__SALOME_EXT__'
46 ARCFILE_EXT = 'salomex'
47 BFILE_EXT = 'salomexb'
48 CFILE_EXT = 'salomexc'
49 DFILE_EXT = 'salomexd'
50 PYFILE_EXT = 'py'
51
52 EXTNAME_KEY = 'name'
53 EXTDESCR_KEY = 'descr'
54 EXTDEPENDSON_KEY = 'depends_on'
55 EXTAUTHOR_KEY = 'author'
56 EXTCOMPONENT_KEY = 'components'
57
58
59 def create_salomexd(name, descr='', depends_on=None, author='', components=None):
60     """
61     Create a basic salomexd file from provided args.
62     Current version is a json file with function args as the keys.
63
64     Args:
65         name - the name of the corresponding salome extension.
66         depends_on - list of the modules that current extension depends on.
67         author - an author of the extension.
68         components - the names of the modules those current extension was built from.
69
70     Raises:
71         Raises OSError exception.
72
73     Returns:
74         None
75     """
76
77     logger.debug('Create salomexd file...')
78
79     if depends_on is None:
80         depends_on = []
81
82     if components is None:
83         components = []
84
85     json_string = json.dumps(
86         {
87             EXTNAME_KEY: name,
88             EXTDESCR_KEY: descr,
89             EXTDEPENDSON_KEY: depends_on,
90             EXTAUTHOR_KEY: author,
91             EXTCOMPONENT_KEY: components
92         },
93         indent=4
94     )
95
96     try:
97         with open(name + '.' + DFILE_EXT, "w", encoding="utf-8") as file:
98             file.write(json_string)
99
100     except OSError:
101         logger.error(format_exc())
102
103
104 def read_salomexd(file_path):
105     """
106     Reads a content of a salomexd file. Current version is a json file.
107     There's no check if the file_path is a valid salomexd file name.
108     It's expected that user call isvalid_filename() in advance.
109
110     Args:
111         file_path - the path to the salomexd file.
112
113     Raises:
114         Raises OSError exception.
115
116     Returns:
117         A dictionary that represents the content of the salomexd file.
118     """
119
120     logger.debug('Read salomexd file %s', file_path)
121
122     try:
123         with open(file_path, 'r', encoding='UTF-8') as file:
124             return json.load(file)
125
126     except OSError:
127         logger.error(format_exc())
128         return {}
129
130
131 def create_salomexb(name, included):
132     """
133     Create a salomexb file from a list of included file names.
134     For example:
135     */*.py
136     doc/*.html
137     doc/*.jp
138
139     Args:
140         name - the name of the corresponding salome extension.
141         included - list of the directories those must be included inside a salomex.
142
143     Raises:
144         Raises OSError exception.
145
146     Returns:
147         None
148     """
149
150     logger.debug('Create salomexb file...')
151
152     try:
153         with open(name + '.' + BFILE_EXT, "w", encoding="utf-8") as file:
154             file.write('\n'.join(included[0:]))
155
156     except OSError:
157         logger.error(format_exc())
158
159
160 def read_salomexb(file_path):
161     """
162     Returns a content af a salomexb file as a list of strings.
163     There's no check if the file_path is a valid salomexb file name.
164     It's expected that user call isvalid_filename() in advance.
165
166     Args:
167         file_path - the path to the salomexb file.
168
169     Raises:
170         Raises OSError exception.
171
172     Returns:
173         List of strings - paths to the directories those must be included in
174         corresponding salomex archive file.
175     """
176
177     logger.debug('Read salomexb file %s', file_path)
178
179     try:
180         with open(file_path, 'r', encoding='UTF-8') as file:
181             return [line.rstrip() for line in file]
182
183     except OSError:
184         logger.error(format_exc())
185         return []
186
187
188 def list_files(dir_path):
189     """
190     Returns the recursive list of relative paths to files as strings
191     in the dir_path root directory and all subdirectories.
192
193     Args:
194         dir_path - the path to the directory where you search for files.
195
196     Raises:
197         Raises OSError exception.
198
199     Returns:
200         A list of relative paths to files inside the given directory.
201     """
202
203     files_list = []
204     for root, _, files in os.walk(dir_path):
205         for file in files:
206             files_list += os.path.relpath(os.path.join(root, file), dir_path)
207
208     return files_list
209
210
211 def list_files_filter(dir_path, filter_patterns):
212     """
213     Returns the recursive list of relative paths to files as strings
214     in the dir_path root directory and all subdirectories.
215
216     Args:
217         dir_path - the path to the directory where you search for files.
218         filter_patterns - list of expressions for matching file names.
219
220     Returns:
221         files_abs - a list of absolute paths to selected files.
222         files_rel - a list of relative paths to selected files.
223     """
224
225     logger.debug('Get list of files to add into archive...')
226
227     files_abs = []
228     files_rel = []
229
230     for root, _, files in os.walk(dir_path):
231         for file in files:
232             for pattern in filter_patterns:
233                 filename_abs = os.path.join(root, file)
234                 filename_rel = os.path.relpath(filename_abs, dir_path)
235
236                 if filename_rel.startswith(pattern):
237                     logger.debug('File name %s matches pattern %s', filename_rel, pattern)
238                     files_abs.append(filename_abs)
239                     files_rel.append(filename_rel)
240
241     return files_abs, files_rel
242
243
244 def list_tonewline_str(str_list):
245     """
246     Converts the given list of strings to a newline separated string.
247
248     Args:
249         dir_path - the path to the directory where you search for files.
250
251     Returns:
252         A newline separated string.
253     """
254     return '\n'.join(file for file in str_list)
255
256
257 def isvalid_filename(filename, extension):
258     """
259     Checks if a given filename is valid in a sense that it exists and have a given extension.
260
261     Args:
262         filename - the name of the file to check.
263         extension - expected file name extension.
264
265     Returns:
266         True if the given filename is valid for given extension.
267     """
268
269     logger.debug('Check if the filename %s exists and has an extension %s', filename, extension)
270
271     # First do we even have something to check here
272     if filename == '' or extension == '':
273         logger.error('A filename and extension cannot be empty! Args: filename=%s, extension=%s',
274             filename, extension)
275         return False
276
277     # Check if the filename matchs the provided extension
278     _, ext = os.path.splitext(filename)
279     ext = ext.lstrip('.')
280     if ext != extension:
281         logger.error('The filename %s doesnt have a valid extension! \
282             The valid extension must be: %s, but get: %s',
283             filename, extension, ext)
284         return False
285
286     # Check if the file base name is not empty
287     base_name = os.path.basename(filename)
288     if base_name == '':
289         logger.error('The file name %s has an empty base name!', filename)
290         return False
291
292     # Check if a file with given filename exists
293     if not os.path.isfile(filename):
294         logger.error('The filename %s is not an existing regular file!', filename)
295         return False
296
297     logger.debug('Filename %s exists and has an extension %s', filename, extension)
298     return True
299
300
301 def isvalid_dirname(dirname):
302     """
303     Checks if a given directory name exists.
304
305     Args:
306         dirname - the name of the directory to check.
307
308     Returns:
309         True if the given dirname is valid.
310     """
311
312     logger.debug('Check if the dirname %s exists', dirname)
313
314     # First do we even have something to check here
315     if dirname == '':
316         logger.error('A dirname argument cannot be empty! dirname=%s', dirname)
317         return False
318
319     # Check if a file with given filename exists
320     if not os.path.isdir(dirname):
321         logger.error('The dirname %s is not an existing regular file!', dirname)
322         return False
323
324     logger.debug('Directory %s exists', dirname)
325     return True