Salome HOME
spns #40790: on Debian distributions, use dpkg-query instead of apt to check system...
[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 def remove_startswith(aStr, startsToCheck):
53   """
54   remove starting strings, if begining of aStr correspond
55   order of list startsToCheck matter
56   do the stuff only for the first correspondence in startsToCheck
57   """
58   for s in startsToCheck:
59     if aStr.startswith(s):
60       return aStr[len(s):]
61   return aStr
62
63 #############################################
64 def toList_majorMinorPatch(aStr, verbose=False):
65   """
66   Returns list of integer as  [major, minor, patch] from a string,
67
68   | accepts '1.2.3' '1_2_3' 'version_1.2.3' 'version1.2.3' 'v1.2.3',
69   | completion '123' means '123.0.0', '1.2' means '1.2.0'
70   | lower or upper
71   | raise exception if problem
72   """
73   if verbose: print("toList_majorMinorPatch('%s')" % aStr)
74   res = aStr.replace(" ", "")
75   res = res.lower()
76   res = remove_startswith(res, "version_ version v".split())
77   res = res.replace(".", "_").split("_")
78   if len(res) > 3:
79     msg = "Not a major_minor_patch correct syntax: '%s'" % aStr
80     raise Exception(msg)
81   if len(res) == 0:
82     msg = "An empty string is not a major_minor_patch syntax"
83     raise Exception(msg)
84
85   # complete MINOR.PATCH if not existing
86   if len(res) == 1:
87     res.append("0")
88   if len(res) == 2:
89     res.append("0")
90
91   try:
92     ii = int(res[0])
93   except:
94     msg = "major in major_minor_patch is not integer: '%s'" % aStr
95     raise Exception(msg)
96   if ii < 0:
97     msg = "major in major_minor_patch is negative integer: '%s'" % aStr
98     raise Exception(msg)
99
100   try:
101     ii = int(res[1])
102   except:
103     msg = "minor in major_minor_patch is not integer: '%s'" % aStr
104     raise Exception(msg)
105   if ii < 0:
106     msg = "minor in major_minor_patch is negative integer: '%s'" % aStr
107     raise Exception(msg)
108
109   try:
110     ii = int(res[2])
111   except:
112     msg = "patch in major_minor_patch is not integer: '%s'" % aStr
113     raise Exception(msg)
114   if ii < 0:
115     msg = "patch in major_minor_patch is negative integer: '%s'" % aStr
116     raise Exception(msg)
117
118   return [int(i) for i in res]
119
120 #############################################
121 def toCompactStr_majorMinorPatch(version):
122   """
123   OBSOLETE method
124   parameter version is list of integer as  [major, minor, patch]
125
126   | returns "789" for [7, 8, 9]
127   | warning:
128   |   minor, pach have to be integer less than 10
129   |   raise exception for [7, 10, 11]
130   |   (which returns "71011" as ambigous 710.1.1 for example)
131   """
132   # forbidden use from nov. 2023 and SALOME 9.10.0
133   raise Exception("obsolete toCompactStr_majorMinorPatch method: forbiden use of compact representation of '%s', fix problem in caller" % version)
134
135
136 #############################################
137 def getRange_majorMinorPatch(aStr, verbose=False):
138   """
139   extract from aStr a version range, defined as
140   '*_from_aMinVersionTag_to_aMaxVersionTag' or
141   '*version_aMinVersionTag_to_aMaxVersionTag'.
142
143   where aMinVersionTag and aMaxVersionTag are compatible with MinorMajorPatch class syntaxes
144   '1.2.3' or '1_2_3' etc.
145   if not found '_from_' or 'version_' first then aMinVersionTag is '0.0.0'
146
147   :param aStr: string to work
148   :return: list [min, max], where min, max are MinorMajorPatch instances.
149            else None if not found
150   """
151   tmp1 = aStr.lower().split("_to_")
152
153   if len(tmp1) < 2:
154     return None # no '_to_'
155   if len(tmp1) > 2:
156     msg = "more than one '_to_' is incorrect for version range: '%s'" % aStr
157     raise Exception(msg)
158   aMax = tmp1[1]
159
160   # accept older syntax as 'version_1_0_0_to_2_0_0', (as '_from_1_0_0_to_2_0_0')
161   if "version_" in tmp1[0] and "_from_" not in tmp1[0]:
162     aStr_with_from = aStr.lower().replace("version_", "_from_", 1)
163   else:
164     aStr_with_from = aStr.lower()
165
166   # print("aStr_with_from '%s' -> '%s'" % (aStr, aStr_with_from))
167
168   tmp0 = aStr_with_from.split("_from_")
169   tmp1 = aStr_with_from.split("_to_")
170
171   if len(tmp0) > 2:
172     msg = "more than one '_from_' is incorrect for version range: '%s'" % aStr
173     raise Exception(msg)
174
175   tmp2 = tmp1[0].split("_from_")
176
177   if len(tmp2) == 2:
178     aMin = tmp2[1]
179   else:
180     aMin ="0.0.0"
181
182   if verbose:
183     msg = "version min '%s' and version max '%s' in version range: '%s'" % (aMin, aMax, aStr)
184     print(msg)
185
186   try:
187     rMin = MinorMajorPatch(aMin)
188     rMax = MinorMajorPatch(aMax)
189   except:
190     msg = "problem version range in '%s'" % aStr
191     raise Exception(msg)
192     """if verbose:
193       print("WARNING: problem version range in '%s'" % aStr)
194     return None"""
195
196   if rMin > rMax:
197     msg = "version min '%s' > version max '%s' in version range: '%s'" % (rMin, rMax, aStr)
198     raise Exception(msg)
199
200   return [rMin, rMax]
201
202 #############################################
203 class MinorMajorPatch(object):
204   """\
205   class to define a version as MAJOR.MINOR.PATCH
206
207   | Given a version number MAJOR.MINOR.PATCH separator "_" or "."
208   | increment the
209   | MAJOR version when you make incompatible API changes,
210   | MINOR version when you add functionality in a backwards-compatible manner,
211   | PATCH version when you make backwards-compatible bug fixes.
212   """
213
214   def __init__(self, version):
215     if type(version) == list:
216       aStr = '_'.join([str(i) for i in version])
217       v = toList_majorMinorPatch(aStr)
218     else:
219       v = toList_majorMinorPatch(version)
220     self.major = v[0]
221     self.minor = v[1]
222     self.patch = v[2]
223
224   def __repr__(self, sep="_"):
225     """example is 'version_1_2_3' """
226     res = "version_%i%s%i%s%i" % (self.major, sep, self.minor, sep, self.patch)
227     return res
228
229   def __str__(self, sep="."):
230     """example is '1.2.3' """
231     res = "%i%s%i%s%i" % (self.major, sep, self.minor, sep, self.patch)
232     return res
233
234   def strSalome(self):
235     """example is '1_2_3' """
236     return self.__str__(sep="_")
237
238   def strClassic(self):
239     """example is '1.2.3' """
240     return self.__str__(sep=".")
241
242   def strCompact(self):
243     """example is '123' from '1.2.3' """
244     # forbidden use from nov. 2023 and SALOME 9.10.0
245     raise Exception("obsolete strCompact method: forbiden use of compact representation of '%s', fix problem in caller" % str(self))
246     # return toCompactStr_majorMinorPatch(self.toList())
247
248   def toList(self):
249     """example is list of integer [1, 2, 3] from '1.2.3' """
250     return [self.major, self.minor, self.patch]
251
252   def __lt__(self, other):
253     res = (self.toList() < other.toList())
254     return res
255
256   def __le__(self, other):
257     res = (self.toList() <= other.toList())
258     return res
259
260   def __gt__(self, other):
261     res = (self.toList() > other.toList())
262     return res
263
264   def __ge__(self, other):
265     res = (self.toList() >= other.toList())
266     return res
267
268   def __eq__(self, other):
269     res = (self.toList() == other.toList())
270     return res
271
272   def __ne__(self, other):
273     res = (self.toList() != other.toList())
274     return res