1 |
EAPI 7 is introducing new version manipulation and comparison functions |
2 |
that aim to replace versionator.eclass. This eclass provides an 'early |
3 |
adopter' versions of those routines. |
4 |
|
5 |
It serves two goals: |
6 |
|
7 |
a. getting wider review and some real-life testing before |
8 |
the specification is set in stone, and |
9 |
|
10 |
b. making it possible to adapt ebuilds to the new routines early, |
11 |
reducing the future work of EAPI 7 porting. |
12 |
|
13 |
For more details on the new logic, please see the eclass documentation. |
14 |
Long story short, we are introducing three functions: |
15 |
|
16 |
1. ver_cut -- to get substrings of the version string, |
17 |
|
18 |
2. ver_rs -- to replace version separators via indices, |
19 |
|
20 |
3. ver_test -- to compare two version numbers. |
21 |
|
22 |
The third function is not implemented in the eclass. It's meant to reuse |
23 |
the algorithms from the package manager, and the final implementation |
24 |
will most likely reuse the code from the package manager (e.g. via IPC). |
25 |
--- |
26 |
eclass/eapi7-ver.eclass | 181 ++++++++++++++++++++++++++++++++++++ |
27 |
eclass/tests/eapi7-ver.sh | 65 +++++++++++++ |
28 |
eclass/tests/eapi7-ver:benchmark.sh | 76 +++++++++++++++ |
29 |
3 files changed, 322 insertions(+) |
30 |
create mode 100644 eclass/eapi7-ver.eclass |
31 |
create mode 100755 eclass/tests/eapi7-ver.sh |
32 |
create mode 100755 eclass/tests/eapi7-ver:benchmark.sh |
33 |
|
34 |
diff --git a/eclass/eapi7-ver.eclass b/eclass/eapi7-ver.eclass |
35 |
new file mode 100644 |
36 |
index 000000000000..c82da6192c94 |
37 |
--- /dev/null |
38 |
+++ b/eclass/eapi7-ver.eclass |
39 |
@@ -0,0 +1,181 @@ |
40 |
+# Copyright 1999-2017 Gentoo Foundation |
41 |
+# Distributed under the terms of the GNU General Public License v2 |
42 |
+ |
43 |
+# @ECLASS: eapi7-ver.eclass |
44 |
+# @MAINTAINER: |
45 |
+# PMS team <pms@g.o> |
46 |
+# @AUTHOR: |
47 |
+# Ulrich Müller <ulm@g.o> |
48 |
+# Michał Górny <mgorny@g.o> |
49 |
+# @BLURB: Testing implementation of EAPI 7 version manipulators |
50 |
+# @DESCRIPTION: |
51 |
+# A stand-alone implementation of the version manipulation functions |
52 |
+# aimed for EAPI 7. Intended to be used for wider testing of |
53 |
+# the proposed functions and to allow ebuilds to switch to the new |
54 |
+# model early, with minimal change needed for actual EAPI 7. |
55 |
+# |
56 |
+# https://bugs.gentoo.org/482170 |
57 |
+# |
58 |
+# Note: version comparison function is not included currently. |
59 |
+# |
60 |
+# Version strings |
61 |
+# =============== |
62 |
+# The functions support arbitrary version strings consisting of version |
63 |
+# components interspersed with (possibly empty) version separators. |
64 |
+# |
65 |
+# A version component can either consist purely of digits ([0-9]+) or |
66 |
+# purely of uppercase and lowercase letters ([a-zA-Z]+). Any other |
67 |
+# character is treated as a version separator. |
68 |
+# |
69 |
+# The version is processed left-to-right, and each successive component |
70 |
+# is assigned numbers starting with 1. The components are either split |
71 |
+# on version separators or on boundaries between digits and letters |
72 |
+# (in which case the separator between the components is empty). |
73 |
+# Version separators are assigned numbers starting with 1 for |
74 |
+# the separator between 1st and 2nd components. As a special case, |
75 |
+# if the version string starts with a separator, it is assigned index 0. |
76 |
+# |
77 |
+# Examples: |
78 |
+# |
79 |
+# 1.2b-alpha4 -> 1 . 2 '' b - alpha '' 4 |
80 |
+# c s c s c s c s c |
81 |
+# 1 1 2 2 3 3 4 4 5 |
82 |
+# |
83 |
+# .11. -> . 11 . |
84 |
+# s c s |
85 |
+# 0 1 1 |
86 |
+# |
87 |
+# Ranges |
88 |
+# ====== |
89 |
+# A range can be specified as 'm' for m-th version component, 'm-' |
90 |
+# for all components starting with m-th or 'm-n' for components starting |
91 |
+# at m-th and ending at n-th (inclusive). If the range spans outside |
92 |
+# the version string, it is truncated silently. |
93 |
+ |
94 |
+case ${EAPI:-0} in |
95 |
+ 0|1|2|3|4|5) |
96 |
+ die "${ECLASS}: EAPI=${EAPI:-0} not supported";; |
97 |
+ 6) |
98 |
+ ;; |
99 |
+ *) |
100 |
+ die "${ECLASS}: EAPI=${EAPI} unknown";; |
101 |
+esac |
102 |
+ |
103 |
+# @FUNCTION: _ver_parse_range |
104 |
+# @INTERNAL |
105 |
+# @USAGE: <range> <max> |
106 |
+# @DESCRIPTION: |
107 |
+# Parse the range string <range>, setting 'start' and 'end' variables |
108 |
+# to the appropriate bounds. <min> and <max> specify the appropriate |
109 |
+# lower and upper bound for the range; the user-specified value is |
110 |
+# truncated to this range. |
111 |
+_ver_parse_range() { |
112 |
+ local range=${1} |
113 |
+ local max=${2} |
114 |
+ |
115 |
+ [[ ${range} == [0-9]* ]] || die "${FUNCNAME}: range must start with a number" |
116 |
+ start=${range%-*} |
117 |
+ [[ ${range} == *-* ]] && end=${range#*-} || end=${start} |
118 |
+ if [[ ${end} ]]; then |
119 |
+ [[ ${start} -le ${end} ]] || die "${FUNCNAME}: end of range must be >= start" |
120 |
+ [[ ${end} -le ${max} ]] || end=${max} |
121 |
+ else |
122 |
+ end=${max} |
123 |
+ fi |
124 |
+} |
125 |
+ |
126 |
+# @FUNCTION: _ver_split |
127 |
+# @INTERNAL |
128 |
+# @USAGE: <version> |
129 |
+# @DESCRIPTION: |
130 |
+# Split the version string <version> into separator-component array. |
131 |
+# Sets 'comp' to an array of the form: ( s_0 c_1 s_1 c_2 s_2 c_3... ) |
132 |
+# where s_i are separators and c_i are components. |
133 |
+_ver_split() { |
134 |
+ local v=${1} LC_ALL=C |
135 |
+ |
136 |
+ comp=() |
137 |
+ |
138 |
+ # get separators and components |
139 |
+ local s c |
140 |
+ while [[ ${v} ]]; do |
141 |
+ # cut the separator |
142 |
+ s=${v%%[a-zA-Z0-9]*} |
143 |
+ v=${v:${#s}} |
144 |
+ # cut the next component; it can be either digits or letters |
145 |
+ [[ ${v} == [0-9]* ]] && c=${v%%[^0-9]*} || c=${v%%[^a-zA-Z]*} |
146 |
+ v=${v:${#c}} |
147 |
+ |
148 |
+ comp+=( "${s}" "${c}" ) |
149 |
+ done |
150 |
+} |
151 |
+ |
152 |
+# @FUNCTION: ver_cut |
153 |
+# @USAGE: <range> [<version>] |
154 |
+# @DESCRIPTION: |
155 |
+# Print the substring of the version string containing components |
156 |
+# defined by the <range> and the version separators between them. |
157 |
+# Processes <version> if specified, ${PV} otherwise. |
158 |
+# |
159 |
+# For the syntax of versions and ranges, please see the eclass |
160 |
+# description. |
161 |
+ver_cut() { |
162 |
+ local range=${1} |
163 |
+ local v=${2:-${PV}} |
164 |
+ local start end |
165 |
+ local -a comp |
166 |
+ |
167 |
+ _ver_split "${v}" |
168 |
+ local max=$((${#comp[@]}/2)) |
169 |
+ _ver_parse_range "${range}" "${max}" |
170 |
+ |
171 |
+ local IFS= |
172 |
+ if [[ ${start} -gt 0 ]]; then |
173 |
+ start=$(( start*2 - 1 )) |
174 |
+ fi |
175 |
+ echo "${comp[*]:start:end*2-start}" |
176 |
+} |
177 |
+ |
178 |
+# @FUNCTION: ver_rs |
179 |
+# @USAGE: <range> <repl> [<range> <repl>...] [<version>] |
180 |
+# @DESCRIPTION: |
181 |
+# Print the version string after substituting the specified version |
182 |
+# separators at <range> with <repl> (string). Multiple '<range> <repl>' |
183 |
+# pairs can be specified. Processes <version> if specified, |
184 |
+# ${PV} otherwise. |
185 |
+# |
186 |
+# For the syntax of versions and ranges, please see the eclass |
187 |
+# description. |
188 |
+ver_rs() { |
189 |
+ local v |
190 |
+ (( ${#} & 1 )) && v=${@: -1} || v=${PV} |
191 |
+ local start end i |
192 |
+ local -a comp |
193 |
+ |
194 |
+ _ver_split "${v}" |
195 |
+ local max=$((${#comp[@]}/2 - 1)) |
196 |
+ |
197 |
+ while [[ ${#} -ge 2 ]]; do |
198 |
+ _ver_parse_range "${1}" "${max}" |
199 |
+ for (( i = start*2; i <= end*2; i+=2 )); do |
200 |
+ [[ ${i} -eq 0 && -z ${comp[i]} ]] && continue |
201 |
+ comp[i]=${2} |
202 |
+ done |
203 |
+ shift 2 |
204 |
+ done |
205 |
+ |
206 |
+ local IFS= |
207 |
+ echo "${comp[*]}" |
208 |
+} |
209 |
+ |
210 |
+# @FUNCTION: ver_test |
211 |
+# @USAGE: [<v1>] <op> <v2> |
212 |
+# @DESCRIPTION: |
213 |
+# Check if the relation <v1> <op> <v2> is true. If <v1> is not specified, |
214 |
+# default to ${PVR}. <op> can be -gt, -ge, -eq, -ne, -le, -lt. |
215 |
+# Both versions must conform to the PMS version syntax (with optional |
216 |
+# revision parts), and the comparison is performed according to |
217 |
+# the algorithm specified in the PMS. |
218 |
+ver_test() { |
219 |
+ die "${FUNCNAME}: not implemented" |
220 |
+} |
221 |
diff --git a/eclass/tests/eapi7-ver.sh b/eclass/tests/eapi7-ver.sh |
222 |
new file mode 100755 |
223 |
index 000000000000..8a96e4d29b1b |
224 |
--- /dev/null |
225 |
+++ b/eclass/tests/eapi7-ver.sh |
226 |
@@ -0,0 +1,65 @@ |
227 |
+#!/bin/bash |
228 |
+# Copyright 1999-2017 Gentoo Foundation |
229 |
+# Distributed under the terms of the GNU General Public License v2 |
230 |
+ |
231 |
+EAPI=6 |
232 |
+ |
233 |
+source tests-common.sh |
234 |
+ |
235 |
+inherit eapi7-ver |
236 |
+ |
237 |
+teq() { |
238 |
+ local expected=${1}; shift |
239 |
+ |
240 |
+ tbegin "${*} -> ${expected}" |
241 |
+ local got=$("${@}") |
242 |
+ [[ ${got} == ${expected} ]] |
243 |
+ tend ${?} "returned: ${got}" |
244 |
+} |
245 |
+ |
246 |
+txf() { |
247 |
+ tbegin "XFAIL: ${*}" |
248 |
+ local got=$("${@}" 2>&1) |
249 |
+ [[ ${got} == die:* ]] |
250 |
+ tend ${?} "function did not die" |
251 |
+} |
252 |
+ |
253 |
+teq 1 ver_cut 1 1.2.3 |
254 |
+teq 1 ver_cut 1-1 1.2.3 |
255 |
+teq 1.2 ver_cut 1-2 1.2.3 |
256 |
+teq 2.3 ver_cut 2- 1.2.3 |
257 |
+teq 1.2.3 ver_cut 1- 1.2.3 |
258 |
+teq 3b ver_cut 3-4 1.2.3b_alpha4 |
259 |
+teq alpha ver_cut 5 1.2.3b_alpha4 |
260 |
+teq 1.2 ver_cut 1-2 .1.2.3 |
261 |
+teq .1.2 ver_cut 0-2 .1.2.3 |
262 |
+teq 2.3 ver_cut 2-3 1.2.3. |
263 |
+teq 2.3. ver_cut 2- 1.2.3. |
264 |
+teq 2.3. ver_cut 2-4 1.2.3. |
265 |
+ |
266 |
+teq 1-2.3 ver_rs 1 - 1.2.3 |
267 |
+teq 1.2-3 ver_rs 2 - 1.2.3 |
268 |
+teq 1-2-3.4 ver_rs 1-2 - 1.2.3.4 |
269 |
+teq 1.2-3-4 ver_rs 2- - 1.2.3.4 |
270 |
+teq 1.2.3 ver_rs 2 . 1.2-3 |
271 |
+teq 1.2.3.a ver_rs 3 . 1.2.3a |
272 |
+teq 1.2-alpha-4 ver_rs 2-3 - 1.2_alpha4 |
273 |
+teq 1.23-b_alpha4 ver_rs 3 - 2 "" 1.2.3b_alpha4 |
274 |
+teq a1b_2-c-3-d4e5 ver_rs 3-5 _ 4-6 - a1b2c3d4e5 |
275 |
+teq .1-2.3 ver_rs 1 - .1.2.3 |
276 |
+teq -1.2.3 ver_rs 0 - .1.2.3 |
277 |
+ |
278 |
+# truncating range |
279 |
+teq 1.2 ver_cut 0-2 1.2.3 |
280 |
+teq 2.3 ver_cut 2-5 1.2.3 |
281 |
+teq "" ver_cut 4 1.2.3 |
282 |
+teq "" ver_cut 0 1.2.3 |
283 |
+teq "" ver_cut 4- 1.2.3 |
284 |
+teq 1.2.3 ver_rs 0 - 1.2.3 |
285 |
+teq 1.2.3 ver_rs 3 . 1.2.3 |
286 |
+teq 1.2.3 ver_rs 3- . 1.2.3 |
287 |
+teq 1.2.3 ver_rs 3-5 . 1.2.3 |
288 |
+ |
289 |
+txf ver_cut foo 1.2.3 |
290 |
+txf ver_rs -3 _ a1b2c3d4e5 |
291 |
+txf ver_rs 5-3 _ a1b2c3d4e5 |
292 |
diff --git a/eclass/tests/eapi7-ver:benchmark.sh b/eclass/tests/eapi7-ver:benchmark.sh |
293 |
new file mode 100755 |
294 |
index 000000000000..4b262ab6accb |
295 |
--- /dev/null |
296 |
+++ b/eclass/tests/eapi7-ver:benchmark.sh |
297 |
@@ -0,0 +1,76 @@ |
298 |
+#!/bin/bash |
299 |
+# Copyright 1999-2017 Gentoo Foundation |
300 |
+# Distributed under the terms of the GNU General Public License v2 |
301 |
+ |
302 |
+EAPI=6 |
303 |
+ |
304 |
+source tests-common.sh |
305 |
+ |
306 |
+inherit eapi7-ver |
307 |
+ |
308 |
+cutting() { |
309 |
+ local x |
310 |
+ for x in {1..1000}; do |
311 |
+ ver_cut 1 1.2.3 |
312 |
+ ver_cut 1-2 1.2.3 |
313 |
+ ver_cut 2- 1.2.3 |
314 |
+ ver_cut 1- 1.2.3 |
315 |
+ ver_cut 3-4 1.2.3b_alpha4 |
316 |
+ ver_cut 5 1.2.3b_alpha4 |
317 |
+ ver_cut 1-2 .1.2.3 |
318 |
+ ver_cut 0-2 .1.2.3 |
319 |
+ ver_cut 2-3 1.2.3. |
320 |
+ ver_cut 2- 1.2.3. |
321 |
+ ver_cut 2-4 1.2.3. |
322 |
+ done >/dev/null |
323 |
+} |
324 |
+ |
325 |
+replacing() { |
326 |
+ local x |
327 |
+ for x in {1..1000}; do |
328 |
+ ver_rs 1 - 1.2.3 |
329 |
+ ver_rs 2 - 1.2.3 |
330 |
+ ver_rs 1-2 - 1.2.3.4 |
331 |
+ ver_rs 2- - 1.2.3.4 |
332 |
+ ver_rs 2 . 1.2-3 |
333 |
+ ver_rs 3 . 1.2.3a |
334 |
+ ver_rs 2-3 - 1.2_alpha4 |
335 |
+ ver_rs 3 - 2 "" 1.2.3b_alpha4 |
336 |
+ ver_rs 3-5 _ 4-6 - a1b2c3d4e5 |
337 |
+ ver_rs 1 - .1.2.3 |
338 |
+ ver_rs 0 - .1.2.3 |
339 |
+ done >/dev/null |
340 |
+} |
341 |
+ |
342 |
+get_times() { |
343 |
+ echo "${*}" |
344 |
+ local real=() |
345 |
+ local user=() |
346 |
+ |
347 |
+ for x in {1..5}; do |
348 |
+ while read tt tv; do |
349 |
+ case ${tt} in |
350 |
+ real) real+=( ${tv} );; |
351 |
+ user) user+=( ${tv} );; |
352 |
+ esac |
353 |
+ done < <( ( time -p "${@}" ) 2>&1 ) |
354 |
+ done |
355 |
+ |
356 |
+ [[ ${#real[@]} == 5 ]] || die "Did not get 5 real times" |
357 |
+ [[ ${#user[@]} == 5 ]] || die "Did not get 5 user times" |
358 |
+ |
359 |
+ local sum |
360 |
+ for v in real user; do |
361 |
+ vr="${v}[*]" |
362 |
+ sum=$(dc -e "${!vr} + + + + 3 k 5 / p") |
363 |
+ |
364 |
+ vr="${v}[@]" |
365 |
+ printf '%s %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n' \ |
366 |
+ "${v}" "${!vr}" "${sum}" |
367 |
+ done |
368 |
+} |
369 |
+ |
370 |
+export LC_ALL=C |
371 |
+ |
372 |
+get_times cutting |
373 |
+get_times replacing |
374 |
-- |
375 |
2.14.1 |