vercmp-bare-formats/default.sh

68 lines
2.4 KiB
Bash
Executable File

#!/bin/sh
set -e
# accepts two semantic-ish versions and echoes a character representing the
# relationship between the two.
# "semantic-ish" means here "a superset of semantic versioning." all correctly
# constructed semantic versions should compare in accordance with version 2.0 of
# the semver.org spec. versions that do not conform to the spec may also
# compare correctly. the primary difference is that there is no limitation on
# the number of version fields.
comparever() { comparever_default $@; }
# a split definition allows other formats to use this function to define their
# own comparever functions if they wish.
comparever_default() {
v1="$1"
v2="$2"
# strip any trailing meta tags
v1="${v1%+*}"
v2="${v2%+*}"
# equal?
[ "$v1" != "$v2" ] || { echo "=" && return 0; }
# strip leading characters that match.
while [ "$(echo "$v1" | cut -c1)" = "$(echo "$v2" | cut -c1)" ]; do
v1="$(echo "$v1" | cut -c2-)"
v2="$(echo "$v2" | cut -c2-)"
done
v1head="$(echo "$v1" | cut -c1)"
v2head="$(echo "$v2" | cut -c1)"
# if the difference is a prerelease tag, the prerelease is lesser.
case "$v1head" in -) echo '<' && return 0;; esac
case "$v2head" in -) echo '>' && return 0;; esac
# otherwise, if one is a prefix of the other, the other is greater.
[ -n "$v1" ] || { echo '<' && return 0; }
[ -n "$v2" ] || { echo '>' && return 0; }
# otherwise, if one starts with a dot, the other is the greater.
case "$v1head" in .) echo '<' && return 0;; esac
case "$v2head" in .) echo '>' && return 0;; esac
# strip any remaining version fields
v1="$(echo "$v1" | sed s/\\..*\$//)"
v2="$(echo "$v2" | sed s/\\..*\$//)"
# if the version tails are numeric, compare numerically. (ignore prerelease
# tags.) otherwise, compare lexically.
if (echo "${v1%-*}${v2%-*}" | grep -q "^[0-9]\+\$"); then
[ "$(echo "${v1%-*}")" -gt "$(echo "${v2%-*}")" ] \
&& echo ">" \
|| echo "<"
else
# v1 and v2 contain only the differences. using 'cut' and tabs here to
# perform a lexical sort on the differences and retrieve the original
# string associated with the greater of the two remainders.
greater=$(printf "%s\t%s\n%s\t%s" "$v1" "$1" "$v2" "$2" \
| sort | tail -n1 | cut -f2)
[ "$greater" = "$1" ] && echo ">" || echo "<"
fi
}