1 |
commit: 0d4a8c22f05f89a465f012e5952ef52cb1ac5deb |
2 |
Author: Ulrich Müller <ulm <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Sep 21 07:34:19 2017 +0000 |
4 |
Commit: Ulrich Müller <ulm <AT> gentoo <DOT> org> |
5 |
CommitDate: Tue Sep 26 18:46:27 2017 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=0d4a8c22 |
7 |
|
8 |
eapi7-ver.eclass: New algorithm for ver_test(). |
9 |
|
10 |
Use a regular expression for version validation and splitting, which |
11 |
turns out to be even faster than the previous "ultra-fast" approach. |
12 |
|
13 |
Thanks to Michał Górny for several optimisations. |
14 |
|
15 |
eclass/eapi7-ver.eclass | 289 ++++++++++++++---------------------------------- |
16 |
1 file changed, 82 insertions(+), 207 deletions(-) |
17 |
|
18 |
diff --git a/eclass/eapi7-ver.eclass b/eclass/eapi7-ver.eclass |
19 |
index 2644832574a..5ca8b8143af 100644 |
20 |
--- a/eclass/eapi7-ver.eclass |
21 |
+++ b/eclass/eapi7-ver.eclass |
22 |
@@ -174,79 +174,92 @@ ver_rs() { |
23 |
echo "${comp[*]}" |
24 |
} |
25 |
|
26 |
-# @FUNCTION: _ver_validate |
27 |
-# @USAGE: <comp[0]>... |
28 |
+# @FUNCTION: _ver_compare |
29 |
+# @USAGE: <va> <vb> |
30 |
+# @RETURN: 1 if <va> < <vb>, 2 if <va> = <vb>, 3 if <va> > <vb> |
31 |
+# @INTERNAL |
32 |
# @DESCRIPTION: |
33 |
-# Verify that the version component array passed as the argument |
34 |
-# validates according to the PMS version rules. Returns 0 if it does, |
35 |
-# 1 otherwise. |
36 |
-_ver_validate() { |
37 |
- local prev=start |
38 |
- |
39 |
- while [[ ${1} || ${2} ]]; do |
40 |
- local s=${1} |
41 |
- local c=${2} |
42 |
- |
43 |
- if [[ -z ${s} ]]; then |
44 |
- if [[ ${c} == [0-9]* ]]; then |
45 |
- # number without preceding sep may be either: |
46 |
- case ${prev} in |
47 |
- # a. 1st version number |
48 |
- start) prev=numeric;; |
49 |
- # b. _foo suffix number |
50 |
- suffix) prev=suffix_num;; |
51 |
- # c. -rN revision number |
52 |
- revision) prev=revision_num;; |
53 |
- *) return 1;; |
54 |
- esac |
55 |
- elif [[ -n ${c} ]]; then |
56 |
- # letter without preceding sep = letter after version |
57 |
- [[ ${prev} == numeric ]] || return 1 |
58 |
- [[ ${#c} -eq 1 ]] || return 1 |
59 |
- prev=letter |
60 |
- fi |
61 |
- elif [[ -z ${c} ]]; then |
62 |
- # trailing suffix? |
63 |
- return 1 |
64 |
- elif [[ ${s} == . ]]; then |
65 |
- # number preceded by dot = numeric component |
66 |
- [[ ${prev} == numeric ]] || return 1 |
67 |
- elif [[ ${s} == _ ]]; then |
68 |
- # _ implies _foo suffix |
69 |
- case ${prev} in |
70 |
- numeric|letter|suffix|suffix_num) ;; |
71 |
- *) return 1;; |
72 |
- esac |
73 |
- |
74 |
- case ${c} in |
75 |
- alpha) ;; |
76 |
- beta) ;; |
77 |
- rc) ;; |
78 |
- pre) ;; |
79 |
- p) ;; |
80 |
- *) return 1;; |
81 |
- esac |
82 |
- prev=suffix |
83 |
- elif [[ ${s} == - ]]; then |
84 |
- # - implies revision |
85 |
- case ${prev} in |
86 |
- numeric|letter|suffix|suffix_num) ;; |
87 |
- *) return 1;; |
88 |
- esac |
89 |
- |
90 |
- [[ ${c} == r ]] || return 1 |
91 |
- prev=revision |
92 |
+# Compare two versions <va> and <vb>. If <va> is less than, equal to, |
93 |
+# or greater than <vb>, return 1, 2, or 3 as exit status, respectively. |
94 |
+_ver_compare() { |
95 |
+ local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C |
96 |
+ |
97 |
+ re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$" |
98 |
+ |
99 |
+ [[ ${va} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${va}" |
100 |
+ an=${BASH_REMATCH[1]} |
101 |
+ al=${BASH_REMATCH[3]} |
102 |
+ as=${BASH_REMATCH[4]} |
103 |
+ ar=${BASH_REMATCH[7]} |
104 |
+ |
105 |
+ [[ ${vb} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${vb}" |
106 |
+ bn=${BASH_REMATCH[1]} |
107 |
+ bl=${BASH_REMATCH[3]} |
108 |
+ bs=${BASH_REMATCH[4]} |
109 |
+ br=${BASH_REMATCH[7]} |
110 |
+ |
111 |
+ # Compare numeric components (PMS algorithm 3.2) |
112 |
+ # First component |
113 |
+ a=${an%%.*} |
114 |
+ b=${bn%%.*} |
115 |
+ [[ 10#${a} -gt 10#${b} ]] && return 3 |
116 |
+ [[ 10#${a} -lt 10#${b} ]] && return 1 |
117 |
+ |
118 |
+ while [[ ${an} == *.* && ${bn} == *.* ]]; do |
119 |
+ # Other components (PMS algorithm 3.3) |
120 |
+ an=${an#*.} |
121 |
+ bn=${bn#*.} |
122 |
+ a=${an%%.*} |
123 |
+ b=${bn%%.*} |
124 |
+ if [[ ${a} == 0* || ${b} == 0* ]]; then |
125 |
+ # Remove any trailing zeros |
126 |
+ [[ ${a} =~ 0+$ ]] && a=${a%"${BASH_REMATCH[0]}"} |
127 |
+ [[ ${b} =~ 0+$ ]] && b=${b%"${BASH_REMATCH[0]}"} |
128 |
+ [[ ${a} > ${b} ]] && return 3 |
129 |
+ [[ ${a} < ${b} ]] && return 1 |
130 |
else |
131 |
- return 1 |
132 |
+ [[ ${a} -gt ${b} ]] && return 3 |
133 |
+ [[ ${a} -lt ${b} ]] && return 1 |
134 |
fi |
135 |
- |
136 |
- shift 2 |
137 |
done |
138 |
+ [[ ${an} == *.* ]] && return 3 |
139 |
+ [[ ${bn} == *.* ]] && return 1 |
140 |
+ |
141 |
+ # Compare letter components (PMS algorithm 3.4) |
142 |
+ [[ ${al} > ${bl} ]] && return 3 |
143 |
+ [[ ${al} < ${bl} ]] && return 1 |
144 |
+ |
145 |
+ # Compare suffixes (PMS algorithm 3.5) |
146 |
+ as=${as#_}${as:+_} |
147 |
+ bs=${bs#_}${bs:+_} |
148 |
+ while [[ -n ${as} && -n ${bs} ]]; do |
149 |
+ # Compare each suffix (PMS algorithm 3.6) |
150 |
+ a=${as%%_*} |
151 |
+ b=${bs%%_*} |
152 |
+ if [[ ${a%%[0-9]*} == "${b%%[0-9]*}" ]]; then |
153 |
+ [[ 10#${a##*[a-z]} -gt 10#${b##*[a-z]} ]] && return 3 |
154 |
+ [[ 10#${a##*[a-z]} -lt 10#${b##*[a-z]} ]] && return 1 |
155 |
+ else |
156 |
+ # Check for p first |
157 |
+ [[ ${a%%[0-9]*} == p ]] && return 3 |
158 |
+ [[ ${b%%[0-9]*} == p ]] && return 1 |
159 |
+ # Hack: Use that alpha < beta < pre < rc alphabetically |
160 |
+ [[ ${a} > ${b} ]] && return 3 || return 1 |
161 |
+ fi |
162 |
+ as=${as#*_} |
163 |
+ bs=${bs#*_} |
164 |
+ done |
165 |
+ if [[ -n ${as} ]]; then |
166 |
+ [[ ${as} == p[_0-9]* ]] && return 3 || return 1 |
167 |
+ elif [[ -n ${bs} ]]; then |
168 |
+ [[ ${bs} == p[_0-9]* ]] && return 1 || return 3 |
169 |
+ fi |
170 |
|
171 |
- # empty version string? |
172 |
- [[ ${prev} != start ]] || return 1 |
173 |
+ # Compare revision components (PMS algorithm 3.7) |
174 |
+ [[ 10#${ar#-r} -gt 10#${br#-r} ]] && return 3 |
175 |
+ [[ 10#${ar#-r} -lt 10#${br#-r} ]] && return 1 |
176 |
|
177 |
- return 0 |
178 |
+ return 2 |
179 |
} |
180 |
|
181 |
# @FUNCTION: ver_test |
182 |
@@ -258,7 +271,6 @@ _ver_validate() { |
183 |
# revision parts), and the comparison is performed according to |
184 |
# the algorithm specified in the PMS. |
185 |
ver_test() { |
186 |
- local LC_ALL=C |
187 |
local va op vb |
188 |
|
189 |
if [[ $# -eq 3 ]]; then |
190 |
@@ -278,143 +290,6 @@ ver_test() { |
191 |
*) die "${FUNCNAME}: invalid operator: ${op}" ;; |
192 |
esac |
193 |
|
194 |
- # explicitly strip -r0[00000...] to avoid overcomplexifying the algo |
195 |
- [[ ${va} == *-r0* && 10#${va#*-r} -eq 0 ]] && va=${va%-r*} |
196 |
- [[ ${vb} == *-r0* && 10#${vb#*-r} -eq 0 ]] && vb=${vb%-r*} |
197 |
- |
198 |
- local comp compb |
199 |
- _ver_split "${vb}" |
200 |
- compb=( "${comp[@]}" ) |
201 |
- _ver_split "${va}" |
202 |
- |
203 |
- _ver_validate "${comp[@]}" || die "${FUNCNAME}: invalid version: ${va}" |
204 |
- _ver_validate "${compb[@]}" || die "${FUNCNAME}: invalid version: ${vb}" |
205 |
- |
206 |
- local i sa sb ca cb wa wb result=0 |
207 |
- for (( i = 0;; i += 2 )); do |
208 |
- sa=${comp[i]} |
209 |
- ca=${comp[i+1]} |
210 |
- sb=${compb[i]} |
211 |
- cb=${compb[i+1]} |
212 |
- |
213 |
- # 1. determine the component type for Ca |
214 |
- if [[ -z ${sa} ]]; then |
215 |
- if [[ ${ca} == [0-9]* ]]; then |
216 |
- # number without preceding sep may be either: |
217 |
- # a. 1st version number |
218 |
- # b. _foo suffix number |
219 |
- # c. -rN revision number |
220 |
- # weight is irrelevant since (a) occurs simultaneously, |
221 |
- # and (b)/(c) use weight of preceding component |
222 |
- wa=0 |
223 |
- # method: plain numeric |
224 |
- m=pn |
225 |
- elif [[ -n ${ca} ]]; then |
226 |
- # letter without preceding sep = letter after version |
227 |
- # weight below numeric, lexical method |
228 |
- wa=9 |
229 |
- m=l |
230 |
- else |
231 |
- # empty == end of version string |
232 |
- # weight below all positive stuff but above negative |
233 |
- wa=6 |
234 |
- m= |
235 |
- fi |
236 |
- elif [[ ${sa} == . ]]; then |
237 |
- # number preceded by dot = numeric component |
238 |
- # highest weight, weird PMS 2+ component comparison |
239 |
- wa=10 |
240 |
- m=wn |
241 |
- elif [[ ${sa} == _ ]]; then |
242 |
- # _ implies _foo suffix |
243 |
- # weights differ, comparison by weight |
244 |
- case ${ca} in |
245 |
- alpha) wa=2 ;; |
246 |
- beta) wa=3 ;; |
247 |
- rc) wa=4 ;; |
248 |
- pre) wa=5 ;; |
249 |
- p) wa=8 ;; |
250 |
- *) die "Invalid version suffix: _${ca}";; |
251 |
- esac |
252 |
- m= |
253 |
- elif [[ ${sa} == - ]]; then |
254 |
- # - implies revision |
255 |
- # weight below positive suffixes, no comparison |
256 |
- [[ ${ca} == r ]] || die "Invalid version part: -${ca}" |
257 |
- wa=7 |
258 |
- m= |
259 |
- fi |
260 |
- |
261 |
- # 2. determine the component type for Cb |
262 |
- if [[ -z ${sb} ]]; then |
263 |
- if [[ ${cb} == [0-9]* ]]; then |
264 |
- wb=0 |
265 |
- elif [[ -n ${cb} ]]; then |
266 |
- wb=9 |
267 |
- else |
268 |
- wb=6 |
269 |
- fi |
270 |
- elif [[ ${sb} == . ]]; then |
271 |
- wb=10 |
272 |
- elif [[ ${sb} == _ ]]; then |
273 |
- case ${cb} in |
274 |
- alpha) wb=2 ;; |
275 |
- beta) wb=3 ;; |
276 |
- rc) wb=4 ;; |
277 |
- pre) wb=5 ;; |
278 |
- p) wb=8 ;; |
279 |
- *) die "Invalid version suffix: _${cb}";; |
280 |
- esac |
281 |
- elif [[ ${sb} == - ]]; then |
282 |
- [[ ${cb} == r ]] || die "Invalid version part: -${cb}" |
283 |
- wb=7 |
284 |
- fi |
285 |
- |
286 |
- # DEBUG |
287 |
- #echo "$sa $ca [$wa] <$m> $sb $cb [$wb]" >&2 |
288 |
- |
289 |
- # 3. compare weights, we can proceed further only if weights match |
290 |
- if [[ ${wa} -ne ${wb} ]]; then |
291 |
- result=$(( wa - wb )) |
292 |
- break |
293 |
- fi |
294 |
- |
295 |
- # 4. both empty maybe? |
296 |
- [[ -z ${ca} && -z ${cb} ]] && break |
297 |
- |
298 |
- # 5. compare components according to the algo |
299 |
- |
300 |
- # weird numeric is weird and reuses pn/l, so do it first |
301 |
- # (PMS algo 3.3) |
302 |
- if [[ ${m} == wn ]]; then |
303 |
- if [[ ${ca} != 0* && ${cb} != 0* ]]; then |
304 |
- # if neither of them starts with 0, use normal numeric |
305 |
- m=pn |
306 |
- else |
307 |
- # strip trailing zeros |
308 |
- while [[ ${ca} == *0 ]]; do ca=${ca::-1}; done |
309 |
- while [[ ${cb} == *0 ]]; do cb=${cb::-1}; done |
310 |
- m=l |
311 |
- fi |
312 |
- fi |
313 |
- |
314 |
- case ${m} in |
315 |
- pn) # plain numeric |
316 |
- if [[ 10#${ca} -ne 10#${cb} ]]; then |
317 |
- result=$(( 10#${ca} - 10#${cb} )) |
318 |
- break |
319 |
- fi |
320 |
- ;; |
321 |
- l) # lexical |
322 |
- if [[ ${ca} != ${cb} ]]; then |
323 |
- [[ ${ca} > ${cb} ]] && result=1 || result=-1 |
324 |
- break |
325 |
- fi |
326 |
- ;; |
327 |
- '') ;; |
328 |
- *) die "Unexpected comparison method m=${m}";; |
329 |
- esac |
330 |
- done |
331 |
- |
332 |
- test "${result}" "${op}" 0 |
333 |
+ _ver_compare "${va}" "${vb}" |
334 |
+ test $? "${op}" 2 |
335 |
} |