Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: lib/cros_portage_versions.py

Issue 4442001: Add more error checking to preflight queue. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git
Patch Set: Address comments. Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« cros_mark_as_stable.py ('K') | « cros_mark_as_stable.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # versions.py -- core Portage functionality
sosa 2010/11/12 21:28:40 This is no longer needed.
davidjames 2010/11/12 21:37:50 Done.
2 # Copyright 1998-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Id: versions.py 15234 2010-01-29 18:45:23Z zmedico $
5
6 import re
7
8
9 # \w is [a-zA-Z0-9_]
10
11 # 2.1.1 A category name may contain any of the characters [A-Za-z0-9+_.-].
12 # It must not begin with a hyphen or a dot.
13 _cat = r'[\w+][\w+.-]*'
14
15 # 2.1.2 A package name may contain any of the characters [A-Za-z0-9+_-].
16 # It must not begin with a hyphen,
17 # and must not end in a hyphen followed by one or more digits.
18 _pkg = r'[\w+][\w+-]*?'
19
20 _v = r'(cvs\.)?(\d+)((\.\d+)*)([a-z]?)((_(pre|p|beta|alpha|rc)\d*)*)'
21 _rev = r'\d+'
22 _vr = _v + '(-r(' + _rev + '))?'
23
24 _cp = '(' + _cat + '/' + _pkg + '(-' + _vr + ')?)'
25 _cpv = '(' + _cp + '-' + _vr + ')'
26 _pv = '(?P<pn>' + _pkg + '(?P<pn_inval>-' + _vr + ')?)' + '-(?P<ver>' + _v + ')( -r(?P<rev>' + _rev + '))?'
27
28 ver_regexp = re.compile("^" + _vr + "$")
29 suffix_regexp = re.compile("^(alpha|beta|rc|pre|p)(\\d*)$")
30 suffix_value = {"pre": -2, "p": 0, "alpha": -4, "beta": -3, "rc": -1}
31 endversion_keys = ["pre", "p", "alpha", "beta", "rc"]
32
33 def ververify(myver, silent=1):
34 if ver_regexp.match(myver):
35 return 1
36 else:
37 if not silent:
38 print("!!! syntax error in version: %s" % myver)
39 return 0
40
41 vercmp_cache = {}
42 def vercmp(ver1, ver2, silent=1):
43 """
44 Compare two versions
45 Example usage:
46 >>> from portage.versions import vercmp
47 >>> vercmp('1.0-r1','1.2-r3')
48 negative number
49 >>> vercmp('1.3','1.2-r3')
50 positive number
51 >>> vercmp('1.0_p3','1.0_p3')
52 0
53
54 @param pkg1: version to compare with (see ver_regexp in portage.versions .py)
55 @type pkg1: string (example: "2.1.2-r3")
56 @param pkg2: version to compare againts (see ver_regexp in portage.versi ons.py)
57 @type pkg2: string (example: "2.1.2_rc5")
58 @rtype: None or float
59 @return:
60 1. positive if ver1 is greater than ver2
61 2. negative if ver1 is less than ver2
62 3. 0 if ver1 equals ver2
63 4. None if ver1 or ver2 are invalid (see ver_regexp in portage.versions. py)
64 """
65
66 if ver1 == ver2:
67 return 0
68 mykey=ver1+":"+ver2
69 try:
70 return vercmp_cache[mykey]
71 except KeyError:
72 pass
73 match1 = ver_regexp.match(ver1)
74 match2 = ver_regexp.match(ver2)
75
76 # checking that the versions are valid
77 if not match1 or not match1.groups():
78 if not silent:
79 print("!!! syntax error in version: %s" % ver1)
80 return None
81 if not match2 or not match2.groups():
82 if not silent:
83 print("!!! syntax error in version: %s" % ver2)
84 return None
85
86 # shortcut for cvs ebuilds (new style)
87 if match1.group(1) and not match2.group(1):
88 vercmp_cache[mykey] = 1
89 return 1
90 elif match2.group(1) and not match1.group(1):
91 vercmp_cache[mykey] = -1
92 return -1
93
94 # building lists of the version parts before the suffix
95 # first part is simple
96 list1 = [int(match1.group(2))]
97 list2 = [int(match2.group(2))]
98
99 # this part would greatly benefit from a fixed-length version pattern
100 if match1.group(3) or match2.group(3):
101 vlist1 = match1.group(3)[1:].split(".")
102 vlist2 = match2.group(3)[1:].split(".")
103
104 for i in range(0, max(len(vlist1), len(vlist2))):
105 # Implcit .0 is given a value of -1, so that 1.0.0 > 1.0 , since it
106 # would be ambiguous if two versions that aren't literal ly equal
107 # are given the same value (in sorting, for example).
108 if len(vlist1) <= i or len(vlist1[i]) == 0:
109 list1.append(-1)
110 list2.append(int(vlist2[i]))
111 elif len(vlist2) <= i or len(vlist2[i]) == 0:
112 list1.append(int(vlist1[i]))
113 list2.append(-1)
114 # Let's make life easy and use integers unless we're for ced to use floats
115 elif (vlist1[i][0] != "0" and vlist2[i][0] != "0"):
116 list1.append(int(vlist1[i]))
117 list2.append(int(vlist2[i]))
118 # now we have to use floats so 1.02 compares correctly a gainst 1.1
119 else:
120 # list1.append(float("0."+vlist1[i]))
121 # list2.append(float("0."+vlist2[i]))
122 # Since python floats have limited range, we mul tiply both
123 # floating point representations by a constant s o that they are
124 # transformed into whole numbers. This allows th e practically
125 # infinite range of a python int to be exploited . The
126 # multiplication is done by padding both literal strings with
127 # zeros as necessary to ensure equal length.
128 max_len = max(len(vlist1[i]), len(vlist2[i]))
129 list1.append(int(vlist1[i].ljust(max_len, "0")))
130 list2.append(int(vlist2[i].ljust(max_len, "0")))
131
132 # and now the final letter
133 # NOTE: Behavior changed in r2309 (between portage-2.0.x and portage-2.1 ).
134 # The new behavior is 12.2.5 > 12.2b which, depending on how you look at ,
135 # may seem counter-intuitive. However, if you really think about it, it
136 # seems like it's probably safe to assume that this is the behavior that
137 # is intended by anyone who would use versions such as these.
138 if len(match1.group(5)):
139 list1.append(ord(match1.group(5)))
140 if len(match2.group(5)):
141 list2.append(ord(match2.group(5)))
142
143 for i in range(0, max(len(list1), len(list2))):
144 if len(list1) <= i:
145 vercmp_cache[mykey] = -1
146 return -1
147 elif len(list2) <= i:
148 vercmp_cache[mykey] = 1
149 return 1
150 elif list1[i] != list2[i]:
151 a = list1[i]
152 b = list2[i]
153 rval = (a > b) - (a < b)
154 vercmp_cache[mykey] = rval
155 return rval
156
157 # main version is equal, so now compare the _suffix part
158 list1 = match1.group(6).split("_")[1:]
159 list2 = match2.group(6).split("_")[1:]
160
161 for i in range(0, max(len(list1), len(list2))):
162 # Implicit _p0 is given a value of -1, so that 1 < 1_p0
163 if len(list1) <= i:
164 s1 = ("p","-1")
165 else:
166 s1 = suffix_regexp.match(list1[i]).groups()
167 if len(list2) <= i:
168 s2 = ("p","-1")
169 else:
170 s2 = suffix_regexp.match(list2[i]).groups()
171 if s1[0] != s2[0]:
172 a = suffix_value[s1[0]]
173 b = suffix_value[s2[0]]
174 rval = (a > b) - (a < b)
175 vercmp_cache[mykey] = rval
176 return rval
177 if s1[1] != s2[1]:
178 # it's possible that the s(1|2)[1] == ''
179 # in such a case, fudge it.
180 try:
181 r1 = int(s1[1])
182 except ValueError:
183 r1 = 0
184 try:
185 r2 = int(s2[1])
186 except ValueError:
187 r2 = 0
188 rval = (r1 > r2) - (r1 < r2)
189 if rval:
190 vercmp_cache[mykey] = rval
191 return rval
192
193 # the suffix part is equal to, so finally check the revision
194 if match1.group(10):
195 r1 = int(match1.group(10))
196 else:
197 r1 = 0
198 if match2.group(10):
199 r2 = int(match2.group(10))
200 else:
201 r2 = 0
202 rval = (r1 > r2) - (r1 < r2)
203 vercmp_cache[mykey] = rval
204 return rval
205
206 def pkgcmp(pkg1, pkg2):
207 """
208 Compare 2 package versions created in pkgsplit format.
209
210 Example usage:
211 >>> from portage.versions import *
212 >>> pkgcmp(pkgsplit('test-1.0-r1'),pkgsplit('test-1.2-r3'))
213 -1
214 >>> pkgcmp(pkgsplit('test-1.3'),pkgsplit('test-1.2-r3'))
215 1
216
217 @param pkg1: package to compare with
218 @type pkg1: list (example: ['test', '1.0', 'r1'])
219 @param pkg2: package to compare againts
220 @type pkg2: list (example: ['test', '1.0', 'r1'])
221 @rtype: None or integer
222 @return:
223 1. None if package names are not the same
224 2. 1 if pkg1 is greater than pkg2
225 3. -1 if pkg1 is less than pkg2
226 4. 0 if pkg1 equals pkg2
227 """
228 if pkg1[0] != pkg2[0]:
229 return None
230 return vercmp("-".join(pkg1[1:]), "-".join(pkg2[1:]))
231
232 _pv_re = re.compile('^' + _pv + '$', re.VERBOSE)
233
234 def _pkgsplit(mypkg):
235 """
236 @param mypkg: pv
237 @return:
238 1. None if input is invalid.
239 2. (pn, ver, rev) if input is pv
240 """
241 m = _pv_re.match(mypkg)
242 if m is None:
243 return None
244
245 if m.group('pn_inval') is not None:
246 # package name appears to have a version-like suffix
247 return None
248
249 rev = m.group('rev')
250 if rev is None:
251 rev = '0'
252 rev = 'r' + rev
253
254 return (m.group('pn'), m.group('ver'), rev)
255
256 _missing_cat = 'null'
257 catcache={}
258 def catpkgsplit(mydata,silent=1):
259 """
260 Takes a Category/Package-Version-Rev and returns a list of each.
261
262 @param mydata: Data to split
263 @type mydata: string
264 @param silent: suppress error messages
265 @type silent: Boolean (integer)
266 @rype: list
267 @return:
268 1. If each exists, it returns [cat, pkgname, version, rev]
269 2. If cat is not specificed in mydata, cat will be "null"
270 3. if rev does not exist it will be '-r0'
271 """
272
273 try:
274 return catcache[mydata]
275 except KeyError:
276 pass
277 mysplit = mydata.split('/', 1)
278 p_split=None
279 if len(mysplit)==1:
280 cat = _missing_cat
281 p_split = _pkgsplit(mydata)
282 elif len(mysplit)==2:
283 cat = mysplit[0]
284 p_split = _pkgsplit(mysplit[1])
285 if not p_split:
286 catcache[mydata]=None
287 return None
288 retval = (cat, p_split[0], p_split[1], p_split[2])
289 catcache[mydata]=retval
290 return retval
291
292 def pkgsplit(mypkg, silent=1):
293 """
294 @param mypkg: either a pv or cpv
295 @return:
296 1. None if input is invalid.
297 2. (pn, ver, rev) if input is pv
298 3. (cp, ver, rev) if input is a cpv
299 """
300 catpsplit = catpkgsplit(mypkg)
301 if catpsplit is None:
302 return None
303 cat, pn, ver, rev = catpsplit
304 if cat is _missing_cat and '/' not in mypkg:
305 return (pn, ver, rev)
306 else:
307 return (cat + '/' + pn, ver, rev)
308
309 def catsplit(mydep):
310 return mydep.split("/", 1)
311
312 def best(mymatches):
313 """Accepts None arguments; assumes matches are valid."""
314 if not mymatches:
315 return ""
316 if len(mymatches) == 1:
317 return mymatches[0]
318 bestmatch = mymatches[0]
319 p2 = catpkgsplit(bestmatch)[1:]
320 for x in mymatches[1:]:
321 p1 = catpkgsplit(x)[1:]
322 if pkgcmp(p1, p2) > 0:
323 bestmatch = x
324 p2 = catpkgsplit(bestmatch)[1:]
325 return bestmatch
OLDNEW
« cros_mark_as_stable.py ('K') | « cros_mark_as_stable.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698