Gentoo Archives: gentoo-commits

From: "Ulrich Müller" <ulm@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: eclass/
Date: Tue, 26 Sep 2017 18:46:38
Message-Id: 1506451587.0d4a8c22f05f89a465f012e5952ef52cb1ac5deb.ulm@gentoo
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 }