11
11
package gover
12
12
13
13
import (
14
- "cmp "
14
+ "internal/gover "
15
15
)
16
16
17
- // A version is a parsed Go version: major[.minor[.patch]][kind[pre]]
18
- // The numbers are the original decimal strings to avoid integer overflows
19
- // and since there is very little actual math. (Probably overflow doesn't matter in practice,
20
- // but at the time this code was written, there was an existing test that used
21
- // go1.99999999999, which does not fit in an int on 32-bit platforms.
22
- // The "big decimal" representation avoids the problem entirely.)
23
- type version struct {
24
- major string // decimal
25
- minor string // decimal or ""
26
- patch string // decimal or ""
27
- kind string // "", "alpha", "beta", "rc"
28
- pre string // decimal or ""
29
- }
30
-
31
17
// Compare returns -1, 0, or +1 depending on whether
32
18
// x < y, x == y, or x > y, interpreted as toolchain versions.
33
19
// The versions x and y must not begin with a "go" prefix: just "1.21" not "go1.21".
34
20
// Malformed versions compare less than well-formed versions and equal to each other.
35
21
// The language version "1.21" compares less than the release candidate and eventual releases "1.21rc1" and "1.21.0".
36
22
func Compare (x , y string ) int {
37
- vx := parse (x )
38
- vy := parse (y )
39
-
40
- if c := cmpInt (vx .major , vy .major ); c != 0 {
41
- return c
42
- }
43
- if c := cmpInt (vx .minor , vy .minor ); c != 0 {
44
- return c
45
- }
46
- if c := cmpInt (vx .patch , vy .patch ); c != 0 {
47
- return c
48
- }
49
- if c := cmp .Compare (vx .kind , vy .kind ); c != 0 { // "" < alpha < beta < rc
50
- return c
51
- }
52
- if c := cmpInt (vx .pre , vy .pre ); c != 0 {
53
- return c
54
- }
55
- return 0
23
+ return gover .Compare (x , y )
56
24
}
57
25
58
26
// Max returns the maximum of x and y interpreted as toolchain versions,
59
27
// compared using Compare.
60
28
// If x and y compare equal, Max returns x.
61
29
func Max (x , y string ) string {
62
- if Compare (x , y ) < 0 {
63
- return y
64
- }
65
- return x
66
- }
67
-
68
- // Toolchain returns the maximum of x and y interpreted as toolchain names,
69
- // compared using Compare(FromToolchain(x), FromToolchain(y)).
70
- // If x and y compare equal, Max returns x.
71
- func ToolchainMax (x , y string ) string {
72
- if Compare (FromToolchain (x ), FromToolchain (y )) < 0 {
73
- return y
74
- }
75
- return x
30
+ return gover .Max (x , y )
76
31
}
77
32
78
33
// IsLang reports whether v denotes the overall Go language version
@@ -85,22 +40,17 @@ func ToolchainMax(x, y string) string {
85
40
// meaning that Go 1.21rc1 and Go 1.21.0 will both handle go.mod files that
86
41
// say "go 1.21", but Go 1.21rc1 will not handle files that say "go 1.21.0".
87
42
func IsLang (x string ) bool {
88
- v := parse (x )
89
- return v != version {} && v .patch == "" && v .kind == "" && v .pre == ""
43
+ return gover .IsLang (x )
90
44
}
91
45
92
46
// Lang returns the Go language version. For example, Lang("1.2.3") == "1.2".
93
47
func Lang (x string ) string {
94
- v := parse (x )
95
- if v .minor == "" {
96
- return v .major
97
- }
98
- return v .major + "." + v .minor
48
+ return gover .Lang (x )
99
49
}
100
50
101
51
// IsPrerelease reports whether v denotes a Go prerelease version.
102
52
func IsPrerelease (x string ) bool {
103
- return parse (x ).kind != ""
53
+ return gover . Parse (x ).Kind != ""
104
54
}
105
55
106
56
// Prev returns the Go major release immediately preceding v,
@@ -112,143 +62,14 @@ func IsPrerelease(x string) bool {
112
62
// Prev("1.2") = "1.1"
113
63
// Prev("1.3rc4") = "1.2"
114
64
func Prev (x string ) string {
115
- v := parse (x )
116
- if cmpInt (v .minor , "1" ) <= 0 {
117
- return v .major
65
+ v := gover . Parse (x )
66
+ if gover . CmpInt (v .Minor , "1" ) <= 0 {
67
+ return v .Major
118
68
}
119
- return v .major + "." + decInt (v .minor )
69
+ return v .Major + "." + gover . DecInt (v .Minor )
120
70
}
121
71
122
72
// IsValid reports whether the version x is valid.
123
73
func IsValid (x string ) bool {
124
- return parse (x ) != version {}
125
- }
126
-
127
- // parse parses the Go version string x into a version.
128
- // It returns the zero version if x is malformed.
129
- func parse (x string ) version {
130
- var v version
131
-
132
- // Parse major version.
133
- var ok bool
134
- v .major , x , ok = cutInt (x )
135
- if ! ok {
136
- return version {}
137
- }
138
- if x == "" {
139
- // Interpret "1" as "1.0.0".
140
- v .minor = "0"
141
- v .patch = "0"
142
- return v
143
- }
144
-
145
- // Parse . before minor version.
146
- if x [0 ] != '.' {
147
- return version {}
148
- }
149
-
150
- // Parse minor version.
151
- v .minor , x , ok = cutInt (x [1 :])
152
- if ! ok {
153
- return version {}
154
- }
155
- if x == "" {
156
- // Patch missing is same as "0" for older versions.
157
- // Starting in Go 1.21, patch missing is different from explicit .0.
158
- if cmpInt (v .minor , "21" ) < 0 {
159
- v .patch = "0"
160
- }
161
- return v
162
- }
163
-
164
- // Parse patch if present.
165
- if x [0 ] == '.' {
166
- v .patch , x , ok = cutInt (x [1 :])
167
- if ! ok || x != "" {
168
- // Note that we are disallowing prereleases (alpha, beta, rc) for patch releases here (x != "").
169
- // Allowing them would be a bit confusing because we already have:
170
- // 1.21 < 1.21rc1
171
- // But a prerelease of a patch would have the opposite effect:
172
- // 1.21.3rc1 < 1.21.3
173
- // We've never needed them before, so let's not start now.
174
- return version {}
175
- }
176
- return v
177
- }
178
-
179
- // Parse prerelease.
180
- i := 0
181
- for i < len (x ) && (x [i ] < '0' || '9' < x [i ]) {
182
- if x [i ] < 'a' || 'z' < x [i ] {
183
- return version {}
184
- }
185
- i ++
186
- }
187
- if i == 0 {
188
- return version {}
189
- }
190
- v .kind , x = x [:i ], x [i :]
191
- if x == "" {
192
- return v
193
- }
194
- v .pre , x , ok = cutInt (x )
195
- if ! ok || x != "" {
196
- return version {}
197
- }
198
-
199
- return v
200
- }
201
-
202
- // cutInt scans the leading decimal number at the start of x to an integer
203
- // and returns that value and the rest of the string.
204
- func cutInt (x string ) (n , rest string , ok bool ) {
205
- i := 0
206
- for i < len (x ) && '0' <= x [i ] && x [i ] <= '9' {
207
- i ++
208
- }
209
- if i == 0 || x [0 ] == '0' && i != 1 {
210
- return "" , "" , false
211
- }
212
- return x [:i ], x [i :], true
213
- }
214
-
215
- // cmpInt returns cmp.Compare(x, y) interpreting x and y as decimal numbers.
216
- // (Copied from golang.org/x/mod/semver's compareInt.)
217
- func cmpInt (x , y string ) int {
218
- if x == y {
219
- return 0
220
- }
221
- if len (x ) < len (y ) {
222
- return - 1
223
- }
224
- if len (x ) > len (y ) {
225
- return + 1
226
- }
227
- if x < y {
228
- return - 1
229
- } else {
230
- return + 1
231
- }
232
- }
233
-
234
- // decInt returns the decimal string decremented by 1, or the empty string
235
- // if the decimal is all zeroes.
236
- // (Copied from golang.org/x/mod/module's decDecimal.)
237
- func decInt (decimal string ) string {
238
- // Scan right to left turning 0s to 9s until you find a digit to decrement.
239
- digits := []byte (decimal )
240
- i := len (digits ) - 1
241
- for ; i >= 0 && digits [i ] == '0' ; i -- {
242
- digits [i ] = '9'
243
- }
244
- if i < 0 {
245
- // decimal is all zeros
246
- return ""
247
- }
248
- if i == 0 && digits [i ] == '1' && len (digits ) > 1 {
249
- digits = digits [1 :]
250
- } else {
251
- digits [i ]--
252
- }
253
- return string (digits )
74
+ return gover .IsValid (x )
254
75
}
0 commit comments