diff options
-rw-r--r-- | eclass/eapi7-ver.eclass | 190 | ||||
-rwxr-xr-x | eclass/tests/eapi7-ver.sh | 65 | ||||
-rwxr-xr-x | eclass/tests/eapi7-ver_benchmark.sh | 113 |
3 files changed, 368 insertions, 0 deletions
diff --git a/eclass/eapi7-ver.eclass b/eclass/eapi7-ver.eclass new file mode 100644 index 000000000000..1e8e3c5e55b3 --- /dev/null +++ b/eclass/eapi7-ver.eclass @@ -0,0 +1,190 @@ +# Copyright 1999-2017 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: eapi7-ver.eclass +# @MAINTAINER: +# PMS team <pms@gentoo.org> +# @AUTHOR: +# Ulrich Müller <ulm@gentoo.org> +# Michał Górny <mgorny@gentoo.org> +# @BLURB: Testing implementation of EAPI 7 version manipulators +# @DESCRIPTION: +# A stand-alone implementation of the version manipulation functions +# aimed for EAPI 7. Intended to be used for wider testing of +# the proposed functions and to allow ebuilds to switch to the new +# model early, with minimal change needed for actual EAPI 7. +# +# https://bugs.gentoo.org/482170 +# +# Note: version comparison function is not included currently. +# +# @ROFF .SS +# Version strings +# +# The functions support arbitrary version strings consisting of version +# components interspersed with (possibly empty) version separators. +# +# A version component can either consist purely of digits ([0-9]+) +# or purely of uppercase and lowercase letters ([A-Za-z]+). A version +# separator is either a string of any other characters ([^A-Za-z0-9]+), +# or it occurs at the transition between a sequence of letters +# and a sequence of digits, or vice versa. In the latter case, +# the version separator is an empty string. +# +# The version is processed left-to-right, and each successive component +# is assigned numbers starting with 1. The components are either split +# on version separators or on boundaries between digits and letters +# (in which case the separator between the components is empty). +# Version separators are assigned numbers starting with 1 for +# the separator between 1st and 2nd components. As a special case, +# if the version string starts with a separator, it is assigned index 0. +# +# Examples: +# +# @CODE +# 1.2b-alpha4 -> 1 . 2 '' b - alpha '' 4 +# c s c s c s c s c +# 1 1 2 2 3 3 4 4 5 +# +# .11. -> . 11 . +# s c s +# 0 1 1 +# @CODE +# +# @ROFF .SS +# Ranges +# +# A range can be specified as 'm' for m-th version component, 'm-' +# for all components starting with m-th or 'm-n' for components starting +# at m-th and ending at n-th (inclusive). If the range spans outside +# the version string, it is truncated silently. + +case ${EAPI:-0} in + 0|1|2|3|4|5) + die "${ECLASS}: EAPI=${EAPI:-0} not supported";; + 6) + ;; + *) + die "${ECLASS}: EAPI=${EAPI} unknown";; +esac + +# @FUNCTION: _ver_parse_range +# @USAGE: <range> <max> +# @INTERNAL +# @DESCRIPTION: +# Parse the range string <range>, setting 'start' and 'end' variables +# to the appropriate bounds. <min> and <max> specify the appropriate +# lower and upper bound for the range; the user-specified value is +# truncated to this range. +_ver_parse_range() { + local range=${1} + local max=${2} + + [[ ${range} == [0-9]* ]] \ + || die "${FUNCNAME}: range must start with a number" + start=${range%-*} + [[ ${range} == *-* ]] && end=${range#*-} || end=${start} + if [[ ${end} ]]; then + [[ ${start} -le ${end} ]] \ + || die "${FUNCNAME}: end of range must be >= start" + [[ ${end} -le ${max} ]] || end=${max} + else + end=${max} + fi +} + +# @FUNCTION: _ver_split +# @USAGE: <version> +# @INTERNAL +# @DESCRIPTION: +# Split the version string <version> into separator-component array. +# Sets 'comp' to an array of the form: ( s_0 c_1 s_1 c_2 s_2 c_3... ) +# where s_i are separators and c_i are components. +_ver_split() { + local v=${1} LC_ALL=C + + comp=() + + # get separators and components + local s c + while [[ ${v} ]]; do + # cut the separator + s=${v%%[a-zA-Z0-9]*} + v=${v:${#s}} + # cut the next component; it can be either digits or letters + [[ ${v} == [0-9]* ]] && c=${v%%[^0-9]*} || c=${v%%[^a-zA-Z]*} + v=${v:${#c}} + + comp+=( "${s}" "${c}" ) + done +} + +# @FUNCTION: ver_cut +# @USAGE: <range> [<version>] +# @DESCRIPTION: +# Print the substring of the version string containing components +# defined by the <range> and the version separators between them. +# Processes <version> if specified, ${PV} otherwise. +# +# For the syntax of versions and ranges, please see the eclass +# description. +ver_cut() { + local range=${1} + local v=${2:-${PV}} + local start end + local -a comp + + _ver_split "${v}" + local max=$((${#comp[@]}/2)) + _ver_parse_range "${range}" "${max}" + + local IFS= + if [[ ${start} -gt 0 ]]; then + start=$(( start*2 - 1 )) + fi + echo "${comp[*]:start:end*2-start}" +} + +# @FUNCTION: ver_rs +# @USAGE: <range> <repl> [<range> <repl>...] [<version>] +# @DESCRIPTION: +# Print the version string after substituting the specified version +# separators at <range> with <repl> (string). Multiple '<range> <repl>' +# pairs can be specified. Processes <version> if specified, +# ${PV} otherwise. +# +# For the syntax of versions and ranges, please see the eclass +# description. +ver_rs() { + local v + (( ${#} & 1 )) && v=${@: -1} || v=${PV} + local start end i + local -a comp + + _ver_split "${v}" + local max=$((${#comp[@]}/2 - 1)) + + while [[ ${#} -ge 2 ]]; do + _ver_parse_range "${1}" "${max}" + for (( i = start*2; i <= end*2; i+=2 )); do + [[ ${i} -eq 0 && -z ${comp[i]} ]] && continue + comp[i]=${2} + done + shift 2 + done + + local IFS= + echo "${comp[*]}" +} + +# @FUNCTION: ver_test +# @USAGE: [<v1>] <op> <v2> +# @DESCRIPTION: +# Check if the relation <v1> <op> <v2> is true. If <v1> is not specified, +# default to ${PVR}. <op> can be -gt, -ge, -eq, -ne, -le, -lt. +# Both versions must conform to the PMS version syntax (with optional +# revision parts), and the comparison is performed according to +# the algorithm specified in the PMS. +ver_test() { + die "${FUNCNAME}: not implemented" +} diff --git a/eclass/tests/eapi7-ver.sh b/eclass/tests/eapi7-ver.sh new file mode 100755 index 000000000000..8a96e4d29b1b --- /dev/null +++ b/eclass/tests/eapi7-ver.sh @@ -0,0 +1,65 @@ +#!/bin/bash +# Copyright 1999-2017 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +EAPI=6 + +source tests-common.sh + +inherit eapi7-ver + +teq() { + local expected=${1}; shift + + tbegin "${*} -> ${expected}" + local got=$("${@}") + [[ ${got} == ${expected} ]] + tend ${?} "returned: ${got}" +} + +txf() { + tbegin "XFAIL: ${*}" + local got=$("${@}" 2>&1) + [[ ${got} == die:* ]] + tend ${?} "function did not die" +} + +teq 1 ver_cut 1 1.2.3 +teq 1 ver_cut 1-1 1.2.3 +teq 1.2 ver_cut 1-2 1.2.3 +teq 2.3 ver_cut 2- 1.2.3 +teq 1.2.3 ver_cut 1- 1.2.3 +teq 3b ver_cut 3-4 1.2.3b_alpha4 +teq alpha ver_cut 5 1.2.3b_alpha4 +teq 1.2 ver_cut 1-2 .1.2.3 +teq .1.2 ver_cut 0-2 .1.2.3 +teq 2.3 ver_cut 2-3 1.2.3. +teq 2.3. ver_cut 2- 1.2.3. +teq 2.3. ver_cut 2-4 1.2.3. + +teq 1-2.3 ver_rs 1 - 1.2.3 +teq 1.2-3 ver_rs 2 - 1.2.3 +teq 1-2-3.4 ver_rs 1-2 - 1.2.3.4 +teq 1.2-3-4 ver_rs 2- - 1.2.3.4 +teq 1.2.3 ver_rs 2 . 1.2-3 +teq 1.2.3.a ver_rs 3 . 1.2.3a +teq 1.2-alpha-4 ver_rs 2-3 - 1.2_alpha4 +teq 1.23-b_alpha4 ver_rs 3 - 2 "" 1.2.3b_alpha4 +teq a1b_2-c-3-d4e5 ver_rs 3-5 _ 4-6 - a1b2c3d4e5 +teq .1-2.3 ver_rs 1 - .1.2.3 +teq -1.2.3 ver_rs 0 - .1.2.3 + +# truncating range +teq 1.2 ver_cut 0-2 1.2.3 +teq 2.3 ver_cut 2-5 1.2.3 +teq "" ver_cut 4 1.2.3 +teq "" ver_cut 0 1.2.3 +teq "" ver_cut 4- 1.2.3 +teq 1.2.3 ver_rs 0 - 1.2.3 +teq 1.2.3 ver_rs 3 . 1.2.3 +teq 1.2.3 ver_rs 3- . 1.2.3 +teq 1.2.3 ver_rs 3-5 . 1.2.3 + +txf ver_cut foo 1.2.3 +txf ver_rs -3 _ a1b2c3d4e5 +txf ver_rs 5-3 _ a1b2c3d4e5 diff --git a/eclass/tests/eapi7-ver_benchmark.sh b/eclass/tests/eapi7-ver_benchmark.sh new file mode 100755 index 000000000000..7e3c830fcb75 --- /dev/null +++ b/eclass/tests/eapi7-ver_benchmark.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# Copyright 1999-2017 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +EAPI=6 + +source tests-common.sh + +inherit eapi7-ver versionator + +cutting() { + local x + for x in {1..1000}; do + ver_cut 1 1.2.3 + ver_cut 1-2 1.2.3 + ver_cut 2- 1.2.3 + ver_cut 1- 1.2.3 + ver_cut 3-4 1.2.3b_alpha4 + ver_cut 5 1.2.3b_alpha4 + ver_cut 1-2 .1.2.3 + ver_cut 0-2 .1.2.3 + ver_cut 2-3 1.2.3. + ver_cut 2- 1.2.3. + ver_cut 2-4 1.2.3. + done >/dev/null +} + +cutting_versionator() { + local x + for x in {1..100}; do + get_version_component_range 1 1.2.3 + get_version_component_range 1-2 1.2.3 + get_version_component_range 2- 1.2.3 + get_version_component_range 1- 1.2.3 + get_version_component_range 3-4 1.2.3b_alpha4 + get_version_component_range 5 1.2.3b_alpha4 + get_version_component_range 1-2 .1.2.3 + get_version_component_range 0-2 .1.2.3 + get_version_component_range 2-3 1.2.3. + get_version_component_range 2- 1.2.3. + get_version_component_range 2-4 1.2.3. + done >/dev/null +} + +replacing() { + local x + for x in {1..1000}; do + ver_rs 1 - 1.2.3 + ver_rs 2 - 1.2.3 + ver_rs 1-2 - 1.2.3.4 + ver_rs 2- - 1.2.3.4 + ver_rs 2 . 1.2-3 + ver_rs 3 . 1.2.3a + ver_rs 2-3 - 1.2_alpha4 + #ver_rs 3 - 2 "" 1.2.3b_alpha4 + #ver_rs 3-5 _ 4-6 - a1b2c3d4e5 + ver_rs 1 - .1.2.3 + ver_rs 0 - .1.2.3 + done >/dev/null +} + +replacing_versionator() { + local x + for x in {1..100}; do + replace_version_separator 1 - 1.2.3 + replace_version_separator 2 - 1.2.3 + replace_version_separator 1-2 - 1.2.3.4 + replace_version_separator 2- - 1.2.3.4 + replace_version_separator 2 . 1.2-3 + replace_version_separator 3 . 1.2.3a + replace_version_separator 2-3 - 1.2_alpha4 + #replace_version_separator 3 - 2 "" 1.2.3b_alpha4 + #replace_version_separator 3-5 _ 4-6 - a1b2c3d4e5 + replace_version_separator 1 - .1.2.3 + replace_version_separator 0 - .1.2.3 + done >/dev/null +} + +get_times() { + local factor=${1}; shift + echo "${*}" + local real=() + local user=() + + for x in {1..5}; do + while read tt tv; do + case ${tt} in + real) real+=( $(dc -e "${tv} ${factor} * p") );; + user) user+=( $(dc -e "${tv} ${factor} * p") );; + esac + done < <( ( time -p "${@}" ) 2>&1 ) + done + + [[ ${#real[@]} == 5 ]] || die "Did not get 5 real times" + [[ ${#user[@]} == 5 ]] || die "Did not get 5 user times" + + local sum + for v in real user; do + vr="${v}[*]" + sum=$(dc -e "${!vr} + + + + 3 k 5 / p") + + vr="${v}[@]" + printf '%s %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n' \ + "${v}" "${!vr}" "${sum}" + done +} + +export LC_ALL=C + +get_times 1 cutting +get_times 10 cutting_versionator +get_times 1 replacing +get_times 10 replacing_versionator |