* vendor: switch from "mcuadros/go-version" to "hashicorp/go-version" * Adapt P1 * simplify * fix lint * adapt * fix lint & rm old code * no deadlock * rm RWMutex and check GoVersion only 1-time * Copyright header Co-authored-by: techknowlogick <techknowlogick@gitea.io>for-closed-social
@ -0,0 +1,354 @@ | |||
Mozilla Public License, version 2.0 | |||
1. Definitions | |||
1.1. “Contributor” | |||
means each individual or legal entity that creates, contributes to the | |||
creation of, or owns Covered Software. | |||
1.2. “Contributor Version” | |||
means the combination of the Contributions of others (if any) used by a | |||
Contributor and that particular Contributor’s Contribution. | |||
1.3. “Contribution” | |||
means Covered Software of a particular Contributor. | |||
1.4. “Covered Software” | |||
means Source Code Form to which the initial Contributor has attached the | |||
notice in Exhibit A, the Executable Form of such Source Code Form, and | |||
Modifications of such Source Code Form, in each case including portions | |||
thereof. | |||
1.5. “Incompatible With Secondary Licenses” | |||
means | |||
a. that the initial Contributor has attached the notice described in | |||
Exhibit B to the Covered Software; or | |||
b. that the Covered Software was made available under the terms of version | |||
1.1 or earlier of the License, but not also under the terms of a | |||
Secondary License. | |||
1.6. “Executable Form” | |||
means any form of the work other than Source Code Form. | |||
1.7. “Larger Work” | |||
means a work that combines Covered Software with other material, in a separate | |||
file or files, that is not Covered Software. | |||
1.8. “License” | |||
means this document. | |||
1.9. “Licensable” | |||
means having the right to grant, to the maximum extent possible, whether at the | |||
time of the initial grant or subsequently, any and all of the rights conveyed by | |||
this License. | |||
1.10. “Modifications” | |||
means any of the following: | |||
a. any file in Source Code Form that results from an addition to, deletion | |||
from, or modification of the contents of Covered Software; or | |||
b. any new file in Source Code Form that contains any Covered Software. | |||
1.11. “Patent Claims” of a Contributor | |||
means any patent claim(s), including without limitation, method, process, | |||
and apparatus claims, in any patent Licensable by such Contributor that | |||
would be infringed, but for the grant of the License, by the making, | |||
using, selling, offering for sale, having made, import, or transfer of | |||
either its Contributions or its Contributor Version. | |||
1.12. “Secondary License” | |||
means either the GNU General Public License, Version 2.0, the GNU Lesser | |||
General Public License, Version 2.1, the GNU Affero General Public | |||
License, Version 3.0, or any later versions of those licenses. | |||
1.13. “Source Code Form” | |||
means the form of the work preferred for making modifications. | |||
1.14. “You” (or “Your”) | |||
means an individual or a legal entity exercising rights under this | |||
License. For legal entities, “You” includes any entity that controls, is | |||
controlled by, or is under common control with You. For purposes of this | |||
definition, “control” means (a) the power, direct or indirect, to cause | |||
the direction or management of such entity, whether by contract or | |||
otherwise, or (b) ownership of more than fifty percent (50%) of the | |||
outstanding shares or beneficial ownership of such entity. | |||
2. License Grants and Conditions | |||
2.1. Grants | |||
Each Contributor hereby grants You a world-wide, royalty-free, | |||
non-exclusive license: | |||
a. under intellectual property rights (other than patent or trademark) | |||
Licensable by such Contributor to use, reproduce, make available, | |||
modify, display, perform, distribute, and otherwise exploit its | |||
Contributions, either on an unmodified basis, with Modifications, or as | |||
part of a Larger Work; and | |||
b. under Patent Claims of such Contributor to make, use, sell, offer for | |||
sale, have made, import, and otherwise transfer either its Contributions | |||
or its Contributor Version. | |||
2.2. Effective Date | |||
The licenses granted in Section 2.1 with respect to any Contribution become | |||
effective for each Contribution on the date the Contributor first distributes | |||
such Contribution. | |||
2.3. Limitations on Grant Scope | |||
The licenses granted in this Section 2 are the only rights granted under this | |||
License. No additional rights or licenses will be implied from the distribution | |||
or licensing of Covered Software under this License. Notwithstanding Section | |||
2.1(b) above, no patent license is granted by a Contributor: | |||
a. for any code that a Contributor has removed from Covered Software; or | |||
b. for infringements caused by: (i) Your and any other third party’s | |||
modifications of Covered Software, or (ii) the combination of its | |||
Contributions with other software (except as part of its Contributor | |||
Version); or | |||
c. under Patent Claims infringed by Covered Software in the absence of its | |||
Contributions. | |||
This License does not grant any rights in the trademarks, service marks, or | |||
logos of any Contributor (except as may be necessary to comply with the | |||
notice requirements in Section 3.4). | |||
2.4. Subsequent Licenses | |||
No Contributor makes additional grants as a result of Your choice to | |||
distribute the Covered Software under a subsequent version of this License | |||
(see Section 10.2) or under the terms of a Secondary License (if permitted | |||
under the terms of Section 3.3). | |||
2.5. Representation | |||
Each Contributor represents that the Contributor believes its Contributions | |||
are its original creation(s) or it has sufficient rights to grant the | |||
rights to its Contributions conveyed by this License. | |||
2.6. Fair Use | |||
This License is not intended to limit any rights You have under applicable | |||
copyright doctrines of fair use, fair dealing, or other equivalents. | |||
2.7. Conditions | |||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in | |||
Section 2.1. | |||
3. Responsibilities | |||
3.1. Distribution of Source Form | |||
All distribution of Covered Software in Source Code Form, including any | |||
Modifications that You create or to which You contribute, must be under the | |||
terms of this License. You must inform recipients that the Source Code Form | |||
of the Covered Software is governed by the terms of this License, and how | |||
they can obtain a copy of this License. You may not attempt to alter or | |||
restrict the recipients’ rights in the Source Code Form. | |||
3.2. Distribution of Executable Form | |||
If You distribute Covered Software in Executable Form then: | |||
a. such Covered Software must also be made available in Source Code Form, | |||
as described in Section 3.1, and You must inform recipients of the | |||
Executable Form how they can obtain a copy of such Source Code Form by | |||
reasonable means in a timely manner, at a charge no more than the cost | |||
of distribution to the recipient; and | |||
b. You may distribute such Executable Form under the terms of this License, | |||
or sublicense it under different terms, provided that the license for | |||
the Executable Form does not attempt to limit or alter the recipients’ | |||
rights in the Source Code Form under this License. | |||
3.3. Distribution of a Larger Work | |||
You may create and distribute a Larger Work under terms of Your choice, | |||
provided that You also comply with the requirements of this License for the | |||
Covered Software. If the Larger Work is a combination of Covered Software | |||
with a work governed by one or more Secondary Licenses, and the Covered | |||
Software is not Incompatible With Secondary Licenses, this License permits | |||
You to additionally distribute such Covered Software under the terms of | |||
such Secondary License(s), so that the recipient of the Larger Work may, at | |||
their option, further distribute the Covered Software under the terms of | |||
either this License or such Secondary License(s). | |||
3.4. Notices | |||
You may not remove or alter the substance of any license notices (including | |||
copyright notices, patent notices, disclaimers of warranty, or limitations | |||
of liability) contained within the Source Code Form of the Covered | |||
Software, except that You may alter any license notices to the extent | |||
required to remedy known factual inaccuracies. | |||
3.5. Application of Additional Terms | |||
You may choose to offer, and to charge a fee for, warranty, support, | |||
indemnity or liability obligations to one or more recipients of Covered | |||
Software. However, You may do so only on Your own behalf, and not on behalf | |||
of any Contributor. You must make it absolutely clear that any such | |||
warranty, support, indemnity, or liability obligation is offered by You | |||
alone, and You hereby agree to indemnify every Contributor for any | |||
liability incurred by such Contributor as a result of warranty, support, | |||
indemnity or liability terms You offer. You may include additional | |||
disclaimers of warranty and limitations of liability specific to any | |||
jurisdiction. | |||
4. Inability to Comply Due to Statute or Regulation | |||
If it is impossible for You to comply with any of the terms of this License | |||
with respect to some or all of the Covered Software due to statute, judicial | |||
order, or regulation then You must: (a) comply with the terms of this License | |||
to the maximum extent possible; and (b) describe the limitations and the code | |||
they affect. Such description must be placed in a text file included with all | |||
distributions of the Covered Software under this License. Except to the | |||
extent prohibited by statute or regulation, such description must be | |||
sufficiently detailed for a recipient of ordinary skill to be able to | |||
understand it. | |||
5. Termination | |||
5.1. The rights granted under this License will terminate automatically if You | |||
fail to comply with any of its terms. However, if You become compliant, | |||
then the rights granted under this License from a particular Contributor | |||
are reinstated (a) provisionally, unless and until such Contributor | |||
explicitly and finally terminates Your grants, and (b) on an ongoing basis, | |||
if such Contributor fails to notify You of the non-compliance by some | |||
reasonable means prior to 60 days after You have come back into compliance. | |||
Moreover, Your grants from a particular Contributor are reinstated on an | |||
ongoing basis if such Contributor notifies You of the non-compliance by | |||
some reasonable means, this is the first time You have received notice of | |||
non-compliance with this License from such Contributor, and You become | |||
compliant prior to 30 days after Your receipt of the notice. | |||
5.2. If You initiate litigation against any entity by asserting a patent | |||
infringement claim (excluding declaratory judgment actions, counter-claims, | |||
and cross-claims) alleging that a Contributor Version directly or | |||
indirectly infringes any patent, then the rights granted to You by any and | |||
all Contributors for the Covered Software under Section 2.1 of this License | |||
shall terminate. | |||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user | |||
license agreements (excluding distributors and resellers) which have been | |||
validly granted by You or Your distributors under this License prior to | |||
termination shall survive termination. | |||
6. Disclaimer of Warranty | |||
Covered Software is provided under this License on an “as is” basis, without | |||
warranty of any kind, either expressed, implied, or statutory, including, | |||
without limitation, warranties that the Covered Software is free of defects, | |||
merchantable, fit for a particular purpose or non-infringing. The entire | |||
risk as to the quality and performance of the Covered Software is with You. | |||
Should any Covered Software prove defective in any respect, You (not any | |||
Contributor) assume the cost of any necessary servicing, repair, or | |||
correction. This disclaimer of warranty constitutes an essential part of this | |||
License. No use of any Covered Software is authorized under this License | |||
except under this disclaimer. | |||
7. Limitation of Liability | |||
Under no circumstances and under no legal theory, whether tort (including | |||
negligence), contract, or otherwise, shall any Contributor, or anyone who | |||
distributes Covered Software as permitted above, be liable to You for any | |||
direct, indirect, special, incidental, or consequential damages of any | |||
character including, without limitation, damages for lost profits, loss of | |||
goodwill, work stoppage, computer failure or malfunction, or any and all | |||
other commercial damages or losses, even if such party shall have been | |||
informed of the possibility of such damages. This limitation of liability | |||
shall not apply to liability for death or personal injury resulting from such | |||
party’s negligence to the extent applicable law prohibits such limitation. | |||
Some jurisdictions do not allow the exclusion or limitation of incidental or | |||
consequential damages, so this exclusion and limitation may not apply to You. | |||
8. Litigation | |||
Any litigation relating to this License may be brought only in the courts of | |||
a jurisdiction where the defendant maintains its principal place of business | |||
and such litigation shall be governed by laws of that jurisdiction, without | |||
reference to its conflict-of-law provisions. Nothing in this Section shall | |||
prevent a party’s ability to bring cross-claims or counter-claims. | |||
9. Miscellaneous | |||
This License represents the complete agreement concerning the subject matter | |||
hereof. If any provision of this License is held to be unenforceable, such | |||
provision shall be reformed only to the extent necessary to make it | |||
enforceable. Any law or regulation which provides that the language of a | |||
contract shall be construed against the drafter shall not be used to construe | |||
this License against a Contributor. | |||
10. Versions of the License | |||
10.1. New Versions | |||
Mozilla Foundation is the license steward. Except as provided in Section | |||
10.3, no one other than the license steward has the right to modify or | |||
publish new versions of this License. Each version will be given a | |||
distinguishing version number. | |||
10.2. Effect of New Versions | |||
You may distribute the Covered Software under the terms of the version of | |||
the License under which You originally received the Covered Software, or | |||
under the terms of any subsequent version published by the license | |||
steward. | |||
10.3. Modified Versions | |||
If you create software not governed by this License, and you want to | |||
create a new license for such software, you may create and use a modified | |||
version of this License if you rename the license and remove any | |||
references to the name of the license steward (except to note that such | |||
modified license differs from this License). | |||
10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses | |||
If You choose to distribute Source Code Form that is Incompatible With | |||
Secondary Licenses under the terms of this version of the License, the | |||
notice described in Exhibit B of this License must be attached. | |||
Exhibit A - Source Code Form License Notice | |||
This Source Code Form is subject to the | |||
terms of the Mozilla Public License, v. | |||
2.0. If a copy of the MPL was not | |||
distributed with this file, You can | |||
obtain one at | |||
http://mozilla.org/MPL/2.0/. | |||
If it is not possible or desirable to put the notice in a particular file, then | |||
You may include the notice in a location (such as a LICENSE file in a relevant | |||
directory) where a recipient would be likely to look for such a notice. | |||
You may add additional accurate notices of copyright ownership. | |||
Exhibit B - “Incompatible With Secondary Licenses” Notice | |||
This Source Code Form is “Incompatible | |||
With Secondary Licenses”, as defined by | |||
the Mozilla Public License, v. 2.0. | |||
@ -0,0 +1,66 @@ | |||
# Versioning Library for Go | |||
[![Build Status](https://circleci.com/gh/hashicorp/go-version/tree/master.svg?style=svg)](https://circleci.com/gh/hashicorp/go-version/tree/master) | |||
[![GoDoc](https://godoc.org/github.com/hashicorp/go-version?status.svg)](https://godoc.org/github.com/hashicorp/go-version) | |||
go-version is a library for parsing versions and version constraints, | |||
and verifying versions against a set of constraints. go-version | |||
can sort a collection of versions properly, handles prerelease/beta | |||
versions, can increment versions, etc. | |||
Versions used with go-version must follow [SemVer](http://semver.org/). | |||
## Installation and Usage | |||
Package documentation can be found on | |||
[GoDoc](http://godoc.org/github.com/hashicorp/go-version). | |||
Installation can be done with a normal `go get`: | |||
``` | |||
$ go get github.com/hashicorp/go-version | |||
``` | |||
#### Version Parsing and Comparison | |||
```go | |||
v1, err := version.NewVersion("1.2") | |||
v2, err := version.NewVersion("1.5+metadata") | |||
// Comparison example. There is also GreaterThan, Equal, and just | |||
// a simple Compare that returns an int allowing easy >=, <=, etc. | |||
if v1.LessThan(v2) { | |||
fmt.Printf("%s is less than %s", v1, v2) | |||
} | |||
``` | |||
#### Version Constraints | |||
```go | |||
v1, err := version.NewVersion("1.2") | |||
// Constraints example. | |||
constraints, err := version.NewConstraint(">= 1.0, < 1.4") | |||
if constraints.Check(v1) { | |||
fmt.Printf("%s satisfies constraints %s", v1, constraints) | |||
} | |||
``` | |||
#### Version Sorting | |||
```go | |||
versionsRaw := []string{"1.1", "0.7.1", "1.4-beta", "1.4", "2"} | |||
versions := make([]*version.Version, len(versionsRaw)) | |||
for i, raw := range versionsRaw { | |||
v, _ := version.NewVersion(raw) | |||
versions[i] = v | |||
} | |||
// After this, the versions are properly sorted | |||
sort.Sort(version.Collection(versions)) | |||
``` | |||
## Issues and Contributing | |||
If you find an issue with this library, please report an issue. If you'd | |||
like, we welcome any contributions. Fork this library and submit a pull | |||
request. |
@ -0,0 +1,204 @@ | |||
package version | |||
import ( | |||
"fmt" | |||
"reflect" | |||
"regexp" | |||
"strings" | |||
) | |||
// Constraint represents a single constraint for a version, such as | |||
// ">= 1.0". | |||
type Constraint struct { | |||
f constraintFunc | |||
check *Version | |||
original string | |||
} | |||
// Constraints is a slice of constraints. We make a custom type so that | |||
// we can add methods to it. | |||
type Constraints []*Constraint | |||
type constraintFunc func(v, c *Version) bool | |||
var constraintOperators map[string]constraintFunc | |||
var constraintRegexp *regexp.Regexp | |||
func init() { | |||
constraintOperators = map[string]constraintFunc{ | |||
"": constraintEqual, | |||
"=": constraintEqual, | |||
"!=": constraintNotEqual, | |||
">": constraintGreaterThan, | |||
"<": constraintLessThan, | |||
">=": constraintGreaterThanEqual, | |||
"<=": constraintLessThanEqual, | |||
"~>": constraintPessimistic, | |||
} | |||
ops := make([]string, 0, len(constraintOperators)) | |||
for k := range constraintOperators { | |||
ops = append(ops, regexp.QuoteMeta(k)) | |||
} | |||
constraintRegexp = regexp.MustCompile(fmt.Sprintf( | |||
`^\s*(%s)\s*(%s)\s*$`, | |||
strings.Join(ops, "|"), | |||
VersionRegexpRaw)) | |||
} | |||
// NewConstraint will parse one or more constraints from the given | |||
// constraint string. The string must be a comma-separated list of | |||
// constraints. | |||
func NewConstraint(v string) (Constraints, error) { | |||
vs := strings.Split(v, ",") | |||
result := make([]*Constraint, len(vs)) | |||
for i, single := range vs { | |||
c, err := parseSingle(single) | |||
if err != nil { | |||
return nil, err | |||
} | |||
result[i] = c | |||
} | |||
return Constraints(result), nil | |||
} | |||
// Check tests if a version satisfies all the constraints. | |||
func (cs Constraints) Check(v *Version) bool { | |||
for _, c := range cs { | |||
if !c.Check(v) { | |||
return false | |||
} | |||
} | |||
return true | |||
} | |||
// Returns the string format of the constraints | |||
func (cs Constraints) String() string { | |||
csStr := make([]string, len(cs)) | |||
for i, c := range cs { | |||
csStr[i] = c.String() | |||
} | |||
return strings.Join(csStr, ",") | |||
} | |||
// Check tests if a constraint is validated by the given version. | |||
func (c *Constraint) Check(v *Version) bool { | |||
return c.f(v, c.check) | |||
} | |||
func (c *Constraint) String() string { | |||
return c.original | |||
} | |||
func parseSingle(v string) (*Constraint, error) { | |||
matches := constraintRegexp.FindStringSubmatch(v) | |||
if matches == nil { | |||
return nil, fmt.Errorf("Malformed constraint: %s", v) | |||
} | |||
check, err := NewVersion(matches[2]) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return &Constraint{ | |||
f: constraintOperators[matches[1]], | |||
check: check, | |||
original: v, | |||
}, nil | |||
} | |||
func prereleaseCheck(v, c *Version) bool { | |||
switch vPre, cPre := v.Prerelease() != "", c.Prerelease() != ""; { | |||
case cPre && vPre: | |||
// A constraint with a pre-release can only match a pre-release version | |||
// with the same base segments. | |||
return reflect.DeepEqual(c.Segments64(), v.Segments64()) | |||
case !cPre && vPre: | |||
// A constraint without a pre-release can only match a version without a | |||
// pre-release. | |||
return false | |||
case cPre && !vPre: | |||
// OK, except with the pessimistic operator | |||
case !cPre && !vPre: | |||
// OK | |||
} | |||
return true | |||
} | |||
//------------------------------------------------------------------- | |||
// Constraint functions | |||
//------------------------------------------------------------------- | |||
func constraintEqual(v, c *Version) bool { | |||
return v.Equal(c) | |||
} | |||
func constraintNotEqual(v, c *Version) bool { | |||
return !v.Equal(c) | |||
} | |||
func constraintGreaterThan(v, c *Version) bool { | |||
return prereleaseCheck(v, c) && v.Compare(c) == 1 | |||
} | |||
func constraintLessThan(v, c *Version) bool { | |||
return prereleaseCheck(v, c) && v.Compare(c) == -1 | |||
} | |||
func constraintGreaterThanEqual(v, c *Version) bool { | |||
return prereleaseCheck(v, c) && v.Compare(c) >= 0 | |||
} | |||
func constraintLessThanEqual(v, c *Version) bool { | |||
return prereleaseCheck(v, c) && v.Compare(c) <= 0 | |||
} | |||
func constraintPessimistic(v, c *Version) bool { | |||
// Using a pessimistic constraint with a pre-release, restricts versions to pre-releases | |||
if !prereleaseCheck(v, c) || (c.Prerelease() != "" && v.Prerelease() == "") { | |||
return false | |||
} | |||
// If the version being checked is naturally less than the constraint, then there | |||
// is no way for the version to be valid against the constraint | |||
if v.LessThan(c) { | |||
return false | |||
} | |||
// We'll use this more than once, so grab the length now so it's a little cleaner | |||
// to write the later checks | |||
cs := len(c.segments) | |||
// If the version being checked has less specificity than the constraint, then there | |||
// is no way for the version to be valid against the constraint | |||
if cs > len(v.segments) { | |||
return false | |||
} | |||
// Check the segments in the constraint against those in the version. If the version | |||
// being checked, at any point, does not have the same values in each index of the | |||
// constraints segments, then it cannot be valid against the constraint. | |||
for i := 0; i < c.si-1; i++ { | |||
if v.segments[i] != c.segments[i] { | |||
return false | |||
} | |||
} | |||
// Check the last part of the segment in the constraint. If the version segment at | |||
// this index is less than the constraints segment at this index, then it cannot | |||
// be valid against the constraint | |||
if c.segments[cs-1] > v.segments[cs-1] { | |||
return false | |||
} | |||
// If nothing has rejected the version by now, it's valid | |||
return true | |||
} |
@ -0,0 +1 @@ | |||
module github.com/hashicorp/go-version |
@ -0,0 +1,384 @@ | |||
package version | |||
import ( | |||
"bytes" | |||
"fmt" | |||
"reflect" | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
) | |||
// The compiled regular expression used to test the validity of a version. | |||
var ( | |||
versionRegexp *regexp.Regexp | |||
semverRegexp *regexp.Regexp | |||
) | |||
// The raw regular expression string used for testing the validity | |||
// of a version. | |||
const ( | |||
VersionRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + | |||
`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-?([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + | |||
`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + | |||
`?` | |||
// SemverRegexpRaw requires a separator between version and prerelease | |||
SemverRegexpRaw string = `v?([0-9]+(\.[0-9]+)*?)` + | |||
`(-([0-9]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)|(-([A-Za-z\-~]+[0-9A-Za-z\-~]*(\.[0-9A-Za-z\-~]+)*)))?` + | |||
`(\+([0-9A-Za-z\-~]+(\.[0-9A-Za-z\-~]+)*))?` + | |||
`?` | |||
) | |||
// Version represents a single version. | |||
type Version struct { | |||
metadata string | |||
pre string | |||
segments []int64 | |||
si int | |||
original string | |||
} | |||
func init() { | |||
versionRegexp = regexp.MustCompile("^" + VersionRegexpRaw + "$") | |||
semverRegexp = regexp.MustCompile("^" + SemverRegexpRaw + "$") | |||
} | |||
// NewVersion parses the given version and returns a new | |||
// Version. | |||
func NewVersion(v string) (*Version, error) { | |||
return newVersion(v, versionRegexp) | |||
} | |||
// NewSemver parses the given version and returns a new | |||
// Version that adheres strictly to SemVer specs | |||
// https://semver.org/ | |||
func NewSemver(v string) (*Version, error) { | |||
return newVersion(v, semverRegexp) | |||
} | |||
func newVersion(v string, pattern *regexp.Regexp) (*Version, error) { | |||
matches := pattern.FindStringSubmatch(v) | |||
if matches == nil { | |||
return nil, fmt.Errorf("Malformed version: %s", v) | |||
} | |||
segmentsStr := strings.Split(matches[1], ".") | |||
segments := make([]int64, len(segmentsStr)) | |||
si := 0 | |||
for i, str := range segmentsStr { | |||
val, err := strconv.ParseInt(str, 10, 64) | |||
if err != nil { | |||
return nil, fmt.Errorf( | |||
"Error parsing version: %s", err) | |||
} | |||
segments[i] = int64(val) | |||
si++ | |||
} | |||
// Even though we could support more than three segments, if we | |||
// got less than three, pad it with 0s. This is to cover the basic | |||
// default usecase of semver, which is MAJOR.MINOR.PATCH at the minimum | |||
for i := len(segments); i < 3; i++ { | |||
segments = append(segments, 0) | |||
} | |||
pre := matches[7] | |||
if pre == "" { | |||
pre = matches[4] | |||
} | |||
return &Version{ | |||
metadata: matches[10], | |||
pre: pre, | |||
segments: segments, | |||
si: si, | |||
original: v, | |||
}, nil | |||
} | |||
// Must is a helper that wraps a call to a function returning (*Version, error) | |||
// and panics if error is non-nil. | |||
func Must(v *Version, err error) *Version { | |||
if err != nil { | |||
panic(err) | |||
} | |||
return v | |||
} | |||
// Compare compares this version to another version. This | |||
// returns -1, 0, or 1 if this version is smaller, equal, | |||
// or larger than the other version, respectively. | |||
// | |||
// If you want boolean results, use the LessThan, Equal, | |||
// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods. | |||
func (v *Version) Compare(other *Version) int { | |||
// A quick, efficient equality check | |||
if v.String() == other.String() { | |||
return 0 | |||
} | |||
segmentsSelf := v.Segments64() | |||
segmentsOther := other.Segments64() | |||
// If the segments are the same, we must compare on prerelease info | |||
if reflect.DeepEqual(segmentsSelf, segmentsOther) { | |||
preSelf := v.Prerelease() | |||
preOther := other.Prerelease() | |||
if preSelf == "" && preOther == "" { | |||
return 0 | |||
} | |||
if preSelf == "" { | |||
return 1 | |||
} | |||
if preOther == "" { | |||
return -1 | |||
} | |||
return comparePrereleases(preSelf, preOther) | |||
} | |||
// Get the highest specificity (hS), or if they're equal, just use segmentSelf length | |||
lenSelf := len(segmentsSelf) | |||
lenOther := len(segmentsOther) | |||
hS := lenSelf | |||
if lenSelf < lenOther { | |||
hS = lenOther | |||
} | |||
// Compare the segments | |||
// Because a constraint could have more/less specificity than the version it's | |||
// checking, we need to account for a lopsided or jagged comparison | |||
for i := 0; i < hS; i++ { | |||
if i > lenSelf-1 { | |||
// This means Self had the lower specificity | |||
// Check to see if the remaining segments in Other are all zeros | |||
if !allZero(segmentsOther[i:]) { | |||
// if not, it means that Other has to be greater than Self | |||
return -1 | |||
} | |||
break | |||
} else if i > lenOther-1 { | |||
// this means Other had the lower specificity | |||
// Check to see if the remaining segments in Self are all zeros - | |||
if !allZero(segmentsSelf[i:]) { | |||
//if not, it means that Self has to be greater than Other | |||
return 1 | |||
} | |||
break | |||
} | |||
lhs := segmentsSelf[i] | |||
rhs := segmentsOther[i] | |||
if lhs == rhs { | |||
continue | |||
} else if lhs < rhs { | |||
return -1 | |||
} | |||
// Otherwis, rhs was > lhs, they're not equal | |||
return 1 | |||
} | |||
// if we got this far, they're equal | |||
return 0 | |||
} | |||
func allZero(segs []int64) bool { | |||
for _, s := range segs { | |||
if s != 0 { | |||
return false | |||
} | |||
} | |||
return true | |||
} | |||
func comparePart(preSelf string, preOther string) int { | |||
if preSelf == preOther { | |||
return 0 | |||
} | |||
var selfInt int64 | |||
selfNumeric := true | |||
selfInt, err := strconv.ParseInt(preSelf, 10, 64) | |||
if err != nil { | |||
selfNumeric = false | |||
} | |||
var otherInt int64 | |||
otherNumeric := true | |||
otherInt, err = strconv.ParseInt(preOther, 10, 64) | |||
if err != nil { | |||
otherNumeric = false | |||
} | |||
// if a part is empty, we use the other to decide | |||
if preSelf == "" { | |||
if otherNumeric { | |||
return -1 | |||
} | |||
return 1 | |||
} | |||
if preOther == "" { | |||
if selfNumeric { | |||
return 1 | |||
} | |||
return -1 | |||
} | |||
if selfNumeric && !otherNumeric { | |||
return -1 | |||
} else if !selfNumeric && otherNumeric { | |||
return 1 | |||
} else if !selfNumeric && !otherNumeric && preSelf > preOther { | |||
return 1 | |||
} else if selfInt > otherInt { | |||
return 1 | |||
} | |||
return -1 | |||
} | |||
func comparePrereleases(v string, other string) int { | |||
// the same pre release! | |||
if v == other { | |||
return 0 | |||
} | |||
// split both pre releases for analyse their parts | |||
selfPreReleaseMeta := strings.Split(v, ".") | |||
otherPreReleaseMeta := strings.Split(other, ".") | |||
selfPreReleaseLen := len(selfPreReleaseMeta) | |||
otherPreReleaseLen := len(otherPreReleaseMeta) | |||
biggestLen := otherPreReleaseLen | |||
if selfPreReleaseLen > otherPreReleaseLen { | |||
biggestLen = selfPreReleaseLen | |||
} | |||
// loop for parts to find the first difference | |||
for i := 0; i < biggestLen; i = i + 1 { | |||
partSelfPre := "" | |||
if i < selfPreReleaseLen { | |||
partSelfPre = selfPreReleaseMeta[i] | |||
} | |||
partOtherPre := "" | |||
if i < otherPreReleaseLen { | |||
partOtherPre = otherPreReleaseMeta[i] | |||
} | |||
compare := comparePart(partSelfPre, partOtherPre) | |||
// if parts are equals, continue the loop | |||
if compare != 0 { | |||
return compare | |||
} | |||
} | |||
return 0 | |||
} | |||
// Equal tests if two versions are equal. | |||
func (v *Version) Equal(o *Version) bool { | |||
if v == nil || o == nil { | |||
return v == o | |||
} | |||
return v.Compare(o) == 0 | |||
} | |||
// GreaterThan tests if this version is greater than another version. | |||
func (v *Version) GreaterThan(o *Version) bool { | |||
return v.Compare(o) > 0 | |||
} | |||
// GreaterThanOrEqual tests if this version is greater than or equal to another version. | |||
func (v *Version) GreaterThanOrEqual(o *Version) bool { | |||
return v.Compare(o) >= 0 | |||
} | |||
// LessThan tests if this version is less than another version. | |||
func (v *Version) LessThan(o *Version) bool { | |||
return v.Compare(o) < 0 | |||
} | |||
// LessThanOrEqual tests if this version is less than or equal to another version. | |||
func (v *Version) LessThanOrEqual(o *Version) bool { | |||
return v.Compare(o) <= 0 | |||
} | |||
// Metadata returns any metadata that was part of the version | |||
// string. | |||
// | |||
// Metadata is anything that comes after the "+" in the version. | |||
// For example, with "1.2.3+beta", the metadata is "beta". | |||
func (v *Version) Metadata() string { | |||
return v.metadata | |||
} | |||
// Prerelease returns any prerelease data that is part of the version, | |||
// or blank if there is no prerelease data. | |||
// | |||
// Prerelease information is anything that comes after the "-" in the | |||
// version (but before any metadata). For example, with "1.2.3-beta", | |||
// the prerelease information is "beta". | |||
func (v *Version) Prerelease() string { | |||
return v.pre | |||
} | |||
// Segments returns the numeric segments of the version as a slice of ints. | |||
// | |||
// This excludes any metadata or pre-release information. For example, | |||
// for a version "1.2.3-beta", segments will return a slice of | |||
// 1, 2, 3. | |||
func (v *Version) Segments() []int { | |||
segmentSlice := make([]int, len(v.segments)) | |||
for i, v := range v.segments { | |||
segmentSlice[i] = int(v) | |||
} | |||
return segmentSlice | |||
} | |||
// Segments64 returns the numeric segments of the version as a slice of int64s. | |||
// | |||
// This excludes any metadata or pre-release information. For example, | |||
// for a version "1.2.3-beta", segments will return a slice of | |||
// 1, 2, 3. | |||
func (v *Version) Segments64() []int64 { | |||
result := make([]int64, len(v.segments)) | |||
copy(result, v.segments) | |||
return result | |||
} | |||
// String returns the full version string included pre-release | |||
// and metadata information. | |||
// | |||
// This value is rebuilt according to the parsed segments and other | |||
// information. Therefore, ambiguities in the version string such as | |||
// prefixed zeroes (1.04.0 => 1.4.0), `v` prefix (v1.0.0 => 1.0.0), and | |||
// missing parts (1.0 => 1.0.0) will be made into a canonicalized form | |||
// as shown in the parenthesized examples. | |||
func (v *Version) String() string { | |||
var buf bytes.Buffer | |||
fmtParts := make([]string, len(v.segments)) | |||
for i, s := range v.segments { | |||
// We can ignore err here since we've pre-parsed the values in segments | |||
str := strconv.FormatInt(s, 10) | |||
fmtParts[i] = str | |||
} | |||
fmt.Fprintf(&buf, strings.Join(fmtParts, ".")) | |||
if v.pre != "" { | |||
fmt.Fprintf(&buf, "-%s", v.pre) | |||
} | |||
if v.metadata != "" { | |||
fmt.Fprintf(&buf, "+%s", v.metadata) | |||
} | |||
return buf.String() | |||
} | |||
// Original returns the original parsed version as-is, including any | |||
// potential whitespace, `v` prefix, etc. | |||
func (v *Version) Original() string { | |||
return v.original | |||
} |
@ -0,0 +1,17 @@ | |||
package version | |||
// Collection is a type that implements the sort.Interface interface | |||
// so that versions can be sorted. | |||
type Collection []*Version | |||
func (v Collection) Len() int { | |||
return len(v) | |||
} | |||
func (v Collection) Less(i, j int) bool { | |||
return v[i].LessThan(v[j]) | |||
} | |||
func (v Collection) Swap(i, j int) { | |||
v[i], v[j] = v[j], v[i] | |||
} |
@ -1,22 +0,0 @@ | |||
# Compiled Object files, Static and Dynamic libs (Shared Objects) | |||
*.o | |||
*.a | |||
*.so | |||
# Folders | |||
_obj | |||
_test | |||
# Architecture specific extensions/prefixes | |||
*.[568vq] | |||
[568vq].out | |||
*.cgo1.go | |||
*.cgo2.c | |||
_cgo_defun.c | |||
_cgo_gotypes.go | |||
_cgo_export.* | |||
_testmain.go | |||
*.exe |
@ -1 +0,0 @@ | |||
language: go |
@ -1,19 +0,0 @@ | |||
Copyright (c) 2013 Máximo Cuadros | |||
Permission is hereby granted, free of charge, to any person obtaining a copy | |||
of this software and associated documentation files (the "Software"), to deal | |||
in the Software without restriction, including without limitation the rights | |||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
copies of the Software, and to permit persons to whom the Software is furnished | |||
to do so, subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all | |||
copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
THE SOFTWARE. |
@ -1,80 +0,0 @@ | |||
go-version [![Build Status](https://travis-ci.org/mcuadros/go-version.svg?branch=master)](https://travis-ci.org/mcuadros/go-version) [![GoDoc](https://godoc.org/github.com/mcuadros/go-version?status.svg)](http://godoc.org/github.com/mcuadros/go-version) | |||
============================== | |||
Version normalizer and comparison library for go, heavy based on PHP version_compare function and Version comparsion libs from [Composer](https://github.com/composer/composer) PHP project | |||
Installation | |||
The recommended way to install go-version | |||
``` | |||
go get github.com/mcuadros/go-version | |||
``` | |||
Examples | |||
How import the package | |||
```go | |||
import ( | |||
"github.com/mcuadros/go-version" | |||
) | |||
``` | |||
`version.Normalize()`: Normalizes a version string to be able to perform comparisons on it | |||
```go | |||
version.Normalize("10.4.13-b") | |||
//Returns: 10.4.13.0-beta | |||
``` | |||
`version.CompareSimple()`: Compares two normalizated version number strings | |||
```go | |||
version.CompareSimple("1.2", "1.0.1") | |||
//Returns: 1 | |||
version.CompareSimple("1.0rc1", "1.0") | |||
//Returns: -1 | |||
``` | |||
`version.Compare()`: Compares two normalizated version number strings, for a particular relationship | |||
```go | |||
version.Compare("1.0-dev", "1.0", "<") | |||
//Returns: true | |||
version.Compare("1.0rc1", "1.0", ">=") | |||
//Returns: false | |||
version.Compare("2.3.4", "v3.1.2", "<") | |||
//Returns: true | |||
``` | |||
`version.ConstrainGroup.Match()`: Match a given version againts a group of constrains, read about constraint string format at [Composer documentation](http://getcomposer.org/doc/01-basic-usage.md#package-versions) | |||
```go | |||
c := version.NewConstrainGroupFromString(">2.0,<=3.0") | |||
c.Match("2.5.0beta") | |||
//Returns: true | |||
c := version.NewConstrainGroupFromString("~1.2.3") | |||
c.Match("1.2.3.5") | |||
//Returns: true | |||
``` | |||
`version.Sort()`: Sorts a string slice of version number strings using version.CompareSimple() | |||
```go | |||
version.Sort([]string{"1.10-dev", "1.0rc1", "1.0", "1.0-dev"}) | |||
//Returns []string{"1.0-dev", "1.0rc1", "1.0", "1.10-dev"} | |||
``` | |||
License | |||
MIT, see [LICENSE](LICENSE) |
@ -1,173 +0,0 @@ | |||
package version | |||
import ( | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
) | |||
var regexpSigns = regexp.MustCompile(`[_\-+]`) | |||
var regexpDotBeforeDigit = regexp.MustCompile(`([^.\d]+)`) | |||
var regexpMultipleDots = regexp.MustCompile(`\.{2,}`) | |||
var specialForms = map[string]int{ | |||
"SNAPSHOT": -7, | |||
"snapshot": -7, | |||
"dev": -6, | |||
"alpha": -5, | |||
"a": -5, | |||
"beta": -4, | |||
"b": -4, | |||
"RC": -3, | |||
"rc": -3, | |||
"#": -2, | |||
"p": 1, | |||
"pl": 1, | |||
} | |||
var unknownForm int = -7 | |||
// Compares two version number strings, for a particular relationship | |||
// | |||
// Usage | |||
// version.Compare("2.3.4", "v3.1.2", "<") | |||
// Returns: true | |||
// | |||
// version.Compare("1.0rc1", "1.0", ">=") | |||
// Returns: false | |||
func Compare(version1, version2, operator string) bool { | |||
version1N := Normalize(version1) | |||
version2N := Normalize(version2) | |||
return CompareNormalized(version1N, version2N, operator) | |||
} | |||
// Compares two normalizated version number strings, for a particular relationship | |||
// | |||
// The function first replaces _, - and + with a dot . in the version strings | |||
// and also inserts dots . before and after any non number so that for example | |||
// '4.3.2RC1' becomes '4.3.2.RC.1'. | |||
// | |||
// Then it splits the results like if you were using Split(version, '.'). | |||
// Then it compares the parts starting from left to right. If a part contains | |||
// special version strings these are handled in the following order: any string | |||
// not found in this list: | |||
// < dev < alpha = a < beta = b < RC = rc < # < pl = p. | |||
// | |||
// Usage | |||
// version.CompareNormalized("1.0-dev", "1.0", "<") | |||
// Returns: true | |||
// | |||
// version.CompareNormalized("1.0rc1", "1.0", ">=") | |||
// Returns: false | |||
// | |||
// version.CompareNormalized("1.0", "1.0b1", "ge") | |||
// Returns: true | |||
func CompareNormalized(version1, version2, operator string) bool { | |||
compare := CompareSimple(version1, version2) | |||
switch { | |||
case operator == ">" || operator == "gt": | |||
return compare > 0 | |||
case operator == ">=" || operator == "ge": | |||
return compare >= 0 | |||
case operator == "<=" || operator == "le": | |||
return compare <= 0 | |||
case operator == "==" || operator == "=" || operator == "eq": | |||
return compare == 0 | |||
case operator == "<>" || operator == "!=" || operator == "ne": | |||
return compare != 0 | |||
case operator == "" || operator == "<" || operator == "lt": | |||
return compare < 0 | |||
} | |||
return false | |||
} | |||
// Compares two normalizated version number strings | |||
// | |||
// Just the same of CompareVersion but return a int result, 0 if both version | |||
// are equal, 1 if the right side is bigger and -1 if the right side is lower | |||
// | |||
// Usage | |||
// version.CompareSimple("1.2", "1.0.1") | |||
// Returns: 1 | |||
// | |||
// version.CompareSimple("1.0rc1", "1.0") | |||
// Returns: -1 | |||
func CompareSimple(version1, version2 string) int { | |||
var x, r, l int = 0, 0, 0 | |||
v1, v2 := prepVersion(version1), prepVersion(version2) | |||
len1, len2 := len(v1), len(v2) | |||
if len1 > len2 { | |||
x = len1 | |||
} else { | |||
x = len2 | |||
} | |||
for i := 0; i < x; i++ { | |||
if i < len1 && i < len2 { | |||
if v1[i] == v2[i] { | |||
continue | |||
} | |||
} | |||
r = 0 | |||
if i < len1 { | |||
r = numVersion(v1[i]) | |||
} | |||
l = 0 | |||
if i < len2 { | |||
l = numVersion(v2[i]) | |||
} | |||
if r < l { | |||
return -1 | |||
} else if r > l { | |||
return 1 | |||
} | |||
} | |||
return 0 | |||
} | |||
func prepVersion(version string) []string { | |||
if len(version) == 0 { | |||
return []string{""} | |||
} | |||
version = regexpSigns.ReplaceAllString(version, ".") | |||
version = regexpDotBeforeDigit.ReplaceAllString(version, ".$1.") | |||
version = regexpMultipleDots.ReplaceAllString(version, ".") | |||
return strings.Split(version, ".") | |||
} | |||
func numVersion(value string) int { | |||
if value == "" { | |||
return 0 | |||
} | |||
if number, err := strconv.Atoi(value); err == nil { | |||
return number | |||
} | |||
if special, ok := specialForms[value]; ok { | |||
return special | |||
} | |||
return unknownForm | |||
} | |||
func ValidSimpleVersionFormat(value string) bool { | |||
normalized := Normalize(value) | |||
for _, component := range prepVersion(normalized) { | |||
if numVersion(component) == unknownForm { | |||
return false | |||
} | |||
} | |||
return true | |||
} |
@ -1,49 +0,0 @@ | |||
package version | |||
import ( | |||
"strings" | |||
) | |||
type Constraint struct { | |||
operator string | |||
version string | |||
} | |||
// Return a new Constrain and sets operator and version to compare | |||
func NewConstrain(operator, version string) *Constraint { | |||
constraint := new(Constraint) | |||
constraint.SetOperator(operator) | |||
constraint.SetVersion(version) | |||
return constraint | |||
} | |||
// Sets operator to compare | |||
func (self *Constraint) SetOperator(operator string) { | |||
self.operator = operator | |||
} | |||
// Get operator to compare | |||
func (self *Constraint) GetOperator() string { | |||
return self.operator | |||
} | |||
// Sets version to compare | |||
func (self *Constraint) SetVersion(version string) { | |||
self.version = version | |||
} | |||
// Get version to compare | |||
func (self *Constraint) GetVersion() string { | |||
return self.version | |||
} | |||
// Match a given version againts the constraint | |||
func (self *Constraint) Match(version string) bool { | |||
return Compare(version, self.version, self.operator) | |||
} | |||
// Return a string representation | |||
func (self *Constraint) String() string { | |||
return strings.Trim(self.operator+" "+self.version, " ") | |||
} |
@ -1,6 +0,0 @@ | |||
/* | |||
Version normalizer and comparison library for go, heavy based on PHP | |||
version_compare function and Version comparsion libs from Composer | |||
(https://github.com/composer/composer) PHP project | |||
*/ | |||
package version |
@ -1,300 +0,0 @@ | |||
package version | |||
import ( | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
"sync" | |||
) | |||
type ConstraintGroup struct { | |||
constraints []*Constraint | |||
} | |||
// Return a new NewConstrainGroup | |||
func NewConstrainGroup() *ConstraintGroup { | |||
group := new(ConstraintGroup) | |||
return group | |||
} | |||
// Return a new NewConstrainGroup and create the constraints based on a string | |||
// | |||
// Version constraints can be specified in a few different ways: | |||
// | |||
// Exact version: You can specify the exact version of a package, for | |||
// example 1.0.2. | |||
// | |||
// Range: By using comparison operators you can specify ranges of valid versions. | |||
// Valid operators are >, >=, <, <=, !=. An example range would be >=1.0. You can | |||
// define multiple ranges, separated by a comma: >=1.0,<2.0. | |||
// | |||
// Wildcard: You can specify a pattern with a * wildcard. 1.0.* is the equivalent | |||
// of >=1.0,<1.1. | |||
// | |||
// Next Significant Release (Tilde Operator): The ~ operator is best explained by | |||
// example: ~1.2 is equivalent to >=1.2,<2.0, while ~1.2.3 is equivalent to | |||
// >=1.2.3,<1.3. As you can see it is mostly useful for projects respecting | |||
// semantic versioning. A common usage would be to mark the minimum minor | |||
// version you depend on, like ~1.2 (which allows anything up to, but not | |||
// including, 2.0). Since in theory there should be no backwards compatibility | |||
// breaks until 2.0, that works well. Another way of looking at it is that | |||
// using ~ specifies a minimum version, but allows the last digit specified | |||
// to go up. | |||
// | |||
// By default only stable releases are taken into consideration. If you would like | |||
// to also get RC, beta, alpha or dev versions of your dependencies you can do so | |||
// using stability flags. To change that for all packages instead of doing per | |||
// dependency you can also use the minimum-stability setting. | |||
// | |||
// From: http://getcomposer.org/doc/01-basic-usage.md#package-versions | |||
func NewConstrainGroupFromString(name string) *ConstraintGroup { | |||
group := new(ConstraintGroup) | |||
group.fromString(name) | |||
return group | |||
} | |||
// Adds a Contraint to the group | |||
func (self *ConstraintGroup) AddConstraint(constraint ...*Constraint) { | |||
if self.constraints == nil { | |||
self.constraints = make([]*Constraint, 0) | |||
} | |||
self.constraints = append(self.constraints, constraint...) | |||
} | |||
// Return all the constraints | |||
func (self *ConstraintGroup) GetConstraints() []*Constraint { | |||
return self.constraints | |||
} | |||
// Match a given version againts the group | |||
// | |||
// Usage | |||
// c := version.NewConstrainGroupFromString(">2.0,<=3.0") | |||
// c.Match("2.5.0beta") | |||
// Returns: true | |||
// | |||
// c := version.NewConstrainGroupFromString("~1.2.3") | |||
// c.Match("1.2.3.5") | |||
// Returns: true | |||
func (self *ConstraintGroup) Match(version string) bool { | |||
for _, constraint := range self.constraints { | |||
if constraint.Match(version) == false { | |||
return false | |||
} | |||
} | |||
return true | |||
} | |||
func (self *ConstraintGroup) fromString(constraint string) bool { | |||
result := RegFind(`(?i)^([^,\s]*?)@(stable|RC|beta|alpha|dev)$`, constraint) | |||
if result != nil { | |||
constraint = result[1] | |||
if constraint == "" { | |||
constraint = "*" | |||
} | |||
} | |||
result = RegFind(`(?i)^(dev-[^,\s@]+?|[^,\s@]+?\.x-dev)#.+$`, constraint) | |||
if result != nil { | |||
if result[1] != "" { | |||
constraint = result[1] | |||
} | |||
} | |||
constraints := RegSplit(`\s*,\s*`, strings.Trim(constraint, " ")) | |||
if len(constraints) > 1 { | |||
for _, part := range constraints { | |||
self.AddConstraint(self.parseConstraint(part)...) | |||
} | |||
return true | |||
} | |||
self.AddConstraint(self.parseConstraint(constraints[0])...) | |||
return true | |||
} | |||
func (self *ConstraintGroup) parseConstraint(constraint string) []*Constraint { | |||
stabilityModifier := "" | |||
result := RegFind(`(?i)^([^,\s]+?)@(stable|RC|beta|alpha|dev)$`, constraint) | |||
if result != nil { | |||
constraint = result[1] | |||
if result[2] != "stable" { | |||
stabilityModifier = result[2] | |||
} | |||
} | |||
result = RegFind(`^[x*](\.[x*])*$`, constraint) | |||
if result != nil { | |||
return make([]*Constraint, 0) | |||
} | |||
highVersion := "" | |||
lowVersion := "" | |||
result = RegFind(`(?i)^~(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:\.(\d+))?`+modifierRegex+`?$`, constraint) | |||
if result != nil { | |||
if len(result) > 4 && result[4] != "" { | |||
last, _ := strconv.Atoi(result[3]) | |||
highVersion = result[1] + "." + result[2] + "." + strconv.Itoa(last+1) + ".0-dev" | |||
lowVersion = result[1] + "." + result[2] + "." + result[3] + "." + result[4] | |||
} else if len(result) > 3 && result[3] != "" { | |||
last, _ := strconv.Atoi(result[2]) | |||
highVersion = result[1] + "." + strconv.Itoa(last+1) + ".0.0-dev" | |||
lowVersion = result[1] + "." + result[2] + "." + result[3] + ".0" | |||
} else { | |||
last, _ := strconv.Atoi(result[1]) | |||
highVersion = strconv.Itoa(last+1) + ".0.0.0-dev" | |||
if len(result) > 2 && result[2] != "" { | |||
lowVersion = result[1] + "." + result[2] + ".0.0" | |||
} else { | |||
lowVersion = result[1] + ".0.0.0" | |||
} | |||
} | |||
if len(result) > 5 && result[5] != "" { | |||
lowVersion = lowVersion + "-" + expandStability(result[5]) | |||
} | |||
if len(result) > 6 && result[6] != "" { | |||
lowVersion = lowVersion + result[6] | |||
} | |||
if len(result) > 7 && result[7] != "" { | |||
lowVersion = lowVersion + "-dev" | |||
} | |||
return []*Constraint{ | |||
{">=", lowVersion}, | |||
{"<", highVersion}, | |||
} | |||
} | |||
result = RegFind(`^(\d+)(?:\.(\d+))?(?:\.(\d+))?\.[x*]$`, constraint) | |||
if result != nil { | |||
if len(result) > 3 && result[3] != "" { | |||
highVersion = result[1] + "." + result[2] + "." + result[3] + ".9999999" | |||
if result[3] == "0" { | |||
last, _ := strconv.Atoi(result[2]) | |||
lowVersion = result[1] + "." + strconv.Itoa(last-1) + ".9999999.9999999" | |||
} else { | |||
last, _ := strconv.Atoi(result[3]) | |||
lowVersion = result[1] + "." + result[2] + "." + strconv.Itoa(last-1) + ".9999999" | |||
} | |||
} else if len(result) > 2 && result[2] != "" { | |||
highVersion = result[1] + "." + result[2] + ".9999999.9999999" | |||
if result[2] == "0" { | |||
last, _ := strconv.Atoi(result[1]) | |||
lowVersion = strconv.Itoa(last-1) + ".9999999.9999999.9999999" | |||
} else { | |||
last, _ := strconv.Atoi(result[2]) | |||
lowVersion = result[1] + "." + strconv.Itoa(last-1) + ".9999999.9999999" | |||
} | |||
} else { | |||
highVersion = result[1] + ".9999999.9999999.9999999" | |||
if result[1] == "0" { | |||
return []*Constraint{{"<", highVersion}} | |||
} else { | |||
last, _ := strconv.Atoi(result[1]) | |||
lowVersion = strconv.Itoa(last-1) + ".9999999.9999999.9999999" | |||
} | |||
} | |||
return []*Constraint{ | |||
{">", lowVersion}, | |||
{"<", highVersion}, | |||
} | |||
} | |||
// match operators constraints | |||
result = RegFind(`^(<>|!=|>=?|<=?|==?)?\s*(.*)`, constraint) | |||
if result != nil { | |||
version := Normalize(result[2]) | |||
if stabilityModifier != "" && parseStability(version) == "stable" { | |||
version = version + "-" + stabilityModifier | |||
} else if result[1] == "<" { | |||
match := RegFind(`(?i)-stable$`, result[2]) | |||
if match == nil { | |||
version = version + "-dev" | |||
} | |||
} | |||
if len(result) > 1 && result[1] != "" { | |||
return []*Constraint{{result[1], version}} | |||
} else { | |||
return []*Constraint{{"=", version}} | |||
} | |||
} | |||
return []*Constraint{{constraint, stabilityModifier}} | |||
} | |||
// PCRegMap : PreCompiled Regex Map | |||
type PCRegMap struct { | |||
sync.RWMutex | |||
m map[string]*regexp.Regexp | |||
} | |||
// MustCompile : to replace regexp.MustCompile in RegFind. | |||
func (p *PCRegMap) MustCompile(pattern string) *regexp.Regexp { | |||
p.RLock() | |||
ret, exist := p.m[pattern] | |||
p.RUnlock() | |||
if exist { | |||
return ret | |||
} | |||
ret = regexp.MustCompile(pattern) | |||
p.Lock() | |||
p.m[pattern] = ret | |||
p.Unlock() | |||
return ret | |||
} | |||
var ( | |||
regexpCache *PCRegMap | |||
) | |||
func init() { | |||
regexpCache = new(PCRegMap) | |||
regexpCache.m = make(map[string]*regexp.Regexp) | |||
} | |||
func RegFind(pattern, subject string) []string { | |||
reg := regexpCache.MustCompile(pattern) | |||
matched := reg.FindAllStringSubmatch(subject, -1) | |||
if matched != nil { | |||
return matched[0] | |||
} | |||
return nil | |||
} | |||
func RegSplit(pattern, subject string) []string { | |||
reg := regexp.MustCompile(pattern) | |||
indexes := reg.FindAllStringIndex(subject, -1) | |||
laststart := 0 | |||
result := make([]string, len(indexes)+1) | |||
for i, element := range indexes { | |||
result[i] = subject[laststart:element[0]] | |||
laststart = element[1] | |||
} | |||
result[len(indexes)] = subject[laststart:len(subject)] | |||
return result | |||
} |
@ -1,116 +0,0 @@ | |||
package version | |||
import ( | |||
"regexp" | |||
"strings" | |||
) | |||
var modifierRegex = `[._-]?(?:(stable|beta|b|RC|alpha|a|patch|pl|p)(?:[.-]?(\d+))?)?([.-]?dev)?` | |||
var regexpMasterLikeBranches = regexp.MustCompile(`^(?:dev-)?(?:master|trunk|default)$`) | |||
var regexpBranchNormalize = regexp.MustCompile(`(?i)^v?(\d+)(\.(?:\d+|[x*]))?(\.(?:\d+|[x*]))?(\.(?:\d+|[x*]))?$`) | |||
// Normalizes a version string to be able to perform comparisons on it | |||
// | |||
// Example: | |||
// version.Normalize("10.4.13-b") | |||
// Returns: 10.4.13.0-beta | |||
// | |||
func Normalize(version string) string { | |||
// ignore aliases and just assume the alias is required instead of the source | |||
result := RegFind(`^([^,\s]+) +as +([^,\s]+)$`, version) | |||
if result != nil { | |||
version = result[1] | |||
} | |||
// match master-like branches | |||
if regexpMasterLikeBranches.MatchString(strings.ToLower(version)) { | |||
return "9999999-dev" | |||
} | |||
if strings.HasPrefix(strings.ToLower(version), "dev-") { | |||
return "dev-" + version[4:len(version)] | |||
} | |||
index := 0 | |||
// match classical versioning | |||
result = RegFind(`(?i)^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?`+modifierRegex+`$`, version) | |||
if result != nil { | |||
version = "" | |||
for _, val := range result[1:5] { | |||
if val != "" { | |||
version = version + val | |||
} else { | |||
version = version + ".0" | |||
} | |||
} | |||
index = 5 | |||
} else { | |||
// match date-based versioning | |||
result = RegFind(`(?i)^v?(\d{4}(?:[.:-]?\d{2}){1,6}(?:[.:-]?\d{1,3})?)`+modifierRegex+`$`, version) | |||
if result != nil { | |||
version = regexp.MustCompile(`\D`).ReplaceAllString(result[1], "-") | |||
index = 2 | |||
} | |||
} | |||
if index != 0 { | |||
if result[index] != "" { | |||
if result[index] == "stable" { | |||
return version | |||
} | |||
version = version + "-" + expandStability(result[index]) | |||
if result[index+1] != "" { | |||
version = version + result[index+1] | |||
} | |||
} | |||
if result[index+2] != "" { | |||
version = version + "-dev" | |||
} | |||
return version | |||
} | |||
result = RegFind(`(?i)(.*?)[.-]?dev$`, version) | |||
if result != nil { | |||
return normalizeBranch(result[1]) | |||
} | |||
return version | |||
} | |||
func normalizeBranch(name string) string { | |||
name = strings.Trim(name, " ") | |||
if name == "master" || name == "trunk" || name == "default" { | |||
return Normalize(name) | |||
} | |||
replace := strings.NewReplacer("*", "9999999", "x", "9999999") | |||
matched := regexpBranchNormalize.FindAllStringSubmatch(name, -1) | |||
if matched != nil { | |||
name = "" | |||
for _, val := range matched[0][1:5] { | |||
if val != "" { | |||
name = name + replace.Replace(val) | |||
} else { | |||
name = name + ".9999999" | |||
} | |||
} | |||
return name + "-dev" | |||
} | |||
if strings.HasSuffix(strings.ToLower(name), "-dev") { | |||
return name | |||
} | |||
return "dev-" + name | |||
} |
@ -1,36 +0,0 @@ | |||
package version | |||
import ( | |||
"sort" | |||
) | |||
// Sorts a string slice of version number strings using version.CompareSimple() | |||
// | |||
// Example: | |||
// version.Sort([]string{"1.10-dev", "1.0rc1", "1.0", "1.0-dev"}) | |||
// Returns []string{"1.0-dev", "1.0rc1", "1.0", "1.10-dev"} | |||
// | |||
func Sort(versionStrings []string) { | |||
versions := versionSlice(versionStrings) | |||
sort.Sort(versions) | |||
} | |||
type versionSlice []string | |||
func (s versionSlice) Len() int { | |||
return len(s) | |||
} | |||
func (s versionSlice) Less(i, j int) bool { | |||
cmp := CompareSimple(Normalize(s[i]), Normalize(s[j])) | |||
if cmp == 0 { | |||
return s[i] < s[j] | |||
} | |||
return cmp < 0 | |||
} | |||
func (s versionSlice) Swap(i, j int) { | |||
tmp := s[j] | |||
s[j] = s[i] | |||
s[i] = tmp | |||
} |
@ -1,83 +0,0 @@ | |||
package version | |||
import ( | |||
"regexp" | |||
"strings" | |||
) | |||
const ( | |||
Development = iota | |||
Alpha | |||
Beta | |||
RC | |||
Stable | |||
) | |||
func expandStability(stability string) string { | |||
stability = strings.ToLower(stability) | |||
switch stability { | |||
case "a": | |||
return "alpha" | |||
case "b": | |||
return "beta" | |||
case "p": | |||
return "patch" | |||
case "pl": | |||
return "patch" | |||
case "rc": | |||
return "RC" | |||
} | |||
return stability | |||
} | |||
func parseStability(version string) string { | |||
version = regexp.MustCompile(`(?i)#.+$`).ReplaceAllString(version, " ") | |||
version = strings.ToLower(version) | |||
if strings.HasPrefix(version, "dev-") || strings.HasSuffix(version, "-dev") { | |||
return "dev" | |||
} | |||
result := RegFind(`(?i)^v?(\d{1,3})(\.\d+)?(\.\d+)?(\.\d+)?`+modifierRegex+`$`, version) | |||
if result != nil { | |||
if len(result) > 3 { | |||
return "dev" | |||
} | |||
} | |||
if result[1] != "" { | |||
if "beta" == result[1] || "b" == result[1] { | |||
return "beta" | |||
} | |||
if "alpha" == result[1] || "a" == result[1] { | |||
return "alpha" | |||
} | |||
if "rc" == result[1] { | |||
return "RC" | |||
} | |||
} | |||
return "stable" | |||
} | |||
func GetStability(version string) int { | |||
result := RegFind(`(?i)(stable|RC|beta|alpha|dev)`, Normalize(version)) | |||
if len(result) == 0 { | |||
return Stable | |||
} | |||
switch result[1] { | |||
case "dev": | |||
return Development | |||
case "alpha": | |||
return Alpha | |||
case "beta": | |||
return Beta | |||
case "RC": | |||
return RC | |||
} | |||
return Stable | |||
} |