summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eclass/eapi7-ver.eclass190
-rwxr-xr-xeclass/tests/eapi7-ver.sh65
-rwxr-xr-xeclass/tests/eapi7-ver_benchmark.sh113
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