Salome HOME
style: black format
[tools/sat.git] / src / versionMinorMajorPatch.py
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3
4 #  Copyright (C) 2010-2018  CEA/DEN
5 #
6 #  This library is free software; you can redistribute it and/or
7 #  modify it under the terms of the GNU Lesser General Public
8 #  License as published by the Free Software Foundation; either
9 #  version 2.1 of the License.
10 #
11 #  This library is distributed in the hope that it will be useful,
12 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 #  Lesser General Public License for more details.
15 #
16 #  You should have received a copy of the GNU Lesser General Public
17 #  License along with this library; if not, write to the Free Software
18 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19
20
21 """\
22 class and utilities to define a version as MAJOR.MINOR.PATCH,
23 and range of versions
24
25 | Given a version number MAJOR.MINOR.PATCH separator "_" or "."
26 | increment the
27 | MAJOR version when you make incompatible API changes,
28 | MINOR version when you add functionality in a backwards-compatible manner,
29 | PATCH version when you make backwards-compatible bug fixes.
30 """
31
32 import os
33 import sys
34
35 verbose = False  # True
36
37 #############################################
38 def only_numbers(aStr):
39     """
40     Remove non numericals characters from string,
41
42     :param aStr: string to work
43     :return: None if no number presence
44     """
45     res = "".join([nb for nb in aStr if nb in "0123456789"])
46     if res == "":
47         return None
48     else:
49         return res
50
51
52 #############################################
53 def remove_startswith(aStr, startsToCheck):
54     """
55     remove starting strings, if begining of aStr correspond
56     order of list startsToCheck matter
57     do the stuff only for the first correspondence in startsToCheck
58     """
59     for s in startsToCheck:
60         if aStr.startswith(s):
61             return aStr[len(s) :]
62     return aStr
63
64
65 #############################################
66 def toList_majorMinorPatch(aStr, verbose=False):
67     """
68     Returns list of integer as  [major, minor, patch] from a string,
69
70     | accepts '1.2.3' '1_2_3' 'version_1.2.3' 'version1.2.3' 'v1.2.3',
71     | completion '123' means '123.0.0', '1.2' means '1.2.0'
72     | lower or upper
73     | raise exception if problem
74     """
75     if verbose:
76         print("toList_majorMinorPatch('%s')" % aStr)
77     res = aStr.replace(" ", "")
78     res = res.lower()
79     res = remove_startswith(res, "version_ version v".split())
80     res = res.replace(".", "_").split("_")
81     if len(res) > 3:
82         msg = "Not a major_minor_patch correct syntax: '%s'" % aStr
83         raise Exception(msg)
84     if len(res) == 0:
85         msg = "An empty string is not a major_minor_patch syntax"
86         raise Exception(msg)
87
88     # complete MINOR.PATCH if not existing
89     if len(res) == 1:
90         res.append("0")
91     if len(res) == 2:
92         res.append("0")
93
94     try:
95         ii = int(res[0])
96     except:
97         msg = "major in major_minor_patch is not integer: '%s'" % aStr
98         raise Exception(msg)
99     if ii < 0:
100         msg = "major in major_minor_patch is negative integer: '%s'" % aStr
101         raise Exception(msg)
102
103     try:
104         ii = int(res[1])
105     except:
106         msg = "minor in major_minor_patch is not integer: '%s'" % aStr
107         raise Exception(msg)
108     if ii < 0:
109         msg = "minor in major_minor_patch is negative integer: '%s'" % aStr
110         raise Exception(msg)
111
112     try:
113         ii = int(res[2])
114     except:
115         msg = "patch in major_minor_patch is not integer: '%s'" % aStr
116         raise Exception(msg)
117     if ii < 0:
118         msg = "patch in major_minor_patch is negative integer: '%s'" % aStr
119         raise Exception(msg)
120
121     return [int(i) for i in res]
122
123
124 #############################################
125 def toCompactStr_majorMinorPatch(version):
126     """
127     OBSOLETE method
128     parameter version is list of integer as  [major, minor, patch]
129
130     | returns "789" for [7, 8, 9]
131     | warning:
132     |   minor, pach have to be integer less than 10
133     |   raise exception for [7, 10, 11]
134     |   (which returns "71011" as ambigous 710.1.1 for example)
135     """
136     # forbidden use from nov. 2023 and SALOME 9.10.0
137     raise Exception(
138         "obsolete toCompactStr_majorMinorPatch method: forbiden use of compact representation of '%s', fix problem in caller"
139         % version
140     )
141
142
143 #############################################
144 def getRange_majorMinorPatch(aStr, verbose=False):
145     """
146     extract from aStr a version range, defined as
147     '*_from_aMinVersionTag_to_aMaxVersionTag' or
148     '*version_aMinVersionTag_to_aMaxVersionTag'.
149
150     where aMinVersionTag and aMaxVersionTag are compatible with MinorMajorPatch class syntaxes
151     '1.2.3' or '1_2_3' etc.
152     if not found '_from_' or 'version_' first then aMinVersionTag is '0.0.0'
153
154     :param aStr: string to work
155     :return: list [min, max], where min, max are MinorMajorPatch instances.
156              else None if not found
157     """
158     tmp1 = aStr.lower().split("_to_")
159
160     if len(tmp1) < 2:
161         return None  # no '_to_'
162     if len(tmp1) > 2:
163         msg = "more than one '_to_' is incorrect for version range: '%s'" % aStr
164         raise Exception(msg)
165     aMax = tmp1[1]
166
167     # accept older syntax as 'version_1_0_0_to_2_0_0', (as '_from_1_0_0_to_2_0_0')
168     if "version_" in tmp1[0] and "_from_" not in tmp1[0]:
169         aStr_with_from = aStr.lower().replace("version_", "_from_", 1)
170     else:
171         aStr_with_from = aStr.lower()
172
173     # print("aStr_with_from '%s' -> '%s'" % (aStr, aStr_with_from))
174
175     tmp0 = aStr_with_from.split("_from_")
176     tmp1 = aStr_with_from.split("_to_")
177
178     if len(tmp0) > 2:
179         msg = "more than one '_from_' is incorrect for version range: '%s'" % aStr
180         raise Exception(msg)
181
182     tmp2 = tmp1[0].split("_from_")
183
184     if len(tmp2) == 2:
185         aMin = tmp2[1]
186     else:
187         aMin = "0.0.0"
188
189     if verbose:
190         msg = "version min '%s' and version max '%s' in version range: '%s'" % (
191             aMin,
192             aMax,
193             aStr,
194         )
195         print(msg)
196
197     try:
198         rMin = MinorMajorPatch(aMin)
199         rMax = MinorMajorPatch(aMax)
200     except:
201         msg = "problem version range in '%s'" % aStr
202         raise Exception(msg)
203         """if verbose:
204       print("WARNING: problem version range in '%s'" % aStr)
205     return None"""
206
207     if rMin > rMax:
208         msg = "version min '%s' > version max '%s' in version range: '%s'" % (
209             rMin,
210             rMax,
211             aStr,
212         )
213         raise Exception(msg)
214
215     return [rMin, rMax]
216
217
218 #############################################
219 class MinorMajorPatch(object):
220     """\
221   class to define a version as MAJOR.MINOR.PATCH
222
223   | Given a version number MAJOR.MINOR.PATCH separator "_" or "."
224   | increment the
225   | MAJOR version when you make incompatible API changes,
226   | MINOR version when you add functionality in a backwards-compatible manner,
227   | PATCH version when you make backwards-compatible bug fixes.
228   """
229
230     def __init__(self, version):
231         if type(version) == list:
232             aStr = "_".join([str(i) for i in version])
233             v = toList_majorMinorPatch(aStr)
234         else:
235             v = toList_majorMinorPatch(version)
236         self.major = v[0]
237         self.minor = v[1]
238         self.patch = v[2]
239
240     def __repr__(self, sep="_"):
241         """example is 'version_1_2_3'"""
242         res = "version_%i%s%i%s%i" % (self.major, sep, self.minor, sep, self.patch)
243         return res
244
245     def __str__(self, sep="."):
246         """example is '1.2.3'"""
247         res = "%i%s%i%s%i" % (self.major, sep, self.minor, sep, self.patch)
248         return res
249
250     def strSalome(self):
251         """example is '1_2_3'"""
252         return self.__str__(sep="_")
253
254     def strClassic(self):
255         """example is '1.2.3'"""
256         return self.__str__(sep=".")
257
258     def strCompact(self):
259         """example is '123' from '1.2.3'"""
260         # forbidden use from nov. 2023 and SALOME 9.10.0
261         raise Exception(
262             "obsolete strCompact method: forbiden use of compact representation of '%s', fix problem in caller"
263             % str(self)
264         )
265         # return toCompactStr_majorMinorPatch(self.toList())
266
267     def toList(self):
268         """example is list of integer [1, 2, 3] from '1.2.3'"""
269         return [self.major, self.minor, self.patch]
270
271     def __lt__(self, other):
272         res = self.toList() < other.toList()
273         return res
274
275     def __le__(self, other):
276         res = self.toList() <= other.toList()
277         return res
278
279     def __gt__(self, other):
280         res = self.toList() > other.toList()
281         return res
282
283     def __ge__(self, other):
284         res = self.toList() >= other.toList()
285         return res
286
287     def __eq__(self, other):
288         res = self.toList() == other.toList()
289         return res
290
291     def __ne__(self, other):
292         res = self.toList() != other.toList()
293         return res