最后活跃于 1740032087

Taken from https://gist.github.com/lxe/b167d3ec4e4f94d246ebdc4bcfdfb6ac

semver.sh 原始文件
1#!/bin/bash
2
3# set -x
4
5# Stupid Simple Semver range validator
6# (no build metadata and no prereleases, and no multiple ranges (||))
7
8# Prints a list of versions that match a semver range
9# ./semver.sh "range" version version version...
10
11# ./semver.sh ">=0.10.32 <7" 0.10.32 6.7.0 6.9.2 6.9.4 6.10.0 7.3.0 7.4.0 | xargs
12# 0.10.32 6.7.0 6.9.2 6.9.4 6.10.0
13
14# ./semver.sh "^6.9.4" 0.10.32 6.7.0 6.9.2 6.9.4 6.10.0 7.3.0 7.4.0 | xargs
15# 6.9.4 6.10.0
16
17# ./semver.sh "~6.9.4" 0.10.32 6.7.0 6.9.2 6.9.4 6.10.0 7.3.0 7.4.0 | xargs
18# 6.9.4
19
20# TODO: error handling, validation
21
22# Basic concept:
23# 1.x.x = ^1.0.0 = (>=1.0.0 <2.0.0)
24# 1.1.x = ~1.1.0 = (>=1.1.0 <1.2.0)
25# ^1.x.x = ^1.0.0
26# ~1.x.x = ~1.0.0
27
28SEMVER_RANGE="$1"; shift
29SEMVER_AVAILABLE_VERSIONS="$@"
30
31SEMVER_RE_COMPARATOR='[<>=\^~]*'
32SEMVER_RE_VERSION='[0-9x\.]+'
33
34# Takes a range with multiple comparisons, and splits it into lines
35# >=1.2.3 < 3
36# >=1.2.3
37# < 3
38semver_split_range () {
39 egrep -o "($SEMVER_RE_COMPARATOR\s*$SEMVER_RE_VERSION)"
40}
41
42# Hacky way to make versions comparable
43# Won't work if version numbers are over 100k'
44# 1.2.3 => 000001000002000003
45semver_to_number () {
46 tr "." " " | xargs printf "%06g"
47}
48
49# Convert a range part into a set of comparison lines processable by bc
50# ^1.2.3 => >=1.2.3 <2.0.0
51# >= 000001000002000003
52# < 000002000000000000
53semver_create_comparator () {
54 local COMPARATOR="$(egrep -o "^$SEMVER_RE_COMPARATOR" <<< "$1")"
55 local VERSION="$(egrep -o "$SEMVER_RE_VERSION$" <<< "$1")"
56 local VP
57
58 local ZERO_OR_X
59 if [[ -n "$COMPARATOR" ]]; then
60 ZERO_OR_X="0"
61 else
62 ZERO_OR_X="x"
63 fi
64
65 # Append either 0's or x's to the version, depending on comparator presence
66 # 4 => 4.x.x
67 # ^4 => 4.0.0
68 while [[ "$(egrep -o "\." <<< "$VERSION" | wc -l)" -lt "2" ]]; do
69 VERSION="$VERSION.$ZERO_OR_X"
70 done
71
72 # If comparator is not defined (1.x.x, 1.x, 1, 1.0.x, 1.0.0 etc),
73 # assign one based on the number of x's
74 # 1.x.x => ^ 1.x.x
75 # 1.0.x => ~ 1.0.x
76 # 1.0.0 => == 1.0.0
77 if [[ -z "$COMPARATOR" ]]; then
78 if [[ "$VERSION" =~ \.x\.x ]]; then
79 COMPARATOR="^"
80 elif [[ "$VERSION" =~ \.x ]]; then
81 COMPARATOR="~"
82 else
83 COMPARATOR="=="
84 fi
85 fi
86
87 # Finally, replace all the x's with 0s'
88 # ^ 1.x.x => ^ 1.0.0
89 VERSION=$(sed -E 's|\.x|\.0|g' <<< "$VERSION")
90
91 # Convert the ~,^ into proper >=, < comparator ranges
92 # ^1.0.0 = (>=1.0.0 <2.0.0)
93 # ~1.0.0 = (>=1.0.0 <1.1.0)
94 if [[ "$COMPARATOR" =~ \^|~ ]]; then
95 IFS="." read -ra VP <<< "$VERSION"
96 if [[ "$COMPARATOR" == "~" ]]; then
97 # Up the minor; 0 the patch
98 VP[1]=$(( ${VP[1]} + 1 ))
99 VP[2]=0
100 else
101 # Up the major; 0 the minor and patch
102 VP[0]=$(( ${VP[0]} + 1 ))
103 VP[1]=0
104 VP[2]=0
105 fi
106 COMPARATOR=">="
107 echo "< $(semver_to_number <<< "${VP[0]}.${VP[1]}.${VP[2]}")"
108 fi
109
110 echo "$COMPARATOR $(semver_to_number <<< "$VERSION")"
111}
112
113# Create all of the comparator lines processable by bc for the entire semver range
114# TODO: make it break for invalid ranges
115semver_create_comparators () {
116 local R
117
118 while read R; do
119 semver_create_comparator "$R"
120 done < <(semver_split_range <<< "$SEMVER_RANGE")
121}
122
123# Run a semver against all comparisons
124# If all conditions pass, return success
125semver_compare () {
126 local C
127
128 while read C; do
129 [[ "$MATCH" == "false" ]] && break
130 if [[ "$(bc <<< "$1 $C")" == "0" ]]; then
131 return 1
132 fi
133 done < <(echo -e "$V_COMPARATORS")
134}
135
136# Precompute the range into bc-processable comparator strings
137V_COMPARATORS="$(semver_create_comparators)"
138
139# Compare each provided version against the provided range, and print
140# the ones that succeed
141for A in $SEMVER_AVAILABLE_VERSIONS; do
142 semver_compare "$(semver_to_number <<< "$A")" && echo $A
143done