Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion arcup/arcup
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -euo pipefail

# NOTE: if you make modifications to this script, please increment the version number.
# WARNING: the SemVer pattern: major.minor.patch must be followed as we use it to determine if the script is up to date.
ARCUP_INSTALLER_VERSION="0.2.0"
ARCUP_INSTALLER_VERSION="0.2.1"

REPO="${ARC_REPO:-circlefin/arc-node}"
if [[ -n "${ARC_REPO:-}" ]] && [[ ! "$ARC_REPO" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then
Expand Down Expand Up @@ -264,6 +264,22 @@ version_gt() {
# Remove 'v' prefix if present
local ver1="${1#v}"
local ver2="${2#v}"

# Build metadata never affects precedence (SemVer 10), and it may itself
# contain '-', so it has to go before the pre-release split below.
ver1="${ver1%%+*}"
ver2="${ver2%%+*}"

# Keep the pre-release tags aside: SemVer orders a release above any
# pre-release of the same major.minor.patch.
local pre1="" pre2=""
if [[ "$ver1" == *-* ]]; then
pre1="${ver1#*-}"
fi
if [[ "$ver2" == *-* ]]; then
pre2="${ver2#*-}"
fi

ver1="${ver1%%-*}"
ver2="${ver2%%-*}"

Expand All @@ -281,6 +297,73 @@ EOF
[ "$patch1" -gt "$patch2" ] && return 0
[ "$patch1" -lt "$patch2" ] && return 1

# Same major.minor.patch. A release outranks any pre-release of it, so
# 0.3.0 is newer than 0.3.0-rc.1 (SemVer 11.3). Two pre-releases are
# ordered identifier by identifier (SemVer 11.4).
if [ -z "$pre1" ] && [ -z "$pre2" ]; then
return 1
fi
if [ -z "$pre1" ]; then
return 0
fi
if [ -z "$pre2" ]; then
return 1
fi
prerelease_gt "$pre1" "$pre2"
}

# Order two dot-separated pre-release identifier lists (SemVer 11.4).
# Returns 0 when the first ranks higher, 1 otherwise.
prerelease_gt() {
local a="$1" b="$2"
local ia ib na nb
# Byte-wise comparison for the alphanumeric case; the locale must not
# decide whether "beta" sorts above "alpha".
local LC_ALL=C

while [ -n "$a" ] || [ -n "$b" ]; do
# With every shared identifier equal, the shorter list ranks lower
# (11.4.4): 1.0.0-alpha < 1.0.0-alpha.1.
if [ -z "$a" ]; then
return 1
fi
if [ -z "$b" ]; then
return 0
fi

ia="${a%%.*}"
ib="${b%%.*}"
if [ "$a" = "$ia" ]; then a=""; else a="${a#*.}"; fi
if [ "$b" = "$ib" ]; then b=""; else b="${b#*.}"; fi

if [ "$ia" = "$ib" ]; then
continue
fi

na=0; nb=0
case "$ia" in ''|*[!0-9]*) ;; *) na=1 ;; esac
case "$ib" in ''|*[!0-9]*) ;; *) nb=1 ;; esac

# Both numeric: compare as numbers, so rc.11 is newer than rc.2 (11.4.1).
if [ "$na" = 1 ] && [ "$nb" = 1 ]; then
if [ "$ia" -gt "$ib" ]; then
return 0
fi
return 1
fi
# A numeric identifier ranks below an alphanumeric one (11.4.3).
if [ "$na" = 1 ]; then
return 1
fi
if [ "$nb" = 1 ]; then
return 0
fi
# Both alphanumeric: ASCII order (11.4.2).
if [[ "$ia" > "$ib" ]]; then
return 0
fi
return 1
done
return 1
}

Expand Down
79 changes: 79 additions & 0 deletions arcup/test_arcup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,83 @@ test_version_comparison() {
fail "same prerelease base is not newer"
fi
pass "same prerelease base is not newer"

if ! version_gt "0.3.0" "0.3.0-rc.1"; then
fail "release is newer than its prerelease"
fi
pass "release is newer than its prerelease"

if ! version_gt "v0.3.0" "v0.3.0-rc.2"; then
fail "release is newer than its prerelease with v prefix"
fi
pass "release is newer than its prerelease with v prefix"
}

# The precedence chain semver.org gives for section 11.4, checked link by link
# in both directions, plus the two pre-release comparisons #205 asks for.
test_prerelease_precedence() {
local chain=(
"1.0.0-alpha"
"1.0.0-alpha.1"
"1.0.0-alpha.beta"
"1.0.0-beta"
"1.0.0-beta.2"
"1.0.0-beta.11"
"1.0.0-rc.1"
"1.0.0"
)
local i lower higher
for ((i = 1; i < ${#chain[@]}; i++)); do
lower="${chain[i-1]}"
higher="${chain[i]}"
if ! version_gt "$higher" "$lower"; then
fail "$higher is newer than $lower"
fi
if version_gt "$lower" "$higher"; then
fail "$lower is not newer than $higher"
fi
done
pass "orders the semver.org 11.4 chain"

if ! version_gt "0.3.0-rc.2" "0.3.0-rc.1"; then
fail "later release candidate is newer"
fi
pass "later release candidate is newer"

if ! version_gt "1.0.0-beta.11" "1.0.0-beta.2"; then
fail "numeric identifiers compare as numbers, not strings"
fi
pass "numeric identifiers compare as numbers, not strings"

if version_gt "1.0.0-rc.1" "1.0.0-rc.1"; then
fail "equal prereleases are not newer"
fi
pass "equal prereleases are not newer"
}

test_build_metadata_is_ignored() {
if version_gt "1.0.0+build.9" "1.0.0+build.1"; then
fail "build metadata does not order releases"
fi
pass "build metadata does not order releases"

if version_gt "1.0.0+build-1" "1.0.0"; then
fail "a hyphen inside build metadata is not a prerelease"
fi
if version_gt "1.0.0" "1.0.0+build-1"; then
fail "a hyphen inside build metadata is not a prerelease"
fi
pass "a hyphen inside build metadata is not a prerelease"

if ! version_gt "1.0.1+build-1" "1.0.0"; then
fail "the core still compares under build metadata"
fi
pass "the core still compares under build metadata"

if ! version_gt "1.0.0-rc.2+b1" "1.0.0-rc.1+b99"; then
fail "prerelease decides when both carry build metadata"
fi
pass "prerelease decides when both carry build metadata"
}

test_target_mapping() {
Expand Down Expand Up @@ -812,6 +889,8 @@ test_install_binary_rejects_symlink() {

test_version_normalization
test_version_comparison
test_prerelease_precedence
test_build_metadata_is_ignored
test_target_mapping
test_unknown_architecture_fails
test_github_api_url_rejects_non_https
Expand Down
Loading