diff options
author | Radek Simko <radek.simko@gmail.com> | 2017-08-10 14:38:14 +0200 |
---|---|---|
committer | Radek Simko <radek.simko@gmail.com> | 2017-08-10 14:38:14 +0200 |
commit | c680a8e1622ed0f18751d9d167c836ee24f5e897 (patch) | |
tree | 864f925049d422033dd25a73bafce32b361c8827 /vendor/github.com/blang/semver/semver.go | |
parent | 38f8880ac81bfabc6d7f82e4dc89661f20fc559e (diff) | |
download | terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.gz terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.tar.zst terraform-provider-statuscake-c680a8e1622ed0f18751d9d167c836ee24f5e897.zip |
vendor: github.com/hashicorp/terraform/...@v0.10.0
Diffstat (limited to 'vendor/github.com/blang/semver/semver.go')
-rw-r--r-- | vendor/github.com/blang/semver/semver.go | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/vendor/github.com/blang/semver/semver.go b/vendor/github.com/blang/semver/semver.go new file mode 100644 index 0000000..8ee0842 --- /dev/null +++ b/vendor/github.com/blang/semver/semver.go | |||
@@ -0,0 +1,418 @@ | |||
1 | package semver | ||
2 | |||
3 | import ( | ||
4 | "errors" | ||
5 | "fmt" | ||
6 | "strconv" | ||
7 | "strings" | ||
8 | ) | ||
9 | |||
10 | const ( | ||
11 | numbers string = "0123456789" | ||
12 | alphas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-" | ||
13 | alphanum = alphas + numbers | ||
14 | ) | ||
15 | |||
16 | // SpecVersion is the latest fully supported spec version of semver | ||
17 | var SpecVersion = Version{ | ||
18 | Major: 2, | ||
19 | Minor: 0, | ||
20 | Patch: 0, | ||
21 | } | ||
22 | |||
23 | // Version represents a semver compatible version | ||
24 | type Version struct { | ||
25 | Major uint64 | ||
26 | Minor uint64 | ||
27 | Patch uint64 | ||
28 | Pre []PRVersion | ||
29 | Build []string //No Precendence | ||
30 | } | ||
31 | |||
32 | // Version to string | ||
33 | func (v Version) String() string { | ||
34 | b := make([]byte, 0, 5) | ||
35 | b = strconv.AppendUint(b, v.Major, 10) | ||
36 | b = append(b, '.') | ||
37 | b = strconv.AppendUint(b, v.Minor, 10) | ||
38 | b = append(b, '.') | ||
39 | b = strconv.AppendUint(b, v.Patch, 10) | ||
40 | |||
41 | if len(v.Pre) > 0 { | ||
42 | b = append(b, '-') | ||
43 | b = append(b, v.Pre[0].String()...) | ||
44 | |||
45 | for _, pre := range v.Pre[1:] { | ||
46 | b = append(b, '.') | ||
47 | b = append(b, pre.String()...) | ||
48 | } | ||
49 | } | ||
50 | |||
51 | if len(v.Build) > 0 { | ||
52 | b = append(b, '+') | ||
53 | b = append(b, v.Build[0]...) | ||
54 | |||
55 | for _, build := range v.Build[1:] { | ||
56 | b = append(b, '.') | ||
57 | b = append(b, build...) | ||
58 | } | ||
59 | } | ||
60 | |||
61 | return string(b) | ||
62 | } | ||
63 | |||
64 | // Equals checks if v is equal to o. | ||
65 | func (v Version) Equals(o Version) bool { | ||
66 | return (v.Compare(o) == 0) | ||
67 | } | ||
68 | |||
69 | // EQ checks if v is equal to o. | ||
70 | func (v Version) EQ(o Version) bool { | ||
71 | return (v.Compare(o) == 0) | ||
72 | } | ||
73 | |||
74 | // NE checks if v is not equal to o. | ||
75 | func (v Version) NE(o Version) bool { | ||
76 | return (v.Compare(o) != 0) | ||
77 | } | ||
78 | |||
79 | // GT checks if v is greater than o. | ||
80 | func (v Version) GT(o Version) bool { | ||
81 | return (v.Compare(o) == 1) | ||
82 | } | ||
83 | |||
84 | // GTE checks if v is greater than or equal to o. | ||
85 | func (v Version) GTE(o Version) bool { | ||
86 | return (v.Compare(o) >= 0) | ||
87 | } | ||
88 | |||
89 | // GE checks if v is greater than or equal to o. | ||
90 | func (v Version) GE(o Version) bool { | ||
91 | return (v.Compare(o) >= 0) | ||
92 | } | ||
93 | |||
94 | // LT checks if v is less than o. | ||
95 | func (v Version) LT(o Version) bool { | ||
96 | return (v.Compare(o) == -1) | ||
97 | } | ||
98 | |||
99 | // LTE checks if v is less than or equal to o. | ||
100 | func (v Version) LTE(o Version) bool { | ||
101 | return (v.Compare(o) <= 0) | ||
102 | } | ||
103 | |||
104 | // LE checks if v is less than or equal to o. | ||
105 | func (v Version) LE(o Version) bool { | ||
106 | return (v.Compare(o) <= 0) | ||
107 | } | ||
108 | |||
109 | // Compare compares Versions v to o: | ||
110 | // -1 == v is less than o | ||
111 | // 0 == v is equal to o | ||
112 | // 1 == v is greater than o | ||
113 | func (v Version) Compare(o Version) int { | ||
114 | if v.Major != o.Major { | ||
115 | if v.Major > o.Major { | ||
116 | return 1 | ||
117 | } | ||
118 | return -1 | ||
119 | } | ||
120 | if v.Minor != o.Minor { | ||
121 | if v.Minor > o.Minor { | ||
122 | return 1 | ||
123 | } | ||
124 | return -1 | ||
125 | } | ||
126 | if v.Patch != o.Patch { | ||
127 | if v.Patch > o.Patch { | ||
128 | return 1 | ||
129 | } | ||
130 | return -1 | ||
131 | } | ||
132 | |||
133 | // Quick comparison if a version has no prerelease versions | ||
134 | if len(v.Pre) == 0 && len(o.Pre) == 0 { | ||
135 | return 0 | ||
136 | } else if len(v.Pre) == 0 && len(o.Pre) > 0 { | ||
137 | return 1 | ||
138 | } else if len(v.Pre) > 0 && len(o.Pre) == 0 { | ||
139 | return -1 | ||
140 | } | ||
141 | |||
142 | i := 0 | ||
143 | for ; i < len(v.Pre) && i < len(o.Pre); i++ { | ||
144 | if comp := v.Pre[i].Compare(o.Pre[i]); comp == 0 { | ||
145 | continue | ||
146 | } else if comp == 1 { | ||
147 | return 1 | ||
148 | } else { | ||
149 | return -1 | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // If all pr versions are the equal but one has further prversion, this one greater | ||
154 | if i == len(v.Pre) && i == len(o.Pre) { | ||
155 | return 0 | ||
156 | } else if i == len(v.Pre) && i < len(o.Pre) { | ||
157 | return -1 | ||
158 | } else { | ||
159 | return 1 | ||
160 | } | ||
161 | |||
162 | } | ||
163 | |||
164 | // Validate validates v and returns error in case | ||
165 | func (v Version) Validate() error { | ||
166 | // Major, Minor, Patch already validated using uint64 | ||
167 | |||
168 | for _, pre := range v.Pre { | ||
169 | if !pre.IsNum { //Numeric prerelease versions already uint64 | ||
170 | if len(pre.VersionStr) == 0 { | ||
171 | return fmt.Errorf("Prerelease can not be empty %q", pre.VersionStr) | ||
172 | } | ||
173 | if !containsOnly(pre.VersionStr, alphanum) { | ||
174 | return fmt.Errorf("Invalid character(s) found in prerelease %q", pre.VersionStr) | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | for _, build := range v.Build { | ||
180 | if len(build) == 0 { | ||
181 | return fmt.Errorf("Build meta data can not be empty %q", build) | ||
182 | } | ||
183 | if !containsOnly(build, alphanum) { | ||
184 | return fmt.Errorf("Invalid character(s) found in build meta data %q", build) | ||
185 | } | ||
186 | } | ||
187 | |||
188 | return nil | ||
189 | } | ||
190 | |||
191 | // New is an alias for Parse and returns a pointer, parses version string and returns a validated Version or error | ||
192 | func New(s string) (vp *Version, err error) { | ||
193 | v, err := Parse(s) | ||
194 | vp = &v | ||
195 | return | ||
196 | } | ||
197 | |||
198 | // Make is an alias for Parse, parses version string and returns a validated Version or error | ||
199 | func Make(s string) (Version, error) { | ||
200 | return Parse(s) | ||
201 | } | ||
202 | |||
203 | // ParseTolerant allows for certain version specifications that do not strictly adhere to semver | ||
204 | // specs to be parsed by this library. It does so by normalizing versions before passing them to | ||
205 | // Parse(). It currently trims spaces, removes a "v" prefix, and adds a 0 patch number to versions | ||
206 | // with only major and minor components specified | ||
207 | func ParseTolerant(s string) (Version, error) { | ||
208 | s = strings.TrimSpace(s) | ||
209 | s = strings.TrimPrefix(s, "v") | ||
210 | |||
211 | // Split into major.minor.(patch+pr+meta) | ||
212 | parts := strings.SplitN(s, ".", 3) | ||
213 | if len(parts) < 3 { | ||
214 | if strings.ContainsAny(parts[len(parts)-1], "+-") { | ||
215 | return Version{}, errors.New("Short version cannot contain PreRelease/Build meta data") | ||
216 | } | ||
217 | for len(parts) < 3 { | ||
218 | parts = append(parts, "0") | ||
219 | } | ||
220 | s = strings.Join(parts, ".") | ||
221 | } | ||
222 | |||
223 | return Parse(s) | ||
224 | } | ||
225 | |||
226 | // Parse parses version string and returns a validated Version or error | ||
227 | func Parse(s string) (Version, error) { | ||
228 | if len(s) == 0 { | ||
229 | return Version{}, errors.New("Version string empty") | ||
230 | } | ||
231 | |||
232 | // Split into major.minor.(patch+pr+meta) | ||
233 | parts := strings.SplitN(s, ".", 3) | ||
234 | if len(parts) != 3 { | ||
235 | return Version{}, errors.New("No Major.Minor.Patch elements found") | ||
236 | } | ||
237 | |||
238 | // Major | ||
239 | if !containsOnly(parts[0], numbers) { | ||
240 | return Version{}, fmt.Errorf("Invalid character(s) found in major number %q", parts[0]) | ||
241 | } | ||
242 | if hasLeadingZeroes(parts[0]) { | ||
243 | return Version{}, fmt.Errorf("Major number must not contain leading zeroes %q", parts[0]) | ||
244 | } | ||
245 | major, err := strconv.ParseUint(parts[0], 10, 64) | ||
246 | if err != nil { | ||
247 | return Version{}, err | ||
248 | } | ||
249 | |||
250 | // Minor | ||
251 | if !containsOnly(parts[1], numbers) { | ||
252 | return Version{}, fmt.Errorf("Invalid character(s) found in minor number %q", parts[1]) | ||
253 | } | ||
254 | if hasLeadingZeroes(parts[1]) { | ||
255 | return Version{}, fmt.Errorf("Minor number must not contain leading zeroes %q", parts[1]) | ||
256 | } | ||
257 | minor, err := strconv.ParseUint(parts[1], 10, 64) | ||
258 | if err != nil { | ||
259 | return Version{}, err | ||
260 | } | ||
261 | |||
262 | v := Version{} | ||
263 | v.Major = major | ||
264 | v.Minor = minor | ||
265 | |||
266 | var build, prerelease []string | ||
267 | patchStr := parts[2] | ||
268 | |||
269 | if buildIndex := strings.IndexRune(patchStr, '+'); buildIndex != -1 { | ||
270 | build = strings.Split(patchStr[buildIndex+1:], ".") | ||
271 | patchStr = patchStr[:buildIndex] | ||
272 | } | ||
273 | |||
274 | if preIndex := strings.IndexRune(patchStr, '-'); preIndex != -1 { | ||
275 | prerelease = strings.Split(patchStr[preIndex+1:], ".") | ||
276 | patchStr = patchStr[:preIndex] | ||
277 | } | ||
278 | |||
279 | if !containsOnly(patchStr, numbers) { | ||
280 | return Version{}, fmt.Errorf("Invalid character(s) found in patch number %q", patchStr) | ||
281 | } | ||
282 | if hasLeadingZeroes(patchStr) { | ||
283 | return Version{}, fmt.Errorf("Patch number must not contain leading zeroes %q", patchStr) | ||
284 | } | ||
285 | patch, err := strconv.ParseUint(patchStr, 10, 64) | ||
286 | if err != nil { | ||
287 | return Version{}, err | ||
288 | } | ||
289 | |||
290 | v.Patch = patch | ||
291 | |||
292 | // Prerelease | ||
293 | for _, prstr := range prerelease { | ||
294 | parsedPR, err := NewPRVersion(prstr) | ||
295 | if err != nil { | ||
296 | return Version{}, err | ||
297 | } | ||
298 | v.Pre = append(v.Pre, parsedPR) | ||
299 | } | ||
300 | |||
301 | // Build meta data | ||
302 | for _, str := range build { | ||
303 | if len(str) == 0 { | ||
304 | return Version{}, errors.New("Build meta data is empty") | ||
305 | } | ||
306 | if !containsOnly(str, alphanum) { | ||
307 | return Version{}, fmt.Errorf("Invalid character(s) found in build meta data %q", str) | ||
308 | } | ||
309 | v.Build = append(v.Build, str) | ||
310 | } | ||
311 | |||
312 | return v, nil | ||
313 | } | ||
314 | |||
315 | // MustParse is like Parse but panics if the version cannot be parsed. | ||
316 | func MustParse(s string) Version { | ||
317 | v, err := Parse(s) | ||
318 | if err != nil { | ||
319 | panic(`semver: Parse(` + s + `): ` + err.Error()) | ||
320 | } | ||
321 | return v | ||
322 | } | ||
323 | |||
324 | // PRVersion represents a PreRelease Version | ||
325 | type PRVersion struct { | ||
326 | VersionStr string | ||
327 | VersionNum uint64 | ||
328 | IsNum bool | ||
329 | } | ||
330 | |||
331 | // NewPRVersion creates a new valid prerelease version | ||
332 | func NewPRVersion(s string) (PRVersion, error) { | ||
333 | if len(s) == 0 { | ||
334 | return PRVersion{}, errors.New("Prerelease is empty") | ||
335 | } | ||
336 | v := PRVersion{} | ||
337 | if containsOnly(s, numbers) { | ||
338 | if hasLeadingZeroes(s) { | ||
339 | return PRVersion{}, fmt.Errorf("Numeric PreRelease version must not contain leading zeroes %q", s) | ||
340 | } | ||
341 | num, err := strconv.ParseUint(s, 10, 64) | ||
342 | |||
343 | // Might never be hit, but just in case | ||
344 | if err != nil { | ||
345 | return PRVersion{}, err | ||
346 | } | ||
347 | v.VersionNum = num | ||
348 | v.IsNum = true | ||
349 | } else if containsOnly(s, alphanum) { | ||
350 | v.VersionStr = s | ||
351 | v.IsNum = false | ||
352 | } else { | ||
353 | return PRVersion{}, fmt.Errorf("Invalid character(s) found in prerelease %q", s) | ||
354 | } | ||
355 | return v, nil | ||
356 | } | ||
357 | |||
358 | // IsNumeric checks if prerelease-version is numeric | ||
359 | func (v PRVersion) IsNumeric() bool { | ||
360 | return v.IsNum | ||
361 | } | ||
362 | |||
363 | // Compare compares two PreRelease Versions v and o: | ||
364 | // -1 == v is less than o | ||
365 | // 0 == v is equal to o | ||
366 | // 1 == v is greater than o | ||
367 | func (v PRVersion) Compare(o PRVersion) int { | ||
368 | if v.IsNum && !o.IsNum { | ||
369 | return -1 | ||
370 | } else if !v.IsNum && o.IsNum { | ||
371 | return 1 | ||
372 | } else if v.IsNum && o.IsNum { | ||
373 | if v.VersionNum == o.VersionNum { | ||
374 | return 0 | ||
375 | } else if v.VersionNum > o.VersionNum { | ||
376 | return 1 | ||
377 | } else { | ||
378 | return -1 | ||
379 | } | ||
380 | } else { // both are Alphas | ||
381 | if v.VersionStr == o.VersionStr { | ||
382 | return 0 | ||
383 | } else if v.VersionStr > o.VersionStr { | ||
384 | return 1 | ||
385 | } else { | ||
386 | return -1 | ||
387 | } | ||
388 | } | ||
389 | } | ||
390 | |||
391 | // PreRelease version to string | ||
392 | func (v PRVersion) String() string { | ||
393 | if v.IsNum { | ||
394 | return strconv.FormatUint(v.VersionNum, 10) | ||
395 | } | ||
396 | return v.VersionStr | ||
397 | } | ||
398 | |||
399 | func containsOnly(s string, set string) bool { | ||
400 | return strings.IndexFunc(s, func(r rune) bool { | ||
401 | return !strings.ContainsRune(set, r) | ||
402 | }) == -1 | ||
403 | } | ||
404 | |||
405 | func hasLeadingZeroes(s string) bool { | ||
406 | return len(s) > 1 && s[0] == '0' | ||
407 | } | ||
408 | |||
409 | // NewBuildVersion creates a new valid build version | ||
410 | func NewBuildVersion(s string) (string, error) { | ||
411 | if len(s) == 0 { | ||
412 | return "", errors.New("Buildversion is empty") | ||
413 | } | ||
414 | if !containsOnly(s, alphanum) { | ||
415 | return "", fmt.Errorf("Invalid character(s) found in build meta data %q", s) | ||
416 | } | ||
417 | return s, nil | ||
418 | } | ||